* Update: Implementing guix system rollback / switch-generation
@ 2016-07-09 2:53 Chris Marusich
2016-07-12 15:30 ` Ludovic Courtès
0 siblings, 1 reply; 3+ messages in thread
From: Chris Marusich @ 2016-07-09 2:53 UTC (permalink / raw)
To: guix-devel
[-- Attachment #1.1: Type: text/plain, Size: 2014 bytes --]
Hi Guix,
I've attached a preliminary patch which adds rudimentary roll-back and
switch-generation commands to "guix system". Currently, the commands
just flip symlinks, which is part of the first milestone that Ludo
suggested in the following thread:
https://lists.gnu.org/archive/html/guix-devel/2016-06/msg00178.html
Please let me know what you think. After getting feedback, I intend to
follow up a more complete patch that contains the following additional
changes:
* Regenerate grub.cfg, to complete the first milestone. I'm not sure
exactly how this will play out, but I imagine I'll need to use the
store somehow to get it done.
* Use a properly formatted ChangeLog-style Git commit message.
* Mention these new commands in the manual.
* Add tests. I'm not new to automated testing, but I haven't done it
using autoconf/make or in Guile, so tips here would be welcome!
* Add these new commands to the emacs interface.
I've tested the changes on my bare metal GuixSD installation. I would
have used a VM, but my system has trouble launching VMs. I first
verified manually that the roll-back command switched the profile's
symlink to the previous generation, by examining the output of
list-generations and ls. I then verified, in the same way, that the
switch-generation command switched the profile's symlink to the
specified generation. I verified that switch-generation works for
arbitrary numbers and relative numbers (note that a negative relative
number must be preceded by the special "--" argument to prevent it from
being interpreted as an option). I also verified that if the user
attempts to switch to a nonexistent generation (or to roll back from
generation 1 in the case of "guix system"), an error is raised without
modifying anything. I repeated this manual verification process for
both the "guix system" and "guix package" commands, since my changes
involve some refactoring in "guix package".
Thank you,
--
Chris
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: 0001-Implement-system-roll-back-and-switch-generation-com.patch --]
[-- Type: text/x-patch, Size: 8824 bytes --]
From 00f8b1ccea6c80e37535cd16b05bafbb9cf3686b Mon Sep 17 00:00:00 2001
From: Chris Marusich <cmmarusich@gmail.com>
Date: Fri, 8 Jul 2016 13:49:25 -0700
Subject: [PATCH] Implement system roll-back and switch-generation commands
Right now, they just switch symlinks.
---
guix/profiles.scm | 21 ++++++++++++++++-
guix/scripts/package.scm | 7 +-----
guix/scripts/system.scm | 59 +++++++++++++++++++++++++++++++++++++-----------
guix/ui.scm | 8 +++++++
4 files changed, 75 insertions(+), 20 deletions(-)
diff --git a/guix/profiles.scm b/guix/profiles.scm
index 90c4332..9b0ce7f 100644
--- a/guix/profiles.scm
+++ b/guix/profiles.scm
@@ -90,11 +90,13 @@
generation-number
generation-numbers
profile-generations
+ relative-generation-spec->number
relative-generation
previous-generation-number
generation-time
generation-file-name
switch-to-generation
+ switch-to-previous-generation
roll-back
delete-generation))
@@ -896,6 +898,21 @@ former profiles were found."
'()
generations)))
+(define (relative-generation-spec->number profile spec)
+ "Return PROFILE's generation specified by SPEC, which is a string. The SPEC
+may be a N, -N, or +N, where N is a number. If the spec is N, then the number
+returned is N. If it is -N, then the number returned is the profile's current
+generation number minus N. If it is +N, then the number returned is the
+profile's current generation number plus N. Return #f if there is no such
+generation."
+ (let ((number (string->number spec)))
+ (and number
+ (case (string-ref spec 0)
+ ((#\+ #\-)
+ (relative-generation profile number))
+ (else number)))))
+
+
(define* (relative-generation profile shift #:optional
(current (generation-number profile)))
"Return PROFILE's generation shifted from the CURRENT generation by SHIFT.
@@ -939,7 +956,9 @@ that fails."
(define (switch-to-generation profile number)
"Atomically switch PROFILE to the generation NUMBER. Return the number of
-the generation that was current before switching."
+the generation that was current before switching. Raise a
+&profile-not-found-error when the profile does not exist. Raise a
+&missing-generation-error when the generation does not exist."
(let ((current (generation-number profile))
(generation (generation-file-name profile number)))
(cond ((not (file-exists? profile))
diff --git a/guix/scripts/package.scm b/guix/scripts/package.scm
index e2e3709..8df5145 100644
--- a/guix/scripts/package.scm
+++ b/guix/scripts/package.scm
@@ -743,12 +743,7 @@ processed, #f otherwise."
#:key dry-run?)
"Switch PROFILE to the generation specified by SPEC."
(unless dry-run?
- (let* ((number (string->number spec))
- (number (and number
- (case (string-ref spec 0)
- ((#\+ #\-)
- (relative-generation profile number))
- (else number)))))
+ (let ((number (relative-generation-spec->number profile spec)))
(if number
(switch-to-generation* profile number)
(leave (_ "cannot switch to generation '~a'~%") spec)))))
diff --git a/guix/scripts/system.scm b/guix/scripts/system.scm
index dd1e534..3548d54 100644
--- a/guix/scripts/system.scm
+++ b/guix/scripts/system.scm
@@ -418,6 +418,23 @@ it atomically, and then run OS's activation script."
\f
;;;
+;;; Roll-back.
+;;;
+(define (roll-back-system)
+ "Roll back the system profile to its previous generation."
+ (switch-to-previous-generation* %system-profile))
+\f
+;;;
+;;; Switch generations.
+;;;
+(define (switch-to-system-generation spec)
+ "Switch the system profile to the generation specified by SPEC."
+ (let ((number (relative-generation-spec->number %system-profile spec)))
+ (if number
+ (switch-to-generation* %system-profile number)
+ (leave (_ "cannot switch to system generation '~a'~%") spec))))
+\f
+;;;
;;; Graphs.
;;;
@@ -649,31 +666,36 @@ building anything."
;;;
(define (show-help)
- (display (_ "Usage: guix system [OPTION] ACTION [FILE]
-Build the operating system declared in FILE according to ACTION.\n"))
+ (display (_ "Usage: guix system [OPTION ...] ACTION [ARG ...] [FILE]
+Build the operating system declared in FILE according to ACTION.
+Some ACTIONS support additional ARGS.\n"))
(newline)
(display (_ "The valid values for ACTION are:\n"))
(newline)
(display (_ "\
- reconfigure switch to a new operating system configuration\n"))
+ reconfigure switch to a new operating system configuration\n"))
+ (display (_ "\
+ roll-back switch to the previous operating system configuration\n"))
(display (_ "\
- list-generations list the system generations\n"))
+ switch-generation switch to a generation matching a pattern\n"))
(display (_ "\
- build build the operating system without installing anything\n"))
+ list-generations list the system generations\n"))
(display (_ "\
- container build a container that shares the host's store\n"))
+ build build the operating system without installing anything\n"))
(display (_ "\
- vm build a virtual machine image that shares the host's store\n"))
+ container build a container that shares the host's store\n"))
(display (_ "\
- vm-image build a freestanding virtual machine image\n"))
+ vm build a virtual machine image that shares the host's store\n"))
(display (_ "\
- disk-image build a disk image, suitable for a USB stick\n"))
+ vm-image build a freestanding virtual machine image\n"))
(display (_ "\
- init initialize a root file system to run GNU\n"))
+ disk-image build a disk image, suitable for a USB stick\n"))
(display (_ "\
- extension-graph emit the service extension graph in Dot format\n"))
+ init initialize a root file system to run GNU\n"))
(display (_ "\
- shepherd-graph emit the graph of shepherd services in Dot format\n"))
+ extension-graph emit the service extension graph in Dot format\n"))
+ (display (_ "\
+ shepherd-graph emit the graph of shepherd services in Dot format\n"))
(show-build-options-help)
(display (_ "
@@ -824,6 +846,16 @@ argument list and OPTS is the option alist."
((pattern) pattern)
(x (leave (_ "wrong number of arguments~%"))))))
(list-generations pattern)))
+ ((roll-back)
+ (let ((pattern (match args
+ (() "")
+ (x (leave (_ "wrong number of arguments~%"))))))
+ (roll-back-system)))
+ ((switch-generation)
+ (let ((pattern (match args
+ ((pattern) pattern)
+ (x (leave (_ "wrong number of arguments~%"))))))
+ (switch-to-system-generation pattern)))
(else
(process-action command args opts))))
@@ -835,7 +867,8 @@ argument list and OPTS is the option alist."
(let ((action (string->symbol arg)))
(case action
((build container vm vm-image disk-image reconfigure init
- extension-graph shepherd-graph list-generations)
+ extension-graph shepherd-graph list-generations roll-back
+ switch-generation)
(alist-cons 'action action result))
(else (leave (_ "~a: unknown action~%") action))))))
diff --git a/guix/ui.scm b/guix/ui.scm
index 4d1b65c..fcf403c 100644
--- a/guix/ui.scm
+++ b/guix/ui.scm
@@ -90,6 +90,7 @@
display-generation
display-profile-content
roll-back*
+ switch-to-previous-generation*
switch-to-generation*
delete-generation*
run-guix-command
@@ -1095,6 +1096,13 @@ way."
(roll-back store profile))
display-generation-change))
+(define (switch-to-previous-generation* profile)
+ "Like switch-to-previous-generation, but display what is happening."
+ (call-with-values
+ (lambda ()
+ (switch-to-previous-generation profile))
+ display-generation-change))
+
(define (switch-to-generation* profile number)
"Like 'switch-generation', but display what is happening."
(let ((previous (switch-to-generation profile number)))
--
2.7.3
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: Update: Implementing guix system rollback / switch-generation
2016-07-09 2:53 Update: Implementing guix system rollback / switch-generation Chris Marusich
@ 2016-07-12 15:30 ` Ludovic Courtès
2016-07-13 6:40 ` Chris Marusich
0 siblings, 1 reply; 3+ messages in thread
From: Ludovic Courtès @ 2016-07-12 15:30 UTC (permalink / raw)
To: Chris Marusich; +Cc: guix-devel
Hello Chris,
Chris Marusich <cmmarusich@gmail.com> skribis:
> I've attached a preliminary patch which adds rudimentary roll-back and
> switch-generation commands to "guix system". Currently, the commands
> just flip symlinks, which is part of the first milestone that Ludo
> suggested in the following thread:
>
> https://lists.gnu.org/archive/html/guix-devel/2016-06/msg00178.html
Awesome!
> Please let me know what you think. After getting feedback, I intend to
> follow up a more complete patch that contains the following additional
> changes:
>
> * Regenerate grub.cfg, to complete the first milestone. I'm not sure
> exactly how this will play out, but I imagine I'll need to use the
> store somehow to get it done.
>
> * Use a properly formatted ChangeLog-style Git commit message.
>
> * Mention these new commands in the manual.
>
> * Add tests. I'm not new to automated testing, but I haven't done it
> using autoconf/make or in Guile, so tips here would be welcome!
>
> * Add these new commands to the emacs interface.
Sounds good to me.
Automated tests for this will be a bit difficult because we don’t have
any ‘guix system’ tests yet. I think this should be done in the new
system test infrastructure.
However, since you’ve done extensive manual testing, this part shouldn’t
block you. We can add it at a later point.
> I've tested the changes on my bare metal GuixSD installation. I would
> have used a VM, but my system has trouble launching VMs. I first
> verified manually that the roll-back command switched the profile's
> symlink to the previous generation, by examining the output of
> list-generations and ls. I then verified, in the same way, that the
> switch-generation command switched the profile's symlink to the
> specified generation. I verified that switch-generation works for
> arbitrary numbers and relative numbers (note that a negative relative
> number must be preceded by the special "--" argument to prevent it from
> being interpreted as an option). I also verified that if the user
> attempts to switch to a nonexistent generation (or to roll back from
> generation 1 in the case of "guix system"), an error is raised without
> modifying anything. I repeated this manual verification process for
> both the "guix system" and "guix package" commands, since my changes
> involve some refactoring in "guix package".
Perfect.
> +(define (relative-generation-spec->number profile spec)
> + "Return PROFILE's generation specified by SPEC, which is a string. The SPEC
> +may be a N, -N, or +N, where N is a number. If the spec is N, then the number
> +returned is N. If it is -N, then the number returned is the profile's current
> +generation number minus N. If it is +N, then the number returned is the
> +profile's current generation number plus N. Return #f if there is no such
> +generation."
> + (let ((number (string->number spec)))
> + (and number
> + (case (string-ref spec 0)
> + ((#\+ #\-)
> + (relative-generation profile number))
> + (else number)))))
(Refactored from (guix scripts package).) Could you make this
refactoring in a separate patch? It LGTM.
> (define (switch-to-generation profile number)
> "Atomically switch PROFILE to the generation NUMBER. Return the number of
> -the generation that was current before switching."
> +the generation that was current before switching. Raise a
> +&profile-not-found-error when the profile does not exist. Raise a
> +&missing-generation-error when the generation does not exist."
Could you add the docstring in a separate patch?
(Isolating changes like this can be tedious but it simplifies review and
bisecting should a regression be introduced.)
> (define (show-help)
> - (display (_ "Usage: guix system [OPTION] ACTION [FILE]
> -Build the operating system declared in FILE according to ACTION.\n"))
> + (display (_ "Usage: guix system [OPTION ...] ACTION [ARG ...] [FILE]
> +Build the operating system declared in FILE according to ACTION.
> +Some ACTIONS support additional ARGS.\n"))
> (newline)
> (display (_ "The valid values for ACTION are:\n"))
> (newline)
> (display (_ "\
> - reconfigure switch to a new operating system configuration\n"))
> + reconfigure switch to a new operating system configuration\n"))
> + (display (_ "\
> + roll-back switch to the previous operating system configuration\n"))
> (display (_ "\
> - list-generations list the system generations\n"))
> + switch-generation switch to a generation matching a pattern\n"))
> (display (_ "\
> - build build the operating system without installing anything\n"))
> + list-generations list the system generations\n"))
> (display (_ "\
> - container build a container that shares the host's store\n"))
> + build build the operating system without installing anything\n"))
> (display (_ "\
> - vm build a virtual machine image that shares the host's store\n"))
> + container build a container that shares the host's store\n"))
> (display (_ "\
> - vm-image build a freestanding virtual machine image\n"))
> + vm build a virtual machine image that shares the host's store\n"))
> (display (_ "\
> - disk-image build a disk image, suitable for a USB stick\n"))
> + vm-image build a freestanding virtual machine image\n"))
> (display (_ "\
> - init initialize a root file system to run GNU\n"))
> + disk-image build a disk image, suitable for a USB stick\n"))
> (display (_ "\
> - extension-graph emit the service extension graph in Dot format\n"))
> + init initialize a root file system to run GNU\n"))
> (display (_ "\
> - shepherd-graph emit the graph of shepherd services in Dot format\n"))
> + extension-graph emit the service extension graph in Dot format\n"))
> + (display (_ "\
> + shepherd-graph emit the graph of shepherd services in Dot format\n"))
Not sure what happened here. :-) Please avoid reformatting such
strings; they are translated so changing them makes translations stale.
Otherwise looks like Milestone #1 is already close to completion!
Thank you,
Ludo’.
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: Update: Implementing guix system rollback / switch-generation
2016-07-12 15:30 ` Ludovic Courtès
@ 2016-07-13 6:40 ` Chris Marusich
0 siblings, 0 replies; 3+ messages in thread
From: Chris Marusich @ 2016-07-13 6:40 UTC (permalink / raw)
To: Ludovic Courtès; +Cc: guix-devel
[-- Attachment #1: Type: text/plain, Size: 1293 bytes --]
ludo@gnu.org (Ludovic Courtès) writes:
> Automated tests for this will be a bit difficult because we don’t have
> any ‘guix system’ tests yet. I think this should be done in the new
> system test infrastructure.
>
> However, since you’ve done extensive manual testing, this part shouldn’t
> block you. We can add it at a later point.
OK. I saw your blog post on Savannah about the system test
infrastructure; I'm excited to play around with that!
> (Refactored from (guix scripts package).) Could you make this
> refactoring in a separate patch? It LGTM.
> ...
> (Isolating changes like this can be tedious but it simplifies review and
> bisecting should a regression be introduced.)
This makes sense. I've split them out. I'll keep this in mind going
forward.
> Not sure what happened here. :-) Please avoid reformatting such
> strings; they are translated so changing them makes translations stale.
I intended to modify the alignment of the second column, but the diff
certainly looks ugly, and I forgot that these strings get translated.
Good point; I will not change the existing strings.
> Otherwise looks like Milestone #1 is already close to completion!
Thank you for your help! Hopefully the rest will be quick.
--
Chris
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 818 bytes --]
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2016-07-13 6:40 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-07-09 2:53 Update: Implementing guix system rollback / switch-generation Chris Marusich
2016-07-12 15:30 ` Ludovic Courtès
2016-07-13 6:40 ` Chris Marusich
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).