docker: Take a list of directives instead of a list of symlinks.

* guix/docker.scm (symlink-source, topmost-component): Remove.
(directive-file): New procedure.
(build-docker-image): Remove #:symlinks and add #:extra-files.
Make a sub-directory "extra" and call 'evaluate-populate-directive' for
EXTRA-FILES in that directory.
* guix/scripts/pack.scm (docker-image)[build](symlink->directives,
directives): New procedures.
Pass #:extra-files instead of #:symlinks to 'build-docker-image'.
This commit is contained in:
Ludovic Courtès 2019-08-27 11:02:14 +02:00
parent b29d6abc8f
commit 2b7c89f4fc
No known key found for this signature in database
GPG Key ID: 090B11993D9AEBB5
2 changed files with 50 additions and 38 deletions

View File

@ -28,11 +28,13 @@
invoke)) invoke))
#:use-module (gnu build install) #:use-module (gnu build install)
#:use-module (json) ;guile-json #:use-module (json) ;guile-json
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-19) #:use-module (srfi srfi-19)
#:use-module (srfi srfi-26) #:use-module (srfi srfi-26)
#:use-module ((texinfo string-utils) #:use-module ((texinfo string-utils)
#:select (escape-special-chars)) #:select (escape-special-chars))
#:use-module (rnrs bytevectors) #:use-module (rnrs bytevectors)
#:use-module (ice-9 ftw)
#:use-module (ice-9 match) #:use-module (ice-9 match)
#:export (build-docker-image)) #:export (build-docker-image))
@ -99,21 +101,18 @@
'("--sort=name" "--mtime=@1" '("--sort=name" "--mtime=@1"
"--owner=root:0" "--group=root:0")) "--owner=root:0" "--group=root:0"))
(define symlink-source (define directive-file
;; Return the file or directory created by a 'evaluate-populate-directive'
;; directive.
(match-lambda (match-lambda
((source '-> target) ((source '-> target)
(string-trim source #\/)))) (string-trim source #\/))
(('directory name _ ...)
(define (topmost-component file) (string-trim name #\/))))
"Return the topmost component of FILE. For instance, if FILE is \"/a/b/c\",
return \"a\"."
(match (string-tokenize file (char-set-complement (char-set #\/)))
((first rest ...)
first)))
(define* (build-docker-image image paths prefix (define* (build-docker-image image paths prefix
#:key #:key
(symlinks '()) (extra-files '())
(transformations '()) (transformations '())
(system (utsname:machine (uname))) (system (utsname:machine (uname)))
database database
@ -133,8 +132,9 @@ entry point in the Docker image JSON structure.
ENVIRONMENT must be a list of name/value pairs. It specifies the environment ENVIRONMENT must be a list of name/value pairs. It specifies the environment
variables that must be defined in the resulting image. variables that must be defined in the resulting image.
SYMLINKS must be a list of (SOURCE -> TARGET) tuples describing symlinks to be EXTRA-FILES must be a list of directives for 'evaluate-populate-directive'
created in the image, where each TARGET is relative to PREFIX. describing non-store files that must be created in the image.
TRANSFORMATIONS must be a list of (OLD -> NEW) tuples describing how to TRANSFORMATIONS must be a list of (OLD -> NEW) tuples describing how to
transform the PATHS. Any path in PATHS that begins with OLD will be rewritten transform the PATHS. Any path in PATHS that begins with OLD will be rewritten
in the Docker image so that it begins with NEW instead. If a path is a in the Docker image so that it begins with NEW instead. If a path is a
@ -199,25 +199,27 @@ SRFI-19 time-utc object, as the creation time in metadata."
(with-output-to-file "json" (with-output-to-file "json"
(lambda () (scm->json (image-description id time)))) (lambda () (scm->json (image-description id time))))
;; Create SYMLINKS. ;; Create a directory for the non-store files that need to go into the
(for-each (match-lambda ;; archive.
((source '-> target) (mkdir "extra")
(let ((source (string-trim source #\/)))
(mkdir-p (dirname source)) (with-directory-excursion "extra"
(symlink (string-append prefix "/" target) ;; Create non-store files.
source)))) (for-each (cut evaluate-populate-directive <> "./")
symlinks) extra-files)
(when database (when database
;; Initialize /var/guix, assuming PREFIX points to a profile. ;; Initialize /var/guix, assuming PREFIX points to a profile.
(install-database-and-gc-roots "." database prefix)) (install-database-and-gc-roots "." database prefix))
(apply invoke "tar" "-cf" "layer.tar" (apply invoke "tar" "-cf" "../layer.tar"
`(,@transformation-options `(,@transformation-options
,@%tar-determinism-options ,@%tar-determinism-options
,@paths ,@paths
,@(if database '("var") '()) ,@(scandir "."
,@(map symlink-source symlinks))) (lambda (file)
(not (member file '("." ".."))))))))
;; It is possible for "/" to show up in the archive, especially when ;; It is possible for "/" to show up in the archive, especially when
;; applying transformations. For example, the transformation ;; applying transformations. For example, the transformation
;; "s,^/a,," will (perhaps surprisingly) cause GNU tar to transform ;; "s,^/a,," will (perhaps surprisingly) cause GNU tar to transform
@ -231,13 +233,7 @@ SRFI-19 time-utc object, as the creation time in metadata."
(lambda () (lambda ()
(system* "tar" "--delete" "/" "-f" "layer.tar"))) (system* "tar" "--delete" "/" "-f" "layer.tar")))
(for-each delete-file-recursively (delete-file-recursively "extra"))
(map (compose topmost-component symlink-source)
symlinks))
;; Delete /var/guix.
(when database
(delete-file-recursively "var")))
(with-output-to-file "config.json" (with-output-to-file "config.json"
(lambda () (lambda ()

View File

@ -490,7 +490,8 @@ the image."
#~(begin #~(begin
(use-modules (guix docker) (guix build store-copy) (use-modules (guix docker) (guix build store-copy)
(guix profiles) (guix search-paths) (guix profiles) (guix search-paths)
(srfi srfi-19) (ice-9 match)) (srfi srfi-1) (srfi srfi-19)
(ice-9 match))
(define environment (define environment
(map (match-lambda (map (match-lambda
@ -499,6 +500,21 @@ the image."
value))) value)))
(profile-search-paths #$profile))) (profile-search-paths #$profile)))
(define symlink->directives
;; Return "populate directives" to make the given symlink and its
;; parent directories.
(match-lambda
((source '-> target)
(let ((target (string-append #$profile "/" target))
(parent (dirname source)))
`((directory ,parent)
(,source -> ,target))))))
(define directives
;; Fully-qualified symlinks.
(append-map symlink->directives '#$symlinks))
(setenv "PATH" (string-append #$archiver "/bin")) (setenv "PATH" (string-append #$archiver "/bin"))
(build-docker-image #$output (build-docker-image #$output
@ -513,7 +529,7 @@ the image."
#$(and entry-point #$(and entry-point
#~(list (string-append #$profile "/" #~(list (string-append #$profile "/"
#$entry-point))) #$entry-point)))
#:symlinks '#$symlinks #:extra-files directives
#:compressor '#$(compressor-command compressor) #:compressor '#$(compressor-command compressor)
#:creation-time (make-time time-utc 0 1)))))) #:creation-time (make-time time-utc 0 1))))))