From mboxrd@z Thu Jan 1 00:00:00 1970 From: Alex Kost Subject: [PATCH] guix package: Add '--switch-generation' option. Date: Mon, 06 Oct 2014 18:14:53 +0400 Message-ID: <8738b1jndu.fsf_-_@gmail.com> References: <87k3719v7p.fsf@gmail.com> <87r419fa50.fsf@gnu.org> <87fvho9fqm.fsf@gmail.com> <87a97taixl.fsf@gmail.com> <87sil2rbly.fsf@gnu.org> <87tx5idn7f.fsf_-_@gmail.com> <87egwlkcy1.fsf@gnu.org> <87ppg5el2i.fsf@gmail.com> <87d2c5h4if.fsf@gnu.org> <87lhqsev1d.fsf@gmail.com> <877g2c74xh.fsf@gnu.org> <87ha1gds3w.fsf@gmail.com> <8761hsmxkl.fsf@gnu.org> <87zjf4d1mh.fsf@gmail.com> <87mwb0b3fq.fsf@gnu.org> <87ha17ctyv.fsf_-_@gmail.com> <87ppfs6gxk.fsf@gnu.org> <87wq8fk979.fsf_-_@gmail.com> <87eguninyx.fsf@gnu.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Return-path: Received: from eggs.gnu.org ([2001:4830:134:3::10]:46061) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Xb945-0007xE-0X for guix-devel@gnu.org; Mon, 06 Oct 2014 10:15:14 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Xb93v-00059k-Vj for guix-devel@gnu.org; Mon, 06 Oct 2014 10:15:04 -0400 Received: from mail-la0-x235.google.com ([2a00:1450:4010:c03::235]:36420) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Xb93v-00059R-Hk for guix-devel@gnu.org; Mon, 06 Oct 2014 10:14:55 -0400 Received: by mail-la0-f53.google.com with SMTP id gq15so4380371lab.26 for ; Mon, 06 Oct 2014 07:14:54 -0700 (PDT) Received: from leviafan (128-70-193-140.broadband.corbina.ru. [128.70.193.140]) by mx.google.com with ESMTPSA id jv4sm5775839lbc.35.2014.10.06.07.14.53 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 06 Oct 2014 07:14:53 -0700 (PDT) In-Reply-To: <87eguninyx.fsf@gnu.org> ("Ludovic \=\?utf-8\?Q\?Court\=C3\=A8s\=22'\?\= \=\?utf-8\?Q\?s\?\= message of "Sat, 04 Oct 2014 22:23:02 +0200") List-Id: "Development of GNU Guix and the GNU System distribution." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-devel-bounces+gcggd-guix-devel=m.gmane.org@gnu.org Sender: guix-devel-bounces+gcggd-guix-devel=m.gmane.org@gnu.org To: guix-devel@gnu.org --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Ludovic Court=C3=A8s (2014-10-05 00:23 +0400) wrote: > Alex Kost skribis:> [...] >> - (Not related to this patch, but still =E2=80=A6) Currently with =E2= =80=9Croll-back=E2=80=9D, >> we can only switch to the previous generation. What about adding a >> possibility to switch to any generation? So that we could use >> something like this: >> >> guix package --switch-generation=3D7 >> >> Also such functionality can be added to Emacs UI: for example pressing >> "C" on a generation in *Guix Generation List* will make this >> generation the current one. >> >> So =E2=80=98roll-back=E2=80=99 procedure may become a special case of = the >> =E2=80=98switch-generation=E2=80=99 one. WDYT? > > I think it=E2=80=99s a good idea! (I think it was suggested in earlier > discussions, but never implemented.) Andreas Enge (2014-10-05 18:44 +0400) wrote: [...] > Actually, sometimes I would like to switch to the next generation ("-roll- > forward", in a sense): I install something, go back with "--roll-back", > and might like to go just one forward again. > > So how about the following: > --switch-generation=3D1 > goes to generation 1; > --switch-generation=3D-1 > goes 1 generation back; > --switch-generation=3D+1 > goes one generation forward. Thanks for the great idea! =E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2= =80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80= =94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94= =E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2= =80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80= =94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94= =E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2= =80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94=E2=80=94 A patch is attached. Some comments: - =E2=80=98shitted-generation=E2=80=99 is not a very good name, I think. I= deas? - =E2=80=98previous-generation-number=E2=80=99 may use =E2=80=98shifted-gen= eration=E2=80=99 now: --=-=-= Content-Type: text/plain Content-Disposition: inline; filename=sample.scm (define* (previous-generation-number profile #:optional (number (generation-number profile))) "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\")." (or (shifted-generation profile -1 number) 0)) --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Worth changing? - Perhaps it would be better to make 2 commits (?): one for adding =E2=80=98shifted-generation=E2=80=99 and =E2=80=98switch-to-generation=E2= =80=99 procedures to (guix profiles) and another is for adding the =E2=80=9C--switch-generation=E2= =80=9D option itself. - Also I made a couple of cosmetic changes in =E2=80=9Cguix/scripts/package= .scm=E2=80=9D: * =E2=80=98filter-map=E2=80=99 was replaced by 'for-each' because it was = called only for side effects there; * =E2=80=98begin=E2=80=99 was removed from =E2=80=98cond=E2=80=99. I think these changes do not deserve a separate commit and may stay in this patch. Is it OK? --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=0001-guix-package-Add-switch-generation-option.patch >From 3cc52d1aade5e9723c38c0af5fa4437cbdf1a9b6 Mon Sep 17 00:00:00 2001 From: Alex Kost Date: Mon, 6 Oct 2014 17:35:51 +0400 Subject: [PATCH] guix package: Add '--switch-generation' option. * doc/guix.texi (Invoking guix package): Update documentation. * guix/profiles.scm (shifted-generation, switch-to-generation): New procedures. * guix/scripts/package.scm: Add '--switch-generation' option. (switch-to-previous-generation): Use 'switch-to-generation'. --- doc/guix.texi | 15 +++++++++++++++ guix/profiles.scm | 36 +++++++++++++++++++++++++++++++++++- guix/scripts/package.scm | 44 +++++++++++++++++++++++++++++++++----------- 3 files changed, 83 insertions(+), 12 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index f6357bd..c6921b1 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -784,6 +784,21 @@ Installing, removing, or upgrading packages from a generation that has been rolled back to overwrites previous future generations. Thus, the history of a profile's generations is always linear. +@item --switch-generation=@var{pattern} +@itemx -S @var{pattern} +Switch to a particular generation defined by @var{pattern}. + +@var{pattern} may be either a generation number or a number prefixed +with ``+'' or ``-''. The latter means: move forward/backward by a +specified number of generations. For example, if you want to return to +the latest generation after @code{--roll-back}, use +@code{--switch-generation=+1}. + +The difference between @code{--roll-back} and +@code{--switch-generation=-1} is that @code{--switch-generation} will +not make a zeroth generation, so if a specified generation does not +exist, the current generation will not be changed. + @item --search-paths @cindex search paths Report environment variable definitions, in Bash syntax, that may be diff --git a/guix/profiles.scm b/guix/profiles.scm index 18733a6..589402e 100644 --- a/guix/profiles.scm +++ b/guix/profiles.scm @@ -71,9 +71,11 @@ generation-number generation-numbers profile-generations + shifted-generation previous-generation-number generation-time - generation-file-name)) + generation-file-name + switch-to-generation)) ;;; Commentary: ;;; @@ -569,6 +571,21 @@ former profiles were found." '() generations))) +(define* (shifted-generation profile shift + #:optional (current (generation-number profile))) + "Return PROFILE's generation shifted from the CURRENT generation by SHIFT. +SHIFT is a positive or negative number. +Return #f if there is no such generation." + (let* ((abs-shift (abs shift)) + (numbers (profile-generations profile)) + (from-current (memq current + (if (negative? shift) + (reverse numbers) + numbers)))) + (and from-current + (< abs-shift (length from-current)) + (list-ref from-current abs-shift)))) + (define (previous-generation-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 @@ -589,4 +606,21 @@ case when generations have been deleted (there are \"holes\")." (make-time time-utc 0 (stat:ctime (stat (generation-file-name profile number))))) +(define (switch-to-generation profile number) + "Atomically switch PROFILE to the generation NUMBER." + (let ((current (generation-number profile)) + (file (generation-file-name profile number))) + (cond ((not (file-exists? profile)) + (format (current-error-port) + (_ "profile '~a' does not exist~%") + profile)) + ((not (file-exists? file)) + (format (current-error-port) + (_ "generation ~a does not exist~%") + number)) + (else + (format #t (_ "switching from generation ~a to ~a~%") + current number) + (switch-symlinks profile file))))) + ;;; profiles.scm ends here diff --git a/guix/scripts/package.scm b/guix/scripts/package.scm index fc9c37b..b071029 100644 --- a/guix/scripts/package.scm +++ b/guix/scripts/package.scm @@ -96,12 +96,9 @@ return PROFILE unchanged. The goal is to treat '-p ~/.guix-profile' as if (define (switch-to-previous-generation profile) "Atomically switch PROFILE to the previous generation." - (let* ((number (generation-number profile)) - (previous-number (previous-generation-number profile number)) - (previous-generation (generation-file-name profile previous-number))) - (format #t (_ "switching from generation ~a to ~a~%") - number previous-number) - (switch-symlinks profile previous-generation))) + (let* ((current (generation-number profile)) + (previous (previous-generation-number profile current))) + (switch-to-generation profile previous))) (define (roll-back store profile) "Roll back to the previous generation of PROFILE." @@ -409,6 +406,9 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n")) -d, --delete-generations[=PATTERN] delete generations matching PATTERN")) (display (_ " + -S, --switch-generation=PATTERN + switch to a generation matching PATTERN")) + (display (_ " -p, --profile=PROFILE use PROFILE instead of the user's default profile")) (newline) (display (_ " @@ -488,6 +488,10 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n")) (values (alist-cons 'delete-generations (or arg "") result) #f))) + (option '(#\S "switch-generation") #t #f + (lambda (opt name arg result arg-handler) + (values (alist-cons 'switch-generation arg result) + #f))) (option '("search-paths") #f #f (lambda (opt name arg result arg-handler) (values (cons `(query search-paths) result) @@ -713,13 +717,31 @@ more information.~%")) (generation-number profile)) ;; First roll back if asked to. - (cond ((and (assoc-ref opts 'roll-back?) (not dry-run?)) - (begin - (roll-back (%store) profile) - (process-actions (alist-delete 'roll-back? opts)))) + (cond ((and (assoc-ref opts 'roll-back?) + (not dry-run?)) + (roll-back (%store) profile) + (process-actions (alist-delete 'roll-back? opts))) + ((and (assoc-ref opts 'switch-generation) + (not dry-run?)) + (for-each + (match-lambda + (('switch-generation . pattern) + (let* ((number (string->number pattern)) + (number (and number + (case (string-ref pattern 0) + ((#\+ #\-) + (shifted-generation profile number)) + (else number))))) + (if number + (switch-to-generation profile number) + (format (current-error-port) + "Cannot switch to generation '~a'~%" pattern))) + (process-actions (alist-delete 'switch-generation opts))) + (_ #f)) + opts)) ((and (assoc-ref opts 'delete-generations) (not dry-run?)) - (filter-map + (for-each (match-lambda (('delete-generations . pattern) (cond ((not (file-exists? profile)) ; XXX: race condition -- 2.1.2 --=-=-= Content-Type: text/plain -- Thanks, Alex --=-=-=--