Emacs/Guix: Add manifest manipulation commands.
parent
8c5da3743e
commit
ce126f34ee
|
@ -44,4 +44,134 @@ with previous."
|
|||
(with-eval-after-load 'guix-ui-generation
|
||||
(define-key guix-generation-list-mode-map "=" #'ambrevar/guix-generations-list-diff-this))
|
||||
|
||||
(defvar ambrevar/guix-extra-channels "~/.guix-extra-channels")
|
||||
(defvar ambrevar/guix-extra-profiles "~/.guix-extra-profiles")
|
||||
(defvar ambrevar/guix-manifest-directory "~/.package-lists")
|
||||
(defvar ambrevar/guix-channel-spec-directory "~/.package-lists")
|
||||
(defvar ambrevar/guix-always-use-channel-specs nil
|
||||
"If non-nil, automatically use a channel specification matching the chosen manifest.
|
||||
The channel specification is looked up in
|
||||
`ambrevar/guix-channel-spec-directory'.")
|
||||
|
||||
(cl-defun ambrevar/guix-query-file (&key file directory
|
||||
(filter ".")
|
||||
(prompt "File: ")
|
||||
(name-function #'identity))
|
||||
"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."
|
||||
(cl-flet ((name (file)
|
||||
(replace-regexp-in-string
|
||||
"-?guix-?" ""
|
||||
(funcall name-function
|
||||
(file-name-base file)))))
|
||||
(if file
|
||||
(list (name file) file)
|
||||
(let ((files (mapcar (lambda (file)
|
||||
(list (name file) file))
|
||||
(directory-files directory 'full filter))))
|
||||
(assoc (completing-read prompt (mapcar #'first files))
|
||||
files)))))
|
||||
|
||||
(defun ambrevar/guix-query-manifest (&optional manifest)
|
||||
"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."
|
||||
(ambrevar/guix-query-file
|
||||
:file manifest
|
||||
:directory ambrevar/guix-manifest-directory
|
||||
:filter "manifest"
|
||||
:prompt "Manifest: "
|
||||
:name-function (lambda (name)
|
||||
(replace-regexp-in-string "-?manifest-?" "" name))))
|
||||
|
||||
(defun ambrevar/guix-query-channel-spec (&optional channel-spec)
|
||||
"Query a channel specification as found in `ambrevar/guix-channel-spec-directory'.
|
||||
Return (NAME FILE).
|
||||
If CHANNEL-SPEC is non-nil, then this function is useful to derive the name of
|
||||
the channel specification."
|
||||
(ambrevar/guix-query-file
|
||||
:file channel-spec
|
||||
:directory ambrevar/guix-channel-spec-directory
|
||||
:filter "channels"
|
||||
:prompt "Channel specification: "
|
||||
:name-function (lambda (name)
|
||||
(replace-regexp-in-string "-?channels?-?" "" name))))
|
||||
|
||||
(defun ambrevar/guix-edit-manifest (&optional manifest)
|
||||
"Edit MANIFEST.
|
||||
If MANIFEST is nil, it is queried from the manifests found in `ambrevar/guix-manifest-directory'."
|
||||
(interactive)
|
||||
(setq manifest (second (ambrevar/guix-query-manifest manifest)))
|
||||
(find-file manifest))
|
||||
(global-set-key (kbd "C-x c g") #'ambrevar/guix-edit-manifest)
|
||||
|
||||
(defun ambrevar/guix-save-channel-specs (dest)
|
||||
"Save current Guix channel specification to DEST."
|
||||
(call-process "guix"
|
||||
nil `(:file ,dest) nil
|
||||
"describe" "--format=channels"))
|
||||
|
||||
(defun ambrevar/guix-find-channel-from-manifest (pattern)
|
||||
"Return the channel specification file matching PATTERN in
|
||||
`ambrevar/guix-channel-spec-directory'."
|
||||
(first (directory-files ambrevar/guix-channel-spec-directory 'full
|
||||
(concat pattern "-channel"))))
|
||||
|
||||
(defun ambrevar/guix-install-manifest (&optional manifest channel)
|
||||
"Install Guix manifest to `ambrevar/guix-extra-profiles'.
|
||||
|
||||
Manifest is 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.
|
||||
|
||||
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)
|
||||
(let* ((manifest-pair (ambrevar/guix-query-manifest manifest))
|
||||
(manifest-name (first manifest-pair))
|
||||
(manifest (second manifest-pair))
|
||||
(channel (or channel
|
||||
(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)
|
||||
(let ((eshell-buffer-name "*guix*"))
|
||||
(eshell)
|
||||
(when (eshell-interactive-process)
|
||||
(eshell t))
|
||||
(eshell-interrupt-process)
|
||||
(insert guix " package" (concat " --manifest=" manifest)
|
||||
(if (string= "default" manifest-name)
|
||||
""
|
||||
(concat " --profile=" (expand-file-name ambrevar/guix-extra-profiles)
|
||||
"/" manifest-name
|
||||
"/" manifest-name)))
|
||||
(eshell-send-input))
|
||||
(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)
|
||||
|
||||
;; TODO: See `guix-apply-manifest' and expand on it.
|
||||
|
||||
(provide 'init-guix)
|
||||
|
|
Loading…
Reference in New Issue