1 ;;; guix-base.el --- Common definitions -*- lexical-binding: t -*-
3 ;; Copyright © 2014, 2015, 2016 Alex Kost <alezost@gmail.com>
5 ;; This file is part of GNU Guix.
7 ;; GNU Guix is free software; you can redistribute it and/or modify
8 ;; it under the terms of the GNU General Public License as published by
9 ;; the Free Software Foundation, either version 3 of the License, or
10 ;; (at your option) any later version.
12 ;; GNU Guix is distributed in the hope that it will be useful,
13 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ;; GNU General Public License for more details.
17 ;; You should have received a copy of the GNU General Public License
18 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
22 ;; This file provides some base and common definitions for guix.el
28 (require 'guix-backend
)
33 (require 'guix-profiles
)
36 "Settings for Guix package manager and friends."
40 (defgroup guix-faces nil
45 (defun guix-package-name-specification (name version
&optional output
)
46 "Return Guix package specification by its NAME, VERSION and OUTPUT."
47 (concat name
"@" version
48 (when output
(concat ":" output
))))
51 ;;; Location of profiles and manifests
53 (defun guix-generation-file (profile generation
)
54 "Return the file name of a PROFILE's GENERATION."
55 (format "%s-%s-link" profile generation
))
57 (defun guix-packages-profile (profile &optional generation system?
)
58 "Return a directory where packages are installed for the
61 If SYSTEM? is non-nil, then PROFILE is considered to be a system
62 profile. Unlike usual profiles, for a system profile, packages
63 are placed in 'profile' subdirectory."
64 (let ((profile (if generation
65 (guix-generation-file profile generation
)
68 (expand-file-name "profile" profile
)
71 (defun guix-manifest-file (profile &optional generation system?
)
72 "Return the file name of a PROFILE's manifest.
73 See `guix-packages-profile'."
74 (expand-file-name "manifest"
75 (guix-packages-profile profile generation system?
)))
78 ;;; Actions on packages and generations
80 (defface guix-operation-option-key
81 '((t :inherit font-lock-warning-face
))
82 "Face used for the keys of operation options."
85 (defcustom guix-operation-confirm t
86 "If nil, do not prompt to confirm an operation."
90 (defcustom guix-use-substitutes t
91 "If non-nil, use substitutes for the Guix packages."
95 (defvar guix-dry-run nil
96 "If non-nil, do not perform the real actions, just simulate.")
98 (defvar guix-temp-buffer-name
" *Guix temp*"
99 "Name of a buffer used for displaying info before executing operation.")
101 (defvar guix-operation-option-true-string
"yes"
102 "String displayed in the mode-line when operation option is t.")
104 (defvar guix-operation-option-false-string
"no "
105 "String displayed in the mode-line when operation option is nil.")
107 (defvar guix-operation-option-separator
" | "
108 "String used in the mode-line to separate operation options.")
110 (defvar guix-operation-options
111 '((?s
"substitutes" guix-use-substitutes
)
112 (?d
"dry-run" guix-dry-run
))
113 "List of available operation options.
114 Each element of the list has a form:
118 KEY is a character that may be pressed during confirmation to
120 NAME is a string displayed in the mode-line.
121 VARIABLE is a name of an option variable.")
123 (defun guix-operation-option-by-key (key)
124 "Return operation option by KEY (character)."
125 (assq key guix-operation-options
))
127 (defun guix-operation-option-key (option)
128 "Return key (character) of the operation OPTION."
131 (defun guix-operation-option-name (option)
132 "Return name of the operation OPTION."
135 (defun guix-operation-option-variable (option)
136 "Return name of the variable of the operation OPTION."
139 (defun guix-operation-option-value (option)
140 "Return boolean value of the operation OPTION."
141 (symbol-value (guix-operation-option-variable option
)))
143 (defun guix-operation-option-string-value (option)
144 "Convert boolean value of the operation OPTION to string and return it."
145 (if (guix-operation-option-value option
)
146 guix-operation-option-true-string
147 guix-operation-option-false-string
))
149 (defun guix-operation-prompt (&optional prompt
)
150 "Prompt a user for continuing the current operation.
151 Return non-nil, if the operation should be continued; nil otherwise.
152 Ask a user with PROMPT for continuing an operation."
153 (let* ((option-keys (mapcar #'guix-operation-option-key
154 guix-operation-options
))
155 (keys (append '(?y ?n
) option-keys
))
156 (prompt (concat (propertize (or prompt
"Continue operation?")
157 'face
'minibuffer-prompt
)
161 (propertize (string key
)
162 'face
'guix-operation-option-key
))
166 (let ((mode-line mode-line-format
))
167 (prog1 (guix-operation-prompt-1 prompt keys
)
168 (setq mode-line-format mode-line
)
169 ;; Clear the minibuffer after prompting.
172 (defun guix-operation-prompt-1 (prompt keys
)
173 "This function is internal for `guix-operation-prompt'."
174 (guix-operation-set-mode-line)
175 (let ((key (read-char-choice prompt
(cons ?\C-g keys
) t
)))
179 (t (let* ((option (guix-operation-option-by-key key
))
180 (var (guix-operation-option-variable option
)))
181 (set var
(not (symbol-value var
)))
182 (guix-operation-prompt-1 prompt keys
))))))
184 (defun guix-operation-set-mode-line ()
185 "Display operation options in the mode-line of the current buffer."
186 (setq mode-line-format
187 (concat (propertize " Options: "
188 'face
'mode-line-buffer-id
)
191 (let ((key (guix-operation-option-key option
))
192 (name (guix-operation-option-name option
))
193 (val (guix-operation-option-string-value option
)))
196 (propertize (string key
)
197 'face
'guix-operation-option-key
)
199 guix-operation-options
200 guix-operation-option-separator
)))
201 (force-mode-line-update))
203 (defun guix-package-source-path (package-id)
204 "Return a store file path to a source of a package PACKAGE-ID."
205 (message "Calculating the source derivation ...")
207 (guix-make-guile-expression
208 'package-source-path package-id
)))
210 (defun guix-package-store-path (package-id)
211 "Return a list of store directories of outputs of package PACKAGE-ID."
212 (message "Calculating the package derivation ...")
214 (guix-make-guile-expression
215 'package-store-path package-id
)))
217 (defvar guix-after-source-download-hook nil
218 "Hook run after successful performing a 'source-download' operation.")
220 (defun guix-package-source-build-derivation (package-id &optional prompt
)
221 "Build source derivation of a package PACKAGE-ID.
222 Ask a user with PROMPT for continuing an operation."
223 (when (or (not guix-operation-confirm
)
224 (guix-operation-prompt (or prompt
225 "Build the source derivation?")))
227 (guix-make-guile-expression
228 'package-source-build-derivation
230 :use-substitutes?
(or guix-use-substitutes
'f
)
231 :dry-run?
(or guix-dry-run
'f
))
232 nil
'source-download
)))
234 (defun guix-build-package (package-id &optional prompt
)
235 "Build package with PACKAGE-ID.
236 Ask a user with PROMPT for continuing the build operation."
237 (when (or (not guix-operation-confirm
)
238 (guix-operation-prompt (or prompt
"Build package?")))
240 (format (concat ",run-in-store "
241 "(build-package (package-by-id %d)"
242 " #:use-substitutes? %s"
245 (guix-guile-boolean guix-use-substitutes
)
246 (guix-guile-boolean guix-dry-run
)))))
249 (defun guix-apply-manifest (profile file
&optional operation-buffer
)
250 "Apply manifest from FILE to PROFILE.
251 This function has the same meaning as 'guix package --manifest' command.
252 See Info node `(guix) Invoking guix package' for details.
254 Interactively, use the current profile and prompt for manifest
255 FILE. With a prefix argument, also prompt for PROFILE."
257 (let* ((current-profile (guix-ui-current-profile))
258 (profile (if current-prefix-arg
259 (guix-profile-prompt)
260 (or current-profile guix-current-profile
)))
261 (file (read-file-name "File with manifest: "))
262 (buffer (and current-profile
(current-buffer))))
263 (list profile file buffer
)))
264 (when (or (not guix-operation-confirm
)
265 (y-or-n-p (format "Apply manifest from '%s' to profile '%s'? "
268 (guix-make-guile-expression
271 (concat "--profile=" (expand-file-name profile
))
272 (concat "--manifest=" (expand-file-name file
)))
276 ;;; Executing guix commands
278 (defcustom guix-run-in-shell-function
#'guix-run-in-shell
279 "Function used to run guix command.
280 The function is called with a single argument - a command line string."
281 :type
'(choice (function-item guix-run-in-shell
)
282 (function-item guix-run-in-eshell
)
283 (function :tag
"Other function"))
286 (defcustom guix-shell-buffer-name
"*shell*"
287 "Default name of a shell buffer used for running guix commands."
291 (declare-function comint-send-input
"comint" t
)
293 (defun guix-run-in-shell (string)
294 "Run command line STRING in `guix-shell-buffer-name' buffer."
295 (shell guix-shell-buffer-name
)
296 (goto-char (point-max))
300 (declare-function eshell-send-input
"esh-mode" t
)
302 (defun guix-run-in-eshell (string)
303 "Run command line STRING in eshell buffer."
305 (goto-char (point-max))
309 (defun guix-run-command-in-shell (args)
310 "Execute 'guix ARGS ...' command in a shell buffer."
311 (funcall guix-run-in-shell-function
312 (guix-command-string args
)))
314 (defun guix-run-command-in-repl (args)
315 "Execute 'guix ARGS ...' command in Guix REPL."
317 (apply #'guix-make-guile-expression
318 'guix-command args
)))
320 (defun guix-command-output (args)
321 "Return string with 'guix ARGS ...' output."
322 (cl-multiple-value-bind (output error
)
323 (guix-eval (apply #'guix-make-guile-expression
324 'guix-command-output args
))
325 ;; Remove trailing new space from the error string.
326 (message (replace-regexp-in-string "\n\\'" "" (read error
)))
329 (defun guix-help-string (&optional commands
)
330 "Return string with 'guix COMMANDS ... --help' output."
332 (apply #'guix-make-guile-expression
333 'help-string commands
)))
338 (defcustom guix-update-after-pull t
339 "If non-nil, update Guix buffers after performing \\[guix-pull]."
343 (defvar guix-after-pull-hook
344 '(guix-restart-repl-after-pull guix-update-buffers-maybe-after-pull
)
345 "Hook run after successful performing `guix-pull' operation.")
347 (defun guix-restart-repl-after-pull ()
348 "Restart Guix REPL after `guix-pull' operation."
350 (guix-start-process-maybe
351 "Restarting Guix REPL after pull operation ..."))
353 (defun guix-update-buffers-maybe-after-pull ()
354 "Update buffers depending on `guix-update-after-pull'."
355 (when guix-update-after-pull
356 (mapc #'guix-ui-update-buffer
357 ;; No need to update "generation" buffers.
358 (guix-ui-buffers '(guix-package-list-mode
359 guix-package-info-mode
360 guix-output-list-mode
361 guix-output-info-mode
)))
362 (message "Guix buffers have been updated.")))
365 (defun guix-pull (&optional verbose
)
366 "Run Guix pull operation.
367 If VERBOSE is non-nil (with prefix argument), produce verbose output."
369 (let ((args (and verbose
'("--verbose"))))
371 (apply #'guix-make-guile-expression
372 'guix-command
"pull" args
)
377 ;;; guix-base.el ends here