From: Alex Kost <alezost@gmail.com>
To: "Ludovic Courtès" <ludo@gnu.org>
Cc: guix-devel@gnu.org
Subject: [PATCH] Emacs interface for Guix
Date: Tue, 12 Aug 2014 14:19:48 +0400 [thread overview]
Message-ID: <87tx5idn7f.fsf_-_@gmail.com> (raw)
In-Reply-To: <87sil2rbly.fsf@gnu.org> ("Ludovic \=\?utf-8\?Q\?Court\=C3\=A8s\=22'\?\= \=\?utf-8\?Q\?s\?\= message of "Mon, 11 Aug 2014 22:54:17 +0200")
[-- Attachment #1: Type: text/plain, Size: 1126 bytes --]
Hello,
Ludovic Courtès (2014-08-12 00:54 +0400) wrote:
> Alex Kost <alezost@gmail.com> skribis:
>
>> - A part of code for installing/upgrading/removing was extracted from
>> ‘guix-package’ function (from ‘process-actions’ more precisely). So
>> the new function (I named it ‘process-package-actions’) can be used in
>> "guix.el".
>
> That looks good, but could you make it a separate patch?
>
> In general, it’s better to send atomic changes, with a commit log, in
> the format produced by ‘git format-patch’ (see HACKING.) That
> facilitates review and incremental changes.
Thanks for pointing. I've never contributed to a real project, so I
don't know the rules actually :)
>> - A bit of code was placed into "profiles.scm" as ‘manifest-add’.
>
> Good idea. Could you send a single patch for this change? I’ll even
> add a couple of test cases in tests/profiles.scm for the new procedure
> if you don’t do it yourself. :-)
Ok, I'm attaching 2 patches with ‘manifest-add’ and
‘process-package-actions’. What should be changed/improved there?
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-profiles-Add-manifest-add.patch --]
[-- Type: text/x-patch, Size: 2954 bytes --]
From af4b8495969d70d59aa9f3f296628daeaf80b0d2 Mon Sep 17 00:00:00 2001
From: Alex Kost <alezost@gmail.com>
Date: Tue, 12 Aug 2014 12:32:16 +0400
Subject: [PATCH 1/2] profiles: Add 'manifest-add'.
* guix/profiles.scm (manifest-add): New procedure.
* tests/profiles.scm (guile-1.8.8): New variable.
("manifest-add"): New test.
---
guix/profiles.scm | 20 ++++++++++++++++++++
tests/profiles.scm | 21 +++++++++++++++++++++
2 files changed, 41 insertions(+)
diff --git a/guix/profiles.scm b/guix/profiles.scm
index 5e69e01..c7aec79 100644
--- a/guix/profiles.scm
+++ b/guix/profiles.scm
@@ -47,6 +47,7 @@
manifest-pattern?
manifest-remove
+ manifest-add
manifest-installed?
manifest-matching-entries
@@ -196,6 +197,25 @@ must be a manifest-pattern."
(manifest-entries manifest)
patterns)))
+(define (manifest-add manifest entries)
+ "Add a list of manifest ENTRIES to MANIFEST and return new manifest.
+Remove MANIFEST entries that have the same name and output as ENTRIES."
+ (define (same-entry? entry name output)
+ (match entry
+ (($ <manifest-entry> entry-name _ entry-output _ ...)
+ (and (equal? name entry-name)
+ (equal? output entry-output)))))
+
+ (make-manifest
+ (append entries
+ (fold (lambda (entry result)
+ (match entry
+ (($ <manifest-entry> name _ out _ ...)
+ (filter (negate (cut same-entry? <> name out))
+ result))))
+ (manifest-entries manifest)
+ entries))))
+
(define (manifest-installed? manifest pattern)
"Return #t if MANIFEST has an entry matching PATTERN (a manifest-pattern),
#f otherwise."
diff --git a/tests/profiles.scm b/tests/profiles.scm
index d405f64..b2919d7 100644
--- a/tests/profiles.scm
+++ b/tests/profiles.scm
@@ -40,6 +40,13 @@
;; Example manifest entries.
+(define guile-1.8.8
+ (manifest-entry
+ (name "guile")
+ (version "1.8.8")
+ (item "/gnu/store/...")
+ (output "out")))
+
(define guile-2.0.9
(manifest-entry
(name "guile")
@@ -101,6 +108,20 @@
(null? (manifest-entries m3))
(null? (manifest-entries m4)))))))
+(test-assert "manifest-add"
+ (let* ((m0 (manifest '()))
+ (m1 (manifest-add m0 (list guile-1.8.8)))
+ (m2 (manifest-add m1 (list guile-2.0.9)))
+ (m3 (manifest-add m2 (list guile-2.0.9:debug)))
+ (m4 (manifest-add m3 (list guile-2.0.9:debug))))
+ (and (match (manifest-entries m1)
+ ((($ <manifest-entry> "guile" "1.8.8" "out")) #t)
+ (_ #f))
+ (match (manifest-entries m2)
+ ((($ <manifest-entry> "guile" "2.0.9" "out")) #t)
+ (_ #f))
+ (equal? m3 m4))))
+
(test-assert "profile-derivation"
(run-with-store %store
(mlet* %store-monad
--
2.0.3
[-- Attachment #3: 0002-guix-package-Add-process-package-actions.patch --]
[-- Type: text/x-patch, Size: 17619 bytes --]
From 5fd45b3f4216921837f522d56b20c4be0a58fe8e Mon Sep 17 00:00:00 2001
From: Alex Kost <alezost@gmail.com>
Date: Tue, 12 Aug 2014 13:54:23 +0400
Subject: [PATCH 2/2] guix package: Add 'process-package-actions'.
* guix/scripts/package.scm (process-package-actions): New procedure.
(guix-package): Use it.
[ensure-default-profile]: Move to top-level.
[substitutes?]: New variable.
[same-package?]: Remove.
(options->installable, options->removable): Change according to
'process-package-actions'.
---
guix/scripts/package.scm | 336 +++++++++++++++++++++++------------------------
1 file changed, 166 insertions(+), 170 deletions(-)
diff --git a/guix/scripts/package.scm b/guix/scripts/package.scm
index 4eb046e..2719b74 100644
--- a/guix/scripts/package.scm
+++ b/guix/scripts/package.scm
@@ -44,6 +44,7 @@
#:use-module ((gnu packages bootstrap) #:select (%bootstrap-guile))
#:use-module (guix gnu-maintenance)
#:export (specification->package+output
+ process-package-actions
guix-package))
(define %store
@@ -619,21 +620,15 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n"))
%standard-build-options))
-(define (options->installable opts manifest)
- "Given MANIFEST, the current manifest, and OPTS, the result of 'args-fold',
-return the new list of manifest entries."
- (define (package->manifest-entry* package output)
- (check-package-freshness package)
- ;; When given a package via `-e', install the first of its
- ;; outputs (XXX).
- (package->manifest-entry package output))
-
+(define (options->installable options manifest)
+ "Given OPTIONS, return a list of patterns for installing/upgrading.
+Returned list is suitable for 'process-package-actions'."
(define upgrade-regexps
(filter-map (match-lambda
(('upgrade . regexp)
(make-regexp (or regexp "")))
(_ #f))
- opts))
+ options))
(define packages-to-upgrade
(match upgrade-regexps
@@ -653,59 +648,18 @@ return the new list of manifest entries."
(_ #f))
(manifest-entries manifest)))))
- (define to-upgrade
- (map (match-lambda
- ((package output)
- (package->manifest-entry* package output)))
- packages-to-upgrade))
-
(define packages-to-install
(filter-map (match-lambda
- (('install . (? package? p))
- (list p "out"))
- (('install . (? string? spec))
- (and (not (store-path? spec))
- (let-values (((package output)
- (specification->package+output spec)))
- (and package (list package output)))))
+ (('install . package) package)
(_ #f))
- opts))
-
- (define to-install
- (append (map (match-lambda
- ((package output)
- (package->manifest-entry* package output)))
- packages-to-install)
- (filter-map (match-lambda
- (('install . (? package?))
- #f)
- (('install . (? store-path? path))
- (let-values (((name version)
- (package-name->name+version
- (store-path-package-name path))))
- (manifest-entry
- (name name)
- (version version)
- (output #f)
- (item path))))
- (_ #f))
- opts)))
-
- (append to-upgrade to-install))
-
-(define (options->removable options manifest)
- "Given options, return the list of manifest patterns of packages to be
-removed from MANIFEST."
+ options))
+
+ (append packages-to-upgrade packages-to-install))
+
+(define (options->removable options)
+ "Given OPTIONS, return a list of package specifications for deleting."
(filter-map (match-lambda
- (('remove . spec)
- (call-with-values
- (lambda ()
- (package-specification->name+version+output spec))
- (lambda (name version output)
- (manifest-pattern
- (name name)
- (version version)
- (output output)))))
+ (('remove . spec) spec)
(_ #f))
options))
@@ -724,6 +678,150 @@ removed from MANIFEST."
file
(apply throw args)))))
+(define (ensure-default-profile)
+ "Ensure the default profile symlink and directory exist and are
+writable."
+ (define (rtfm)
+ (format (current-error-port)
+ (_ "Try \"info '(guix) Invoking guix package'\" for \
+more information.~%"))
+ (exit 1))
+
+ ;; Create ~/.guix-profile if it doesn't exist yet.
+ (when (and %user-profile-directory
+ %current-profile
+ (not (false-if-exception
+ (lstat %user-profile-directory))))
+ (symlink %current-profile %user-profile-directory))
+
+ (let ((s (stat %profile-directory #f)))
+ ;; Attempt to create /…/profiles/per-user/$USER if needed.
+ (unless (and s (eq? 'directory (stat:type s)))
+ (catch 'system-error
+ (lambda ()
+ (mkdir-p %profile-directory))
+ (lambda args
+ ;; Often, we cannot create %PROFILE-DIRECTORY because its
+ ;; parent directory is root-owned and we're running
+ ;; unprivileged.
+ (format (current-error-port)
+ (_ "error: while creating directory `~a': ~a~%")
+ %profile-directory
+ (strerror (system-error-errno args)))
+ (format (current-error-port)
+ (_ "Please create the `~a' directory, with you as the owner.~%")
+ %profile-directory)
+ (rtfm))))
+
+ ;; Bail out if it's not owned by the user.
+ (unless (or (not s) (= (stat:uid s) (getuid)))
+ (format (current-error-port)
+ (_ "error: directory `~a' is not owned by you~%")
+ %profile-directory)
+ (format (current-error-port)
+ (_ "Please change the owner of `~a' to user ~s.~%")
+ %profile-directory (or (getenv "USER")
+ (getenv "LOGNAME")
+ (getuid)))
+ (rtfm))))
+
+(define* (process-package-actions store profile
+ #:key (install '()) (remove '())
+ dry-run? (use-substitutes? #t))
+ "Install/remove packages.
+
+INSTALL is a list of package patterns for installation. Each element of
+the list may be a package, a list (PACKAGE OUTPUT), a string with name
+specification or a store path.
+
+REMOVE is a list of name specifications for removing from PROFILE
+manifest."
+ (define (package->manifest-entry* package output)
+ (check-package-freshness package)
+ ;; When given a package via `-e', install the first of its
+ ;; outputs (XXX).
+ (package->manifest-entry package output))
+
+ (define (entries-to-install install)
+ ;; Return a list of manifest entries for installing.
+ (filter-map (match-lambda
+ ((? package? package)
+ (package->manifest-entry* package "out"))
+ (((? package? package) output)
+ (package->manifest-entry* package output))
+ ((? string? spec-or-path)
+ (if (store-path? spec-or-path)
+ (let-values (((name version)
+ (package-name->name+version
+ (store-path-package-name spec-or-path))))
+ (manifest-entry
+ (name name)
+ (version version)
+ (output #f)
+ (item spec-or-path)))
+ (let-values (((package output)
+ (specification->package+output spec-or-path)))
+ (and package (package->manifest-entry* package output)))))
+ (_ #f))
+ install))
+
+ (define (patterns-to-remove remove)
+ ;; Return a list of manifest patterns for removing.
+ (map (lambda (spec)
+ (call-with-values
+ (lambda ()
+ (package-specification->name+version+output spec))
+ (lambda (name version output)
+ (manifest-pattern
+ (name name)
+ (version version)
+ (output output)))))
+ remove))
+
+ (let* ((manifest (profile-manifest profile))
+ (install (entries-to-install install))
+ (remove (patterns-to-remove remove))
+ (new (manifest-add (manifest-remove manifest remove)
+ install))
+ (entries (manifest-entries new)))
+
+ (unless (and (null? install) (null? remove))
+ (when (equal? profile %current-profile)
+ (ensure-default-profile))
+
+ (let* ((prof-drv (run-with-store store (profile-derivation new)))
+ (prof (derivation->output-path prof-drv))
+ (remove (manifest-matching-entries manifest remove)))
+ (show-what-to-remove/install remove install dry-run?)
+ (show-what-to-build store (list prof-drv)
+ #:use-substitutes? use-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 ((count (length entries)))
+ (switch-symlinks name prof)
+ (switch-symlinks profile name)
+ (maybe-register-gc-root store profile)
+ (format #t (N_ "~a package in profile~%"
+ "~a packages in profile~%"
+ count)
+ count)
+ (display-search-paths entries
+ profile))))))))))
+
\f
;;;
;;; Entry point.
@@ -742,65 +840,12 @@ removed from MANIFEST."
%default-options
#f))
- (define (ensure-default-profile)
- ;; Ensure the default profile symlink and directory exist and are
- ;; writable.
-
- (define (rtfm)
- (format (current-error-port)
- (_ "Try \"info '(guix) Invoking guix package'\" for \
-more information.~%"))
- (exit 1))
-
- ;; Create ~/.guix-profile if it doesn't exist yet.
- (when (and %user-profile-directory
- %current-profile
- (not (false-if-exception
- (lstat %user-profile-directory))))
- (symlink %current-profile %user-profile-directory))
-
- (let ((s (stat %profile-directory #f)))
- ;; Attempt to create /…/profiles/per-user/$USER if needed.
- (unless (and s (eq? 'directory (stat:type s)))
- (catch 'system-error
- (lambda ()
- (mkdir-p %profile-directory))
- (lambda args
- ;; Often, we cannot create %PROFILE-DIRECTORY because its
- ;; parent directory is root-owned and we're running
- ;; unprivileged.
- (format (current-error-port)
- (_ "error: while creating directory `~a': ~a~%")
- %profile-directory
- (strerror (system-error-errno args)))
- (format (current-error-port)
- (_ "Please create the `~a' directory, with you as the owner.~%")
- %profile-directory)
- (rtfm))))
-
- ;; Bail out if it's not owned by the user.
- (unless (or (not s) (= (stat:uid s) (getuid)))
- (format (current-error-port)
- (_ "error: directory `~a' is not owned by you~%")
- %profile-directory)
- (format (current-error-port)
- (_ "Please change the owner of `~a' to user ~s.~%")
- %profile-directory (or (getenv "USER")
- (getenv "LOGNAME")
- (getuid)))
- (rtfm))))
-
(define (process-actions opts)
;; Process any install/remove/upgrade action from OPTS.
- (define dry-run? (assoc-ref opts 'dry-run?))
- (define profile (assoc-ref opts 'profile))
-
- (define (same-package? entry name output)
- (match entry
- (($ <manifest-entry> entry-name _ entry-output _ ...)
- (and (equal? name entry-name)
- (equal? output entry-output)))))
+ (define substitutes? (assoc-ref opts 'substitutes?))
+ (define dry-run? (assoc-ref opts 'dry-run?))
+ (define profile (assoc-ref opts 'profile))
(define current-generation-number
(generation-number profile))
@@ -869,61 +914,12 @@ more information.~%"))
(_ #f))
opts))
(else
- (let* ((manifest (profile-manifest profile))
- (install (options->installable opts manifest))
- (remove (options->removable opts manifest))
- (entries
- (append install
- (fold (lambda (package result)
- (match package
- (($ <manifest-entry> name _ out _ ...)
- (filter (negate
- (cut same-package? <>
- name out))
- result))))
- (manifest-entries
- (manifest-remove manifest remove))
- install)))
- (new (make-manifest entries)))
-
- (when (equal? profile %current-profile)
- (ensure-default-profile))
-
- (unless (and (null? install) (null? remove))
- (let* ((prof-drv (run-with-store (%store)
- (profile-derivation new)))
- (prof (derivation->output-path prof-drv))
- (remove (manifest-matching-entries manifest remove)))
- (show-what-to-remove/install remove install 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 ((count (length entries)))
- (switch-symlinks name prof)
- (switch-symlinks profile name)
- (maybe-register-gc-root (%store) profile)
- (format #t (N_ "~a package in profile~%"
- "~a packages in profile~%"
- count)
- count)
- (display-search-paths entries
- profile))))))))))))
+ (process-package-actions
+ (%store) profile
+ #:install (options->installable opts (profile-manifest profile))
+ #:remove (options->removable opts)
+ #:use-substitutes? substitutes?
+ #:dry-run? dry-run?))))
(define (process-query opts)
;; Process any query specified by OPTS. Return #t when a query was
--
2.0.3
next prev parent reply other threads:[~2014-08-12 10:20 UTC|newest]
Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-07-25 17:58 Emacs interface for Guix Alex Kost
2014-07-25 20:36 ` Ludovic Courtès
2014-07-26 17:44 ` Alex Kost
2014-07-28 10:15 ` Alex Kost
2014-08-11 20:54 ` Ludovic Courtès
2014-08-12 10:19 ` Alex Kost [this message]
2014-08-12 14:19 ` [PATCH] " Ludovic Courtès
2014-08-12 16:20 ` Alex Kost
2014-08-12 19:50 ` Ludovic Courtès
2014-08-13 6:57 ` Alex Kost
2014-08-13 16:03 ` Ludovic Courtès
2014-08-13 20:58 ` Alex Kost
2014-08-15 5:51 ` Alex Kost
2014-08-16 9:27 ` Ludovic Courtès
2014-08-16 10:52 ` [PATCH] manifest-transaction Alex Kost
2014-08-20 12:10 ` [PATCH] profiles: Report about upgrades Alex Kost
2014-08-23 11:58 ` Ludovic Courtès
2014-08-30 19:56 ` Ludovic Courtès
2014-08-31 6:04 ` Alex Kost
2014-08-31 19:57 ` Ludovic Courtès
2014-08-31 22:54 ` Jason Self
2014-09-01 7:13 ` Alex Kost
2014-09-02 19:45 ` Ludovic Courtès
[not found] ` <87egvrke1z.fsf@gmail.com>
2014-09-04 19:37 ` Ludovic Courtès
2014-08-16 12:24 ` [PATCH] Emacs interface for Guix Ludovic Courtès
2014-08-16 13:07 ` Alex Kost
2014-08-19 21:00 ` Ludovic Courtès
2014-08-20 10:54 ` Alex Kost
2014-08-22 8:56 ` Ludovic Courtès
2014-08-22 12:44 ` Alex Kost
2014-08-27 8:34 ` Ludovic Courtès
2014-10-04 17:59 ` [PATCH] guix package: Export generation procedures Alex Kost
2014-10-04 20:23 ` Ludovic Courtès
2014-10-05 8:54 ` [PATCH] emacs: Add support for deleting generations Alex Kost
2014-10-05 13:14 ` Ludovic Courtès
2014-10-05 18:23 ` Alex Kost
2014-10-05 19:20 ` Ludovic Courtès
2014-10-05 20:04 ` Alex Kost
2014-10-06 7:36 ` Ludovic Courtès
2014-10-06 14:14 ` [PATCH] guix package: Add '--switch-generation' option Alex Kost
2014-10-06 19:27 ` Ludovic Courtès
2014-10-07 10:04 ` Alex Kost
2014-10-07 16:00 ` Ludovic Courtès
2014-10-07 21:32 ` Alex Kost
2014-10-08 9:44 ` Ludovic Courtès
2014-10-05 14:44 ` [PATCH] guix package: Export generation procedures Andreas Enge
2014-10-05 19:21 ` Ludovic Courtès
2014-07-26 20:58 ` Emacs interface for Guix Ludovic Courtès
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://guix.gnu.org/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87tx5idn7f.fsf_-_@gmail.com \
--to=alezost@gmail.com \
--cc=guix-devel@gnu.org \
--cc=ludo@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).