Subject: [PATCH 2/5] guix system: Use 'provenance-service-type', add "--save-provenance".

From: Ludovic Courtès <[email-masked]>
Date: Sat, 30 Nov 2019 23:31:45 +0100

* guix/scripts/system.scm (show-help, %options): Add "--save-provenance".
(process-action): Define 'save-provenance?' and 'transform'; call
'transform' on the OS.
* doc/guix.texi (Invoking guix system): Document it under 'reconfigure'.
(Service Reference): Mention that 'provenance-service-type' is
automatically added by 'reconfigure' & 'init'.
---
 doc/guix.texi           | 61 +++++++++++++++++++++++++++++++++++------
 guix/scripts/system.scm | 47 ++++++++++++++++++++-----------
 2 files changed, 84 insertions(+), 24 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index fd40b6535f..3dc2fd1318 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -25839,6 +25839,15 @@ switch to it@footnote{This action (and the related actions
 @code{switch-generation} and @code{roll-back}) are usable only on
 systems already running Guix System.}.
 
+@quotation Note
+@c The paragraph below refers to the problem discussed at
+@c <https://lists.gnu.org/archive/html/guix-devel/2014-08/msg00057.html>.
+It is highly recommended to run @command{guix pull} once before you run
+@command{guix system reconfigure} for the first time (@pxref{Invoking
+guix pull}).  Failing to do that you would see an older version of Guix
+once @command{reconfigure} has completed.
+@end quotation
+
 This effects all the configuration specified in @var{file}: user
 accounts, system services, global package list, setuid programs, etc.
 The command starts system services specified in @var{file} that are not
@@ -25857,14 +25866,27 @@ It also adds a bootloader menu entry for the new OS configuration,
 entries for older configurations to a submenu, allowing you to choose
 an older system generation at boot time should you need it.
 
-@quotation Note
-@c The paragraph below refers to the problem discussed at
-@c <https://lists.gnu.org/archive/html/guix-devel/2014-08/msg00057.html>.
-It is highly recommended to run @command{guix pull} once before you run
-@command{guix system reconfigure} for the first time (@pxref{Invoking
-guix pull}).  Failing to do that you would see an older version of Guix
-once @command{reconfigure} has completed.
-@end quotation
+@cindex provenance tracking, of the operating system
+Upon completion, the new system is deployed under
+@file{/run/current-system}.  This directory contains @dfn{provenance
+meta-data}: the list of channels in use (@pxref{Channels}) and
+@var{file} itself, when available.  This information is useful should
+you later want to inspect how this particular generation was built.
+
+In fact, assuming @var{file} is self-contained, you can later rebuild
+generation @var{n} of your operating system with:
+
+@example
+guix time-machine \
+  -C /var/guix/profiles/system-@var{n}-link/channels.scm -- \
+  system reconfigure \
+  /var/guix/profiles/system-@var{n}-link/configuration.scm
+@end example
+
+You can think of it as some sort of built-in version control!  Your
+system is not just a binary artifact: @emph{it carries its own source}.
+@xref{Service Reference, @code{provenance-service-type}}, for more
+information on provenance tracking.
 
 @item switch-generation
 @cindex generations
@@ -26126,6 +26148,25 @@ This works as per @command{guix build} (@pxref{Invoking guix build}).
 Return the derivation file name of the given operating system without
 building anything.
 
+@cindex provenance tracking, of the operating system
+@item --save-provenance
+As discussed above, @command{guix system init} and @command{guix system
+reconfigure} always save provenance information @i{via} a dedicated
+service (@pxref{Service Reference, @code{provenance-service-type}}).
+However, other commands don't do that by default.  If you wish to, say,
+create a virtual machine image that contains provenance information, you
+can run:
+
+@example
+guix system vm-image --save-provenance config.scm
+@end example
+
+That way, the resulting image will effectively ``embed its own source''
+in the form of meta-data in @file{/run/current-system}.  With that
+information, one can rebuild the image to make sure it really contains
+what it pretends to contain; or they could use that to derive a variant
+of the image.
+
 @item --file-system-type=@var{type}
 @itemx -t @var{type}
 For the @code{disk-image} action, create a file system of the given
@@ -27013,6 +27054,10 @@ channels can lead to the same system, bit-for-bit; when
 different meta-data and thus different store file names, which makes
 comparison less trivial.
 @end quotation
+
+This service is automatically added to your operating system
+configuration when you use @command{guix system reconfigure} or
+@command{guix system init}.
 @end defvr
 
 @node Shepherd Services
diff --git a/guix/scripts/system.scm b/guix/scripts/system.scm
index e49c9d36b9..b22945658e 100644
--- a/guix/scripts/system.scm
+++ b/guix/scripts/system.scm
@@ -722,7 +722,9 @@ and TARGET arguments."
      (return (primitive-eval (lowered-gexp-sexp lowered))))))
 
 (define* (perform-action action os
-                         #:key skip-safety-checks?
+                         #:key
+                         save-provenance?
+                         skip-safety-checks?
                          install-bootloader?
                          dry-run? derivations-only?
                          use-substitutes? bootloader-target target
@@ -917,16 +919,18 @@ Some ACTIONS support additional ARGS.\n"))
       --image-size=SIZE  for 'vm-image', produce an image of SIZE"))
   (display (G_ "
       --no-bootloader    for 'init', do not install a bootloader"))
+  (display (G_ "
+      --save-provenance  save provenance information"))
   (display (G_ "
       --share=SPEC       for 'vm', share host file system according to SPEC"))
+  (display (G_ "
+      --expose=SPEC      for 'vm', expose host file system according to SPEC"))
   (display (G_ "
   -N, --network          for 'container', allow containers to access the network"))
   (display (G_ "
   -r, --root=FILE        for 'vm', 'vm-image', 'disk-image', 'container',
                          and 'build', make FILE a symlink to the result, and
                          register it as a garbage collector root"))
-  (display (G_ "
-      --expose=SPEC      for 'vm', expose host file system according to SPEC"))
   (display (G_ "
       --full-boot        for 'vm', make a full boot sequence"))
   (display (G_ "
@@ -977,6 +981,9 @@ Some ACTIONS support additional ARGS.\n"))
          (option '("full-boot") #f #f
                  (lambda (opt name arg result)
                    (alist-cons 'full-boot? #t result)))
+         (option '("save-provenance") #f #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'save-provenance? #t result)))
          (option '("skip-checks") #f #f
                  (lambda (opt name arg result)
                    (alist-cons 'skip-safety-checks? #t result)))
@@ -1040,24 +1047,32 @@ resulting from command-line parsing."
              file-or-exp))
     obj)
 
+  (define save-provenance?
+    (or (assoc-ref opts 'save-provenance?)
+        (memq action '(init reconfigure))))
+
   (let* ((file        (match args
                         (() #f)
                         ((x . _) x)))
          (expr        (assoc-ref opts 'expression))
          (system      (assoc-ref opts 'system))
-         (os          (ensure-operating-system
-                       (or file expr)
-                       (cond
-                        ((and expr file)
-                         (leave
-                          (G_ "both file and expression cannot be specified~%")))
-                        (expr
-                         (read/eval expr))
-                        (file
-                         (load* file %user-module
-                                #:on-error (assoc-ref opts 'on-error)))
-                        (else
-                         (leave (G_ "no configuration specified~%"))))))
+         (transform   (if save-provenance?
+                          (cut operating-system-with-provenance <> file)
+                          identity))
+         (os          (transform
+                       (ensure-operating-system
+                        (or file expr)
+                        (cond
+                         ((and expr file)
+                          (leave
+                           (G_ "both file and expression cannot be specified~%")))
+                         (expr
+                          (read/eval expr))
+                         (file
+                          (load* file %user-module
+                                 #:on-error (assoc-ref opts 'on-error)))
+                         (else
+                          (leave (G_ "no configuration specified~%")))))))
 
          (dry?        (assoc-ref opts 'dry-run?))
          (bootloader? (assoc-ref opts 'install-bootloader?))
-- 
2.24.0