* Reproducible profiles @ 2015-05-15 1:19 David Thompson 2015-05-16 11:16 ` Ludovic Courtès 2015-05-18 21:07 ` David Thompson 0 siblings, 2 replies; 15+ messages in thread From: David Thompson @ 2015-05-15 1:19 UTC (permalink / raw) To: guix-devel [-- Attachment #1: Type: text/plain, Size: 960 bytes --] Hey folks, Lately I've been wanting to version control the list of packages that I install in my user profile so that I can sync it amongst many machines. So, I took a stab at adding a new '--apply' option to 'guix package' that reads in a package list from a Scheme file and creates a new generation of the profile with only those packages are installed. Here's an example configuration: (use-modules (gnu)) (use-package-modules base less guile emacs admin ruby mail pumpio man) (list ruby coreutils less man-db notmuch guile-2.0 emacs dmd offlineimap pumpa) Below is a naive patch that does the job, but is unideal because it doesn't do some nice things like display the diff between generations before building. I'm looking for some guidance to make this option mesh better with the rest of the 'guix package' utility. Any help is appreciated. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-package-Add-apply-option.patch --] [-- Type: text/x-diff, Size: 7705 bytes --] From b5348fb46fc5b6167099ed817aad8587bfbad20a Mon Sep 17 00:00:00 2001 From: David Thompson <dthompson2@worcester.edu> Date: Thu, 14 May 2015 21:11:57 -0400 Subject: [PATCH] package: Add --apply option. --- guix/scripts/package.scm | 104 +++++++++++++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 44 deletions(-) diff --git a/guix/scripts/package.scm b/guix/scripts/package.scm index 15f3e13..bb76fc3 100644 --- a/guix/scripts/package.scm +++ b/guix/scripts/package.scm @@ -426,6 +426,9 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n")) (display (_ " -u, --upgrade[=REGEXP] upgrade all the installed packages matching REGEXP")) (display (_ " + --apply=FILE create a new generation with only the packages listed + in FILE installed")) + (display (_ " --do-not-upgrade[=REGEXP] do not upgrade any packages matching REGEXP")) (display (_ " --roll-back roll back to the previous generation")) @@ -517,6 +520,10 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n")) (lambda (opt name arg result arg-handler) (values (alist-cons 'roll-back? #t result) #f))) + (option '("apply") #t #f + (lambda (opt name arg result arg-handler) + (values (alist-cons 'apply (load arg) result) + arg-handler))) (option '(#\l "list-generations") #f #t (lambda (opt name arg result arg-handler) (values (cons `(query list-generations ,(or arg "")) @@ -783,6 +790,50 @@ more information.~%")) (define dry-run? (assoc-ref opts 'dry-run?)) (define profile (assoc-ref opts 'profile)) + (define (build-and-use-profile manifest) + (let* ((bootstrap? (assoc-ref opts 'bootstrap?))) + + (when (equal? profile %current-profile) + (ensure-default-profile)) + + (let* ((prof-drv (run-with-store (%store) + (profile-derivation + manifest + #:hooks (if bootstrap? + '() + %default-profile-hooks)))) + (prof (derivation->output-path prof-drv))) + (show-what-to-build (%store) (list prof-drv) + #:use-substitutes? + (assoc-ref opts 'substitutes?) + #:dry-run? dry-run?) + + (cond + (dry-run? #t) + ((and (file-exists? profile) + (and=> (readlink* profile) (cut string=? prof <>))) + (format (current-error-port) (_ "nothing to be done~%"))) + (else + (let* ((number (generation-number profile)) + + ;; Always use NUMBER + 1 for the new profile, + ;; possibly overwriting a "previous future + ;; generation". + (name (generation-file-name profile + (+ 1 number)))) + (and (build-derivations (%store) (list prof-drv)) + (let* ((entries (manifest-entries manifest)) + (count (length entries))) + (switch-symlinks name prof) + (switch-symlinks profile name) + (unless (string=? profile %current-profile) + (register-gc-root (%store) name)) + (format #t (N_ "~a package in profile~%" + "~a packages in profile~%" + count) + count) + (display-search-paths entries profile))))))))) + ;; First roll back if asked to. (cond ((and (assoc-ref opts 'roll-back?) (not dry-run?)) @@ -817,60 +868,25 @@ more information.~%")) (alist-delete 'delete-generations opts))) (_ #f)) opts)) + ((and (assoc-ref opts 'apply) + (not dry-run?)) + (let* ((packages (assoc-ref opts 'apply)) + (manifest (make-manifest + (map package->manifest-entry packages)))) + (build-and-use-profile manifest))) (else (let* ((manifest (profile-manifest profile)) (install (options->installable opts manifest)) (remove (options->removable opts manifest)) - (bootstrap? (assoc-ref opts 'bootstrap?)) (transaction (manifest-transaction (install install) (remove remove))) (new (manifest-perform-transaction manifest transaction))) - (when (equal? profile %current-profile) - (ensure-default-profile)) - (unless (and (null? install) (null? remove)) - (let* ((prof-drv (run-with-store (%store) - (profile-derivation - new - #:hooks (if bootstrap? - '() - %default-profile-hooks)))) - (prof (derivation->output-path prof-drv))) - (show-manifest-transaction (%store) manifest transaction - #:dry-run? dry-run?) - (show-what-to-build (%store) (list prof-drv) - #:use-substitutes? - (assoc-ref opts 'substitutes?) - #:dry-run? dry-run?) - - (cond - (dry-run? #t) - ((and (file-exists? profile) - (and=> (readlink* profile) (cut string=? prof <>))) - (format (current-error-port) (_ "nothing to be done~%"))) - (else - (let* ((number (generation-number profile)) - - ;; Always use NUMBER + 1 for the new profile, - ;; possibly overwriting a "previous future - ;; generation". - (name (generation-file-name profile - (+ 1 number)))) - (and (build-derivations (%store) (list prof-drv)) - (let* ((entries (manifest-entries new)) - (count (length entries))) - (switch-symlinks name prof) - (switch-symlinks profile name) - (unless (string=? profile %current-profile) - (register-gc-root (%store) name)) - (format #t (N_ "~a package in profile~%" - "~a packages in profile~%" - count) - count) - (display-search-paths entries - profile)))))))))))) + (show-manifest-transaction (%store) manifest transaction + #:dry-run? dry-run?) + (build-and-use-profile new)))))) (define (process-query opts) ;; Process any query specified by OPTS. Return #t when a query was -- 2.1.4 [-- Attachment #3: Type: text/plain, Size: 145 bytes --] Thanks! -- David Thompson Web Developer - Free Software Foundation - http://fsf.org GPG Key: 0FF1D807 Support the FSF: https://fsf.org/donate ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: Reproducible profiles 2015-05-15 1:19 Reproducible profiles David Thompson @ 2015-05-16 11:16 ` Ludovic Courtès 2015-05-16 11:35 ` 宋文武 ` (2 more replies) 2015-05-18 21:07 ` David Thompson 1 sibling, 3 replies; 15+ messages in thread From: Ludovic Courtès @ 2015-05-16 11:16 UTC (permalink / raw) To: David Thompson; +Cc: guix-devel David Thompson <dthompson2@worcester.edu> skribis: > Lately I've been wanting to version control the list of packages that I > install in my user profile so that I can sync it amongst many machines. > So, I took a stab at adding a new '--apply' option to 'guix package' > that reads in a package list from a Scheme file and creates a new > generation of the profile with only those packages are installed. > Here's an example configuration: > > (use-modules (gnu)) > (use-package-modules base less guile emacs admin ruby mail pumpio man) > > (list ruby > coreutils > less > man-db > notmuch > guile-2.0 > emacs > dmd > offlineimap > pumpa) Yes, that sounds very useful. As usual though, there’s the issue of multiple-output packages. The above snippet is nice, but doesn’t allow you to specify a particular output of a package. What about instead requiring people to return a manifest: (use-modules (guix profiles)) (use-package-modules base emacs guile) (manifest (cons (package->manifest-entry gcc-toolchain "debug") (map package->entry (list gcc-toolchain emacs guile-2.0)))) That means we’ll have to document (guix profiles). It’s more verbose than what you suggest, though. If you insist ;-), we could allow a list of packages instead of a manifest, though I’d prefer not to do that. WDYT? > Below is a naive patch that does the job, but is unideal because it > doesn't do some nice things like display the diff between generations > before building. For that you would need a procedure to infer the manifest transaction: (manifests->transaction m1 m2) ;; returns a <manifest-transaction> and then that could be passed to ‘show-manifest-transaction’. However, I’m not sure it’s very useful. Perhaps it would be enough to write “installing new manifest from foo.scm with 42 entries.” WDYT? > I'm looking for some guidance to make this option mesh better with the > rest of the 'guix package' utility. Any help is appreciated. Overall it looks OK to me! [...] > + (option '("apply") #t #f > + (lambda (opt name arg result arg-handler) > + (values (alist-cons 'apply (load arg) result) > + arg-handler))) It would be better to delay loading until after arguments have been parsed, as in ‘guix system’. The procedure to load the file should be similar to ‘read-operating-system’. We’ll need documentation and tests, too. :-) Thank you! Ludo’. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Reproducible profiles 2015-05-16 11:16 ` Ludovic Courtès @ 2015-05-16 11:35 ` 宋文武 2015-05-16 20:05 ` Ludovic Courtès 2015-05-17 19:27 ` David Thompson 2015-05-17 19:23 ` David Thompson 2015-05-18 13:38 ` Reproducible profiles David Thompson 2 siblings, 2 replies; 15+ messages in thread From: 宋文武 @ 2015-05-16 11:35 UTC (permalink / raw) To: Ludovic Courtès, David Thompson; +Cc: guix-devel Ludovic Courtès <ludo@gnu.org> writes: > David Thompson <dthompson2@worcester.edu> skribis: > >> Lately I've been wanting to version control the list of packages that I >> install in my user profile so that I can sync it amongst many machines. >> So, I took a stab at adding a new '--apply' option to 'guix package' >> that reads in a package list from a Scheme file and creates a new >> generation of the profile with only those packages are installed. >> Here's an example configuration: >> >> (use-modules (gnu)) >> (use-package-modules base less guile emacs admin ruby mail pumpio man) >> >> (list ruby >> coreutils >> less >> man-db >> notmuch >> guile-2.0 >> emacs >> dmd >> offlineimap >> pumpa) > > Yes, that sounds very useful. > > As usual though, there’s the issue of multiple-output packages. The > above snippet is nice, but doesn’t allow you to specify a particular > output of a package. > > What about instead requiring people to return a manifest: > > (use-modules (guix profiles)) > (use-package-modules base emacs guile) > > (manifest (cons (package->manifest-entry gcc-toolchain "debug") > (map package->entry > (list gcc-toolchain emacs guile-2.0)))) > > That means we’ll have to document (guix profiles). > > It’s more verbose than what you suggest, though. If you insist ;-), we > could allow a list of packages instead of a manifest, though I’d prefer > not to do that. > > WDYT? > +1 for return 'manifest', in a same way as 'operating-system'. And how about use specification instead of package, so I can: (manifest (map package-specification->manifest-entry '("emacs" "font-adobe-source-han-sans:cn"))) ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Reproducible profiles 2015-05-16 11:35 ` 宋文武 @ 2015-05-16 20:05 ` Ludovic Courtès 2015-05-17 19:27 ` David Thompson 1 sibling, 0 replies; 15+ messages in thread From: Ludovic Courtès @ 2015-05-16 20:05 UTC (permalink / raw) To: 宋文武; +Cc: guix-devel 宋文武 <iyzsong@gmail.com> skribis: > And how about use specification instead of package, so I can: > > (manifest > (map package-specification->manifest-entry > '("emacs" > "font-adobe-source-han-sans:cn"))) Sure, with: (use-modules (gnu) (guix profiles)) (define package-specification->manifest-entry (compose package->manifest-entry specification->package)) The advantage of using package names like this is that it’s less sensitive to module changes; the disadvantage is that it is not as precise, particularly if there are several packages matching a given name. Ludo’. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Reproducible profiles 2015-05-16 11:35 ` 宋文武 2015-05-16 20:05 ` Ludovic Courtès @ 2015-05-17 19:27 ` David Thompson 2015-05-22 12:02 ` 宋文武 1 sibling, 1 reply; 15+ messages in thread From: David Thompson @ 2015-05-17 19:27 UTC (permalink / raw) To: 宋文武, Ludovic Courtès; +Cc: guix-devel 宋文武 <iyzsong@gmail.com> writes: > +1 for return 'manifest', in a same way as 'operating-system'. > And how about use specification instead of package, so I can: > > (manifest > (map package-specification->manifest-entry > '("emacs" > "font-adobe-source-han-sans:cn"))) I don't like that idea because the text specification is just a syntax for shell users. In Scheme, we can use the package objects directly rather than encode them as strings. -- David Thompson GPG Key: 0FF1D807 ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Reproducible profiles 2015-05-17 19:27 ` David Thompson @ 2015-05-22 12:02 ` 宋文武 0 siblings, 0 replies; 15+ messages in thread From: 宋文武 @ 2015-05-22 12:02 UTC (permalink / raw) To: David Thompson; +Cc: guix-devel David Thompson <dthompson2@worcester.edu> writes: > 宋文武 <iyzsong@gmail.com> writes: > >> +1 for return 'manifest', in a same way as 'operating-system'. >> And how about use specification instead of package, so I can: >> >> (manifest >> (map package-specification->manifest-entry >> '("emacs" >> "font-adobe-source-han-sans:cn"))) > > I don't like that idea because the text specification is just a syntax > for shell users. In Scheme, we can use the package objects directly > rather than encode them as strings. Well, by this way, I don't need to figure out which modules packages belong to. It works great, thanks! ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Reproducible profiles 2015-05-16 11:16 ` Ludovic Courtès 2015-05-16 11:35 ` 宋文武 @ 2015-05-17 19:23 ` David Thompson 2015-05-17 20:22 ` Ludovic Courtès 2015-05-18 13:38 ` Reproducible profiles David Thompson 2 siblings, 1 reply; 15+ messages in thread From: David Thompson @ 2015-05-17 19:23 UTC (permalink / raw) To: Ludovic Courtès; +Cc: guix-devel Ludovic Courtès <ludo@gnu.org> writes: > David Thompson <dthompson2@worcester.edu> skribis: > >> Lately I've been wanting to version control the list of packages that I >> install in my user profile so that I can sync it amongst many machines. >> So, I took a stab at adding a new '--apply' option to 'guix package' >> that reads in a package list from a Scheme file and creates a new >> generation of the profile with only those packages are installed. >> Here's an example configuration: >> >> (use-modules (gnu)) >> (use-package-modules base less guile emacs admin ruby mail pumpio man) >> >> (list ruby >> coreutils >> less >> man-db >> notmuch >> guile-2.0 >> emacs >> dmd >> offlineimap >> pumpa) > > Yes, that sounds very useful. > > As usual though, there’s the issue of multiple-output packages. The > above snippet is nice, but doesn’t allow you to specify a particular > output of a package. I left it out of my example, but I figured one could specify the output like so: (list ruby coreutils `(,glib "bin")) > What about instead requiring people to return a manifest: > > (use-modules (guix profiles)) > (use-package-modules base emacs guile) > > (manifest (cons (package->manifest-entry gcc-toolchain "debug") > (map package->entry > (list gcc-toolchain emacs guile-2.0)))) > > That means we’ll have to document (guix profiles). > > It’s more verbose than what you suggest, though. If you insist ;-), we > could allow a list of packages instead of a manifest, though I’d prefer > not to do that. Expecting a manifest always sounds good. How about adding a convenience procedure for the (map package->entry ...) pattern since I think it will be the most common thing users will want to do? (packages->manifest (list guile-2.0 guile-opengl guile-sdl)) It could even support using other outputs like in that other example I gave: (packages->manifest (list guile-2.0 guile-opengl guile-sdl `(,gcc-toolchain "debug")) >> Below is a naive patch that does the job, but is unideal because it >> doesn't do some nice things like display the diff between generations >> before building. > > For that you would need a procedure to infer the manifest transaction: > > (manifests->transaction m1 m2) > ;; returns a <manifest-transaction> > > and then that could be passed to ‘show-manifest-transaction’. > > However, I’m not sure it’s very useful. Perhaps it would be enough to > write “installing new manifest from foo.scm with 42 entries.” > WDYT? Okay, I'll do that instead. I would be interested in seeing what has changed when I apply a new manifest, but it's probably not worth the effort right now. >> + (option '("apply") #t #f >> + (lambda (opt name arg result arg-handler) >> + (values (alist-cons 'apply (load arg) result) >> + arg-handler))) > > It would be better to delay loading until after arguments have been > parsed, as in ‘guix system’. The procedure to load the file should be > similar to ‘read-operating-system’. Sure. The use of 'load' was a quick hack for this prototype. :) > We’ll need documentation and tests, too. :-) Naturally. Thanks, now I have enough direction to do another iteration. :) -- David Thompson GPG Key: 0FF1D807 ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Reproducible profiles 2015-05-17 19:23 ` David Thompson @ 2015-05-17 20:22 ` Ludovic Courtès 2015-05-17 20:51 ` David Thompson 0 siblings, 1 reply; 15+ messages in thread From: Ludovic Courtès @ 2015-05-17 20:22 UTC (permalink / raw) To: David Thompson; +Cc: guix-devel David Thompson <dthompson2@worcester.edu> skribis: > Ludovic Courtès <ludo@gnu.org> writes: [...] >> What about instead requiring people to return a manifest: >> >> (use-modules (guix profiles)) >> (use-package-modules base emacs guile) >> >> (manifest (cons (package->manifest-entry gcc-toolchain "debug") >> (map package->entry >> (list gcc-toolchain emacs guile-2.0)))) >> >> That means we’ll have to document (guix profiles). >> >> It’s more verbose than what you suggest, though. If you insist ;-), we >> could allow a list of packages instead of a manifest, though I’d prefer >> not to do that. > > Expecting a manifest always sounds good. How about adding a convenience > procedure for the (map package->entry ...) pattern since I think it will > be the most common thing users will want to do? > > (packages->manifest (list guile-2.0 guile-opengl guile-sdl)) > > It could even support using other outputs like in that other example I > gave: > > (packages->manifest > (list guile-2.0 > guile-opengl > guile-sdl > `(,gcc-toolchain "debug")) Sounds good to me. (FWIW I’m not fond of the `(,gcc-toolchain "debug") notation that we also use in packages, but it has the advantage of being concise.) >>> Below is a naive patch that does the job, but is unideal because it >>> doesn't do some nice things like display the diff between generations >>> before building. >> >> For that you would need a procedure to infer the manifest transaction: >> >> (manifests->transaction m1 m2) >> ;; returns a <manifest-transaction> >> >> and then that could be passed to ‘show-manifest-transaction’. >> >> However, I’m not sure it’s very useful. Perhaps it would be enough to >> write “installing new manifest from foo.scm with 42 entries.” >> WDYT? > > Okay, I'll do that instead. I would be interested in seeing what has > changed when I apply a new manifest, but it's probably not worth the > effort right now. Yeah. And note that this can always be done from the wonderful guix.el (info "(guix) Emacs List Buffer"). Thanks, Ludo’. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Reproducible profiles 2015-05-17 20:22 ` Ludovic Courtès @ 2015-05-17 20:51 ` David Thompson 2015-05-18 19:28 ` Syntax for package inputs Ludovic Courtès 0 siblings, 1 reply; 15+ messages in thread From: David Thompson @ 2015-05-17 20:51 UTC (permalink / raw) To: Ludovic Courtès; +Cc: guix-devel Ludovic Courtès <ludo@gnu.org> writes: > (FWIW I’m not fond of the `(,gcc-toolchain "debug") notation that we > also use in packages, but it has the advantage of being concise.) Do you have plans to introduce a better notation? G-exps? -- David Thompson GPG Key: 0FF1D807 ^ permalink raw reply [flat|nested] 15+ messages in thread
* Syntax for package inputs 2015-05-17 20:51 ` David Thompson @ 2015-05-18 19:28 ` Ludovic Courtès 0 siblings, 0 replies; 15+ messages in thread From: Ludovic Courtès @ 2015-05-18 19:28 UTC (permalink / raw) To: David Thompson; +Cc: guix-devel David Thompson <dthompson2@worcester.edu> skribis: > Ludovic Courtès <ludo@gnu.org> writes: > >> (FWIW I’m not fond of the `(,gcc-toolchain "debug") notation that we >> also use in packages, but it has the advantage of being concise.) > > Do you have plans to introduce a better notation? G-exps? No concrete plan yet. A remote possibility might be to indeed rely more on gexps and maybe get rid of input labels, like: (define foo (package ;; ... (inputs (list guile-2.0 gtk+ (gexp-input glib "bin"))))) but this introduces other challenges in particular wrt. package customizations. So, we’ll see. However, for new APIs, I find it usually better to use the above gexp style rather than the current package-input style. Ludo’. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Reproducible profiles 2015-05-16 11:16 ` Ludovic Courtès 2015-05-16 11:35 ` 宋文武 2015-05-17 19:23 ` David Thompson @ 2015-05-18 13:38 ` David Thompson 2015-05-18 19:29 ` Ludovic Courtès 2 siblings, 1 reply; 15+ messages in thread From: David Thompson @ 2015-05-18 13:38 UTC (permalink / raw) To: Ludovic Courtès; +Cc: guix-devel Ludovic Courtès <ludo@gnu.org> writes: > We’ll need documentation and tests, too. :-) Regarding tests, where should I add them? I can see that tests/guix-package.sh uses the '-n' flag to avoid building things. Simply running 'guix package -n --apply=test-manifest.scm' and getting a 0 exit value would suffice as a basic integration test, I think. Anything else that you would recommend? -- David Thompson GPG Key: 0FF1D807 ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Reproducible profiles 2015-05-18 13:38 ` Reproducible profiles David Thompson @ 2015-05-18 19:29 ` Ludovic Courtès 0 siblings, 0 replies; 15+ messages in thread From: Ludovic Courtès @ 2015-05-18 19:29 UTC (permalink / raw) To: David Thompson; +Cc: guix-devel David Thompson <dthompson2@worcester.edu> skribis: > Ludovic Courtès <ludo@gnu.org> writes: > >> We’ll need documentation and tests, too. :-) > > Regarding tests, where should I add them? I can see that > tests/guix-package.sh uses the '-n' flag to avoid building things. > Simply running 'guix package -n --apply=test-manifest.scm' and getting a > 0 exit value would suffice as a basic integration test, I think. > Anything else that you would recommend? As discussed on IRC, this sounds good to me. Probably in guix-package.sh, which is for tests that do not require network access, or otherwise in guix-package-net.sh. Ludo’. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Reproducible profiles 2015-05-15 1:19 Reproducible profiles David Thompson 2015-05-16 11:16 ` Ludovic Courtès @ 2015-05-18 21:07 ` David Thompson 2015-05-20 12:36 ` Ludovic Courtès 1 sibling, 1 reply; 15+ messages in thread From: David Thompson @ 2015-05-18 21:07 UTC (permalink / raw) To: guix-devel [-- Attachment #1: Type: text/plain, Size: 274 bytes --] Below is a new patch set taking into account the feedback received thus far. The (guix profiles) module still needs to be documented in the manual, but there's quite a lot of procedures and variables to account for. Would anyone be intertested in helping with this part? [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-ui-Factorize-user-provided-Scheme-file-loading.patch --] [-- Type: text/x-diff, Size: 3064 bytes --] From d506ad1d8824cc694364be502acddb25b76d0020 Mon Sep 17 00:00:00 2001 From: David Thompson <dthompson2@worcester.edu> Date: Mon, 18 May 2015 07:49:44 -0400 Subject: [PATCH 1/3] ui: Factorize user-provided Scheme file loading. * guix/ui.scm (make-user-module, read-scheme-file): New procedures. * guix/scripts/system.scm (%user-module): Define in terms of 'make-user-module'. (read-operating-system): Define in terms of 'read-scheme-file'. --- guix/scripts/system.scm | 22 ++++------------------ guix/ui.scm | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/guix/scripts/system.scm b/guix/scripts/system.scm index 1838e89..2d7c5d1 100644 --- a/guix/scripts/system.scm +++ b/guix/scripts/system.scm @@ -48,28 +48,14 @@ (define %user-module ;; Module in which the machine description file is loaded. - (let ((module (make-fresh-user-module))) - (for-each (lambda (iface) - (module-use! module (resolve-interface iface))) - '((gnu system) - (gnu services) - (gnu system shadow))) - module)) + (make-user-module '((gnu system) + (gnu services) + (gnu system shadow)))) (define (read-operating-system file) "Read the operating-system declaration from FILE and return it." - ;; TODO: Factorize. - (catch #t - (lambda () - ;; Avoid ABI incompatibility with the <operating-system> record. - (set! %fresh-auto-compile #t) + (read-scheme-file file %user-module)) - (save-module-excursion - (lambda () - (set-current-module %user-module) - (primitive-load file)))) - (lambda args - (report-load-error file args)))) \f ;;; diff --git a/guix/ui.scm b/guix/ui.scm index 911e5ee..5a76cf4 100644 --- a/guix/ui.scm +++ b/guix/ui.scm @@ -48,6 +48,8 @@ P_ report-error leave + make-user-module + read-scheme-file report-load-error warn-about-load-error show-version-and-exit @@ -133,6 +135,28 @@ messages." (report-error args ...) (exit 1))) +(define (make-user-module modules) + "Return a new user module with the additional MODULES loaded." + ;; Module in which the machine description file is loaded. + (let ((module (make-fresh-user-module))) + (for-each (lambda (iface) + (module-use! module (resolve-interface iface))) + modules) + module)) + +(define (read-scheme-file file user-module) + "Read the user provided Scheme source code FILE." + (catch #t + (lambda () + (set! %fresh-auto-compile #t) + + (save-module-excursion + (lambda () + (set-current-module user-module) + (primitive-load file)))) + (lambda args + (report-load-error file args)))) + (define (report-load-error file args) "Report the failure to load FILE, a user-provided Scheme file, and exit. ARGS is the list of arguments received by the 'throw' handler." -- 2.1.4 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #3: 0002-profiles-Add-packages-manifest-procedure.patch --] [-- Type: text/x-diff, Size: 1333 bytes --] From 5665da9934726ce0a8c4ed358b7f606d917c300a Mon Sep 17 00:00:00 2001 From: David Thompson <dthompson2@worcester.edu> Date: Mon, 18 May 2015 07:51:56 -0400 Subject: [PATCH 2/3] profiles: Add 'packages->manifest' procedure. * guix/profiles.scm (packages->manifest): New procedure. --- guix/profiles.scm | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/guix/profiles.scm b/guix/profiles.scm index 11d9bf0..cbc8a9a 100644 --- a/guix/profiles.scm +++ b/guix/profiles.scm @@ -80,6 +80,7 @@ profile-manifest package->manifest-entry + packages->manifest %default-profile-hooks profile-derivation generation-number @@ -172,6 +173,16 @@ omitted or #f, use the first output of PACKAGE." (dependencies (delete-duplicates deps)) (search-paths (package-native-search-paths package))))) +(define (packages->manifest packages) + "Convert PACKAGES into a manifest containing entries for all of them." + (manifest + (map (match-lambda + ((package output) + (package->manifest-entry package output)) + (package + (package->manifest-entry package))) + packages))) + (define (manifest->gexp manifest) "Return a representation of MANIFEST as a gexp." (define (entry->gexp entry) -- 2.1.4 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #4: 0003-package-Add-manifest-option.patch --] [-- Type: text/x-diff, Size: 9529 bytes --] From 3be657353bfebc33dc9733b820165699ac07b43d Mon Sep 17 00:00:00 2001 From: David Thompson <dthompson2@worcester.edu> Date: Thu, 14 May 2015 21:11:57 -0400 Subject: [PATCH 3/3] package: Add --manifest option. * guix/scripts/package.scm (show-help): Add help text. (%options): Add manifest option. (guix-package): Add manifest option handler. * doc/guix.texi ("Invoking guix package"): Document it. * tests/guix-package.sh: Add test. --- doc/guix.texi | 17 ++++++++ guix/scripts/package.scm | 107 ++++++++++++++++++++++++++++------------------- tests/guix-package.sh | 10 +++++ 3 files changed, 90 insertions(+), 44 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index 049292d..ca5f82d 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -1057,6 +1057,23 @@ substring ``emacs'': $ guix package --upgrade . --do-not-upgrade emacs @end example +@item --manifest=@var{file} +@itemx -m @var{file} +Create a new @dfn{generation} of the profile from the manifest object +contained in @var{file}, a Scheme source code file. + +A manifest file may look like this: + +@example +(use-package-modules guile emacs gcc) + +(packages->manifest + (list guile-2.0 + emacs + ;; Use a specific package output. + (list gcc "debug"))) +@end example + @item --roll-back Roll back to the previous @dfn{generation} of the profile---i.e., undo the last transaction. diff --git a/guix/scripts/package.scm b/guix/scripts/package.scm index 15f3e13..f2ca663 100644 --- a/guix/scripts/package.scm +++ b/guix/scripts/package.scm @@ -426,6 +426,9 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n")) (display (_ " -u, --upgrade[=REGEXP] upgrade all the installed packages matching REGEXP")) (display (_ " + -m, --manifest=FILE create a new profile generation with the manifest + contained within FILE.")) + (display (_ " --do-not-upgrade[=REGEXP] do not upgrade any packages matching REGEXP")) (display (_ " --roll-back roll back to the previous generation")) @@ -517,6 +520,10 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n")) (lambda (opt name arg result arg-handler) (values (alist-cons 'roll-back? #t result) #f))) + (option '(#\m "manifest") #t #f + (lambda (opt name arg result arg-handler) + (values (alist-cons 'manifest arg result) + arg-handler))) (option '(#\l "list-generations") #f #t (lambda (opt name arg result arg-handler) (values (cons `(query list-generations ,(or arg "")) @@ -783,6 +790,50 @@ more information.~%")) (define dry-run? (assoc-ref opts 'dry-run?)) (define profile (assoc-ref opts 'profile)) + (define (build-and-use-profile manifest) + (let* ((bootstrap? (assoc-ref opts 'bootstrap?))) + + (when (equal? profile %current-profile) + (ensure-default-profile)) + + (let* ((prof-drv (run-with-store (%store) + (profile-derivation + manifest + #:hooks (if bootstrap? + '() + %default-profile-hooks)))) + (prof (derivation->output-path prof-drv))) + (show-what-to-build (%store) (list prof-drv) + #:use-substitutes? + (assoc-ref opts 'substitutes?) + #:dry-run? dry-run?) + + (cond + (dry-run? #t) + ((and (file-exists? profile) + (and=> (readlink* profile) (cut string=? prof <>))) + (format (current-error-port) (_ "nothing to be done~%"))) + (else + (let* ((number (generation-number profile)) + + ;; Always use NUMBER + 1 for the new profile, + ;; possibly overwriting a "previous future + ;; generation". + (name (generation-file-name profile + (+ 1 number)))) + (and (build-derivations (%store) (list prof-drv)) + (let* ((entries (manifest-entries manifest)) + (count (length entries))) + (switch-symlinks name prof) + (switch-symlinks profile name) + (unless (string=? profile %current-profile) + (register-gc-root (%store) name)) + (format #t (N_ "~a package in profile~%" + "~a packages in profile~%" + count) + count) + (display-search-paths entries profile))))))))) + ;; First roll back if asked to. (cond ((and (assoc-ref opts 'roll-back?) (not dry-run?)) @@ -817,60 +868,28 @@ more information.~%")) (alist-delete 'delete-generations opts))) (_ #f)) opts)) + ((and (assoc-ref opts 'manifest) + (not dry-run?)) + (let* ((file-name (assoc-ref opts 'manifest)) + (user-module (make-user-module '((guix profiles) + (gnu)))) + (manifest (read-scheme-file file-name user-module))) + (format #t (_ "installing new manifest from ~a with ~d entries.~%") + file-name (length (manifest-entries manifest))) + (build-and-use-profile manifest))) (else (let* ((manifest (profile-manifest profile)) (install (options->installable opts manifest)) (remove (options->removable opts manifest)) - (bootstrap? (assoc-ref opts 'bootstrap?)) (transaction (manifest-transaction (install install) (remove remove))) (new (manifest-perform-transaction manifest transaction))) - (when (equal? profile %current-profile) - (ensure-default-profile)) - (unless (and (null? install) (null? remove)) - (let* ((prof-drv (run-with-store (%store) - (profile-derivation - new - #:hooks (if bootstrap? - '() - %default-profile-hooks)))) - (prof (derivation->output-path prof-drv))) - (show-manifest-transaction (%store) manifest transaction - #:dry-run? dry-run?) - (show-what-to-build (%store) (list prof-drv) - #:use-substitutes? - (assoc-ref opts 'substitutes?) - #:dry-run? dry-run?) - - (cond - (dry-run? #t) - ((and (file-exists? profile) - (and=> (readlink* profile) (cut string=? prof <>))) - (format (current-error-port) (_ "nothing to be done~%"))) - (else - (let* ((number (generation-number profile)) - - ;; Always use NUMBER + 1 for the new profile, - ;; possibly overwriting a "previous future - ;; generation". - (name (generation-file-name profile - (+ 1 number)))) - (and (build-derivations (%store) (list prof-drv)) - (let* ((entries (manifest-entries new)) - (count (length entries))) - (switch-symlinks name prof) - (switch-symlinks profile name) - (unless (string=? profile %current-profile) - (register-gc-root (%store) name)) - (format #t (N_ "~a package in profile~%" - "~a packages in profile~%" - count) - count) - (display-search-paths entries - profile)))))))))))) + (show-manifest-transaction (%store) manifest transaction + #:dry-run? dry-run?) + (build-and-use-profile new)))))) (define (process-query opts) ;; Process any query specified by OPTS. Return #t when a query was diff --git a/tests/guix-package.sh b/tests/guix-package.sh index a732110..4591333 100644 --- a/tests/guix-package.sh +++ b/tests/guix-package.sh @@ -237,3 +237,13 @@ export GUIX_BUILD_OPTIONS available2="`guix package -A | sort`" test "$available2" = "$available" guix package -I + +unset GUIX_BUILD_OPTIONS + +# Applying a manifest file +cat > "$module_dir/manifest.scm"<<EOF +(use-package-modules bootstrap) + +(packages->manifest (list %bootstrap-guile)) +EOF +guix package --bootstrap -m "$module_dir/manifest.scm" -- 2.1.4 [-- Attachment #5: Type: text/plain, Size: 38 bytes --] -- David Thompson GPG Key: 0FF1D807 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: Reproducible profiles 2015-05-18 21:07 ` David Thompson @ 2015-05-20 12:36 ` Ludovic Courtès 2015-05-20 16:14 ` David Thompson 0 siblings, 1 reply; 15+ messages in thread From: Ludovic Courtès @ 2015-05-20 12:36 UTC (permalink / raw) To: David Thompson; +Cc: guix-devel David Thompson <dthompson2@worcester.edu> skribis: > Below is a new patch set taking into account the feedback received thus > far. The (guix profiles) module still needs to be documented in the > manual, but there's quite a lot of procedures and variables to account > for. Would anyone be intertested in helping with this part? I can help with that, but it’s even better if someone else does it. :-) > From d506ad1d8824cc694364be502acddb25b76d0020 Mon Sep 17 00:00:00 2001 > From: David Thompson <dthompson2@worcester.edu> > Date: Mon, 18 May 2015 07:49:44 -0400 > Subject: [PATCH 1/3] ui: Factorize user-provided Scheme file loading. > > * guix/ui.scm (make-user-module, read-scheme-file): New procedures. > * guix/scripts/system.scm (%user-module): Define in terms of > 'make-user-module'. > (read-operating-system): Define in terms of 'read-scheme-file'. [...] > +(define (read-scheme-file file user-module) > + "Read the user provided Scheme source code FILE." What about calling it ‘load*’ and s/Read/Load/ in the docstring? It’s really a variant of ‘load’ rather than a variant of ‘read’. If that’s fine with you, OK to push with this change. > From 5665da9934726ce0a8c4ed358b7f606d917c300a Mon Sep 17 00:00:00 2001 > From: David Thompson <dthompson2@worcester.edu> > Date: Mon, 18 May 2015 07:51:56 -0400 > Subject: [PATCH 2/3] profiles: Add 'packages->manifest' procedure. > > * guix/profiles.scm (packages->manifest): New procedure. [...] > +(define (packages->manifest packages) > + "Convert PACKAGES into a manifest containing entries for all of them." What about something like: Return a list of manifest entries, one for each item listed in PACKAGES. Elements of PACKAGES can be either package objects or package/string tuples denoting a specific output of a package. OK to push with something along these lines. > From 3be657353bfebc33dc9733b820165699ac07b43d Mon Sep 17 00:00:00 2001 > From: David Thompson <dthompson2@worcester.edu> > Date: Thu, 14 May 2015 21:11:57 -0400 > Subject: [PATCH 3/3] package: Add --manifest option. > > * guix/scripts/package.scm (show-help): Add help text. > (%options): Add manifest option. > (guix-package): Add manifest option handler. > * doc/guix.texi ("Invoking guix package"): Document it. > * tests/guix-package.sh: Add test. [...] > +@item --manifest=@var{file} > +@itemx -m @var{file} > +Create a new @dfn{generation} of the profile from the manifest object > +contained in @var{file}, a Scheme source code file. s/contained in.*/returned by the Scheme code in @var{file}./ > +A manifest file may look like this: > + > +@example > +(use-package-modules guile emacs gcc) > + > +(packages->manifest > + (list guile-2.0 > + emacs > + ;; Use a specific package output. > + (list gcc "debug"))) > +@end example Maybe s/gcc/guile-2.0/, which might better illustrate the use case. > + -m, --manifest=FILE create a new profile generation with the manifest > + contained within FILE.")) s/contained within/from/ Also no period at the end. > +# Applying a manifest file > +cat > "$module_dir/manifest.scm"<<EOF > +(use-package-modules bootstrap) > + > +(packages->manifest (list %bootstrap-guile)) > +EOF > +guix package --bootstrap -m "$module_dir/manifest.scm" Maybe just add something like: guix package -I | grep guile test `guix package -I | wc -l` -eq 1 OK with these changes! I think it’s going to be nice to be able to use this declarative approach for user profiles, have the file under VC, etc. Thanks! Ludo’. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Reproducible profiles 2015-05-20 12:36 ` Ludovic Courtès @ 2015-05-20 16:14 ` David Thompson 0 siblings, 0 replies; 15+ messages in thread From: David Thompson @ 2015-05-20 16:14 UTC (permalink / raw) To: Ludovic Courtès; +Cc: guix-devel Ludovic Courtès <ludo@gnu.org> writes: > David Thompson <dthompson2@worcester.edu> skribis: > >> Below is a new patch set taking into account the feedback received thus >> far. The (guix profiles) module still needs to be documented in the >> manual, but there's quite a lot of procedures and variables to account >> for. Would anyone be intertested in helping with this part? > > I can help with that, but it’s even better if someone else does it. > :-) Okay. :) >> From d506ad1d8824cc694364be502acddb25b76d0020 Mon Sep 17 00:00:00 2001 >> From: David Thompson <dthompson2@worcester.edu> >> Date: Mon, 18 May 2015 07:49:44 -0400 >> Subject: [PATCH 1/3] ui: Factorize user-provided Scheme file loading. >> >> * guix/ui.scm (make-user-module, read-scheme-file): New procedures. >> * guix/scripts/system.scm (%user-module): Define in terms of >> 'make-user-module'. >> (read-operating-system): Define in terms of 'read-scheme-file'. > > [...] > >> +(define (read-scheme-file file user-module) >> + "Read the user provided Scheme source code FILE." > > What about calling it ‘load*’ and s/Read/Load/ in the docstring? > It’s really a variant of ‘load’ rather than a variant of ‘read’. > > If that’s fine with you, OK to push with this change. Done. >> From 5665da9934726ce0a8c4ed358b7f606d917c300a Mon Sep 17 00:00:00 2001 >> From: David Thompson <dthompson2@worcester.edu> >> Date: Mon, 18 May 2015 07:51:56 -0400 >> Subject: [PATCH 2/3] profiles: Add 'packages->manifest' procedure. >> >> * guix/profiles.scm (packages->manifest): New procedure. > > [...] > >> +(define (packages->manifest packages) >> + "Convert PACKAGES into a manifest containing entries for all of them." > > What about something like: > > Return a list of manifest entries, one for each item listed in > PACKAGES. Elements of PACKAGES can be either package objects or > package/string tuples denoting a specific output of a package. > > OK to push with something along these lines. Done. >> From 3be657353bfebc33dc9733b820165699ac07b43d Mon Sep 17 00:00:00 2001 >> From: David Thompson <dthompson2@worcester.edu> >> Date: Thu, 14 May 2015 21:11:57 -0400 >> Subject: [PATCH 3/3] package: Add --manifest option. >> >> * guix/scripts/package.scm (show-help): Add help text. >> (%options): Add manifest option. >> (guix-package): Add manifest option handler. >> * doc/guix.texi ("Invoking guix package"): Document it. >> * tests/guix-package.sh: Add test. > > > [...] > >> +@item --manifest=@var{file} >> +@itemx -m @var{file} >> +Create a new @dfn{generation} of the profile from the manifest object >> +contained in @var{file}, a Scheme source code file. > > s/contained in.*/returned by the Scheme code in @var{file}./ Done. >> +A manifest file may look like this: >> + >> +@example >> +(use-package-modules guile emacs gcc) >> + >> +(packages->manifest >> + (list guile-2.0 >> + emacs >> + ;; Use a specific package output. >> + (list gcc "debug"))) >> +@end example > > Maybe s/gcc/guile-2.0/, which might better illustrate the use case. > >> + -m, --manifest=FILE create a new profile generation with the manifest >> + contained within FILE.")) > > s/contained within/from/ > > Also no period at the end. Done. >> +# Applying a manifest file >> +cat > "$module_dir/manifest.scm"<<EOF >> +(use-package-modules bootstrap) >> + >> +(packages->manifest (list %bootstrap-guile)) >> +EOF >> +guix package --bootstrap -m "$module_dir/manifest.scm" > > Maybe just add something like: > > guix package -I | grep guile > test `guix package -I | wc -l` -eq 1 Done. > OK with these changes! I think it’s going to be nice to be able to > use this declarative approach for user profiles, have the file under > VC, etc. Me too! Pushed all 3 patches! -- David Thompson GPG Key: 0FF1D807 ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2015-05-22 12:02 UTC | newest] Thread overview: 15+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2015-05-15 1:19 Reproducible profiles David Thompson 2015-05-16 11:16 ` Ludovic Courtès 2015-05-16 11:35 ` 宋文武 2015-05-16 20:05 ` Ludovic Courtès 2015-05-17 19:27 ` David Thompson 2015-05-22 12:02 ` 宋文武 2015-05-17 19:23 ` David Thompson 2015-05-17 20:22 ` Ludovic Courtès 2015-05-17 20:51 ` David Thompson 2015-05-18 19:28 ` Syntax for package inputs Ludovic Courtès 2015-05-18 13:38 ` Reproducible profiles David Thompson 2015-05-18 19:29 ` Ludovic Courtès 2015-05-18 21:07 ` David Thompson 2015-05-20 12:36 ` Ludovic Courtès 2015-05-20 16:14 ` David Thompson
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).