aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLudovic Courtès <ludo@gnu.org>2013-01-17 22:41:47 +0100
committerLudovic Courtès <ludo@gnu.org>2013-01-17 22:42:39 +0100
commit9241172c9dc41ac026f05837dc6f089b1a3745e0 (patch)
treeede4741b6a1ae27286b450c716212557d3937005
parent24e262f086980a13d9d0a27615ed7eaec4aacbff (diff)
downloadguix-9241172c9dc41ac026f05837dc6f089b1a3745e0.tar
guix-9241172c9dc41ac026f05837dc6f089b1a3745e0.tar.gz
guix-package: Allow `--roll-back' to skip missing generations.
* guix-package.in (profile-numbers): New procedure. (latest-profile-number): Use it. (previous-profile-number): New procedure. (roll-back): Use it lieu of `1-'. Check whether PREVIOUS-NUMBER is zero, and raise an error when it is. * tests/guix-package.sh: Test whether we can roll back over a "hole".
-rw-r--r--guix-package.in65
-rw-r--r--tests/guix-package.sh6
2 files changed, 47 insertions, 24 deletions
diff --git a/guix-package.in b/guix-package.in
index 5dd4724b53..217c888d2f 100644
--- a/guix-package.in
+++ b/guix-package.in
@@ -95,9 +95,9 @@ exec ${GUILE-@GUILE@} -L "@guilemoduledir@" -l "$0" \
(make-regexp (string-append "^" (regexp-quote (basename profile))
"-([0-9]+)")))
-(define (latest-profile-number profile)
- "Return the identifying number of the latest generation of PROFILE.
-PROFILE is the name of the symlink to the current generation."
+(define (profile-numbers profile)
+ "Return the list of generation numbers of PROFILE, or '(0) if no
+former profiles were found."
(define* (scandir name #:optional (select? (const #t))
(entry<? (@ (ice-9 i18n) string-locale<?)))
;; XXX: Bug-fix version introduced in Guile v2.0.6-62-g139ce19.
@@ -135,21 +135,35 @@ PROFILE is the name of the symlink to the current generation."
(match (scandir (dirname profile)
(cute regexp-exec (profile-regexp profile) <>))
(#f ; no profile directory
- 0)
+ '(0))
(() ; no profiles
- 0)
+ '(0))
((profiles ...) ; former profiles around
- (let ((numbers
- (map (compose string->number
- (cut match:substring <> 1)
- (cut regexp-exec (profile-regexp profile) <>))
- profiles)))
- (fold (lambda (number highest)
- (if (> number highest)
- number
- highest))
- 0
- numbers)))))
+ (map (compose string->number
+ (cut match:substring <> 1)
+ (cute regexp-exec (profile-regexp profile) <>))
+ profiles))))
+
+(define (latest-profile-number profile)
+ "Return the identifying number of the latest generation of PROFILE.
+PROFILE is the name of the symlink to the current generation."
+ (fold (lambda (number highest)
+ (if (> number highest)
+ number
+ highest))
+ 0
+ (profile-numbers profile)))
+
+(define (previous-profile-number profile number)
+ "Return the number of the generation before generation NUMBER of
+PROFILE, or 0 if none exists. It could be NUMBER - 1, but it's not the
+case when generations have been deleted (there are \"holes\")."
+ (fold (lambda (candidate highest)
+ (if (and (< candidate number) (> candidate highest))
+ candidate
+ highest))
+ 0
+ (profile-numbers profile)))
(define (profile-derivation store packages)
"Return a derivation that builds a profile (a user environment) with
@@ -192,12 +206,12 @@ all of PACKAGES, a list of name/version/output/path tuples."
(define (roll-back profile)
"Roll back to the previous generation of PROFILE."
;; XXX: Get the previous generation number from the manifest?
- (let* ((number (profile-number profile))
- (previous-number (1- number))
+ (let* ((number (profile-number profile))
+ (previous-number (previous-profile-number profile number))
(previous-profile (format #f "~a/~a-~a-link"
(dirname profile) profile
previous-number))
- (manifest (string-append previous-profile "/manifest")))
+ (manifest (string-append previous-profile "/manifest")))
(define (switch-link)
;; Atomically switch PROFILE to the previous profile.
@@ -207,11 +221,14 @@ all of PACKAGES, a list of name/version/output/path tuples."
(symlink previous-profile pivot)
(rename-file pivot profile)))
- (if (= number 0)
- (leave (_ "error: `~a' is not a valid profile~%") profile)
- (if (file-exists? previous-profile)
- (switch-link)
- (leave (_ "error: no previous profile; not rolling back~%"))))))
+ (cond ((zero? number)
+ (format (current-error-port)
+ (_ "error: `~a' is not a valid profile~%")
+ profile))
+ ((or (zero? previous-number)
+ (not (file-exists? previous-profile)))
+ (leave (_ "error: no previous profile; not rolling back~%")))
+ (else (switch-link)))))
;;;
diff --git a/tests/guix-package.sh b/tests/guix-package.sh
index fd778f4f4f..fc80939646 100644
--- a/tests/guix-package.sh
+++ b/tests/guix-package.sh
@@ -95,6 +95,12 @@ then
guix-package --bootstrap -p "$profile" --roll-back -i "$boot_guile"
test "`readlink_base "$profile"`" = "$profile-5-link"
test -x "$profile/bin/guile" && test -x "$profile/bin/make"
+
+ # Make a "hole" in the list of generations, and make sure we can
+ # roll back "over" it.
+ rm "$profile-4-link"
+ guix-package --bootstrap -p "$profile" --roll-back
+ test "`readlink_base "$profile"`" = "$profile-3-link"
fi
# Make sure the `:' syntax works.