unofficial mirror of guix-patches@gnu.org 
 help / color / mirror / code / Atom feed
* [bug#37978] [PATCH] guix: new command "guix time-machine"
@ 2019-10-25 15:42 Konrad Hinsen
  2019-10-25 15:42 ` [bug#37978] [PATCH 1/3] " Konrad Hinsen
                   ` (4 more replies)
  0 siblings, 5 replies; 22+ messages in thread
From: Konrad Hinsen @ 2019-10-25 15:42 UTC (permalink / raw)
  To: 37978

* guix/scripts/time-machine.scm: New file.
* guix/scripts/pull.scm: Export function channel-list.
* guix/inferior.scm: New function cached-guix-filetree-for-channels.
* doc/guix.texi: Document "git time-machine"
---
 doc/guix.texi                 |  47 +++++++++++++++-
 guix/inferior.scm             |  38 +++++++++----
 guix/scripts/pull.scm         |   1 +
 guix/scripts/time-machine.scm | 101 ++++++++++++++++++++++++++++++++++
 4 files changed, 174 insertions(+), 13 deletions(-)
 create mode 100644 guix/scripts/time-machine.scm

diff --git a/doc/guix.texi b/doc/guix.texi
index 7cc33c6e22..a147f16088 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -247,6 +247,7 @@ Utilities
 * Invoking guix container::     Process isolation.
 * Invoking guix weather::       Assessing substitute availability.
 * Invoking guix processes::     Listing client processes.
+* Invoking guix time-machine::  Running an older version of Guix.
 
 Invoking @command{guix build}
 
@@ -4142,7 +4143,10 @@ say, on another machine, by providing a channel specification in
 @end lisp
 
 The @command{guix describe --format=channels} command can even generate this
-list of channels directly (@pxref{Invoking guix describe}).
+list of channels directly (@pxref{Invoking guix describe}). The resulting
+file can be used with the -C options of @command{guix pull}
+(@pxref{Invoking guix pull}) or @command{guix time-machine}
+(@pxref{Invoking guix time-machine}).
 
 At this point the two machines run the @emph{exact same Guix}, with access to
 the @emph{exact same packages}.  The output of @command{guix build gimp} on
@@ -7894,6 +7898,7 @@ the Scheme programming interface of Guix in a convenient way.
 * Invoking guix container::     Process isolation.
 * Invoking guix weather::       Assessing substitute availability.
 * Invoking guix processes::     Listing client processes.
+* Invoking guix time-machine::  Running an older version of Guix.
 @end menu
 
 @node Invoking guix build
@@ -10563,6 +10568,46 @@ ClientPID: 19419
 ClientCommand: cuirass --cache-directory /var/cache/cuirass @dots{}
 @end example
 
+@node Invoking guix time-machine
+@section Invoking @command{guix time-machine}
+
+@cindex @command{guix time-machine}
+@cindex pinning, channels
+@cindex replicating Guix
+@cindex reproducibility, of Guix
+
+The @command{guix time-machine} command provides access to older
+versions of Guix, for example to install older versions of packages,
+or to reproduce a computation in an identical environment. The version
+of Guix to be used is defined by a commit or by a channel
+description file created by @command{guix describe}
+(@pxref{Invoking guix describe}).
+
+The general syntax is:
+
+@example
+guix time-machine @var{channels} -- @var{command} @var {arg}@dots{}
+@end example
+
+where @var{command} and @var{arg}@dots{} are passed unmodified to the
+@command{guix} command in its old version.  The @var{channels} that define
+this version can be specified using the following options:
+
+@table @code
+@item --url=@var{url}
+@itemx --commit=@var{commit}
+@itemx --branch=@var{branch}
+Use the @code{guix} channel from the specified @var{url}, at the
+given @var{commit} (a valid Git commit ID represented as a hexadecimal
+string), or @var{branch}.
+
+@item --channels=@var{file}
+@itemx -C @var{file}
+Read the list of channels from @var{file}.  @var{file} must contain
+Scheme code that evaluates to a list of channel objects.
+@xref{Channels} for more information.
+@end table
+
 
 @node System Configuration
 @chapter System Configuration
diff --git a/guix/inferior.scm b/guix/inferior.scm
index b8e2f21f42..cb80bb43d5 100644
--- a/guix/inferior.scm
+++ b/guix/inferior.scm
@@ -89,6 +89,7 @@
             gexp->derivation-in-inferior
 
             %inferior-cache-directory
+            cached-guix-filetree-for-channels
             inferior-for-channels))
 
 ;;; Commentary:
@@ -635,16 +636,13 @@ failing when GUIX is too old and lacks the 'guix repl' command."
   (make-parameter (string-append (cache-directory #:ensure? #f)
                                  "/inferiors")))
 
-(define* (inferior-for-channels channels
-                                #:key
-                                (cache-directory (%inferior-cache-directory))
-                                (ttl (* 3600 24 30)))
-  "Return an inferior for CHANNELS, a list of channels.  Use the cache at
-CACHE-DIRECTORY, where entries can be reclaimed after TTL seconds.  This
-procedure opens a new connection to the build daemon.
-
-This is a convenience procedure that people may use in manifests passed to
-'guix package -m', for instance."
+(define* (cached-guix-filetree-for-channels channels
+                                            #:key
+                                            (cache-directory (%inferior-cache-directory))
+                                            (ttl (* 3600 24 30)))
+  "Return a directory containing a guix filetree defined by CHANNELS, a list of channels.
+The directory is a subdirectory of CACHE-DIRECTORY, where entries can be reclaimed after TTL seconds.
+This procedure opens a new connection to the build daemon."
   (with-store store
     (let ()
       (define instances
@@ -680,7 +678,7 @@ This is a convenience procedure that people may use in manifests passed to
                                           (file-expiration-time ttl))
 
       (if (file-exists? cached)
-          (open-inferior cached)
+          cached
           (run-with-store store
             (mlet %store-monad ((profile
                                  (channel-instances->derivation instances)))
@@ -689,4 +687,20 @@ This is a convenience procedure that people may use in manifests passed to
                 (built-derivations (list profile))
                 (symlink* (derivation->output-path profile) cached)
                 (add-indirect-root* cached)
-                (return (open-inferior cached)))))))))
+                (return cached))))))))
+
+(define* (inferior-for-channels channels
+                                #:key
+                                (cache-directory (%inferior-cache-directory))
+                                (ttl (* 3600 24 30)))
+  "Return an inferior for CHANNELS, a list of channels.  Use the cache at
+CACHE-DIRECTORY, where entries can be reclaimed after TTL seconds.  This
+procedure opens a new connection to the build daemon.
+
+This is a convenience procedure that people may use in manifests passed to
+'guix package -m', for instance."
+  (define cached
+    (cached-guix-filetree-for-channels channels
+                                       #:cache-directory cache-directory
+                                       #:ttl ttl))
+  (open-inferior cached))
diff --git a/guix/scripts/pull.scm b/guix/scripts/pull.scm
index 80d070652b..a508e817b2 100644
--- a/guix/scripts/pull.scm
+++ b/guix/scripts/pull.scm
@@ -56,6 +56,7 @@
   #:use-module (ice-9 vlist)
   #:use-module (ice-9 format)
   #:export (display-profile-content
+            channel-list
             guix-pull))
 
 \f
diff --git a/guix/scripts/time-machine.scm b/guix/scripts/time-machine.scm
new file mode 100644
index 0000000000..8e954d51e1
--- /dev/null
+++ b/guix/scripts/time-machine.scm
@@ -0,0 +1,101 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Konrad Hinsen <konrad.hinsen@fastmail.net>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix scripts time-machine)
+  #:use-module (guix ui)
+  #:use-module (guix scripts)
+  #:use-module (guix inferior)
+  #:use-module (guix channels)
+  #:use-module ((guix scripts pull) #:select (channel-list))
+  #:use-module (ice-9 match)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-26)
+  #:use-module (srfi srfi-37)
+  #:export (guix-time-machine))
+
+\f
+;;;
+;;; Command-line options.
+;;;
+
+(define (show-help)
+  (display (G_ "Usage: guix time-machine [OPTION] -- COMMAND ARGS...
+Execute COMMAND ARGS... in an older version of Guix.\n"))
+  (display (G_ "
+  -C, --channels=FILE    deploy the channels defined in FILE"))
+  (display (G_ "
+      --url=URL          use the Git repository at URL"))
+  (display (G_ "
+      --commit=COMMIT    use the specified COMMIT"))
+  (display (G_ "
+      --branch=BRANCH    use the tip of the specified BRANCH"))
+  (display (G_ "
+  -h, --help             display this help and exit"))
+  (display (G_ "
+  -V, --version          display version information and exit"))
+  (newline)
+  (show-bug-report-information))
+
+(define %options
+  ;; Specifications of the command-line options.
+  (list (option '(#\C "channels") #t #f
+                (lambda (opt name arg result)
+                  (alist-cons 'channel-file arg result)))
+         (option '("url") #t #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'repository-url arg
+                               (alist-delete 'repository-url result))))
+         (option '("commit") #t #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'ref `(commit . ,arg) result)))
+         (option '("branch") #t #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'ref `(branch . ,arg) result)))
+        (option '(#\h "help") #f #f
+                (lambda args
+                  (show-help)
+                  (exit 0)))
+        (option '(#\V "version") #f #f
+                (lambda args
+                  (show-version-and-exit "guix time-machine")))))
+
+(define (parse-args args)
+  "Parse the list of command line arguments ARGS."
+  ;; The '--' token is used to separate the command to run from the rest of
+  ;; the operands.
+  (let-values (((args command) (break (cut string=? "--" <>) args)))
+    (let ((opts (parse-command-line args %options '(()) #:build-options? #f)))
+      (match command
+        (() opts)
+        (("--") opts)
+        (("--" command ...) (alist-cons 'exec command opts))))))
+
+\f
+;;;
+;;; Entry point.
+;;;
+
+(define (guix-time-machine . args)
+  (with-error-handling
+    (let* ((opts         (parse-args args))
+           (channels     (channel-list opts))
+           (command-line (assoc-ref opts 'exec))
+           (directory    (cached-guix-filetree-for-channels channels))
+           (executable   (string-append directory "/bin/guix")))
+      (apply system* (cons executable command-line)))))
-- 
2.23.0

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

* [bug#37978] [PATCH 1/3] guix: new command "guix time-machine"
  2019-10-25 15:42 [bug#37978] [PATCH] guix: new command "guix time-machine" Konrad Hinsen
@ 2019-10-25 15:42 ` Konrad Hinsen
  2019-11-06 13:53 ` [bug#37978] [PATCH] " Ludovic Courtès
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 22+ messages in thread
From: Konrad Hinsen @ 2019-10-25 15:42 UTC (permalink / raw)
  To: 37978

* guix/scripts/time-machine.scm: New file.
* Makefile.am: (MODULES): Add it.
* guix/scripts/pull.scm: Export function channel-list.
* guix/inferior.scm: New exported function cached-channel-instance.
* doc/guix.texi: Document "guix time-machine".
---
 Makefile.am                   |   1 +
 doc/guix.texi                 |  59 +++++++++++++++++++-
 guix/inferior.scm             |  38 +++++++++----
 guix/scripts/pull.scm         |   1 +
 guix/scripts/time-machine.scm | 102 ++++++++++++++++++++++++++++++++++
 5 files changed, 187 insertions(+), 14 deletions(-)
 create mode 100644 guix/scripts/time-machine.scm

diff --git a/Makefile.am b/Makefile.am
index b1f33946c5..b3f03d44c8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -278,6 +278,7 @@ MODULES =					\
   guix/scripts/container.scm			\
   guix/scripts/container/exec.scm		\
   guix/scripts/deploy.scm			\
+  guix/scripts/time-machine.scm			\
   guix.scm					\
   $(GNU_SYSTEM_MODULES)
 
diff --git a/doc/guix.texi b/doc/guix.texi
index 3b8e5935bb..3d4192cab2 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -197,6 +197,7 @@ Package Management
 * Invoking guix gc::            Running the garbage collector.
 * Invoking guix pull::          Fetching the latest Guix and distribution.
 * Channels::                    Customizing the package collection.
+* Invoking guix time-machine::  Running an older revision of Guix.
 * Inferiors::                   Interacting with another revision of Guix.
 * Invoking guix describe::      Display information about your Guix revision.
 * Invoking guix archive::       Exporting and importing store files.
@@ -2548,6 +2549,7 @@ guix install emacs-guix
 * Invoking guix gc::            Running the garbage collector.
 * Invoking guix pull::          Fetching the latest Guix and distribution.
 * Channels::                    Customizing the package collection.
+* Invoking guix time-machine::  Running an older revision of Guix.
 * Inferiors::                   Interacting with another revision of Guix.
 * Invoking guix describe::      Display information about your Guix revision.
 * Invoking guix archive::       Exporting and importing store files.
@@ -4150,7 +4152,10 @@ say, on another machine, by providing a channel specification in
 @end lisp
 
 The @command{guix describe --format=channels} command can even generate this
-list of channels directly (@pxref{Invoking guix describe}).
+list of channels directly (@pxref{Invoking guix describe}).  The resulting
+file can be used with the -C options of @command{guix pull}
+(@pxref{Invoking guix pull}) or @command{guix time-machine}
+(@pxref{Invoking guix time-machine}).
 
 At this point the two machines run the @emph{exact same Guix}, with access to
 the @emph{exact same packages}.  The output of @command{guix build gimp} on
@@ -4164,6 +4169,57 @@ artifacts with very fine grain, and to reproduce software environments at
 will---some sort of ``meta reproducibility'' capabilities, if you will.
 @xref{Inferiors}, for another way to take advantage of these super powers.
 
+@node Invoking guix time-machine
+@section Invoking @command{guix time-machine}
+
+@cindex @command{guix time-machine}
+@cindex pinning, channels
+@cindex replicating Guix
+@cindex reproducibility, of Guix
+
+The @command{guix time-machine} command provides access to other
+revisions of Guix, for example to install older versions of packages,
+or to reproduce a computation in an identical environment.  The revision
+of Guix to be used is defined by a commit or by a channel
+description file created by @command{guix describe}
+(@pxref{Invoking guix describe}).
+
+The general syntax is:
+
+@example
+guix time-machine @var{options}@dots{} -- @var{command} @var {arg}@dots{}
+@end example
+
+where @var{command} and @var{arg}@dots{} are passed unmodified to the
+@command{guix} command if the specified revision.  The @var{options} that define
+this revision are the same as for @command{guix pull} (@pxref{Invoking guix pull}):
+
+@table @code
+@item --url=@var{url}
+@itemx --commit=@var{commit}
+@itemx --branch=@var{branch}
+Use the @code{guix} channel from the specified @var{url}, at the
+given @var{commit} (a valid Git commit ID represented as a hexadecimal
+string), or @var{branch}.
+
+@item --channels=@var{file}
+@itemx -C @var{file}
+Read the list of channels from @var{file}.  @var{file} must contain
+Scheme code that evaluates to a list of channel objects.
+@xref{Channels} for more information.
+@end table
+
+As for @command{guix pull}, the absence of any options means that the
+the latest commit on the master branch will be used. The command
+
+@example
+guix time-machine -- build hello
+@end example
+
+will thus build the package @code{hello} as defined in the master branch,
+which is in general a newer revison of Guix than you have installed.
+Time travel works in both directions!
+
 @node Inferiors
 @section Inferiors
 
@@ -10582,7 +10638,6 @@ ClientPID: 19419
 ClientCommand: cuirass --cache-directory /var/cache/cuirass @dots{}
 @end example
 
-
 @node System Configuration
 @chapter System Configuration
 
diff --git a/guix/inferior.scm b/guix/inferior.scm
index b8e2f21f42..be50e0ec26 100644
--- a/guix/inferior.scm
+++ b/guix/inferior.scm
@@ -89,6 +89,7 @@
             gexp->derivation-in-inferior
 
             %inferior-cache-directory
+            cached-channel-instance
             inferior-for-channels))
 
 ;;; Commentary:
@@ -635,16 +636,13 @@ failing when GUIX is too old and lacks the 'guix repl' command."
   (make-parameter (string-append (cache-directory #:ensure? #f)
                                  "/inferiors")))
 
-(define* (inferior-for-channels channels
-                                #:key
-                                (cache-directory (%inferior-cache-directory))
-                                (ttl (* 3600 24 30)))
-  "Return an inferior for CHANNELS, a list of channels.  Use the cache at
-CACHE-DIRECTORY, where entries can be reclaimed after TTL seconds.  This
-procedure opens a new connection to the build daemon.
-
-This is a convenience procedure that people may use in manifests passed to
-'guix package -m', for instance."
+(define* (cached-channel-instance channels
+                                  #:key
+                                  (cache-directory (%inferior-cache-directory))
+                                  (ttl (* 3600 24 30)))
+  "Return a directory containing a guix filetree defined by CHANNELS, a list of channels.
+The directory is a subdirectory of CACHE-DIRECTORY, where entries can be reclaimed after TTL seconds.
+This procedure opens a new connection to the build daemon."
   (with-store store
     (let ()
       (define instances
@@ -680,7 +678,7 @@ This is a convenience procedure that people may use in manifests passed to
                                           (file-expiration-time ttl))
 
       (if (file-exists? cached)
-          (open-inferior cached)
+          cached
           (run-with-store store
             (mlet %store-monad ((profile
                                  (channel-instances->derivation instances)))
@@ -689,4 +687,20 @@ This is a convenience procedure that people may use in manifests passed to
                 (built-derivations (list profile))
                 (symlink* (derivation->output-path profile) cached)
                 (add-indirect-root* cached)
-                (return (open-inferior cached)))))))))
+                (return cached))))))))
+
+(define* (inferior-for-channels channels
+                                #:key
+                                (cache-directory (%inferior-cache-directory))
+                                (ttl (* 3600 24 30)))
+  "Return an inferior for CHANNELS, a list of channels.  Use the cache at
+CACHE-DIRECTORY, where entries can be reclaimed after TTL seconds.  This
+procedure opens a new connection to the build daemon.
+
+This is a convenience procedure that people may use in manifests passed to
+'guix package -m', for instance."
+  (define cached
+    (cached-channel-instance channels
+                             #:cache-directory cache-directory
+                             #:ttl ttl))
+  (open-inferior cached))
diff --git a/guix/scripts/pull.scm b/guix/scripts/pull.scm
index 92aac6066e..d6173a6acb 100644
--- a/guix/scripts/pull.scm
+++ b/guix/scripts/pull.scm
@@ -56,6 +56,7 @@
   #:use-module (ice-9 vlist)
   #:use-module (ice-9 format)
   #:export (display-profile-content
+            channel-list
             guix-pull))
 
 \f
diff --git a/guix/scripts/time-machine.scm b/guix/scripts/time-machine.scm
new file mode 100644
index 0000000000..a6598fb0f7
--- /dev/null
+++ b/guix/scripts/time-machine.scm
@@ -0,0 +1,102 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Konrad Hinsen <konrad.hinsen@fastmail.net>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix scripts time-machine)
+  #:use-module (guix ui)
+  #:use-module (guix scripts)
+  #:use-module (guix inferior)
+  #:use-module (guix channels)
+  #:use-module ((guix scripts pull) #:select (channel-list))
+  #:use-module (ice-9 match)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-26)
+  #:use-module (srfi srfi-37)
+  #:export (guix-time-machine))
+
+\f
+;;;
+;;; Command-line options.
+;;;
+
+(define (show-help)
+  (display (G_ "Usage: guix time-machine [OPTION] -- COMMAND ARGS...
+Execute COMMAND ARGS... in an older version of Guix.\n"))
+  (display (G_ "
+  -C, --channels=FILE    deploy the channels defined in FILE"))
+  (display (G_ "
+      --url=URL          use the Git repository at URL"))
+  (display (G_ "
+      --commit=COMMIT    use the specified COMMIT"))
+  (display (G_ "
+      --branch=BRANCH    use the tip of the specified BRANCH"))
+  (display (G_ "
+  -h, --help             display this help and exit"))
+  (display (G_ "
+  -V, --version          display version information and exit"))
+  (newline)
+  (show-bug-report-information))
+
+(define %options
+  ;; Specifications of the command-line options.
+  (list (option '(#\C "channels") #t #f
+                (lambda (opt name arg result)
+                  (alist-cons 'channel-file arg result)))
+         (option '("url") #t #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'repository-url arg
+                               (alist-delete 'repository-url result))))
+         (option '("commit") #t #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'ref `(commit . ,arg) result)))
+         (option '("branch") #t #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'ref `(branch . ,arg) result)))
+        (option '(#\h "help") #f #f
+                (lambda args
+                  (show-help)
+                  (exit 0)))
+        (option '(#\V "version") #f #f
+                (lambda args
+                  (show-version-and-exit "guix time-machine")))))
+
+(define (parse-args args)
+  "Parse the list of command line arguments ARGS."
+  ;; The '--' token is used to separate the command to run from the rest of
+  ;; the operands.
+  (let-values (((args command) (break (cut string=? "--" <>) args)))
+    (let ((opts (parse-command-line args %options '(()) #:build-options? #f)))
+      (match command
+        (() opts)
+        (("--") opts)
+        (("--" command ...) (alist-cons 'exec command opts))))))
+
+\f
+;;;
+;;; Entry point.
+;;;
+
+(define (guix-time-machine . args)
+  (with-error-handling
+    (let* ((opts         (parse-args args))
+           (channels     (channel-list opts))
+           (command-line (assoc-ref opts 'exec)))
+      (when command-line
+        (let* ((directory  (cached-channel-instance channels))
+               (executable (string-append directory "/bin/guix")))
+          (apply execl (cons* executable executable command-line)))))))
-- 
2.24.0

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

* [bug#37978] [PATCH] guix: new command "guix time-machine"
  2019-10-25 15:42 [bug#37978] [PATCH] guix: new command "guix time-machine" Konrad Hinsen
  2019-10-25 15:42 ` [bug#37978] [PATCH 1/3] " Konrad Hinsen
@ 2019-11-06 13:53 ` Ludovic Courtès
  2019-11-06 14:27   ` Tobias Geerinckx-Rice via Guix-patches via
                     ` (2 more replies)
  2019-11-08 10:16 ` [bug#37978] [PATCH 3/3] news: Add entry for " Konrad Hinsen
                   ` (2 subsequent siblings)
  4 siblings, 3 replies; 22+ messages in thread
From: Ludovic Courtès @ 2019-11-06 13:53 UTC (permalink / raw)
  To: Konrad Hinsen; +Cc: 37978

Hello Konrad!

Konrad Hinsen <konrad.hinsen@fastmail.net> skribis:

> * guix/scripts/time-machine.scm: New file.
> * guix/scripts/pull.scm: Export function channel-list.
> * guix/inferior.scm: New function cached-guix-filetree-for-channels.
> * doc/guix.texi: Document "git time-machine"

Awesome.  :-)

Please also add time-machine.scm to Makefile.am.  In the commit log,
you’ll get bonus points if you mention the modified entities in
parentheses (see ‘git log’ for examples.)  :-)

> @@ -247,6 +247,7 @@ Utilities
>  * Invoking guix container::     Process isolation.
>  * Invoking guix weather::       Assessing substitute availability.
>  * Invoking guix processes::     Listing client processes.
> +* Invoking guix time-machine::  Running an older version of Guix.

How about moving this section a bit higher, because it’s more widely
useful than ‘guix processes’ for instance?  Actually, it could go under
“Package Management” right before “Inferiors”, WDYT?

>  The @command{guix describe --format=channels} command can even generate this
> -list of channels directly (@pxref{Invoking guix describe}).
> +list of channels directly (@pxref{Invoking guix describe}). The resulting
> +file can be used with the -C options of @command{guix pull}
> +(@pxref{Invoking guix pull}) or @command{guix time-machine}
> +(@pxref{Invoking guix time-machine}).

Nitpick: Please write two spaces after an end-of-sentence period.

> +The general syntax is:
> +
> +@example
> +guix time-machine @var{channels} -- @var{command} @var {arg}@dots{}
> +@end example

I think it should be “guix time-machine @var{options}@dots{} -- …”,
right?

IIUC, if you run:

  guix time-machine -- build hello

you build “hello” with the latest master, right?

Perhaps it would be good to add an example like this one actually, WDYT?

> +where @var{command} and @var{arg}@dots{} are passed unmodified to the
> +@command{guix} command in its old version.  The @var{channels} that define
> +this version can be specified using the following options:

Perhaps add “like for @command{guix pull}”.

> -(define* (inferior-for-channels channels
> -                                #:key
> -                                (cache-directory (%inferior-cache-directory))
> -                                (ttl (* 3600 24 30)))
> -  "Return an inferior for CHANNELS, a list of channels.  Use the cache at
> -CACHE-DIRECTORY, where entries can be reclaimed after TTL seconds.  This
> -procedure opens a new connection to the build daemon.
> -
> -This is a convenience procedure that people may use in manifests passed to
> -'guix package -m', for instance."
> +(define* (cached-guix-filetree-for-channels channels
> +                                            #:key
> +                                            (cache-directory (%inferior-cache-directory))
> +                                            (ttl (* 3600 24 30)))
> +  "Return a directory containing a guix filetree defined by CHANNELS, a list of channels.
> +The directory is a subdirectory of CACHE-DIRECTORY, where entries can be reclaimed after TTL seconds.
> +This procedure opens a new connection to the build daemon."

How about (1) calling it ‘cached-channel-instance’ (or similar), and (2)
not opening a connection to the daemon?

Regarding (2), it means that procedure would be a monadic procedure and
it’s up to the user to do with-store + run-with-store or whatever.  The
general convention is to not open new connections on behalf of the user
(‘inferior-for-channels’ is one of the only exceptions to the rule
because it’s a convenience function for use in manifests.)

Perhaps this change should be a separate patch.

> +(define (guix-time-machine . args)
> +  (with-error-handling
> +    (let* ((opts         (parse-args args))
> +           (channels     (channel-list opts))
> +           (command-line (assoc-ref opts 'exec))
> +           (directory    (cached-guix-filetree-for-channels channels))
> +           (executable   (string-append directory "/bin/guix")))
> +      (apply system* (cons executable command-line)))))

I think this should be:

  (apply execl executable command-line)

so that we don’t create an extra process and actually get the exit code
for that sub-process.

Thanks,
Ludo’.

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

* [bug#37978] [PATCH] guix: new command "guix time-machine"
  2019-11-06 13:53 ` [bug#37978] [PATCH] " Ludovic Courtès
@ 2019-11-06 14:27   ` Tobias Geerinckx-Rice via Guix-patches via
  2019-11-07 13:11     ` Konrad Hinsen
  2019-11-06 14:30   ` Ludovic Courtès
  2019-11-08  7:14   ` Konrad Hinsen
  2 siblings, 1 reply; 22+ messages in thread
From: Tobias Geerinckx-Rice via Guix-patches via @ 2019-11-06 14:27 UTC (permalink / raw)
  To: 37978; +Cc: konrad.hinsen

[-- Attachment #1: Type: text/plain, Size: 171 bytes --]

Konrad,

Thank you!  This is neat!

Konrad Hinsen 写道:
> * doc/guix.texi: Document "git time-machine"
                             ^^^
Kind regards,

T G-R

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

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

* [bug#37978] [PATCH] guix: new command "guix time-machine"
  2019-11-06 13:53 ` [bug#37978] [PATCH] " Ludovic Courtès
  2019-11-06 14:27   ` Tobias Geerinckx-Rice via Guix-patches via
@ 2019-11-06 14:30   ` Ludovic Courtès
  2019-11-07 19:40     ` Konrad Hinsen
  2019-11-08  7:14   ` Konrad Hinsen
  2 siblings, 1 reply; 22+ messages in thread
From: Ludovic Courtès @ 2019-11-06 14:30 UTC (permalink / raw)
  To: Konrad Hinsen; +Cc: 37978

Another thing that comes to mind: it’d be nice to add an entry in
‘etc/news.scm’ to let users know about the new command!

Ludo’.

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

* [bug#37978] [PATCH] guix: new command "guix time-machine"
  2019-11-06 14:27   ` Tobias Geerinckx-Rice via Guix-patches via
@ 2019-11-07 13:11     ` Konrad Hinsen
  0 siblings, 0 replies; 22+ messages in thread
From: Konrad Hinsen @ 2019-11-07 13:11 UTC (permalink / raw)
  To: Tobias Geerinckx-Rice; +Cc: 37978

Tobias Geerinckx-Rice <me@tobias.gr> writes:

> Konrad Hinsen 写道:
>> * doc/guix.texi: Document "git time-machine"
>                              ^^^

Ouch. That's me. I always confuse "git" and "guix" on the command line.
It's worst for "pull", which works with both.

Is command-line dyslexia a thing already ? ;-)

Thanks for spotting the typo,
  Konrad.

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

* [bug#37978] [PATCH] guix: new command "guix time-machine"
  2019-11-06 14:30   ` Ludovic Courtès
@ 2019-11-07 19:40     ` Konrad Hinsen
  2019-11-07 21:10       ` Ludovic Courtès
  0 siblings, 1 reply; 22+ messages in thread
From: Konrad Hinsen @ 2019-11-07 19:40 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: 37978

Ludovic Courtès <ludo@gnu.org> writes:

> Another thing that comes to mind: it’d be nice to add an entry in
> ‘etc/news.scm’ to let users know about the new command!

If I understand the format correctly, I can't write this entry before
the command is merged into master, because I need the commit that
implements it.

Konrad.

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

* [bug#37978] [PATCH] guix: new command "guix time-machine"
  2019-11-07 19:40     ` Konrad Hinsen
@ 2019-11-07 21:10       ` Ludovic Courtès
  0 siblings, 0 replies; 22+ messages in thread
From: Ludovic Courtès @ 2019-11-07 21:10 UTC (permalink / raw)
  To: Konrad Hinsen; +Cc: 37978

Konrad Hinsen <konrad.hinsen@fastmail.net> skribis:

> Ludovic Courtès <ludo@gnu.org> writes:
>
>> Another thing that comes to mind: it’d be nice to add an entry in
>> ‘etc/news.scm’ to let users know about the new command!
>
> If I understand the format correctly, I can't write this entry before
> the command is merged into master, because I need the commit that
> implements it.

Exactly, so whoever pushes it must adjust the commit ID in the news
entry right before pushing.  You can just write (commit "XXX") in the
meantime.

Ludo’.

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

* [bug#37978] [PATCH] guix: new command "guix time-machine"
  2019-11-06 13:53 ` [bug#37978] [PATCH] " Ludovic Courtès
  2019-11-06 14:27   ` Tobias Geerinckx-Rice via Guix-patches via
  2019-11-06 14:30   ` Ludovic Courtès
@ 2019-11-08  7:14   ` Konrad Hinsen
  2019-11-08 14:13     ` [bug#37978] [PATCH 1/2] " Konrad Hinsen
                       ` (3 more replies)
  2 siblings, 4 replies; 22+ messages in thread
From: Konrad Hinsen @ 2019-11-08  7:14 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: 37978

Hi Ludo,

Thanks for your detailed comments, most of which I agree with, and I
will make the required changes. There is one issue I see:

> How about (1) calling it ‘cached-channel-instance’ (or similar), and (2)
> not opening a connection to the daemon?
>
> Regarding (2), it means that procedure would be a monadic procedure and
> it’s up to the user to do with-store + run-with-store or whatever.  The

That would imply that the user always opens a daemon, even if it is not
necessary because the required instance is already in the cache. Is that
a price worth paying for a more conventional interface, in your opinion?

Cheers,
  Konrad.

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

* [bug#37978] [PATCH 3/3] news: Add entry for "guix time-machine".
  2019-10-25 15:42 [bug#37978] [PATCH] guix: new command "guix time-machine" Konrad Hinsen
  2019-10-25 15:42 ` [bug#37978] [PATCH 1/3] " Konrad Hinsen
  2019-11-06 13:53 ` [bug#37978] [PATCH] " Ludovic Courtès
@ 2019-11-08 10:16 ` Konrad Hinsen
  2019-11-08 14:15 ` [bug#37978] [PATCH 2/2] " Konrad Hinsen
  2019-11-12 15:39 ` [bug#37978] [PATCH 2/3] guix: don't connect to daemon in cached-channel-instance Konrad Hinsen
  4 siblings, 0 replies; 22+ messages in thread
From: Konrad Hinsen @ 2019-11-08 10:16 UTC (permalink / raw)
  To: 37978

---
 etc/news.scm | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/etc/news.scm b/etc/news.scm
index 08e06351e9..bc6d173365 100644
--- a/etc/news.scm
+++ b/etc/news.scm
@@ -9,6 +9,24 @@
 (channel-news
  (version 0)
 
+ (entry (commit "XXX")
+        (title (en "New command @command{guix time-machine}")
+               (de "Neuer Befehl @command{guix time-machine}")
+               (fr "Nouvelle commande @command{guix time-machine}"))
+        (body (en "The new command @command{guix time-machine} facilitates
+access to older or newer revisions of Guix than the one that is installed.
+It can be used to install different versions of packages, and to
+re-create computational environments exactly as used in the past.")
+              (de "Der neue Befehl @command{guix time-machine} vereinfacht
+den Zugriff auf ältere oder neuere Guix-Versionen als die installierte.
+Er kann zur Installation bestimmer Paketversionen verwendet werden, aber
+auch zur Wiederherstellung von Entwicklungsumgebungen, wie sie in der
+Vergagngenheit verwendet wurden.")
+              (fr "La nouvelle commande @command{guix time-machine}
+facilite l'accès à des versions antérieures ou postérieures par rapport
+à la version installée.  Elle sert à installer des versions spécifiques
+de paquets, ainsi à la restauration d'environnements dans un état
+historique.")))
  (entry (commit "3e962e59d849e4300e447d94487684102d9d412e")
         (title (en "@command{guix graph} now supports package
 transformations"))
-- 
2.24.0

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

* [bug#37978] [PATCH 1/2] guix: new command "guix time-machine"
  2019-11-08  7:14   ` Konrad Hinsen
@ 2019-11-08 14:13     ` Konrad Hinsen
  2019-11-10 12:00       ` Ludovic Courtès
  2019-11-08 14:15     ` [bug#37978] [PATCH 2/2] news: Add entry for " Konrad Hinsen
                       ` (2 subsequent siblings)
  3 siblings, 1 reply; 22+ messages in thread
From: Konrad Hinsen @ 2019-11-08 14:13 UTC (permalink / raw)
  To: 37978

* guix/scripts/time-machine.scm: New file.
* Makefile.am: (MODULES): Add it.
* guix/scripts/pull.scm: Export function channel-list.
* guix/inferior.scm: New function cached-guix-filetree-for-channels.
* doc/guix.texi: Document "guix time-machine"
---
 Makefile.am                   |   1 +
 doc/guix.texi                 |  59 +++++++++++++++++++-
 guix/inferior.scm             |  38 +++++++++----
 guix/scripts/pull.scm         |   1 +
 guix/scripts/time-machine.scm | 102 ++++++++++++++++++++++++++++++++++
 5 files changed, 187 insertions(+), 14 deletions(-)
 create mode 100644 guix/scripts/time-machine.scm

diff --git a/Makefile.am b/Makefile.am
index b1f33946c5..b3f03d44c8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -278,6 +278,7 @@ MODULES =					\
   guix/scripts/container.scm			\
   guix/scripts/container/exec.scm		\
   guix/scripts/deploy.scm			\
+  guix/scripts/time-machine.scm			\
   guix.scm					\
   $(GNU_SYSTEM_MODULES)
 
diff --git a/doc/guix.texi b/doc/guix.texi
index 3b8e5935bb..3d4192cab2 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -197,6 +197,7 @@ Package Management
 * Invoking guix gc::            Running the garbage collector.
 * Invoking guix pull::          Fetching the latest Guix and distribution.
 * Channels::                    Customizing the package collection.
+* Invoking guix time-machine::  Running an older revision of Guix.
 * Inferiors::                   Interacting with another revision of Guix.
 * Invoking guix describe::      Display information about your Guix revision.
 * Invoking guix archive::       Exporting and importing store files.
@@ -2548,6 +2549,7 @@ guix install emacs-guix
 * Invoking guix gc::            Running the garbage collector.
 * Invoking guix pull::          Fetching the latest Guix and distribution.
 * Channels::                    Customizing the package collection.
+* Invoking guix time-machine::  Running an older revision of Guix.
 * Inferiors::                   Interacting with another revision of Guix.
 * Invoking guix describe::      Display information about your Guix revision.
 * Invoking guix archive::       Exporting and importing store files.
@@ -4150,7 +4152,10 @@ say, on another machine, by providing a channel specification in
 @end lisp
 
 The @command{guix describe --format=channels} command can even generate this
-list of channels directly (@pxref{Invoking guix describe}).
+list of channels directly (@pxref{Invoking guix describe}).  The resulting
+file can be used with the -C options of @command{guix pull}
+(@pxref{Invoking guix pull}) or @command{guix time-machine}
+(@pxref{Invoking guix time-machine}).
 
 At this point the two machines run the @emph{exact same Guix}, with access to
 the @emph{exact same packages}.  The output of @command{guix build gimp} on
@@ -4164,6 +4169,57 @@ artifacts with very fine grain, and to reproduce software environments at
 will---some sort of ``meta reproducibility'' capabilities, if you will.
 @xref{Inferiors}, for another way to take advantage of these super powers.
 
+@node Invoking guix time-machine
+@section Invoking @command{guix time-machine}
+
+@cindex @command{guix time-machine}
+@cindex pinning, channels
+@cindex replicating Guix
+@cindex reproducibility, of Guix
+
+The @command{guix time-machine} command provides access to other
+revisions of Guix, for example to install older versions of packages,
+or to reproduce a computation in an identical environment.  The revision
+of Guix to be used is defined by a commit or by a channel
+description file created by @command{guix describe}
+(@pxref{Invoking guix describe}).
+
+The general syntax is:
+
+@example
+guix time-machine @var{options}@dots{} -- @var{command} @var {arg}@dots{}
+@end example
+
+where @var{command} and @var{arg}@dots{} are passed unmodified to the
+@command{guix} command if the specified revision.  The @var{options} that define
+this revision are the same as for @command{guix pull} (@pxref{Invoking guix pull}):
+
+@table @code
+@item --url=@var{url}
+@itemx --commit=@var{commit}
+@itemx --branch=@var{branch}
+Use the @code{guix} channel from the specified @var{url}, at the
+given @var{commit} (a valid Git commit ID represented as a hexadecimal
+string), or @var{branch}.
+
+@item --channels=@var{file}
+@itemx -C @var{file}
+Read the list of channels from @var{file}.  @var{file} must contain
+Scheme code that evaluates to a list of channel objects.
+@xref{Channels} for more information.
+@end table
+
+As for @command{guix pull}, the absence of any options means that the
+the latest commit on the master branch will be used. The command
+
+@example
+guix time-machine -- build hello
+@end example
+
+will thus build the package @code{hello} as defined in the master branch,
+which is in general a newer revison of Guix than you have installed.
+Time travel works in both directions!
+
 @node Inferiors
 @section Inferiors
 
@@ -10582,7 +10638,6 @@ ClientPID: 19419
 ClientCommand: cuirass --cache-directory /var/cache/cuirass @dots{}
 @end example
 
-
 @node System Configuration
 @chapter System Configuration
 
diff --git a/guix/inferior.scm b/guix/inferior.scm
index b8e2f21f42..cb80bb43d5 100644
--- a/guix/inferior.scm
+++ b/guix/inferior.scm
@@ -89,6 +89,7 @@
             gexp->derivation-in-inferior
 
             %inferior-cache-directory
+            cached-guix-filetree-for-channels
             inferior-for-channels))
 
 ;;; Commentary:
@@ -635,16 +636,13 @@ failing when GUIX is too old and lacks the 'guix repl' command."
   (make-parameter (string-append (cache-directory #:ensure? #f)
                                  "/inferiors")))
 
-(define* (inferior-for-channels channels
-                                #:key
-                                (cache-directory (%inferior-cache-directory))
-                                (ttl (* 3600 24 30)))
-  "Return an inferior for CHANNELS, a list of channels.  Use the cache at
-CACHE-DIRECTORY, where entries can be reclaimed after TTL seconds.  This
-procedure opens a new connection to the build daemon.
-
-This is a convenience procedure that people may use in manifests passed to
-'guix package -m', for instance."
+(define* (cached-guix-filetree-for-channels channels
+                                            #:key
+                                            (cache-directory (%inferior-cache-directory))
+                                            (ttl (* 3600 24 30)))
+  "Return a directory containing a guix filetree defined by CHANNELS, a list of channels.
+The directory is a subdirectory of CACHE-DIRECTORY, where entries can be reclaimed after TTL seconds.
+This procedure opens a new connection to the build daemon."
   (with-store store
     (let ()
       (define instances
@@ -680,7 +678,7 @@ This is a convenience procedure that people may use in manifests passed to
                                           (file-expiration-time ttl))
 
       (if (file-exists? cached)
-          (open-inferior cached)
+          cached
           (run-with-store store
             (mlet %store-monad ((profile
                                  (channel-instances->derivation instances)))
@@ -689,4 +687,20 @@ This is a convenience procedure that people may use in manifests passed to
                 (built-derivations (list profile))
                 (symlink* (derivation->output-path profile) cached)
                 (add-indirect-root* cached)
-                (return (open-inferior cached)))))))))
+                (return cached))))))))
+
+(define* (inferior-for-channels channels
+                                #:key
+                                (cache-directory (%inferior-cache-directory))
+                                (ttl (* 3600 24 30)))
+  "Return an inferior for CHANNELS, a list of channels.  Use the cache at
+CACHE-DIRECTORY, where entries can be reclaimed after TTL seconds.  This
+procedure opens a new connection to the build daemon.
+
+This is a convenience procedure that people may use in manifests passed to
+'guix package -m', for instance."
+  (define cached
+    (cached-guix-filetree-for-channels channels
+                                       #:cache-directory cache-directory
+                                       #:ttl ttl))
+  (open-inferior cached))
diff --git a/guix/scripts/pull.scm b/guix/scripts/pull.scm
index 92aac6066e..d6173a6acb 100644
--- a/guix/scripts/pull.scm
+++ b/guix/scripts/pull.scm
@@ -56,6 +56,7 @@
   #:use-module (ice-9 vlist)
   #:use-module (ice-9 format)
   #:export (display-profile-content
+            channel-list
             guix-pull))
 
 \f
diff --git a/guix/scripts/time-machine.scm b/guix/scripts/time-machine.scm
new file mode 100644
index 0000000000..bc7ae573a3
--- /dev/null
+++ b/guix/scripts/time-machine.scm
@@ -0,0 +1,102 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Konrad Hinsen <konrad.hinsen@fastmail.net>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix scripts time-machine)
+  #:use-module (guix ui)
+  #:use-module (guix scripts)
+  #:use-module (guix inferior)
+  #:use-module (guix channels)
+  #:use-module ((guix scripts pull) #:select (channel-list))
+  #:use-module (ice-9 match)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-26)
+  #:use-module (srfi srfi-37)
+  #:export (guix-time-machine))
+
+\f
+;;;
+;;; Command-line options.
+;;;
+
+(define (show-help)
+  (display (G_ "Usage: guix time-machine [OPTION] -- COMMAND ARGS...
+Execute COMMAND ARGS... in an older version of Guix.\n"))
+  (display (G_ "
+  -C, --channels=FILE    deploy the channels defined in FILE"))
+  (display (G_ "
+      --url=URL          use the Git repository at URL"))
+  (display (G_ "
+      --commit=COMMIT    use the specified COMMIT"))
+  (display (G_ "
+      --branch=BRANCH    use the tip of the specified BRANCH"))
+  (display (G_ "
+  -h, --help             display this help and exit"))
+  (display (G_ "
+  -V, --version          display version information and exit"))
+  (newline)
+  (show-bug-report-information))
+
+(define %options
+  ;; Specifications of the command-line options.
+  (list (option '(#\C "channels") #t #f
+                (lambda (opt name arg result)
+                  (alist-cons 'channel-file arg result)))
+         (option '("url") #t #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'repository-url arg
+                               (alist-delete 'repository-url result))))
+         (option '("commit") #t #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'ref `(commit . ,arg) result)))
+         (option '("branch") #t #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'ref `(branch . ,arg) result)))
+        (option '(#\h "help") #f #f
+                (lambda args
+                  (show-help)
+                  (exit 0)))
+        (option '(#\V "version") #f #f
+                (lambda args
+                  (show-version-and-exit "guix time-machine")))))
+
+(define (parse-args args)
+  "Parse the list of command line arguments ARGS."
+  ;; The '--' token is used to separate the command to run from the rest of
+  ;; the operands.
+  (let-values (((args command) (break (cut string=? "--" <>) args)))
+    (let ((opts (parse-command-line args %options '(()) #:build-options? #f)))
+      (match command
+        (() opts)
+        (("--") opts)
+        (("--" command ...) (alist-cons 'exec command opts))))))
+
+\f
+;;;
+;;; Entry point.
+;;;
+
+(define (guix-time-machine . args)
+  (with-error-handling
+    (let* ((opts         (parse-args args))
+           (channels     (channel-list opts))
+           (command-line (assoc-ref opts 'exec)))
+      (when command-line
+        (let* ((directory  (cached-guix-filetree-for-channels channels))
+               (executable (string-append directory "/bin/guix")))
+          (apply execl (cons* executable executable command-line)))))))
-- 
2.23.0

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

* [bug#37978] [PATCH 2/2] news: Add entry for "guix time-machine".
  2019-11-08  7:14   ` Konrad Hinsen
  2019-11-08 14:13     ` [bug#37978] [PATCH 1/2] " Konrad Hinsen
@ 2019-11-08 14:15     ` Konrad Hinsen
  2019-11-08 20:43       ` pelzflorian (Florian Pelz)
  2019-11-08 14:16     ` [bug#37978] [PATCH] guix: new command " Konrad Hinsen
  2019-11-08 20:09     ` Ludovic Courtès
  3 siblings, 1 reply; 22+ messages in thread
From: Konrad Hinsen @ 2019-11-08 14:15 UTC (permalink / raw)
  To: 37978

* etc/news.scm: Add entry for "guix time-machine".
---
 etc/news.scm | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/etc/news.scm b/etc/news.scm
index 08e06351e9..b6a7f46ee9 100644
--- a/etc/news.scm
+++ b/etc/news.scm
@@ -9,6 +9,24 @@
 (channel-news
  (version 0)
 
+ (entry (commit "XXX")
+        (title (en "New command @command{guix time-machine}")
+               (de "Neuer Befehl @command{guix time-machine}")
+               (fr "Nouvelle commande @command{guix time-machine}"))
+        (body (en "The new command @command{guix time-machine} facilitates
+access to older or newer revisions of Guix than the one that is installed.
+It can be used to install different versions of packages, and to
+re-create computational environments exactly as used in the past.")
+              (de "Der neue Befehl @command{guix time-machine} vereinfacht
+den Zugriff auf ältere oder neuere Guix-Versionen als die installierte.
+Er kann zur Installation bestimmer Paket-Versionen verwendet werden, aber
+auch zur Wiederherstellung von Entwicklungsumgebungen wie sie in der
+Vergagngenheit verwendet wurden.")
+              (fr "La nouvelle commande @command{guix time-machine}
+facilite l'accès à des versions antérieures ou postérieures par rapport
+à la version installée.  Elle sert à installer des versions spécifiques
+de paquets, ainsi à la restauration d'environnements dans un état
+historique.")))
  (entry (commit "3e962e59d849e4300e447d94487684102d9d412e")
         (title (en "@command{guix graph} now supports package
 transformations"))
-- 
2.23.0

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

* [bug#37978] [PATCH 2/2] news: Add entry for "guix time-machine".
  2019-10-25 15:42 [bug#37978] [PATCH] guix: new command "guix time-machine" Konrad Hinsen
                   ` (2 preceding siblings ...)
  2019-11-08 10:16 ` [bug#37978] [PATCH 3/3] news: Add entry for " Konrad Hinsen
@ 2019-11-08 14:15 ` Konrad Hinsen
  2019-11-12 15:39 ` [bug#37978] [PATCH 2/3] guix: don't connect to daemon in cached-channel-instance Konrad Hinsen
  4 siblings, 0 replies; 22+ messages in thread
From: Konrad Hinsen @ 2019-11-08 14:15 UTC (permalink / raw)
  To: 37978

* etc/news.scm: Add entry for "guix time-machine".
---
 etc/news.scm | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/etc/news.scm b/etc/news.scm
index 08e06351e9..b6a7f46ee9 100644
--- a/etc/news.scm
+++ b/etc/news.scm
@@ -9,6 +9,24 @@
 (channel-news
  (version 0)
 
+ (entry (commit "XXX")
+        (title (en "New command @command{guix time-machine}")
+               (de "Neuer Befehl @command{guix time-machine}")
+               (fr "Nouvelle commande @command{guix time-machine}"))
+        (body (en "The new command @command{guix time-machine} facilitates
+access to older or newer revisions of Guix than the one that is installed.
+It can be used to install different versions of packages, and to
+re-create computational environments exactly as used in the past.")
+              (de "Der neue Befehl @command{guix time-machine} vereinfacht
+den Zugriff auf ältere oder neuere Guix-Versionen als die installierte.
+Er kann zur Installation bestimmer Paket-Versionen verwendet werden, aber
+auch zur Wiederherstellung von Entwicklungsumgebungen wie sie in der
+Vergagngenheit verwendet wurden.")
+              (fr "La nouvelle commande @command{guix time-machine}
+facilite l'accès à des versions antérieures ou postérieures par rapport
+à la version installée.  Elle sert à installer des versions spécifiques
+de paquets, ainsi à la restauration d'environnements dans un état
+historique.")))
  (entry (commit "3e962e59d849e4300e447d94487684102d9d412e")
         (title (en "@command{guix graph} now supports package
 transformations"))
-- 
2.23.0

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

* [bug#37978] [PATCH] guix: new command "guix time-machine"
  2019-11-08  7:14   ` Konrad Hinsen
  2019-11-08 14:13     ` [bug#37978] [PATCH 1/2] " Konrad Hinsen
  2019-11-08 14:15     ` [bug#37978] [PATCH 2/2] news: Add entry for " Konrad Hinsen
@ 2019-11-08 14:16     ` Konrad Hinsen
  2019-11-15 22:35       ` bug#37978: " Ludovic Courtès
  2019-11-08 20:09     ` Ludovic Courtès
  3 siblings, 1 reply; 22+ messages in thread
From: Konrad Hinsen @ 2019-11-08 14:16 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: 37978

Konrad Hinsen <konrad.hinsen@fastmail.net> writes:

> Thanks for your detailed comments, most of which I agree with, and I
> will make the required changes.

I just submitted two new patches. Looking forward to everyone's feedbck!

Cheers,
  Konrad.

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

* [bug#37978] [PATCH] guix: new command "guix time-machine"
  2019-11-08  7:14   ` Konrad Hinsen
                       ` (2 preceding siblings ...)
  2019-11-08 14:16     ` [bug#37978] [PATCH] guix: new command " Konrad Hinsen
@ 2019-11-08 20:09     ` Ludovic Courtès
  3 siblings, 0 replies; 22+ messages in thread
From: Ludovic Courtès @ 2019-11-08 20:09 UTC (permalink / raw)
  To: Konrad Hinsen; +Cc: 37978

Hello,

Konrad Hinsen <konrad.hinsen@fastmail.net> skribis:

>> How about (1) calling it ‘cached-channel-instance’ (or similar), and (2)
>> not opening a connection to the daemon?
>>
>> Regarding (2), it means that procedure would be a monadic procedure and
>> it’s up to the user to do with-store + run-with-store or whatever.  The
>
> That would imply that the user always opens a daemon, even if it is not
> necessary because the required instance is already in the cache. Is that
> a price worth paying for a more conventional interface, in your opinion?

Ah, I hadn’t thought about it.

Hmm opening a connection to the daemon doesn’t cost much, but OTOH it’s
best if we can avoid it here since ‘guix time-machine’ is just a
trampoline.

Dunno, I’ll comment on the new patches and we’ll see.  :-)

Ludo’.

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

* [bug#37978] [PATCH 2/2] news: Add entry for "guix time-machine".
  2019-11-08 14:15     ` [bug#37978] [PATCH 2/2] news: Add entry for " Konrad Hinsen
@ 2019-11-08 20:43       ` pelzflorian (Florian Pelz)
  2019-11-10 12:02         ` Ludovic Courtès
  0 siblings, 1 reply; 22+ messages in thread
From: pelzflorian (Florian Pelz) @ 2019-11-08 20:43 UTC (permalink / raw)
  To: Konrad Hinsen; +Cc: 37978

Thank you for not only this useful command but also providing
translations.  It does not really matter, but:

On Fri, Nov 08, 2019 at 03:15:16PM +0100, Konrad Hinsen wrote:
> * etc/news.scm: Add entry for "guix time-machine".
> ---
>  etc/news.scm | 18 ++++++++++++++++++
>  1 file changed, 18 insertions(+)
> […]
> +              (de "Der neue Befehl @command{guix time-machine} vereinfacht
> +den Zugriff auf ältere oder neuere Guix-Versionen als die installierte.
> +Er kann zur Installation bestimmer Paket-Versionen verwendet werden, aber

I would prefer „Paketversionen“ rather than „Paket-Versionen“ because
the hyphen does not make it easier to read.


> +auch zur Wiederherstellung von Entwicklungsumgebungen wie sie in der
> +Vergagngenheit verwendet wurden.")

There needs to be a comma before „wie“ because what follows is a
separate nebensatz.

Regards,
Florian

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

* [bug#37978] [PATCH 1/2] guix: new command "guix time-machine"
  2019-11-08 14:13     ` [bug#37978] [PATCH 1/2] " Konrad Hinsen
@ 2019-11-10 12:00       ` Ludovic Courtès
  2019-11-12 15:52         ` Konrad Hinsen
  0 siblings, 1 reply; 22+ messages in thread
From: Ludovic Courtès @ 2019-11-10 12:00 UTC (permalink / raw)
  To: Konrad Hinsen; +Cc: 37978

Hi Konrad,

Thanks for the updated patch!

Konrad Hinsen <konrad.hinsen@fastmail.net> skribis:

> * guix/scripts/time-machine.scm: New file.
> * Makefile.am: (MODULES): Add it.
> * guix/scripts/pull.scm: Export function channel-list.
> * guix/inferior.scm: New function cached-guix-filetree-for-channels.
> * doc/guix.texi: Document "guix time-machine"

[...]

> +(define* (cached-guix-filetree-for-channels channels
> +                                            #:key
> +                                            (cache-directory (%inferior-cache-directory))
> +                                            (ttl (* 3600 24 30)))
> +  "Return a directory containing a guix filetree defined by CHANNELS, a list of channels.
> +The directory is a subdirectory of CACHE-DIRECTORY, where entries can be reclaimed after TTL seconds.
> +This procedure opens a new connection to the build daemon."
>    (with-store store

It’s the same as in v1, right?

How about (1) calling it ‘cached-channel-instance’ (or similar; as a
rule of thumb, I try to avoid “guix” in identifiers as well as
neologisms), and (2) not opening a connection to the daemon?  :-)

As it stands, this procedure opens a connection unconditionally anyway,
so it’s fine IMO to just move that ‘with-store’ to time-machine.scm and
to ‘inferior-for-channels’.

I also think it would be preferable to make it a separate patch
(separate from the one that adds time-machine.scm), if it’s OK for you.

Thoughts?

Thank you!

Ludo’.

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

* [bug#37978] [PATCH 2/2] news: Add entry for "guix time-machine".
  2019-11-08 20:43       ` pelzflorian (Florian Pelz)
@ 2019-11-10 12:02         ` Ludovic Courtès
  0 siblings, 0 replies; 22+ messages in thread
From: Ludovic Courtès @ 2019-11-10 12:02 UTC (permalink / raw)
  To: pelzflorian (Florian Pelz); +Cc: Konrad Hinsen, 37978

"pelzflorian (Florian Pelz)" <pelzflorian@pelzflorian.de> skribis:

> Thank you for not only this useful command but also providing
> translations.

Ah yes, I forgot to say it Konrad, but you can Cc: guix-i18n@gnu.org to
obtain translations.  It’s convenient to be polyglot though.  ;-)

Ludo’.

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

* [bug#37978] [PATCH 2/3] guix: don't connect to daemon in cached-channel-instance
  2019-10-25 15:42 [bug#37978] [PATCH] guix: new command "guix time-machine" Konrad Hinsen
                   ` (3 preceding siblings ...)
  2019-11-08 14:15 ` [bug#37978] [PATCH 2/2] " Konrad Hinsen
@ 2019-11-12 15:39 ` Konrad Hinsen
  4 siblings, 0 replies; 22+ messages in thread
From: Konrad Hinsen @ 2019-11-12 15:39 UTC (permalink / raw)
  To: 37978

* guix/inferior.scm (cached-channel-instance): take an explicit store argument
* guix/inferior.scm (inferior-for-channels): wrap call to
  cached-channel-instance in with-store
* guix/time-machine.scm (guix-time-machine): wrap call to
  cached-channel-instance in with-store
---
 guix/inferior.scm             | 99 ++++++++++++++++++-----------------
 guix/scripts/time-machine.scm |  4 +-
 2 files changed, 53 insertions(+), 50 deletions(-)

diff --git a/guix/inferior.scm b/guix/inferior.scm
index be50e0ec26..71dae89e92 100644
--- a/guix/inferior.scm
+++ b/guix/inferior.scm
@@ -636,58 +636,57 @@ failing when GUIX is too old and lacks the 'guix repl' command."
   (make-parameter (string-append (cache-directory #:ensure? #f)
                                  "/inferiors")))
 
-(define* (cached-channel-instance channels
+(define* (cached-channel-instance store
+                                  channels
                                   #:key
                                   (cache-directory (%inferior-cache-directory))
                                   (ttl (* 3600 24 30)))
   "Return a directory containing a guix filetree defined by CHANNELS, a list of channels.
 The directory is a subdirectory of CACHE-DIRECTORY, where entries can be reclaimed after TTL seconds.
 This procedure opens a new connection to the build daemon."
-  (with-store store
-    (let ()
-      (define instances
-        (latest-channel-instances store channels))
-
-      (define key
-        (bytevector->base32-string
-         (sha256
-          (string->utf8
-           (string-concatenate (map channel-instance-commit instances))))))
-
-      (define cached
-        (string-append cache-directory "/" key))
-
-      (define (base32-encoded-sha256? str)
-        (= (string-length str) 52))
-
-      (define (cache-entries directory)
-        (map (lambda (file)
-               (string-append directory "/" file))
-             (scandir directory base32-encoded-sha256?)))
-
-      (define symlink*
-        (lift2 symlink %store-monad))
-
-      (define add-indirect-root*
-        (store-lift add-indirect-root))
-
-      (mkdir-p cache-directory)
-      (maybe-remove-expired-cache-entries cache-directory
-                                          cache-entries
-                                          #:entry-expiration
-                                          (file-expiration-time ttl))
-
-      (if (file-exists? cached)
-          cached
-          (run-with-store store
-            (mlet %store-monad ((profile
-                                 (channel-instances->derivation instances)))
-              (mbegin %store-monad
-                (show-what-to-build* (list profile))
-                (built-derivations (list profile))
-                (symlink* (derivation->output-path profile) cached)
-                (add-indirect-root* cached)
-                (return cached))))))))
+  (define instances
+    (latest-channel-instances store channels))
+
+  (define key
+    (bytevector->base32-string
+     (sha256
+      (string->utf8
+       (string-concatenate (map channel-instance-commit instances))))))
+
+  (define cached
+    (string-append cache-directory "/" key))
+
+  (define (base32-encoded-sha256? str)
+    (= (string-length str) 52))
+
+  (define (cache-entries directory)
+    (map (lambda (file)
+           (string-append directory "/" file))
+         (scandir directory base32-encoded-sha256?)))
+
+  (define symlink*
+    (lift2 symlink %store-monad))
+
+  (define add-indirect-root*
+    (store-lift add-indirect-root))
+
+  (mkdir-p cache-directory)
+  (maybe-remove-expired-cache-entries cache-directory
+                                      cache-entries
+                                      #:entry-expiration
+                                      (file-expiration-time ttl))
+
+  (if (file-exists? cached)
+      cached
+      (run-with-store store
+        (mlet %store-monad ((profile
+                             (channel-instances->derivation instances)))
+          (mbegin %store-monad
+            (show-what-to-build* (list profile))
+            (built-derivations (list profile))
+            (symlink* (derivation->output-path profile) cached)
+            (add-indirect-root* cached)
+            (return cached))))))
 
 (define* (inferior-for-channels channels
                                 #:key
@@ -700,7 +699,9 @@ procedure opens a new connection to the build daemon.
 This is a convenience procedure that people may use in manifests passed to
 'guix package -m', for instance."
   (define cached
-    (cached-channel-instance channels
-                             #:cache-directory cache-directory
-                             #:ttl ttl))
+    (with-store store
+      (cached-channel-instance store
+                               channels
+                               #:cache-directory cache-directory
+                               #:ttl ttl)))
   (open-inferior cached))
diff --git a/guix/scripts/time-machine.scm b/guix/scripts/time-machine.scm
index a6598fb0f7..a64badc27b 100644
--- a/guix/scripts/time-machine.scm
+++ b/guix/scripts/time-machine.scm
@@ -21,6 +21,7 @@
   #:use-module (guix scripts)
   #:use-module (guix inferior)
   #:use-module (guix channels)
+  #:use-module (guix store)
   #:use-module ((guix scripts pull) #:select (channel-list))
   #:use-module (ice-9 match)
   #:use-module (srfi srfi-1)
@@ -97,6 +98,7 @@ Execute COMMAND ARGS... in an older version of Guix.\n"))
            (channels     (channel-list opts))
            (command-line (assoc-ref opts 'exec)))
       (when command-line
-        (let* ((directory  (cached-channel-instance channels))
+        (let* ((directory  (with-store store
+                             (cached-channel-instance store channels)))
                (executable (string-append directory "/bin/guix")))
           (apply execl (cons* executable executable command-line)))))))
-- 
2.24.0

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

* [bug#37978] [PATCH 1/2] guix: new command "guix time-machine"
  2019-11-10 12:00       ` Ludovic Courtès
@ 2019-11-12 15:52         ` Konrad Hinsen
  0 siblings, 0 replies; 22+ messages in thread
From: Konrad Hinsen @ 2019-11-12 15:52 UTC (permalink / raw)
  To: Ludovic Courtès, pelzflorian (Florian Pelz), 37978

Hi Ludo and Florian,

Thanks for your comments and corrections. I have prepared a third
version, now consisting of three patches. I'll send them in a minute...

Cheers,
  Konrad.

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

* bug#37978: [PATCH] guix: new command "guix time-machine"
  2019-11-08 14:16     ` [bug#37978] [PATCH] guix: new command " Konrad Hinsen
@ 2019-11-15 22:35       ` Ludovic Courtès
  2019-11-16  9:06         ` [bug#37978] " Konrad Hinsen
  0 siblings, 1 reply; 22+ messages in thread
From: Ludovic Courtès @ 2019-11-15 22:35 UTC (permalink / raw)
  To: Konrad Hinsen; +Cc: 37978-done

Hi Konrad,

Konrad Hinsen <konrad.hinsen@fastmail.net> skribis:

> Konrad Hinsen <konrad.hinsen@fastmail.net> writes:
>
>> Thanks for your detailed comments, most of which I agree with, and I
>> will make the required changes.
>
> I just submitted two new patches. Looking forward to everyone's feedbck!

I’ve just applied them, thank you!

I followed up with one commit to gracefully handle Git errors (e.g.,
when one type ‘--commit=foobar’) and another one to handle build options
like the other commands.  Let me know if anything looks wrong.

Anyway, I can do things like this:

--8<---------------cut here---------------start------------->8---
$ ./pre-inst-env guix time-machine --commit=65956ad3526ba09e1f7a40722c96c6ef7c0936fe -- package -A |wc -l
Updating channel 'guix' from Git repository at 'https://git.savannah.gnu.org/git/guix.git'...
guile: warning: failed to install locale
warning: failed to install locale: Invalid argument
7666
--8<---------------cut here---------------end--------------->8---

… where the commit in question is from June 2018.  Pretty fun!

It would be neat if the “Updating…” message wouldn’t show up when in
fact everything is already available.  Also, it’d be nice if we could
write (and in ‘guix pull’ too) ‘--date=2019-07-07’ or
‘--date=last-month’.  Future work!  :-)

Thanks again for this nifty command!

Ludo’.

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

* [bug#37978] [PATCH] guix: new command "guix time-machine"
  2019-11-15 22:35       ` bug#37978: " Ludovic Courtès
@ 2019-11-16  9:06         ` Konrad Hinsen
  0 siblings, 0 replies; 22+ messages in thread
From: Konrad Hinsen @ 2019-11-16  9:06 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: 37978-done

Hi Ludo,

> I followed up with one commit to gracefully handle Git errors (e.g.,
> when one type ‘--commit=foobar’) and another one to handle build options
> like the other commands.  Let me know if anything looks wrong.

Quite on the contrary, everything looks fine - thanks!

I hadn't realized that "guix pull" takes build options, but obviously
that makes sense.

> It would be neat if the “Updating…” message wouldn’t show up when in
> fact everything is already available.  Also, it’d be nice if we could
> write (and in ‘guix pull’ too) ‘--date=2019-07-07’ or
> ‘--date=last-month’.  Future work!  :-)

Right. Also not pulling anything if the requested channels are identical
to those of the current guix version. There's always more to to!

Cheers,
  Konrad.

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

end of thread, other threads:[~2019-11-16  9:07 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-25 15:42 [bug#37978] [PATCH] guix: new command "guix time-machine" Konrad Hinsen
2019-10-25 15:42 ` [bug#37978] [PATCH 1/3] " Konrad Hinsen
2019-11-06 13:53 ` [bug#37978] [PATCH] " Ludovic Courtès
2019-11-06 14:27   ` Tobias Geerinckx-Rice via Guix-patches via
2019-11-07 13:11     ` Konrad Hinsen
2019-11-06 14:30   ` Ludovic Courtès
2019-11-07 19:40     ` Konrad Hinsen
2019-11-07 21:10       ` Ludovic Courtès
2019-11-08  7:14   ` Konrad Hinsen
2019-11-08 14:13     ` [bug#37978] [PATCH 1/2] " Konrad Hinsen
2019-11-10 12:00       ` Ludovic Courtès
2019-11-12 15:52         ` Konrad Hinsen
2019-11-08 14:15     ` [bug#37978] [PATCH 2/2] news: Add entry for " Konrad Hinsen
2019-11-08 20:43       ` pelzflorian (Florian Pelz)
2019-11-10 12:02         ` Ludovic Courtès
2019-11-08 14:16     ` [bug#37978] [PATCH] guix: new command " Konrad Hinsen
2019-11-15 22:35       ` bug#37978: " Ludovic Courtès
2019-11-16  9:06         ` [bug#37978] " Konrad Hinsen
2019-11-08 20:09     ` Ludovic Courtès
2019-11-08 10:16 ` [bug#37978] [PATCH 3/3] news: Add entry for " Konrad Hinsen
2019-11-08 14:15 ` [bug#37978] [PATCH 2/2] " Konrad Hinsen
2019-11-12 15:39 ` [bug#37978] [PATCH 2/3] guix: don't connect to daemon in cached-channel-instance Konrad Hinsen

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).