me
/
guix
Archived
1
0
Fork 0

pack: Add support for the deb format.

* .dir-locals.el (scheme-mode)[gexp->derivation]: Define indentation rule.
* guix/scripts/pack.scm (debian-archive): New procedure.
(%formats): Register the new deb format.
(show-formats): Add it to the usage string.
* tests/pack.scm (%ar-bootstrap): New variable.
(deb archive with symlinks): New test.
* doc/guix.texi (Invoking guix pack): Document it.
* NEWS: Add news entry.
master
Maxim Cournoyer 2021-06-15 10:21:50 -04:00
parent 8108c266dc
commit 82daab4281
No known key found for this signature in database
GPG Key ID: 1260E46482E63562
5 changed files with 265 additions and 3 deletions

View File

@ -75,6 +75,7 @@
(eval . (put 'origin 'scheme-indent-function 0)) (eval . (put 'origin 'scheme-indent-function 0))
(eval . (put 'build-system 'scheme-indent-function 0)) (eval . (put 'build-system 'scheme-indent-function 0))
(eval . (put 'bag 'scheme-indent-function 0)) (eval . (put 'bag 'scheme-indent-function 0))
(eval . (put 'gexp->derivation 'scheme-indent-function 1))
(eval . (put 'graft 'scheme-indent-function 0)) (eval . (put 'graft 'scheme-indent-function 0))
(eval . (put 'operating-system 'scheme-indent-function 0)) (eval . (put 'operating-system 'scheme-indent-function 0))
(eval . (put 'file-system 'scheme-indent-function 0)) (eval . (put 'file-system 'scheme-indent-function 0))

7
NEWS
View File

@ -4,6 +4,7 @@
Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org> Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
Copyright © 2016, 2017, 2018 Ricardo Wurmus <rekado@elephly.net> Copyright © 2016, 2017, 2018 Ricardo Wurmus <rekado@elephly.net>
Copyright © 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com>
Copying and distribution of this file, with or without modification, Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright are permitted in any medium without royalty provided the copyright
@ -11,10 +12,12 @@ Copyright © 2016, 2017, 2018 Ricardo Wurmus <rekado@elephly.net>
Please send Guix bug reports to bug-guix@gnu.org. Please send Guix bug reports to bug-guix@gnu.org.
* Changes in 1.3.0 (since 1.2.0) * Changes in 1.4.0 (since 1.3.0)
** Package management ** Package management
* New 'deb' format for the 'guix pack' command
* Changes in 1.3.0 (since 1.2.0)
** Package management
*** POWER9 (powerpc64le-linux) is now supported as a technology preview *** POWER9 (powerpc64le-linux) is now supported as a technology preview
*** New --export-manifest and --export-channels options of guix package *** New --export-manifest and --export-channels options of guix package
*** New --profile option for guix environment *** New --profile option for guix environment

View File

@ -6028,6 +6028,11 @@ This produces a SquashFS image containing all the specified binaries and
symlinks, as well as empty mount points for virtual file systems like symlinks, as well as empty mount points for virtual file systems like
procfs. procfs.
@item deb
This produces a Debian archive (a package with the @samp{.deb} file
extension) containing all the specified binaries and symbolic links,
that can be installed on top of any dpkg-based GNU/Linux distribution.
@quotation Note @quotation Note
Singularity @emph{requires} you to provide @file{/bin/sh} in the image. Singularity @emph{requires} you to provide @file{/bin/sh} in the image.
For that reason, @command{guix pack -f squashfs} always implies @code{-S For that reason, @command{guix pack -f squashfs} always implies @code{-S

View File

@ -6,6 +6,7 @@
;;; Copyright © 2018 Efraim Flashner <efraim@flashner.co.il> ;;; Copyright © 2018 Efraim Flashner <efraim@flashner.co.il>
;;; Copyright © 2020 Tobias Geerinckx-Rice <me@tobias.gr> ;;; Copyright © 2020 Tobias Geerinckx-Rice <me@tobias.gr>
;;; Copyright © 2020 Eric Bavier <bavier@posteo.net> ;;; Copyright © 2020 Eric Bavier <bavier@posteo.net>
;;; Copyright © 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;; ;;;
;;; This file is part of GNU Guix. ;;; This file is part of GNU Guix.
;;; ;;;
@ -65,6 +66,7 @@
%compressors %compressors
lookup-compressor lookup-compressor
self-contained-tarball self-contained-tarball
debian-archive
docker-image docker-image
squashfs-image squashfs-image
@ -346,6 +348,10 @@ added to the pack."
#:target target #:target target
#:references-graphs `(("profile" ,profile)))) #:references-graphs `(("profile" ,profile))))
;;;
;;; Singularity.
;;;
(define (singularity-environment-file profile) (define (singularity-environment-file profile)
"Return a shell script that defines the environment variables corresponding "Return a shell script that defines the environment variables corresponding
to the search paths of PROFILE." to the search paths of PROFILE."
@ -372,6 +378,10 @@ to the search paths of PROFILE."
(computed-file "singularity-environment.sh" build)) (computed-file "singularity-environment.sh" build))
;;;
;;; SquashFS image format.
;;;
(define* (squashfs-image name profile (define* (squashfs-image name profile
#:key target #:key target
(profile-name "guix-profile") (profile-name "guix-profile")
@ -546,6 +556,10 @@ added to the pack."
#:target target #:target target
#:references-graphs `(("profile" ,profile)))) #:references-graphs `(("profile" ,profile))))
;;;
;;; Docker image format.
;;;
(define* (docker-image name profile (define* (docker-image name profile
#:key target #:key target
(profile-name "guix-profile") (profile-name "guix-profile")
@ -633,6 +647,167 @@ the image."
#:target target #:target target
#:references-graphs `(("profile" ,profile)))) #:references-graphs `(("profile" ,profile))))
;;;
;;; Debian archive format.
;;;
;;; TODO: When relocatable option is selected, install to a unique prefix.
;;; This would enable installation of multiple deb packs with conflicting
;;; files at the same time.
;;; TODO: Allow passing a custom control file from the CLI.
;;; TODO: Allow providing a postinst script.
(define* (debian-archive name profile
#:key target
(profile-name "guix-profile")
deduplicate?
entry-point
(compressor (first %compressors))
localstatedir?
(symlinks '())
(archiver tar))
"Return a Debian archive (.deb) containing a store initialized with the
closure of PROFILE, a derivation. The archive contains /gnu/store; if
LOCALSTATEDIR? is true, it also contains /var/guix, including /var/guix/db
with a properly initialized store database. The supported compressors are
\"none\", \"gz\" or \"xz\".
SYMLINKS must be a list of (SOURCE -> TARGET) tuples denoting symlinks to be
added to the pack."
;; For simplicity, limit the supported compressors to the superset of
;; compressors able to compress both the control file (gz or xz) and the
;; data tarball (gz, bz2 or xz).
(define %valid-compressors '("gzip" "xz" "none"))
(let ((compressor-name (compressor-name compressor)))
(unless (member compressor-name %valid-compressors)
(leave (G_ "~a is not a valid Debian archive compressor. \
Valid compressors are: ~a~%") compressor-name %valid-compressors)))
(when entry-point
(warning (G_ "entry point not supported in the '~a' format~%")
'deb))
(define data-tarball
(computed-file (string-append "data.tar"
(compressor-extension compressor))
(self-contained-tarball/builder
profile
#:profile-name profile-name
#:compressor compressor
#:localstatedir? localstatedir?
#:symlinks symlinks
#:archiver archiver)
#:local-build? #f ;allow offloading
#:options (list #:references-graphs `(("profile" ,profile))
#:target target)))
(define build
(with-extensions (list guile-gcrypt)
(with-imported-modules `(((guix config) => ,(make-config.scm))
,@(source-module-closure
`((guix build pack)
(guix build utils)
(guix profiles))
#:select? not-config?))
#~(begin
(use-modules (guix build pack)
(guix build utils)
(guix profiles)
(ice-9 match)
(srfi srfi-1))
(define machine-type
;; Extract the machine type from the specified target, else from the
;; current system.
(and=> (or #$target %host-type) (lambda (triplet)
(first (string-split triplet #\-)))))
(define (gnu-machine-type->debian-machine-type type)
"Translate machine TYPE from the GNU to Debian terminology."
;; Debian has its own jargon, different from the one used in GNU, for
;; machine types (see data/cputable in the sources of dpkg).
(match type
("i586" "i386")
("i486" "i386")
("i686" "i386")
("x86_64" "amd64")
("aarch64" "arm64")
("mipsisa32r6" "mipsr6")
("mipsisa32r6el" "mipsr6el")
("mipsisa64r6" "mips64r6")
("mipsisa64r6el" "mips64r6el")
("powerpcle" "powerpcel")
("powerpc64" "ppc64")
("powerpc64le" "ppc64el")
(machine machine)))
(define architecture
(gnu-machine-type->debian-machine-type machine-type))
#$(procedure-source manifest->friendly-name)
(define manifest (profile-manifest #$profile))
(define single-entry ;manifest entry
(match (manifest-entries manifest)
((entry)
entry)
(() #f)))
(define package-name (or (and=> single-entry manifest-entry-name)
(manifest->friendly-name manifest)))
(define package-version
(or (and=> single-entry manifest-entry-version)
"0.0.0"))
(define debian-format-version "2.0")
;; Generate the debian-binary file.
(call-with-output-file "debian-binary"
(lambda (port)
(format port "~a~%" debian-format-version)))
(define data-tarball-file-name (strip-store-file-name
#+data-tarball))
(copy-file #+data-tarball data-tarball-file-name)
(define control-tarball-file-name
(string-append "control.tar"
#$(compressor-extension compressor)))
;; Write the compressed control tarball. Only the control file is
;; mandatory (see: 'man deb' and 'man deb-control').
(call-with-output-file "control"
(lambda (port)
(format port "\
Package: ~a
Version: ~a
Description: Debian archive generated by GNU Guix.
Maintainer: GNU Guix
Architecture: ~a
~%" package-name package-version architecture)))
(define tar (string-append #+archiver "/bin/tar"))
(apply invoke tar
`(,@(tar-base-options
#:tar tar
#:compressor '#+(and=> compressor compressor-command))
"-cvf" ,control-tarball-file-name
"control"))
;; Create the .deb archive using GNU ar.
(invoke (string-append #+binutils "/bin/ar") "-rv" #$output
"debian-binary"
control-tarball-file-name data-tarball-file-name)))))
(gexp->derivation (string-append name ".deb")
build
#:target target
#:references-graphs `(("profile" ,profile))))
;;; ;;;
;;; Compiling C programs. ;;; Compiling C programs.
@ -965,7 +1140,8 @@ last resort for relocation."
;; Supported pack formats. ;; Supported pack formats.
`((tarball . ,self-contained-tarball) `((tarball . ,self-contained-tarball)
(squashfs . ,squashfs-image) (squashfs . ,squashfs-image)
(docker . ,docker-image))) (docker . ,docker-image)
(deb . ,debian-archive)))
(define (show-formats) (define (show-formats)
;; Print the supported pack formats. ;; Print the supported pack formats.
@ -977,6 +1153,8 @@ last resort for relocation."
squashfs Squashfs image suitable for Singularity")) squashfs Squashfs image suitable for Singularity"))
(display (G_ " (display (G_ "
docker Tarball ready for 'docker load'")) docker Tarball ready for 'docker load'"))
(display (G_ "
deb Debian archive installable via dpkg/apt"))
(newline)) (newline))
(define %options (define %options

View File

@ -1,6 +1,7 @@
;;; GNU Guix --- Functional package management for GNU ;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net> ;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;; ;;;
;;; This file is part of GNU Guix. ;;; This file is part of GNU Guix.
;;; ;;;
@ -32,6 +33,7 @@
#:use-module ((gnu packages base) #:select (glibc-utf8-locales)) #:use-module ((gnu packages base) #:select (glibc-utf8-locales))
#:use-module (gnu packages bootstrap) #:use-module (gnu packages bootstrap)
#:use-module ((gnu packages compression) #:select (squashfs-tools)) #:use-module ((gnu packages compression) #:select (squashfs-tools))
#:use-module ((gnu packages debian) #:select (dpkg))
#:use-module ((gnu packages guile) #:select (guile-sqlite3)) #:use-module ((gnu packages guile) #:select (guile-sqlite3))
#:use-module ((gnu packages gnupg) #:select (guile-gcrypt)) #:use-module ((gnu packages gnupg) #:select (guile-gcrypt))
#:use-module (srfi srfi-64)) #:use-module (srfi srfi-64))
@ -56,6 +58,8 @@
(define %tar-bootstrap %bootstrap-coreutils&co) (define %tar-bootstrap %bootstrap-coreutils&co)
(define %ar-bootstrap %bootstrap-binutils)
(test-begin "pack") (test-begin "pack")
@ -270,6 +274,77 @@
1) 1)
(pk 'guilelink (readlink "bin")))) (pk 'guilelink (readlink "bin"))))
(mkdir #$output)))))))) (mkdir #$output))))))))
(built-derivations (list check))))
(unless store (test-skip 1))
(test-assertm "deb archive with symlinks" store
(mlet* %store-monad
((guile (set-guile-for-build (default-guile)))
(profile (profile-derivation (packages->manifest
(list %bootstrap-guile))
#:hooks '()
#:locales? #f))
(deb (debian-archive "deb-pack" profile
#:compressor %gzip-compressor
#:symlinks '(("/opt/gnu/bin" -> "bin"))
#:archiver %tar-bootstrap))
(check
(gexp->derivation "check-deb-pack"
(with-imported-modules '((guix build utils))
#~(begin
(use-modules (guix build utils)
(ice-9 match)
(ice-9 popen)
(ice-9 rdelim)
(ice-9 textual-ports)
(rnrs base))
(setenv "PATH" (string-join
(list (string-append #+%tar-bootstrap "/bin")
(string-append #+dpkg "/bin")
(string-append #+%ar-bootstrap "/bin"))
":"))
;; Validate the output of 'dpkg --info'.
(let* ((port (open-pipe* OPEN_READ "dpkg" "--info" #$deb))
(info (get-string-all port))
(exit-val (status:exit-val (close-pipe port))))
(assert (zero? exit-val))
(assert (string-contains
info
(string-append "Package: "
#+(package-name %bootstrap-guile))))
(assert (string-contains
info
(string-append "Version: "
#+(package-version %bootstrap-guile)))))
;; Sanity check .deb contents.
(invoke "ar" "-xv" #$deb)
(assert (file-exists? "debian-binary"))
(assert (file-exists? "data.tar.gz"))
(assert (file-exists? "control.tar.gz"))
;; Verify there are no hard links in data.tar.gz, as hard
;; links would cause dpkg to fail unpacking the archive.
(define hard-links
(let ((port (open-pipe* OPEN_READ "tar" "-tvf" "data.tar.gz")))
(let loop ((hard-links '()))
(match (read-line port)
((? eof-object?)
(assert (zero? (status:exit-val (close-pipe port))))
hard-links)
(line
(if (string-prefix? "u" line)
(loop (cons line hard-links))
(loop hard-links)))))))
(unless (null? hard-links)
(error "hard links found in data.tar.gz" hard-links))
(mkdir #$output))))))
(built-derivations (list check))))) (built-derivations (list check)))))
(test-end) (test-end)