Emacs/Guix: Support installing multiple manifests at once.

master
Pierre Neidhardt 2020-06-11 15:43:54 +02:00
parent 83b8b865d6
commit ef2105d0e7
1 changed files with 82 additions and 41 deletions

View File

@ -59,11 +59,13 @@ The channel specification is looked up in
(cl-defun ambrevar/guix-query-file (&key file directory
(filter ".")
(prompt "File: ")
(name-function #'identity))
(name-function #'identity)
(multiple? nil))
"Query a file matching FILTER in DIRECTORY.
Return (NAME FILE).
If FILE is non-nil, then this function is useful to derive the name of the manifest.
NAME-FUNCTION take the file base name as argument and returns NAME."
NAME-FUNCTION take the file base name as argument and returns NAME.
If MULTIPLE? is non-nil, return a list of (NAME FILE) of the selected manifests."
(cl-flet ((name (file)
(replace-regexp-in-string
"-?guix-?" ""
@ -74,20 +76,26 @@ NAME-FUNCTION take the file base name as argument and returns NAME."
(let ((files (mapcar (lambda (file)
(list (name file) file))
(directory-files directory 'full filter))))
(assoc (completing-read prompt (mapcar #'first files))
files)))))
(if multiple?
(mapcar (lambda (name)
(assoc name files))
(completing-read-multiple prompt (mapcar #'first files)))
(assoc (completing-read prompt (mapcar #'first files))
files))))))
(defun ambrevar/guix-query-manifest (&optional manifest)
(defun ambrevar/guix-query-manifest (&optional manifest multiple?)
"Query a manifest as found in `ambrevar/guix-manifest-directory'.
Return (NAME FILE).
If MANIFEST is non-nil, then this function is useful to derive the name of the manifest."
If MANIFEST is non-nil, then this function is useful to derive the name of the manifest.
If MULTIPLE? is non-nil, allow querying multiple manifests."
(ambrevar/guix-query-file
:file manifest
:directory ambrevar/guix-manifest-directory
:filter "manifest"
:prompt "Manifest: "
:prompt "Manifest(s): "
:name-function (lambda (name)
(replace-regexp-in-string "-?manifest-?" "" name))))
(replace-regexp-in-string "-?manifest-?" "" name))
:multiple? multiple?))
(defun ambrevar/guix-query-channel-spec (&optional channel-spec)
"Query a channel specification as found in `ambrevar/guix-channel-spec-directory'.
@ -157,6 +165,54 @@ If MANIFEST is nil, it is queried from the manifests found in `ambrevar/guix-man
(not (eql (point)
(marker-position (cdr comint-last-prompt)))))))
(defun %ambrevar/guix-install-manifest (&optional manifests channel)
"Install list of (NAME MANIFEST-FILE) using CHANNEL."
(require 'init-eshell) ; For `ambrevar/prefer-eshell'.
(let* ((guix (if channel
(let ((dest (expand-file-name
manifest-name
ambrevar/guix-extra-channels)))
(make-directory dest 'parents)
(format "guix pull --channels=%s --profile=%s/guix && %s/guix/bin/guix"
(shell-quote-argument channel)
(shell-quote-argument dest)
(shell-quote-argument dest)))
"guix")))
(dolist (manifest-pair manifests)
(let ((manifest-name (first manifest-pair)))
(make-directory (expand-file-name manifest-name
ambrevar/guix-extra-profiles)
'parents)))
(funcall (if ambrevar/prefer-eshell
'ambrevar/run-in-eshell
'ambrevar/run-in-shell)
(mapconcat #'identity
(mapcar (lambda (manifest-pair)
(let ((manifest-name (first manifest-pair))
(manifest (second manifest-pair))
(profile (expand-file-name ambrevar/guix-extra-profiles)))
(string-join
(list "echo" (format "'==> Installing manifest %S to profile %S'"
manifest-name profile)
";"
guix "package" (concat "--manifest=" manifest)
(if (string= "default" manifest-name)
""
(concat "--profile=" profile
"/" manifest-name
"/" manifest-name)))
" ")))
manifests)
" ; "))
(unless channel
;; TODO: Only do this when manifest install has succeeded.
(dolist (manifest-pair manifests)
(let ((manifest-name (first manifest-pair)))
(ambrevar/guix-save-channel-specs
(format "%s/guix-%s-channels.scm"
ambrevar/guix-channel-spec-directory
manifest-name)))))))
(defun ambrevar/guix-install-manifest (&optional manifest channel)
"Install Guix manifest to `ambrevar/guix-extra-profiles'.
@ -169,7 +225,6 @@ If CHANNEL is nil and `ambrevar/guix-always-use-channel-specs' is
non-nil, then try to use a channel specification file from
`ambrevar/guix-channel-spec-directory' if any."
(interactive)
(require 'init-eshell) ; For `ambrevar/prefer-eshell'.
(let* ((manifest-pair (ambrevar/guix-query-manifest manifest))
(manifest-name (first manifest-pair))
(manifest (second manifest-pair))
@ -177,40 +232,26 @@ non-nil, then try to use a channel specification file from
(and current-prefix-arg
(second (ambrevar/guix-query-channel-spec)))
(and ambrevar/guix-always-use-channel-specs
(ambrevar/guix-find-channel-from-manifest manifest-name))))
(guix (if channel
(let ((dest (expand-file-name
manifest-name
ambrevar/guix-extra-channels)))
(make-directory dest 'parents)
(format "guix pull --channels=%s --profile=%s/guix && %s/guix/bin/guix"
(shell-quote-argument channel)
(shell-quote-argument dest)
(shell-quote-argument dest)))
"guix")))
(make-directory (expand-file-name manifest-name
ambrevar/guix-extra-profiles)
'parents)
(funcall (if ambrevar/prefer-eshell
'ambrevar/run-in-eshell
'ambrevar/run-in-shell)
(string-join
(list guix " package" (concat " --manifest=" manifest)
(if (string= "default" manifest-name)
""
(concat " --profile=" (expand-file-name ambrevar/guix-extra-profiles)
"/" manifest-name
"/" manifest-name)))))
(unless channel
;; TODO: Only do this when manifest install has succeeded.
(ambrevar/guix-save-channel-specs
(format "%s/guix-%s-channels.scm"
ambrevar/guix-channel-spec-directory
manifest-name)))))
(global-set-key (kbd "C-x c G") #'ambrevar/guix-install-manifest)
(ambrevar/guix-find-channel-from-manifest manifest-name)))))
(%ambrevar/guix-install-manifest (list manifest-pair) channel)))
(defun ambrevar/guix-install-manifests (&optional manifests channel)
"Install Guix manifests to `ambrevar/guix-extra-profiles'.
Manifests are queried from those found in `ambrevar/guix-manifest-directory'.
Guix channel specification is stored in `ambrevar/guix-channel-spec-directory'.
With a prefix argument, query for a channel specification file."
(interactive)
(let* ((manifests (or manifests (ambrevar/guix-query-manifest nil :multiple)))
(channel (or channel
(and current-prefix-arg
(second (ambrevar/guix-query-channel-spec))))))
(%ambrevar/guix-install-manifest manifests channel)))
(global-set-key (kbd "C-x c G") #'ambrevar/guix-install-manifests)
(with-eval-after-load 'evil
(dolist (mode '(normal insert))
(evil-global-set-key mode (kbd "C-x c G") #'ambrevar/guix-install-manifest)))
(evil-global-set-key mode (kbd "C-x c G") #'ambrevar/guix-install-manifests)))
;; TODO: See `guix-apply-manifest' and expand on it.
;; TODO: Use --max-jobs=N.