pack: Honor symlinks in the Docker back-end.

* guix/docker.scm (symlink-source, topmost-component): New procedures.
(build-docker-image): Add #:symlinks parameter and honor it.  Remove
hard-coded /bin symlink.
* guix/scripts/pack.scm (docker-image): Pass #:symlinks to
'build-docker-image'.
This commit is contained in:
Ludovic Courtès 2017-03-16 22:40:06 +01:00
parent 54241dc8e6
commit 9e84ea3673
No known key found for this signature in database
GPG key ID: 090B11993D9AEBB5
2 changed files with 38 additions and 11 deletions

View file

@ -21,7 +21,8 @@ (define-module (guix docker)
#:use-module (guix hash) #:use-module (guix hash)
#:use-module (guix base16) #:use-module (guix base16)
#:use-module ((guix build utils) #:use-module ((guix build utils)
#:select (delete-file-recursively #:select (mkdir-p
delete-file-recursively
with-directory-excursion)) with-directory-excursion))
#:use-module (guix build store-copy) #:use-module (guix build store-copy)
#:use-module (srfi srfi-19) #:use-module (srfi srfi-19)
@ -89,14 +90,30 @@ (define %tar-determinism-options
'("--sort=name" "--mtime=@1" '("--sort=name" "--mtime=@1"
"--owner=root:0" "--group=root:0")) "--owner=root:0" "--group=root:0"))
(define symlink-source
(match-lambda
((source '-> target)
(string-trim source #\/))))
(define (topmost-component file)
"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 path (define* (build-docker-image image path
#:key closure compressor #:key closure compressor
(symlinks '())
(creation-time (current-time time-utc))) (creation-time (current-time time-utc)))
"Write to IMAGE a Docker image archive from the given store PATH. The image "Write to IMAGE a Docker image archive from the given store PATH. The image
contains the closure of PATH, as specified in CLOSURE (a file produced by contains the closure of PATH, as specified in CLOSURE (a file produced by
#:references-graphs). Use COMPRESSOR, a command such as '(\"gzip\" \"-9n\"), #:references-graphs). SYMLINKS must be a list of (SOURCE -> TARGET) tuples
to compress IMAGE. Use CREATION-TIME, a SRFI-19 time-utc object, as the describing symlinks to be created in the image, where each TARGET is relative
creation time in metadata." to PATH.
Use COMPRESSOR, a command such as '(\"gzip\" \"-9n\"), to compress IMAGE. Use
CREATION-TIME, a SRFI-19 time-utc object, as the creation time in metadata."
(let ((directory "/tmp/docker-image") ;temporary working directory (let ((directory "/tmp/docker-image") ;temporary working directory
(closure (canonicalize-path closure)) (closure (canonicalize-path closure))
(id (docker-id path)) (id (docker-id path))
@ -110,9 +127,6 @@ (define* (build-docker-image image path
(mkdir directory) (mkdir directory)
(and (with-directory-excursion directory (and (with-directory-excursion directory
;; Add symlink from /bin to /gnu/store/.../bin
(symlink (string-append path "/bin") "bin")
(mkdir id) (mkdir id)
(with-directory-excursion id (with-directory-excursion id
(with-output-to-file "VERSION" (with-output-to-file "VERSION"
@ -120,13 +134,25 @@ (define* (build-docker-image image path
(with-output-to-file "json" (with-output-to-file "json"
(lambda () (scm->json (image-description id time)))) (lambda () (scm->json (image-description id time))))
;; Wrap it up ;; Wrap it up.
(let ((items (call-with-input-file closure (let ((items (call-with-input-file closure
read-reference-graph))) read-reference-graph)))
;; Create SYMLINKS.
(for-each (match-lambda
((source '-> target)
(let ((source (string-trim source #\/)))
(mkdir-p (dirname source))
(symlink (string-append path "/" target)
source))))
symlinks)
(and (zero? (apply system* "tar" "-cf" "layer.tar" (and (zero? (apply system* "tar" "-cf" "layer.tar"
(append %tar-determinism-options (append %tar-determinism-options
(cons "../bin" items)))) items
(delete-file "../bin")))) (map symlink-source symlinks))))
(for-each delete-file-recursively
(map (compose topmost-component symlink-source)
symlinks)))))
(with-output-to-file "config.json" (with-output-to-file "config.json"
(lambda () (lambda ()

View file

@ -189,7 +189,7 @@ (define* (docker-image name profile
"Return a derivation to construct a Docker image of PROFILE. The "Return a derivation to construct a Docker image of PROFILE. The
image is a tarball conforming to the Docker Image Specification, compressed image is a tarball conforming to the Docker Image Specification, compressed
with COMPRESSOR. It can be passed to 'docker load'." with COMPRESSOR. It can be passed to 'docker load'."
;; FIXME: Honor SYMLINKS and LOCALSTATEDIR?. ;; FIXME: Honor LOCALSTATEDIR?.
(define not-config? (define not-config?
(match-lambda (match-lambda
(('guix 'config) #f) (('guix 'config) #f)
@ -227,6 +227,7 @@ (define build
(build-docker-image #$output #$profile (build-docker-image #$output #$profile
#:closure "profile" #:closure "profile"
#:symlinks '#$symlinks
#:compressor '#$(compressor-command compressor) #:compressor '#$(compressor-command compressor)
#:creation-time (make-time time-utc 0 1))))) #:creation-time (make-time time-utc 0 1)))))