unofficial mirror of guix-patches@gnu.org 
 help / color / mirror / code / Atom feed
* [bug#49348] [PATCH] pack: Allow embedding custom control files in deb packs.
@ 2021-07-03  6:06 Maxim Cournoyer
  2021-07-06 21:11 ` [bug#49348] [PATCH v2 1/4] " Maxim Cournoyer
       [not found] ` <handler.49348.B.1625292420813.ack@debbugs.gnu.org>
  0 siblings, 2 replies; 6+ messages in thread
From: Maxim Cournoyer @ 2021-07-03  6:06 UTC (permalink / raw)
  To: 49348; +Cc: Maxim Cournoyer

* guix/scripts/pack.scm (self-contained-tarball/builder)
[extra-options]: New argument.
(self-contained-tarball, squashfs-image, docker-image)
(debian-archive): Likewise.  Remove two TODO comments.  Document
EXTRA-OPTIONS.  Use the custom control files when provided.
(%deb-format-options): New variable.
(show-deb-format-options, show-deb-format-options/detailed): New procedures.
(%options): Register new options.
(show-help): Augment with new usage.
(guix-pack): Validate and propagate new argument values.
* doc/guix.texi (Invoking guix pack)[deb]: Document how to list advanced
options.  Add an example.
* tests/pack.scm (deb archive...): Provide extra-options to the debian-archive
procedure, and validate that the provided files are embedded in the pack.
---
 doc/guix.texi         |   8 +++
 guix/scripts/pack.scm | 121 +++++++++++++++++++++++++++++++++++-------
 tests/pack.scm        |  27 ++++++++--
 3 files changed, 133 insertions(+), 23 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 8681645021..4bdc4e4127 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -6047,6 +6047,14 @@ such file or directory'' message.
 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.
+Advanced options can be revealed via the @option{--help-deb-format}
+option.  They allow embedding control files for more fine-grained
+control, such as activating specific triggers or providing a maintainer
+configure script to run arbitrary setup code upon installation.
+
+@example
+guix pack -f deb -C xz -S /usr/bin/hello=bin/hello hello
+@end example
 
 @quotation Note
 Because archives produced with @command{guix pack} contain a collection
diff --git a/guix/scripts/pack.scm b/guix/scripts/pack.scm
index 6d8b70d1c7..6a8d49e042 100644
--- a/guix/scripts/pack.scm
+++ b/guix/scripts/pack.scm
@@ -205,7 +205,8 @@ its source property."
                                          (compressor (first %compressors))
                                          localstatedir?
                                          (symlinks '())
-                                         (archiver tar))
+                                         (archiver tar)
+                                         (extra-options '()))
   "Return the G-Expression of the builder used for self-contained-tarball."
   (define database
     (and localstatedir?
@@ -324,7 +325,8 @@ its source property."
                                  (compressor (first %compressors))
                                  localstatedir?
                                  (symlinks '())
-                                 (archiver tar))
+                                 (archiver tar)
+                                 (extra-options '()))
   "Return a self-contained tarball containing a store initialized with the
 closure of PROFILE, a derivation.  The tarball contains /gnu/store; if
 LOCALSTATEDIR? is true, it also contains /var/guix, including /var/guix/db
@@ -389,7 +391,8 @@ to the search paths of PROFILE."
                          entry-point
                          localstatedir?
                          (symlinks '())
-                         (archiver squashfs-tools))
+                         (archiver squashfs-tools)
+                         (extra-options '()))
   "Return a squashfs image containing a store initialized with the closure of
 PROFILE, a derivation.  The image contains a subset of /gnu/store, empty mount
 points for virtual file systems (like procfs), and optional symlinks.
@@ -567,7 +570,8 @@ added to the pack."
                        entry-point
                        localstatedir?
                        (symlinks '())
-                       (archiver tar))
+                       (archiver tar)
+                       (extra-options '()))
   "Return a derivation to construct a Docker image of PROFILE.  The
 image is a tarball conforming to the Docker Image Specification, compressed
 with COMPRESSOR.  It can be passed to 'docker load'.  If TARGET is true, it
@@ -654,8 +658,6 @@ the image."
 ;;; 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")
@@ -664,7 +666,8 @@ the image."
                          (compressor (first %compressors))
                          localstatedir?
                          (symlinks '())
-                         (archiver tar))
+                         (archiver tar)
+                         (extra-options '()))
   "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
@@ -672,7 +675,8 @@ 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."
+added to the pack.  EXTRA-OPTIONS may contain the CONFIG-FILE, POSTINST-FILE
+or TRIGGERS-FILE keyword arguments."
   ;; 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).
@@ -714,21 +718,23 @@ Valid compressors are: ~a~%") compressor-name %valid-compressors)))
                          (guix build utils)
                          (guix profiles)
                          (ice-9 match)
+                         ((oop goops) #:select (get-keyword))
                          (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 #\-)))))
+              (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")
+                ("i586" "i386")
                 ("i686" "i386")
                 ("x86_64" "amd64")
                 ("aarch64" "arm64")
@@ -773,21 +779,40 @@ Valid compressors are: ~a~%") compressor-name %valid-compressors)))
 
             (copy-file #+data-tarball data-tarball-file-name)
 
+            ;; Generate the control archive.
+            (define control-file
+              (get-keyword #:control-file '#$extra-options))
+
+            (define postinst-file
+              (get-keyword #:postinst-file '#$extra-options))
+
+            (define triggers-file
+              (get-keyword #:triggers-file '#$extra-options))
+
             (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 "\
+            (if control-file
+                (copy-file control-file "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)))
+~%" package-name package-version architecture))))
+
+            (when postinst-file
+              (copy-file postinst-file "postinst")
+              (chmod "postinst" #o755))
+
+            (when triggers-file
+              (copy-file triggers-file "triggers"))
 
             (define tar (string-append #+archiver "/bin/tar"))
 
@@ -796,7 +821,9 @@ Architecture: ~a
                         #:tar tar
                         #:compressor '#+(and=> compressor compressor-command))
                      "-cvf" ,control-tarball-file-name
-                     "control"))
+                     "control"
+                     ,@(if postinst-file '("postinst") '())
+                     ,@(if triggers-file '("triggers") '())))
 
             ;; Create the .deb archive using GNU ar.
             (invoke (string-append #+binutils "/bin/ar") "-rv" #$output
@@ -1157,6 +1184,34 @@ last resort for relocation."
   deb           Debian archive installable via dpkg/apt"))
   (newline))
 
+(define %deb-format-options
+  (let ((required-option (lambda (symbol)
+                           (option (list (symbol->string symbol)) #t #f
+                                   (lambda (opt name arg result . rest)
+                                     (apply values
+                                            (alist-cons symbol arg result)
+                                            rest))))))
+    (list (required-option 'control-file)
+          (required-option 'postinst-file)
+          (required-option 'triggers-file))))
+
+(define (show-deb-format-options)
+  (display (G_ "
+      --help-deb-format  list options specific to the deb format")))
+
+(define (show-deb-format-options/detailed)
+  (display (G_ "
+      --control-file=FILE
+                         Embed the provided control FILE"))
+  (display (G_ "
+      --postinst-file=FILE
+                         Embed the provided postinst script"))
+  (display (G_ "
+      --triggers-file=FILE
+                         Embed the provided triggers FILE"))
+  (newline)
+  (exit 0))
+
 (define %options
   ;; Specifications of the command-line options.
   (cons* (option '(#\h "help") #f #f
@@ -1250,7 +1305,12 @@ last resort for relocation."
                  (lambda (opt name arg result)
                    (alist-cons 'bootstrap? #t result)))
 
-         (append %transformation-options
+         (option '("help-deb-format") #f #f
+                 (lambda args
+                   (show-deb-format-options/detailed)))
+
+         (append %deb-format-options
+                 %transformation-options
                  %standard-build-options)))
 
 (define (show-help)
@@ -1260,6 +1320,8 @@ Create a bundle of PACKAGE.\n"))
   (newline)
   (show-transformation-options-help)
   (newline)
+  (show-deb-format-options)
+  (newline)
   (display (G_ "
   -f, --format=FORMAT    build a pack in the given FORMAT"))
   (display (G_ "
@@ -1369,6 +1431,18 @@ Create a bundle of PACKAGE.\n"))
         (else
          (packages->manifest packages))))))
 
+  (define (process-file-arg opts name)
+    ;; Validate that the file exists and return it as a <local-file> object,
+    ;; else #f.
+    (let ((value (assoc-ref opts name)))
+      (match value
+        ((and (? string?) (not (? file-exists?)))
+         (leave (G_ "file provided with option ~a does not exist: ~a~%")
+                (string-append "--" (symbol->string name)) value))
+        ((? string?)
+         (local-file value))
+        (#f #f))))
+
   (with-error-handling
     (with-store store
       (with-status-verbosity (assoc-ref opts 'verbosity)
@@ -1401,6 +1475,15 @@ Create a bundle of PACKAGE.\n"))
                                        manifest)
                                       manifest)))
                    (pack-format (assoc-ref opts 'format))
+                   (extra-options (match pack-format
+                                    ('deb
+                                     (list #:control-file
+                                           (process-file-arg opts 'control-file)
+                                           #:postinst-file
+                                           (process-file-arg opts 'postinst-file)
+                                           #:triggers-file
+                                           (process-file-arg opts 'triggers-file)))
+                                    (_ '())))
                    (target      (assoc-ref opts 'target))
                    (bootstrap?  (assoc-ref opts 'bootstrap?))
                    (compressor  (if bootstrap?
@@ -1465,7 +1548,9 @@ to your package list.")))
                                                        #:profile-name
                                                        profile-name
                                                        #:archiver
-                                                       archiver)))
+                                                       archiver
+                                                       #:extra-options
+                                                       extra-options)))
                   (mbegin %store-monad
                     (mwhen derivation?
                       (return (format #t "~a~%"
diff --git a/tests/pack.scm b/tests/pack.scm
index 9473d4f384..e9b4c36e0e 100644
--- a/tests/pack.scm
+++ b/tests/pack.scm
@@ -277,17 +277,25 @@
       (built-derivations (list check))))
 
   (unless store (test-skip 1))
-  (test-assertm "deb archive with symlinks" store
+  (test-assertm "deb archive with symlinks and control files" 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))
+         (deb (debian-archive
+               "deb-pack" profile
+               #:compressor %gzip-compressor
+               #:symlinks '(("/opt/gnu/bin" -> "bin"))
+               #:archiver %tar-bootstrap
+               #:extra-options
+               (list #:triggers-file
+                     (plain-file "triggers"
+                                 "activate-noawait /usr/share/icons/hicolor\n")
+                     #:postinst-file
+                     (plain-file "postinst"
+                                 "echo running configure script\n"))))
          (check
           (gexp->derivation "check-deb-pack"
             (with-imported-modules '((guix build utils))
@@ -344,6 +352,15 @@
                   (unless (null? hard-links)
                     (error "hard links found in data.tar.gz" hard-links))
 
+                  ;; Verify the presence of the control files.
+                  (invoke "tar" "-xf" "control.tar.gz")
+                  (assert (file-exists? "control"))
+                  (assert (and (file-exists? "postinst")
+                               (= #o111 ;script is executable
+                                  (logand #o111 (stat:perms
+                                                 (stat "postinst"))))))
+                  (assert (file-exists? "triggers"))
+
                   (mkdir #$output))))))
       (built-derivations (list check)))))
 
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [bug#49348] [PATCH v2 1/4] pack: Allow embedding custom control files in deb packs.
  2021-07-03  6:06 [bug#49348] [PATCH] pack: Allow embedding custom control files in deb packs Maxim Cournoyer
@ 2021-07-06 21:11 ` Maxim Cournoyer
  2021-07-06 21:11   ` [bug#49348] [PATCH v2 2/4] pack/deb: Add default section and priority fields to the control file Maxim Cournoyer
                     ` (2 more replies)
       [not found] ` <handler.49348.B.1625292420813.ack@debbugs.gnu.org>
  1 sibling, 3 replies; 6+ messages in thread
From: Maxim Cournoyer @ 2021-07-06 21:11 UTC (permalink / raw)
  To: 49348; +Cc: Maxim Cournoyer

* guix/scripts/pack.scm (self-contained-tarball/builder)
[extra-options]: New argument.
(self-contained-tarball, squashfs-image, docker-image)
(debian-archive): Likewise.  Remove two TODO comments.  Document
EXTRA-OPTIONS.  Use the custom control files when provided.
(%deb-format-options): New variable.
(show-deb-format-options, show-deb-format-options/detailed): New procedures.
(%options): Register new options.
(show-help): Augment with new usage.
(guix-pack): Validate and propagate new argument values.
* doc/guix.texi (Invoking guix pack)[deb]: Document how to list advanced
options.  Add an example.
* tests/pack.scm (deb archive...): Provide extra-options to the debian-archive
procedure, and validate that the provided files are embedded in the pack.
---
 doc/guix.texi         |   8 +++
 guix/scripts/pack.scm | 121 +++++++++++++++++++++++++++++++++++-------
 tests/pack.scm        |  27 ++++++++--
 3 files changed, 133 insertions(+), 23 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 1086d3220b..39d4cb1929 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -6047,6 +6047,14 @@ such file or directory'' message.
 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.
+Advanced options can be revealed via the @option{--help-deb-format}
+option.  They allow embedding control files for more fine-grained
+control, such as activating specific triggers or providing a maintainer
+configure script to run arbitrary setup code upon installation.
+
+@example
+guix pack -f deb -C xz -S /usr/bin/hello=bin/hello hello
+@end example
 
 @quotation Note
 Because archives produced with @command{guix pack} contain a collection
diff --git a/guix/scripts/pack.scm b/guix/scripts/pack.scm
index 6d8b70d1c7..6a8d49e042 100644
--- a/guix/scripts/pack.scm
+++ b/guix/scripts/pack.scm
@@ -205,7 +205,8 @@ its source property."
                                          (compressor (first %compressors))
                                          localstatedir?
                                          (symlinks '())
-                                         (archiver tar))
+                                         (archiver tar)
+                                         (extra-options '()))
   "Return the G-Expression of the builder used for self-contained-tarball."
   (define database
     (and localstatedir?
@@ -324,7 +325,8 @@ its source property."
                                  (compressor (first %compressors))
                                  localstatedir?
                                  (symlinks '())
-                                 (archiver tar))
+                                 (archiver tar)
+                                 (extra-options '()))
   "Return a self-contained tarball containing a store initialized with the
 closure of PROFILE, a derivation.  The tarball contains /gnu/store; if
 LOCALSTATEDIR? is true, it also contains /var/guix, including /var/guix/db
@@ -389,7 +391,8 @@ to the search paths of PROFILE."
                          entry-point
                          localstatedir?
                          (symlinks '())
-                         (archiver squashfs-tools))
+                         (archiver squashfs-tools)
+                         (extra-options '()))
   "Return a squashfs image containing a store initialized with the closure of
 PROFILE, a derivation.  The image contains a subset of /gnu/store, empty mount
 points for virtual file systems (like procfs), and optional symlinks.
@@ -567,7 +570,8 @@ added to the pack."
                        entry-point
                        localstatedir?
                        (symlinks '())
-                       (archiver tar))
+                       (archiver tar)
+                       (extra-options '()))
   "Return a derivation to construct a Docker image of PROFILE.  The
 image is a tarball conforming to the Docker Image Specification, compressed
 with COMPRESSOR.  It can be passed to 'docker load'.  If TARGET is true, it
@@ -654,8 +658,6 @@ the image."
 ;;; 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")
@@ -664,7 +666,8 @@ the image."
                          (compressor (first %compressors))
                          localstatedir?
                          (symlinks '())
-                         (archiver tar))
+                         (archiver tar)
+                         (extra-options '()))
   "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
@@ -672,7 +675,8 @@ 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."
+added to the pack.  EXTRA-OPTIONS may contain the CONFIG-FILE, POSTINST-FILE
+or TRIGGERS-FILE keyword arguments."
   ;; 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).
@@ -714,21 +718,23 @@ Valid compressors are: ~a~%") compressor-name %valid-compressors)))
                          (guix build utils)
                          (guix profiles)
                          (ice-9 match)
+                         ((oop goops) #:select (get-keyword))
                          (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 #\-)))))
+              (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")
+                ("i586" "i386")
                 ("i686" "i386")
                 ("x86_64" "amd64")
                 ("aarch64" "arm64")
@@ -773,21 +779,40 @@ Valid compressors are: ~a~%") compressor-name %valid-compressors)))
 
             (copy-file #+data-tarball data-tarball-file-name)
 
+            ;; Generate the control archive.
+            (define control-file
+              (get-keyword #:control-file '#$extra-options))
+
+            (define postinst-file
+              (get-keyword #:postinst-file '#$extra-options))
+
+            (define triggers-file
+              (get-keyword #:triggers-file '#$extra-options))
+
             (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 "\
+            (if control-file
+                (copy-file control-file "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)))
+~%" package-name package-version architecture))))
+
+            (when postinst-file
+              (copy-file postinst-file "postinst")
+              (chmod "postinst" #o755))
+
+            (when triggers-file
+              (copy-file triggers-file "triggers"))
 
             (define tar (string-append #+archiver "/bin/tar"))
 
@@ -796,7 +821,9 @@ Architecture: ~a
                         #:tar tar
                         #:compressor '#+(and=> compressor compressor-command))
                      "-cvf" ,control-tarball-file-name
-                     "control"))
+                     "control"
+                     ,@(if postinst-file '("postinst") '())
+                     ,@(if triggers-file '("triggers") '())))
 
             ;; Create the .deb archive using GNU ar.
             (invoke (string-append #+binutils "/bin/ar") "-rv" #$output
@@ -1157,6 +1184,34 @@ last resort for relocation."
   deb           Debian archive installable via dpkg/apt"))
   (newline))
 
+(define %deb-format-options
+  (let ((required-option (lambda (symbol)
+                           (option (list (symbol->string symbol)) #t #f
+                                   (lambda (opt name arg result . rest)
+                                     (apply values
+                                            (alist-cons symbol arg result)
+                                            rest))))))
+    (list (required-option 'control-file)
+          (required-option 'postinst-file)
+          (required-option 'triggers-file))))
+
+(define (show-deb-format-options)
+  (display (G_ "
+      --help-deb-format  list options specific to the deb format")))
+
+(define (show-deb-format-options/detailed)
+  (display (G_ "
+      --control-file=FILE
+                         Embed the provided control FILE"))
+  (display (G_ "
+      --postinst-file=FILE
+                         Embed the provided postinst script"))
+  (display (G_ "
+      --triggers-file=FILE
+                         Embed the provided triggers FILE"))
+  (newline)
+  (exit 0))
+
 (define %options
   ;; Specifications of the command-line options.
   (cons* (option '(#\h "help") #f #f
@@ -1250,7 +1305,12 @@ last resort for relocation."
                  (lambda (opt name arg result)
                    (alist-cons 'bootstrap? #t result)))
 
-         (append %transformation-options
+         (option '("help-deb-format") #f #f
+                 (lambda args
+                   (show-deb-format-options/detailed)))
+
+         (append %deb-format-options
+                 %transformation-options
                  %standard-build-options)))
 
 (define (show-help)
@@ -1260,6 +1320,8 @@ Create a bundle of PACKAGE.\n"))
   (newline)
   (show-transformation-options-help)
   (newline)
+  (show-deb-format-options)
+  (newline)
   (display (G_ "
   -f, --format=FORMAT    build a pack in the given FORMAT"))
   (display (G_ "
@@ -1369,6 +1431,18 @@ Create a bundle of PACKAGE.\n"))
         (else
          (packages->manifest packages))))))
 
+  (define (process-file-arg opts name)
+    ;; Validate that the file exists and return it as a <local-file> object,
+    ;; else #f.
+    (let ((value (assoc-ref opts name)))
+      (match value
+        ((and (? string?) (not (? file-exists?)))
+         (leave (G_ "file provided with option ~a does not exist: ~a~%")
+                (string-append "--" (symbol->string name)) value))
+        ((? string?)
+         (local-file value))
+        (#f #f))))
+
   (with-error-handling
     (with-store store
       (with-status-verbosity (assoc-ref opts 'verbosity)
@@ -1401,6 +1475,15 @@ Create a bundle of PACKAGE.\n"))
                                        manifest)
                                       manifest)))
                    (pack-format (assoc-ref opts 'format))
+                   (extra-options (match pack-format
+                                    ('deb
+                                     (list #:control-file
+                                           (process-file-arg opts 'control-file)
+                                           #:postinst-file
+                                           (process-file-arg opts 'postinst-file)
+                                           #:triggers-file
+                                           (process-file-arg opts 'triggers-file)))
+                                    (_ '())))
                    (target      (assoc-ref opts 'target))
                    (bootstrap?  (assoc-ref opts 'bootstrap?))
                    (compressor  (if bootstrap?
@@ -1465,7 +1548,9 @@ to your package list.")))
                                                        #:profile-name
                                                        profile-name
                                                        #:archiver
-                                                       archiver)))
+                                                       archiver
+                                                       #:extra-options
+                                                       extra-options)))
                   (mbegin %store-monad
                     (mwhen derivation?
                       (return (format #t "~a~%"
diff --git a/tests/pack.scm b/tests/pack.scm
index 9473d4f384..e9b4c36e0e 100644
--- a/tests/pack.scm
+++ b/tests/pack.scm
@@ -277,17 +277,25 @@
       (built-derivations (list check))))
 
   (unless store (test-skip 1))
-  (test-assertm "deb archive with symlinks" store
+  (test-assertm "deb archive with symlinks and control files" 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))
+         (deb (debian-archive
+               "deb-pack" profile
+               #:compressor %gzip-compressor
+               #:symlinks '(("/opt/gnu/bin" -> "bin"))
+               #:archiver %tar-bootstrap
+               #:extra-options
+               (list #:triggers-file
+                     (plain-file "triggers"
+                                 "activate-noawait /usr/share/icons/hicolor\n")
+                     #:postinst-file
+                     (plain-file "postinst"
+                                 "echo running configure script\n"))))
          (check
           (gexp->derivation "check-deb-pack"
             (with-imported-modules '((guix build utils))
@@ -344,6 +352,15 @@
                   (unless (null? hard-links)
                     (error "hard links found in data.tar.gz" hard-links))
 
+                  ;; Verify the presence of the control files.
+                  (invoke "tar" "-xf" "control.tar.gz")
+                  (assert (file-exists? "control"))
+                  (assert (and (file-exists? "postinst")
+                               (= #o111 ;script is executable
+                                  (logand #o111 (stat:perms
+                                                 (stat "postinst"))))))
+                  (assert (file-exists? "triggers"))
+
                   (mkdir #$output))))))
       (built-derivations (list check)))))
 
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [bug#49348] [PATCH v2 2/4] pack/deb: Add default section and priority fields to the control file.
  2021-07-06 21:11 ` [bug#49348] [PATCH v2 1/4] " Maxim Cournoyer
@ 2021-07-06 21:11   ` Maxim Cournoyer
  2021-07-06 21:11   ` [bug#49348] [PATCH v2 3/4] pack: Streamline how files are included in tarballs Maxim Cournoyer
  2021-07-06 21:11   ` [bug#49348] [PATCH v2 4/4] build: pack: Mute error output when checking if tar supports --sort Maxim Cournoyer
  2 siblings, 0 replies; 6+ messages in thread
From: Maxim Cournoyer @ 2021-07-06 21:11 UTC (permalink / raw)
  To: 49348; +Cc: Maxim Cournoyer

These fields, while optional per dpkg, are required by other tools such as
reprepro, commonly used to generate apt repositories.

* guix/scripts/pack.scm (debian-archive): Set the control file section field
to 'misc' and the priority field to 'optional'.
---
 guix/scripts/pack.scm | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/guix/scripts/pack.scm b/guix/scripts/pack.scm
index 6a8d49e042..78201d6f5f 100644
--- a/guix/scripts/pack.scm
+++ b/guix/scripts/pack.scm
@@ -805,6 +805,8 @@ Version: ~a
 Description: Debian archive generated by GNU Guix.
 Maintainer: GNU Guix
 Architecture: ~a
+Priority: optional
+Section: misc
 ~%" package-name package-version architecture))))
 
             (when postinst-file
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [bug#49348] [PATCH v2 3/4] pack: Streamline how files are included in tarballs.
  2021-07-06 21:11 ` [bug#49348] [PATCH v2 1/4] " Maxim Cournoyer
  2021-07-06 21:11   ` [bug#49348] [PATCH v2 2/4] pack/deb: Add default section and priority fields to the control file Maxim Cournoyer
@ 2021-07-06 21:11   ` Maxim Cournoyer
  2021-07-06 21:11   ` [bug#49348] [PATCH v2 4/4] build: pack: Mute error output when checking if tar supports --sort Maxim Cournoyer
  2 siblings, 0 replies; 6+ messages in thread
From: Maxim Cournoyer @ 2021-07-06 21:11 UTC (permalink / raw)
  To: 49348; +Cc: Maxim Cournoyer

Thanks to Guillem Jover <guillem@debian.org> on the OFTC's #debian-dpkg
channel for helping with troubleshooting.

Letting GNU Tar recursively walk the complete files hierarchy side-steps the
risks associated with providing a list of file names:

1. Duplicated files in the archive (recorded as hard links by GNU Tar)
2. Missing parent directories.

The above would cause dpkg to malfunction, for example by aborting early and
skipping triggers when there are missing parent directories.

* guix/scripts/pack.scm (self-contained-tarball/builder): Do not call
POPULATE-SINGLE-PROFILE-DIRECTORY, which creates extraneous files such as
/root.  Instead, call POPULATE-STORE and INSTALL-DATABASE-AND-GC-ROOTS
individually to more precisely generate the file system.  Replace the list of
files by the current directory, "." and streamline the way options are passed.
* gnu/system/file-systems.scm (reduce-directories): Remove procedure.
* tests/file-systems.scm ("reduce-directories"): Remove test.
---
 gnu/system/file-systems.scm | 22 -----------------
 guix/scripts/pack.scm       | 49 ++++++++++++-------------------------
 tests/file-systems.scm      |  7 +-----
 3 files changed, 17 insertions(+), 61 deletions(-)

diff --git a/gnu/system/file-systems.scm b/gnu/system/file-systems.scm
index 4a3c1fe008..b9eda80958 100644
--- a/gnu/system/file-systems.scm
+++ b/gnu/system/file-systems.scm
@@ -55,7 +55,6 @@
             file-system-dependencies
             file-system-location
 
-            reduce-directories
             file-system-type-predicate
             btrfs-subvolume?
             btrfs-store-subvolume-file-name
@@ -266,27 +265,6 @@ For example:
 (define (file-name-depth file-name)
   (length (string-tokenize file-name %not-slash)))
 
-(define (reduce-directories file-names)
-  "Eliminate entries in FILE-NAMES that are children of other entries in
-FILE-NAMES.  This is for example useful when passing a list of files to GNU
-tar, which would otherwise descend into each directory passed and archive the
-duplicate files as hard links, which can be undesirable."
-  (let* ((file-names/sorted
-          ;; Ascending sort by file hierarchy depth, then by file name length.
-          (stable-sort (delete-duplicates file-names)
-                       (lambda (f1 f2)
-                         (let ((depth1 (file-name-depth f1))
-                               (depth2 (file-name-depth f2)))
-                           (if (= depth1 depth2)
-                               (string< f1 f2)
-                               (< depth1 depth2)))))))
-    (reverse (fold (lambda (file-name results)
-                     (if (find (cut file-prefix? <> file-name) results)
-                         results        ;parent found -- skipping
-                         (cons file-name results)))
-                   '()
-                   file-names/sorted))))
-
 (define* (file-system-device->string device #:key uuid-type)
   "Return the string representations of the DEVICE field of a <file-system>
 record.  When the device is a UUID, its representation is chosen depending on
diff --git a/guix/scripts/pack.scm b/guix/scripts/pack.scm
index 78201d6f5f..9e1f270dfb 100644
--- a/guix/scripts/pack.scm
+++ b/guix/scripts/pack.scm
@@ -231,17 +231,17 @@ its source property."
 
   (with-imported-modules (source-module-closure
                           `((guix build pack)
+                            (guix build store-copy)
                             (guix build utils)
                             (guix build union)
-                            (gnu build install)
-                            (gnu system file-systems))
+                            (gnu build install))
                           #:select? import-module?)
     #~(begin
         (use-modules (guix build pack)
+                     (guix build store-copy)
                      (guix build utils)
                      ((guix build union) #:select (relative-file-name))
                      (gnu build install)
-                     ((gnu system file-systems) #:select (reduce-directories))
                      (srfi srfi-1)
                      (srfi srfi-26)
                      (ice-9 match))
@@ -279,11 +279,11 @@ its source property."
         ;; Furthermore GNU tar < 1.30 sometimes fails to extract tarballs
         ;; with hard links:
         ;; <http://lists.gnu.org/archive/html/bug-tar/2017-11/msg00009.html>.
-        (populate-single-profile-directory %root
-                                           #:profile #$profile
-                                           #:profile-name #$profile-name
-                                           #:closure "profile"
-                                           #:database #+database)
+        (populate-store (list "profile") %root #:deduplicate? #f)
+
+        (when #+localstatedir?
+          (install-database-and-gc-roots %root #+database #$profile
+                                         #:profile-name #$profile-name))
 
         ;; Create SYMLINKS.
         (for-each (cut evaluate-populate-directive <> %root)
@@ -291,31 +291,14 @@ its source property."
 
         ;; Create the tarball.
         (with-directory-excursion %root
-          (apply invoke tar
-                 `(,@(tar-base-options
-                      #:tar tar
-                      #:compressor '#+(and=> compressor compressor-command))
-                   "-cvf" ,#$output
-                   ;; Avoid adding / and /var to the tarball, so
-                   ;; that the ownership and permissions of those
-                   ;; directories will not be overwritten when
-                   ;; extracting the archive.  Do not include /root
-                   ;; because the root account might have a
-                   ;; different home directory.
-                   ,#$@(if localstatedir?
-                           '("./var/guix")
-                           '())
-
-                   ,(string-append "." (%store-directory))
-
-                   ,@(reduce-directories
-                      (filter-map (match-lambda
-                                    (('directory directory)
-                                     (string-append "." directory))
-                                    ((source '-> _)
-                                     (string-append "." source))
-                                    (_ #f))
-                                  directives))))))))
+          ;; GNU Tar recurses directories by default.  Simply add the whole
+          ;; current directory, which contains all the generated files so far.
+          ;; This avoids creating duplicate files in the archives that would
+          ;; be stored as hard links by GNU Tar.
+          (apply invoke tar "-cvf" #$output "."
+                 (tar-base-options
+                  #:tar tar
+                  #:compressor '#+(and=> compressor compressor-command)))))))
 
 (define* (self-contained-tarball name profile
                                  #:key target
diff --git a/tests/file-systems.scm b/tests/file-systems.scm
index 80acb6d5b9..7f7c373884 100644
--- a/tests/file-systems.scm
+++ b/tests/file-systems.scm
@@ -1,6 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2015, 2017 Ludovic Courtès <ludo@gnu.org>
-;;; Copyright © 2020, 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com>
+;;; Copyright © 2020 Maxim Cournoyer <maxim.cournoyer@gmail.com>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -50,11 +50,6 @@
                    (device "/foo")
                    (flags '(bind-mount read-only)))))))))
 
-(test-equal "reduce-directories"
-  '("./opt/gnu/" "./opt/gnuism" "a/b/c")
-  (reduce-directories '("./opt/gnu/etc" "./opt/gnu/" "./opt/gnu/bin"
-                        "./opt/gnu/lib/debug" "./opt/gnuism" "a/b/c" "a/b/c")))
-
 (test-assert "does not pull (guix config)"
   ;; This module is meant both for the host side and "build side", so make
   ;; sure it doesn't pull in (guix config), which depends on the user's
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [bug#49348] [PATCH v2 4/4] build: pack: Mute error output when checking if tar supports --sort.
  2021-07-06 21:11 ` [bug#49348] [PATCH v2 1/4] " Maxim Cournoyer
  2021-07-06 21:11   ` [bug#49348] [PATCH v2 2/4] pack/deb: Add default section and priority fields to the control file Maxim Cournoyer
  2021-07-06 21:11   ` [bug#49348] [PATCH v2 3/4] pack: Streamline how files are included in tarballs Maxim Cournoyer
@ 2021-07-06 21:11   ` Maxim Cournoyer
  2 siblings, 0 replies; 6+ messages in thread
From: Maxim Cournoyer @ 2021-07-06 21:11 UTC (permalink / raw)
  To: 49348; +Cc: Maxim Cournoyer

* guix/build/pack.scm (tar-base-options) [tar-supports-sort?]: Redirect error
output to void.
---
 guix/build/pack.scm | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/guix/build/pack.scm b/guix/build/pack.scm
index 05c7a3c594..3b73d1b227 100644
--- a/guix/build/pack.scm
+++ b/guix/build/pack.scm
@@ -27,8 +27,10 @@ deterministically.  When TAR, a GNU tar command file name, is provided, the
 '(\"gzip\" \"-9n\"), is provided, the compressor is explicitly specified via
 the `-I' option."
   (define (tar-supports-sort? tar)
-    (zero? (system* tar "cf" "/dev/null" "--files-from=/dev/null"
-                    "--sort=name")))
+    (with-error-to-port (%make-void-port "w")
+      (lambda ()
+        (zero? (system* tar "cf" "/dev/null" "--files-from=/dev/null"
+                        "--sort=name")))))
 
   `(,@(if compressor
           (list "-I" (string-join compressor))
-- 
2.32.0





^ permalink raw reply related	[flat|nested] 6+ messages in thread

* bug#49348: Acknowledgement ([PATCH] pack: Allow embedding custom control files in deb packs.)
       [not found] ` <handler.49348.B.1625292420813.ack@debbugs.gnu.org>
@ 2021-07-18 16:26   ` Maxim Cournoyer
  0 siblings, 0 replies; 6+ messages in thread
From: Maxim Cournoyer @ 2021-07-18 16:26 UTC (permalink / raw)
  To: 49348-done

Hello,

Pushed with commit c170abba4735a2c8a6845063fae8bf090975cbf9.

Closing.

Maxim




^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2021-07-18 18:22 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-03  6:06 [bug#49348] [PATCH] pack: Allow embedding custom control files in deb packs Maxim Cournoyer
2021-07-06 21:11 ` [bug#49348] [PATCH v2 1/4] " Maxim Cournoyer
2021-07-06 21:11   ` [bug#49348] [PATCH v2 2/4] pack/deb: Add default section and priority fields to the control file Maxim Cournoyer
2021-07-06 21:11   ` [bug#49348] [PATCH v2 3/4] pack: Streamline how files are included in tarballs Maxim Cournoyer
2021-07-06 21:11   ` [bug#49348] [PATCH v2 4/4] build: pack: Mute error output when checking if tar supports --sort Maxim Cournoyer
     [not found] ` <handler.49348.B.1625292420813.ack@debbugs.gnu.org>
2021-07-18 16:26   ` bug#49348: Acknowledgement ([PATCH] pack: Allow embedding custom control files in deb packs.) Maxim Cournoyer

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/guix.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).