doc: Add a REPL example.
[jackhill/guix/guix.git] / guix / ui.scm
CommitLineData
233e7676 1;;; GNU Guix --- Functional package management for GNU
e9651e39 2;;; Copyright © 2012, 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org>
e49951eb 3;;; Copyright © 2013 Mark H Weaver <mhw@netris.org>
98eb8cbe 4;;; Copyright © 2013 Nikita Karetnikov <nikita@karetnikov.org>
88981dd3
AK
5;;; Copyright © 2014 Cyril Roelandt <tipecaml@gmail.com>
6;;; Copyright © 2014 Cyrill Schenkel <cyrill.schenkel@gmail.com>
caa6732e 7;;; Copyright © 2014, 2015 Alex Kost <alezost@gmail.com>
88981dd3 8;;; Copyright © 2015 David Thompson <davet@gnu.org>
1cd4027c 9;;; Copyright © 2015 Mathieu Lirzin <mthl@openmailbox.org>
073c34d7 10;;;
233e7676 11;;; This file is part of GNU Guix.
073c34d7 12;;;
233e7676 13;;; GNU Guix is free software; you can redistribute it and/or modify it
073c34d7
LC
14;;; under the terms of the GNU General Public License as published by
15;;; the Free Software Foundation; either version 3 of the License, or (at
16;;; your option) any later version.
17;;;
233e7676 18;;; GNU Guix is distributed in the hope that it will be useful, but
073c34d7
LC
19;;; WITHOUT ANY WARRANTY; without even the implied warranty of
20;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21;;; GNU General Public License for more details.
22;;;
23;;; You should have received a copy of the GNU General Public License
233e7676 24;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
073c34d7
LC
25
26(define-module (guix ui)
27 #:use-module (guix utils)
28 #:use-module (guix store)
cdd5d6f9 29 #:use-module (guix config)
073c34d7 30 #:use-module (guix packages)
5d7a8584 31 #:use-module (guix profiles)
9bb2b96a 32 #:use-module (guix derivations)
b7071bc5
LC
33 #:use-module (guix build-system)
34 #:use-module (guix serialization)
59758816 35 #:use-module ((guix build utils) #:select (mkdir-p))
299112d3 36 #:use-module ((guix licenses) #:select (license? license-name))
f535dcbe 37 #:use-module (gnu system file-systems)
299112d3
LC
38 #:use-module (srfi srfi-1)
39 #:use-module (srfi srfi-11)
2cd09108 40 #:use-module (srfi srfi-19)
073c34d7 41 #:use-module (srfi srfi-26)
2abcc97f 42 #:use-module (srfi srfi-31)
073c34d7 43 #:use-module (srfi srfi-34)
c1d52c71 44 #:use-module (srfi srfi-35)
e31ff8b8 45 #:autoload (ice-9 ftw) (scandir)
64fc89b6 46 #:use-module (ice-9 match)
9bb2b96a 47 #:use-module (ice-9 format)
2cd09108 48 #:use-module (ice-9 regex)
db030303
LC
49 #:autoload (system repl repl) (start-repl)
50 #:autoload (system repl debug) (make-debug stack->vector)
1cd4027c
ML
51 #:use-module (texinfo)
52 #:use-module (texinfo plain-text)
53 #:use-module (texinfo string-utils)
073c34d7
LC
54 #:export (_
55 N_
ee764179 56 P_
70e629f5 57 report-error
073c34d7 58 leave
7ea1432e
DT
59 make-user-module
60 load*
4ae7559f 61 warn-about-load-error
cdd5d6f9 62 show-version-and-exit
3441e164 63 show-bug-report-information
969e678e 64 string->number*
1d6243cf 65 size->number
fa394eb9 66 show-derivation-outputs
9bb2b96a 67 show-what-to-build
4d043ab6 68 show-what-to-build*
5d7a8584 69 show-manifest-transaction
073c34d7 70 call-with-error-handling
64fc89b6 71 with-error-handling
df36e629 72 leave-on-EPIPE
ac5de156 73 read/eval
eb0880e7 74 read/eval-package-expression
299112d3 75 location->string
c61b026e 76 switch-symlinks
f651b477 77 config-directory
299112d3 78 fill-paragraph
2748ee3b 79 texi->plain-text
1cd4027c 80 package-description-string
299112d3 81 string->recutils
e49951eb 82 package->recutils
2876b989 83 package-specification->name+version+output
f535dcbe 84 specification->file-system-mapping
2cd09108
NK
85 string->generations
86 string->duration
e49951eb 87 run-guix-command
caa6732e 88 run-guix
a2011be5
LC
89 program-name
90 guix-warning-port
91 warning
e49951eb 92 guix-main))
073c34d7
LC
93
94;;; Commentary:
95;;;
96;;; User interface facilities for command-line tools.
97;;;
98;;; Code:
99
100(define %gettext-domain
ee764179 101 ;; Text domain for strings used in the tools.
073c34d7
LC
102 "guix")
103
ee764179
LC
104(define %package-text-domain
105 ;; Text domain for package synopses and descriptions.
106 "guix-packages")
107
073c34d7
LC
108(define _ (cut gettext <> %gettext-domain))
109(define N_ (cut ngettext <> <> <> %gettext-domain))
a5c0d8bc
LC
110
111(define (P_ msgid)
112 "Return the translation of the package description or synopsis MSGID."
113 ;; Descriptions/synopses might occasionally be empty strings, even if that
114 ;; is something we try to avoid. Since (gettext "") can return a non-empty
115 ;; string, explicitly check for that case.
116 (if (string-null? msgid)
117 msgid
118 (gettext msgid %package-text-domain)))
073c34d7 119
b2a886f6
LC
120(define-syntax-rule (define-diagnostic name prefix)
121 "Create a diagnostic macro (i.e., NAME), which will prepend PREFIX to all
122messages."
123 (define-syntax name
124 (lambda (x)
125 (define (augmented-format-string fmt)
126 (string-append "~:[~*~;guix ~a: ~]~a" (syntax->datum fmt)))
127
89d02b98
LC
128 (syntax-case x ()
129 ((name (underscore fmt) args (... ...))
130 (and (string? (syntax->datum #'fmt))
131 (free-identifier=? #'underscore #'_))
b2a886f6
LC
132 (with-syntax ((fmt* (augmented-format-string #'fmt))
133 (prefix (datum->syntax x prefix)))
134 #'(format (guix-warning-port) (gettext fmt*)
135 (program-name) (program-name) prefix
136 args (... ...))))
89d02b98 137 ((name (N-underscore singular plural n) args (... ...))
b2a886f6 138 (and (string? (syntax->datum #'singular))
89d02b98
LC
139 (string? (syntax->datum #'plural))
140 (free-identifier=? #'N-underscore #'N_))
b2a886f6
LC
141 (with-syntax ((s (augmented-format-string #'singular))
142 (p (augmented-format-string #'plural))
143 (prefix (datum->syntax x prefix)))
144 #'(format (guix-warning-port)
145 (ngettext s p n %gettext-domain)
146 (program-name) (program-name) prefix
147 args (... ...))))))))
148
149(define-diagnostic warning "warning: ") ; emit a warning
150
151(define-diagnostic report-error "error: ")
152(define-syntax-rule (leave args ...)
153 "Emit an error message and exit."
154 (begin
155 (report-error args ...)
156 (exit 1)))
157
7ea1432e
DT
158(define (make-user-module modules)
159 "Return a new user module with the additional MODULES loaded."
160 ;; Module in which the machine description file is loaded.
161 (let ((module (make-fresh-user-module)))
162 (for-each (lambda (iface)
163 (module-use! module (resolve-interface iface)))
164 modules)
165 module))
166
db030303
LC
167(define* (load* file user-module
168 #:key (on-error 'nothing-special))
7ea1432e 169 "Load the user provided Scheme source code FILE."
2abcc97f
LC
170 (define (frame-with-source frame)
171 ;; Walk from FRAME upwards until source location information is found.
172 (let loop ((frame frame)
173 (previous frame))
174 (if (not frame)
175 previous
176 (if (frame-source frame)
177 frame
178 (loop (frame-previous frame) frame)))))
179
db030303
LC
180 (define (error-string frame args)
181 (call-with-output-string
182 (lambda (port)
183 (apply display-error frame port (cdr args)))))
184
185 (define tag
186 (make-prompt-tag "user-code"))
187
7ea1432e
DT
188 (catch #t
189 (lambda ()
2abcc97f 190 ;; XXX: Force a recompilation to avoid ABI issues.
7ea1432e 191 (set! %fresh-auto-compile #t)
2abcc97f 192 (set! %load-should-auto-compile #t)
7ea1432e
DT
193
194 (save-module-excursion
195 (lambda ()
196 (set-current-module user-module)
7ea1432e 197
2abcc97f
LC
198 ;; Hide the "auto-compiling" messages.
199 (parameterize ((current-warning-port (%make-void-port "w")))
db030303
LC
200 (call-with-prompt tag
201 (lambda ()
202 ;; Give 'load' an absolute file name so that it doesn't try to
203 ;; search for FILE in %LOAD-PATH. Note: use 'load', not
204 ;; 'primitive-load', so that FILE is compiled, which then allows us
205 ;; to provide better error reporting with source line numbers.
206 (load (canonicalize-path file)))
207 (const #f))))))
2abcc97f
LC
208 (lambda _
209 ;; XXX: Errors are reported from the pre-unwind handler below, but
210 ;; calling 'exit' from there has no effect, so we call it here.
211 (exit 1))
212 (rec (handle-error . args)
213 ;; Capture the stack up to this procedure call, excluded, and pass
214 ;; the faulty stack frame to 'report-load-error'.
db030303 215 (let* ((stack (make-stack #t handle-error tag))
2abcc97f
LC
216 (depth (stack-length stack))
217 (last (and (> depth 0) (stack-ref stack 0)))
218 (frame (frame-with-source
219 (if (> depth 1)
220 (stack-ref stack 1) ;skip the 'throw' frame
221 last))))
db030303
LC
222
223 (report-load-error file args frame)
224
225 (case on-error
226 ((debug)
227 (newline)
228 (display (_ "entering debugger; type ',bt' for a backtrace\n"))
229 (start-repl #:debug (make-debug (stack->vector stack) 0
230 (error-string frame args)
231 #f)))
232 ((backtrace)
233 (newline (current-error-port))
234 (display-backtrace stack (current-error-port)))
235 (else
236 #t))))))
2abcc97f
LC
237
238(define* (report-load-error file args #:optional frame)
db030303 239 "Report the failure to load FILE, a user-provided Scheme file.
1151f6ae
LC
240ARGS is the list of arguments received by the 'throw' handler."
241 (match args
242 (('system-error . _)
243 (let ((err (system-error-errno args)))
db030303 244 (report-error (_ "failed to load '~a': ~a~%") file (strerror err))))
1151f6ae
LC
245 (('syntax-error proc message properties form . rest)
246 (let ((loc (source-properties->location properties)))
247 (format (current-error-port) (_ "~a: error: ~a~%")
db030303 248 (location->string loc) message)))
23185cea
LC
249 (('srfi-34 obj)
250 (report-error (_ "exception thrown: ~s~%") obj))
1151f6ae
LC
251 ((error args ...)
252 (report-error (_ "failed to load '~a':~%") file)
db030303 253 (apply display-error frame (current-error-port) args))))
1151f6ae 254
4ae7559f
LC
255(define (warn-about-load-error file args) ;FIXME: factorize with ↑
256 "Report the failure to load FILE, a user-provided Scheme file, without
257exiting. ARGS is the list of arguments received by the 'throw' handler."
258 (match args
259 (('system-error . _)
260 (let ((err (system-error-errno args)))
261 (warning (_ "failed to load '~a': ~a~%") file (strerror err))))
262 (('syntax-error proc message properties form . rest)
263 (let ((loc (source-properties->location properties)))
264 (format (current-error-port) (_ "~a: warning: ~a~%")
265 (location->string loc) message)))
23185cea
LC
266 (('srfi-34 obj)
267 (warning (_ "failed to load '~a': exception thrown: ~s~%")
268 file obj))
4ae7559f
LC
269 ((error args ...)
270 (warning (_ "failed to load '~a':~%") file)
271 (apply display-error #f (current-error-port) args))))
272
b2a886f6
LC
273(define (install-locale)
274 "Install the current locale settings."
275 (catch 'system-error
276 (lambda _
277 (setlocale LC_ALL ""))
278 (lambda args
279 (warning (_ "failed to install locale: ~a~%")
280 (strerror (system-error-errno args))))))
281
e49951eb 282(define (initialize-guix)
633f045f 283 "Perform the usual initialization for stand-alone Guix commands."
e49951eb 284 (install-locale)
39e9f95d 285 (textdomain %gettext-domain)
e14c3929
LC
286
287 ;; Ignore SIGPIPE. If the daemon closes the connection, we prefer to be
288 ;; notified via an EPIPE later.
289 (sigaction SIGPIPE SIG_IGN)
290
e49951eb
MW
291 (setvbuf (current-output-port) _IOLBF)
292 (setvbuf (current-error-port) _IOLBF))
293
cdd5d6f9
LC
294(define* (show-version-and-exit #:optional (command (car (command-line))))
295 "Display version information for COMMAND and `(exit 0)'."
296 (simple-format #t "~a (~a) ~a~%"
297 command %guix-package-name %guix-version)
9250b304 298 (display (_ "Copyright (C) 2015 the Guix authors
64a967cc
LC
299License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
300This is free software: you are free to change and redistribute it.
301There is NO WARRANTY, to the extent permitted by law.
302"))
cdd5d6f9
LC
303 (exit 0))
304
3441e164
LC
305(define (show-bug-report-information)
306 (format #t (_ "
307Report bugs to: ~a.") %guix-bug-report-address)
308 (format #t (_ "
309~a home page: <~a>") %guix-package-name %guix-home-page-url)
310 (display (_ "
311General help using GNU software: <http://www.gnu.org/gethelp/>"))
312 (newline))
313
7522a016
LC
314(set! symlink
315 ;; We 'set!' the global binding because (gnu build ...) modules and similar
316 ;; typically don't use (guix ui).
44fd6ef1
LC
317 (let ((real-symlink (@ (guile) symlink)))
318 (lambda (target link)
319 "This is a 'symlink' replacement that provides proper error reporting."
320 (catch 'system-error
321 (lambda ()
322 (real-symlink target link))
323 (lambda (key proc fmt args errno)
324 ;; Augment the FMT and ARGS with information about LINK (this
325 ;; information is missing as of Guile 2.0.11, making the exception
326 ;; uninformative.)
327 (apply throw key proc "~A: ~S"
6ec1f4ca
LC
328 (list (strerror (car errno)) link)
329 (list errno)))))))
44fd6ef1 330
9b14107f
LC
331(set! copy-file
332 ;; Note: here we use 'set!', not #:replace, because UIs typically use
333 ;; 'copy-recursively', which doesn't use (guix ui).
334 (let ((real-copy-file (@ (guile) copy-file)))
335 (lambda (source target)
336 "This is a 'copy-file' replacement that provides proper error reporting."
337 (catch 'system-error
338 (lambda ()
339 (real-copy-file source target))
340 (lambda (key proc fmt args errno)
341 ;; Augment the FMT and ARGS with information about TARGET (this
342 ;; information is missing as of Guile 2.0.11, making the exception
343 ;; uninformative.)
344 (apply throw key proc "~A: ~S"
345 (list (strerror (car errno)) target)
346 (list errno)))))))
347
969e678e
LC
348(define (string->number* str)
349 "Like `string->number', but error out with an error message on failure."
350 (or (string->number str)
351 (leave (_ "~a: invalid number~%") str)))
352
1d6243cf
LC
353(define (size->number str)
354 "Convert STR, a storage measurement representation such as \"1024\" or
355\"1MiB\", to a number of bytes. Raise an error if STR could not be
356interpreted."
357 (define unit-pos
358 (string-rindex str char-set:digit))
359
360 (define unit
361 (and unit-pos (substring str (+ 1 unit-pos))))
362
363 (let* ((numstr (if unit-pos
364 (substring str 0 (+ 1 unit-pos))
365 str))
366 (num (string->number numstr)))
367 (unless num
368 (leave (_ "invalid number: ~a~%") numstr))
369
370 ((compose inexact->exact round)
371 (* num
372 (match unit
4a44d7bb
LC
373 ((or "KiB" "K" "k") (expt 2 10))
374 ((or "MiB" "M") (expt 2 20))
375 ((or "GiB" "G") (expt 2 30))
376 ((or "TiB" "T") (expt 2 40))
377 ((or "PiB" "P") (expt 2 50))
378 ((or "EiB" "E") (expt 2 60))
379 ((or "ZiB" "Z") (expt 2 70))
380 ((or "YiB" "Y") (expt 2 80))
381 ("kB" (expt 10 3))
1d6243cf
LC
382 ("MB" (expt 10 6))
383 ("GB" (expt 10 9))
384 ("TB" (expt 10 12))
4a44d7bb
LC
385 ("PB" (expt 10 15))
386 ("EB" (expt 10 18))
387 ("ZB" (expt 10 21))
388 ("YB" (expt 10 24))
1d6243cf
LC
389 ("" 1)
390 (_
391 (leave (_ "unknown unit: ~a~%") unit)))))))
392
073c34d7
LC
393(define (call-with-error-handling thunk)
394 "Call THUNK within a user-friendly error handler."
395 (guard (c ((package-input-error? c)
396 (let* ((package (package-error-package c))
397 (input (package-error-invalid-input c))
398 (location (package-location package))
399 (file (location-file location))
400 (line (location-line location))
401 (column (location-column location)))
98eb8cbe 402 (leave (_ "~a:~a:~a: package `~a' has an invalid input: ~s~%")
073c34d7
LC
403 file line column
404 (package-full-name package) input)))
9b222abe
LC
405 ((package-cross-build-system-error? c)
406 (let* ((package (package-error-package c))
407 (loc (package-location package))
408 (system (package-build-system package)))
409 (leave (_ "~a: ~a: build system `~a' does not support cross builds~%")
410 (location->string loc)
411 (package-full-name package)
412 (build-system-name system))))
c0c018f1
AK
413 ((profile-not-found-error? c)
414 (leave (_ "profile '~a' does not exist~%")
415 (profile-error-profile c)))
416 ((missing-generation-error? c)
417 (leave (_ "generation ~a of profile '~a' does not exist~%")
418 (missing-generation-error-generation c)
419 (profile-error-profile c)))
b7071bc5
LC
420 ((nar-error? c)
421 (let ((file (nar-error-file c))
422 (port (nar-error-port c)))
423 (if file
424 (leave (_ "corrupt input while restoring '~a' from ~s~%")
425 file (or (port-filename port) port))
426 (leave (_ "corrupt input while restoring archive from ~s~%")
427 (or (port-filename port) port)))))
ef86c39f 428 ((nix-connection-error? c)
98eb8cbe 429 (leave (_ "failed to connect to `~a': ~a~%")
ef86c39f
LC
430 (nix-connection-error-file c)
431 (strerror (nix-connection-error-code c))))
073c34d7
LC
432 ((nix-protocol-error? c)
433 ;; FIXME: Server-provided error messages aren't i18n'd.
98eb8cbe 434 (leave (_ "build failed: ~a~%")
c1d52c71 435 (nix-protocol-error-message c)))
f304c9c2
LC
436 ((derivation-missing-output-error? c)
437 (leave (_ "reference to invalid output '~a' of derivation '~a'~%")
438 (derivation-missing-output c)
439 (derivation-file-name (derivation-error-derivation c))))
c1d52c71
LC
440 ((message-condition? c)
441 ;; Normally '&message' error conditions have an i18n'd message.
12703d08
LC
442 (leave (_ "~a~%")
443 (gettext (condition-message c) %gettext-domain))))
e14c3929
LC
444 ;; Catch EPIPE and the likes.
445 (catch 'system-error
446 thunk
bde8c0e6
LC
447 (lambda (key proc format-string format-args . rest)
448 (leave (_ "~a: ~a~%") proc
449 (apply format #f format-string format-args))))))
073c34d7 450
df36e629
LC
451(define-syntax-rule (leave-on-EPIPE exp ...)
452 "Run EXP... in a context when EPIPE errors are caught and lead to 'exit'
453with successful exit code. This is useful when writing to the standard output
454may lead to EPIPE, because the standard output is piped through 'head' or
455similar."
456 (catch 'system-error
457 (lambda ()
458 exp ...)
459 (lambda args
460 ;; We really have to exit this brutally, otherwise Guile eventually
461 ;; attempts to flush all the ports, leading to an uncaught EPIPE down
462 ;; the path.
463 (if (= EPIPE (system-error-errno args))
464 (primitive-_exit 0)
465 (apply throw args)))))
466
56b82106
LC
467(define %guix-user-module
468 ;; Module in which user expressions are evaluated.
07254feb
LC
469 ;; Compute lazily to avoid circularity with (guix gexp).
470 (delay
471 (let ((module (make-module)))
472 (beautify-user-module! module)
473 ;; Use (guix gexp) so that one can use #~ & co.
474 (module-use! module (resolve-interface '(guix gexp)))
475 module)))
56b82106 476
ac5de156
LC
477(define (read/eval str)
478 "Read and evaluate STR, raising an error if something goes wrong."
eb0880e7
LC
479 (let ((exp (catch #t
480 (lambda ()
481 (call-with-input-string str read))
482 (lambda args
483 (leave (_ "failed to read expression ~s: ~s~%")
484 str args)))))
ac5de156
LC
485 (catch #t
486 (lambda ()
07254feb 487 (eval exp (force %guix-user-module)))
ac5de156 488 (lambda args
41766807
LC
489 (report-error (_ "failed to evaluate expression '~a':~%") exp)
490 (match args
491 (('syntax-error proc message properties form . rest)
492 (report-error (_ "syntax error: ~a~%") message))
23185cea
LC
493 (('srfi-34 obj)
494 (report-error (_ "exception thrown: ~s~%") obj))
41766807
LC
495 ((error args ...)
496 (apply display-error #f (current-error-port) args))
497 (what? #f))
498 (exit 1)))))
ac5de156
LC
499
500(define (read/eval-package-expression str)
501 "Read and evaluate STR and return the package it refers to, or exit an
502error."
503 (match (read/eval str)
504 ((? package? p) p)
505 (_
506 (leave (_ "expression ~s does not evaluate to a package~%")
507 str))))
eb0880e7 508
fa394eb9
AK
509(define (show-derivation-outputs derivation)
510 "Show the output file names of DERIVATION."
511 (format #t "~{~a~%~}"
512 (map (match-lambda
513 ((out-name . out)
514 (derivation->output-path derivation out-name)))
515 (derivation-outputs derivation))))
516
dd36b51b
LC
517(define* (show-what-to-build store drv
518 #:key dry-run? (use-substitutes? #t))
9bb2b96a 519 "Show what will or would (depending on DRY-RUN?) be built in realizing the
4d60610a 520derivations listed in DRV. Return #t if there's something to build, #f
dd36b51b
LC
521otherwise. When USE-SUBSTITUTES?, check and report what is prerequisites are
522available for download."
e9651e39
LC
523 (define substitutable?
524 ;; Call 'substitutation-oracle' upfront so we don't end up launching the
525 ;; substituter many times. This makes a big difference, especially when
526 ;; DRV is a long list as is the case with 'guix environment'.
527 (if use-substitutes?
528 (substitution-oracle store drv)
529 (const #f)))
530
52ddf2ae 531 (define (built-or-substitutable? drv)
f304c9c2
LC
532 (or (null? (derivation-outputs drv))
533 (let ((out (derivation->output-path drv))) ;XXX: assume "out" exists
52ddf2ae 534 (or (valid-path? store out)
e9651e39 535 (substitutable? out)))))
52ddf2ae 536
dd36b51b 537 (let*-values (((build download)
59688fc4
LC
538 (fold2 (lambda (drv build download)
539 (let-values (((b d)
540 (derivation-prerequisites-to-build
541 store drv
e9651e39 542 #:substitutable? substitutable?)))
59688fc4
LC
543 (values (append b build)
544 (append d download))))
dd36b51b
LC
545 '() '()
546 drv))
547 ((build) ; add the DRV themselves
548 (delete-duplicates
59688fc4 549 (append (map derivation-file-name
52ddf2ae 550 (remove built-or-substitutable? drv))
dd36b51b
LC
551 (map derivation-input-path build))))
552 ((download) ; add the references of DOWNLOAD
1a8b7834
LC
553 (if use-substitutes?
554 (delete-duplicates
555 (append download
556 (remove (cut valid-path? store <>)
557 (append-map
558 substitutable-references
559 (substitutable-path-info store
560 download)))))
561 download)))
00554b2a 562 ;; TODO: Show the installed size of DOWNLOAD.
9bb2b96a 563 (if dry-run?
dd36b51b
LC
564 (begin
565 (format (current-error-port)
83e61a73
LC
566 (N_ "~:[The following derivation would be built:~%~{ ~a~%~}~;~]"
567 "~:[The following derivations would be built:~%~{ ~a~%~}~;~]"
dd36b51b
LC
568 (length build))
569 (null? build) build)
570 (format (current-error-port)
83e61a73
LC
571 (N_ "~:[The following file would be downloaded:~%~{ ~a~%~}~;~]"
572 "~:[The following files would be downloaded:~%~{ ~a~%~}~;~]"
dd36b51b
LC
573 (length download))
574 (null? download) download))
575 (begin
576 (format (current-error-port)
83e61a73
LC
577 (N_ "~:[The following derivation will be built:~%~{ ~a~%~}~;~]"
578 "~:[The following derivations will be built:~%~{ ~a~%~}~;~]"
dd36b51b
LC
579 (length build))
580 (null? build) build)
581 (format (current-error-port)
83e61a73
LC
582 (N_ "~:[The following file will be downloaded:~%~{ ~a~%~}~;~]"
583 "~:[The following files will be downloaded:~%~{ ~a~%~}~;~]"
dd36b51b
LC
584 (length download))
585 (null? download) download)))
586 (pair? build)))
9bb2b96a 587
4d043ab6
DT
588(define show-what-to-build*
589 (store-lift show-what-to-build))
590
5d7a8584
AK
591(define (right-arrow port)
592 "Return either a string containing the 'RIGHT ARROW' character, or an ASCII
593replacement if PORT is not Unicode-capable."
594 (with-fluids ((%default-port-encoding (port-encoding port)))
595 (let ((arrow "→"))
596 (catch 'encoding-error
597 (lambda ()
598 (call-with-output-string
599 (lambda (port)
600 (set-port-conversion-strategy! port 'error)
601 (display arrow port))))
602 (lambda (key . args)
603 "->")))))
604
605(define* (show-manifest-transaction store manifest transaction
606 #:key dry-run?)
607 "Display what will/would be installed/removed from MANIFEST by TRANSACTION."
608 (define (package-strings name version output item)
609 (map (lambda (name version output item)
610 (format #f " ~a~:[:~a~;~*~]\t~a\t~a"
611 name
612 (equal? output "out") output version
613 (if (package? item)
614 (package-output store item output)
615 item)))
616 name version output item))
617
618 (define → ;an arrow that can be represented on stderr
619 (right-arrow (current-error-port)))
620
621 (define (upgrade-string name old-version new-version output item)
622 (format #f " ~a~:[:~a~;~*~]\t~a ~a ~a\t~a"
623 name (equal? output "out") output
624 old-version → new-version
625 (if (package? item)
626 (package-output store item output)
627 item)))
628
46b23e1a 629 (let-values (((remove install upgrade downgrade)
5d7a8584
AK
630 (manifest-transaction-effects manifest transaction)))
631 (match remove
632 ((($ <manifest-entry> name version output item) ..1)
633 (let ((len (length name))
634 (remove (package-strings name version output item)))
635 (if dry-run?
636 (format (current-error-port)
637 (N_ "The following package would be removed:~%~{~a~%~}~%"
638 "The following packages would be removed:~%~{~a~%~}~%"
639 len)
640 remove)
641 (format (current-error-port)
642 (N_ "The following package will be removed:~%~{~a~%~}~%"
643 "The following packages will be removed:~%~{~a~%~}~%"
644 len)
645 remove))))
646 (_ #f))
46b23e1a
LC
647 (match downgrade
648 (((($ <manifest-entry> name old-version)
649 . ($ <manifest-entry> _ new-version output item)) ..1)
650 (let ((len (length name))
651 (downgrade (map upgrade-string
652 name old-version new-version output item)))
653 (if dry-run?
654 (format (current-error-port)
655 (N_ "The following package would be downgraded:~%~{~a~%~}~%"
656 "The following packages would be downgraded:~%~{~a~%~}~%"
657 len)
658 downgrade)
659 (format (current-error-port)
660 (N_ "The following package will be downgraded:~%~{~a~%~}~%"
661 "The following packages will be downgraded:~%~{~a~%~}~%"
662 len)
663 downgrade))))
664 (_ #f))
5d7a8584
AK
665 (match upgrade
666 (((($ <manifest-entry> name old-version)
667 . ($ <manifest-entry> _ new-version output item)) ..1)
668 (let ((len (length name))
669 (upgrade (map upgrade-string
670 name old-version new-version output item)))
671 (if dry-run?
672 (format (current-error-port)
673 (N_ "The following package would be upgraded:~%~{~a~%~}~%"
674 "The following packages would be upgraded:~%~{~a~%~}~%"
675 len)
676 upgrade)
677 (format (current-error-port)
678 (N_ "The following package will be upgraded:~%~{~a~%~}~%"
679 "The following packages will be upgraded:~%~{~a~%~}~%"
680 len)
681 upgrade))))
682 (_ #f))
683 (match install
684 ((($ <manifest-entry> name version output item _) ..1)
685 (let ((len (length name))
686 (install (package-strings name version output item)))
687 (if dry-run?
688 (format (current-error-port)
689 (N_ "The following package would be installed:~%~{~a~%~}~%"
690 "The following packages would be installed:~%~{~a~%~}~%"
691 len)
692 install)
693 (format (current-error-port)
694 (N_ "The following package will be installed:~%~{~a~%~}~%"
695 "The following packages will be installed:~%~{~a~%~}~%"
696 len)
697 install))))
698 (_ #f))))
699
073c34d7
LC
700(define-syntax with-error-handling
701 (syntax-rules ()
702 "Run BODY within a user-friendly error condition handler."
703 ((_ body ...)
704 (call-with-error-handling
705 (lambda ()
706 body ...)))))
707
64fc89b6
LC
708(define (location->string loc)
709 "Return a human-friendly, GNU-standard representation of LOC."
710 (match loc
711 (#f (_ "<unknown location>"))
712 (($ <location> file line column)
713 (format #f "~a:~a:~a" file line column))))
714
c61b026e
LC
715(define (switch-symlinks link target)
716 "Atomically switch LINK, a symbolic link, to point to TARGET. Works
717both when LINK already exists and when it does not."
718 (let ((pivot (string-append link ".new")))
719 (symlink target pivot)
720 (rename-file pivot link)))
721
f651b477
LC
722(define (config-directory)
723 "Return the name of the configuration directory, after making sure that it
724exists. Honor the XDG specs,
725<http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html>."
726 (let ((dir (and=> (or (getenv "XDG_CONFIG_HOME")
727 (and=> (getenv "HOME")
728 (cut string-append <> "/.config")))
729 (cut string-append <> "/guix"))))
730 (catch 'system-error
731 (lambda ()
59758816 732 (mkdir-p dir)
f651b477
LC
733 dir)
734 (lambda args
59758816
LC
735 (let ((err (system-error-errno args)))
736 ;; ERR is necessarily different from EEXIST.
737 (leave (_ "failed to create configuration directory `~a': ~a~%")
738 dir (strerror err)))))))
f651b477 739
299112d3
LC
740(define* (fill-paragraph str width #:optional (column 0))
741 "Fill STR such that each line contains at most WIDTH characters, assuming
742that the first character is at COLUMN.
743
744When STR contains a single line break surrounded by other characters, it is
745converted to a space; sequences of more than one line break are preserved."
746 (define (maybe-break chr result)
747 (match result
748 ((column newlines chars)
749 (case chr
750 ((#\newline)
751 `(,column ,(+ 1 newlines) ,chars))
752 (else
3a09e1d2
CS
753 (let* ((spaces (if (and (pair? chars) (eqv? (car chars) #\.)) 2 1))
754 (chars (case newlines
755 ((0) chars)
756 ((1)
757 (append (make-list spaces #\space) chars))
758 (else
759 (append (make-list newlines #\newline) chars))))
760 (column (case newlines
761 ((0) column)
762 ((1) (+ spaces column))
763 (else 0))))
299112d3
LC
764 (let ((chars (cons chr chars))
765 (column (+ 1 column)))
766 (if (> column width)
767 (let*-values (((before after)
768 (break (cut eqv? #\space <>) chars))
769 ((len)
770 (length before)))
771 (if (<= len width)
772 `(,len
773 0
774 ,(if (null? after)
775 before
3a09e1d2
CS
776 (append before
777 (cons #\newline
778 (drop-while (cut eqv? #\space <>)
779 after)))))
299112d3
LC
780 `(,column 0 ,chars))) ; unbreakable
781 `(,column 0 ,chars)))))))))
782
783 (match (string-fold maybe-break
784 `(,column 0 ())
785 str)
786 ((_ _ chars)
787 (list->string (reverse chars)))))
788
2876b989
LC
789\f
790;;;
791;;; Packages.
792;;;
793
1cd4027c
ML
794(define %text-width
795 (make-parameter (or (and=> (getenv "WIDTH") string->number)
796 80)))
797
798(set! (@@ (texinfo plain-text) wrap*)
799 ;; XXX: Monkey patch this private procedure to let 'package->recutils'
800 ;; parameterize the fill of description field correctly.
801 (lambda strings
802 (let ((indent (fluid-ref (@@ (texinfo plain-text) *indent*))))
803 (fill-string (string-concatenate strings)
804 #:line-width (%text-width) #:initial-indent indent
805 #:subsequent-indent indent))))
806
807(define (texi->plain-text str)
808 "Return a plain-text representation of texinfo fragment STR."
08d7e359
LC
809 ;; 'texi-fragment->stexi' uses a string port so make sure it's a
810 ;; Unicode-capable one (see <http://bugs.gnu.org/11197>.)
811 (with-fluids ((%default-port-encoding "UTF-8"))
812 (stexi->plain-text (texi-fragment->stexi str))))
1cd4027c
ML
813
814(define (package-description-string package)
815 "Return a plain-text representation of PACKAGE description field."
816 (and=> (package-description package)
817 (compose texi->plain-text P_)))
818
299112d3
LC
819(define (string->recutils str)
820 "Return a version of STR where newlines have been replaced by newlines
821followed by \"+ \", which makes for a valid multi-line field value in the
822`recutils' syntax."
823 (list->string
824 (string-fold-right (lambda (chr result)
825 (if (eqv? chr #\newline)
826 (cons* chr #\+ #\space result)
827 (cons chr result)))
828 '()
829 str)))
830
1cd4027c 831(define* (package->recutils p port #:optional (width (%text-width)))
299112d3
LC
832 "Write to PORT a `recutils' record of package P, arranging to fit within
833WIDTH columns."
20ffce82
LC
834 (define (dependencies->recutils packages)
835 (let ((list (string-join (map package-full-name
836 (sort packages package<?)) " ")))
837 (string->recutils
838 (fill-paragraph list width
839 (string-length "dependencies: ")))))
840
9c0fc279
CR
841 (define (package<? p1 p2)
842 (string<? (package-full-name p1) (package-full-name p2)))
843
299112d3
LC
844 ;; Note: Don't i18n field names so that people can post-process it.
845 (format port "name: ~a~%" (package-name p))
846 (format port "version: ~a~%" (package-version p))
6bf99bac 847 (format port "outputs: ~a~%" (string-join (package-outputs p)))
5763ad92
LC
848 (format port "systems: ~a~%"
849 (string-join (package-transitive-supported-systems p)))
9c0fc279
CR
850 (format port "dependencies: ~a~%"
851 (match (package-direct-inputs p)
5e6feee6
EB
852 (((labels inputs . _) ...)
853 (dependencies->recutils (filter package? inputs)))))
299112d3
LC
854 (format port "location: ~a~%"
855 (or (and=> (package-location p) location->string)
856 (_ "unknown")))
8fa3e6b3
LC
857
858 ;; Note: Starting from version 1.6 or recutils, hyphens are not allowed in
859 ;; field identifiers.
860 (format port "homepage: ~a~%" (package-home-page p))
861
299112d3
LC
862 (format port "license: ~a~%"
863 (match (package-license p)
864 (((? license? licenses) ...)
865 (string-join (map license-name licenses)
866 ", "))
867 ((? license? license)
868 (license-name license))
869 (x
870 (_ "unknown"))))
871 (format port "synopsis: ~a~%"
872 (string-map (match-lambda
873 (#\newline #\space)
874 (chr chr))
ee764179 875 (or (and=> (package-synopsis p) P_)
299112d3 876 "")))
1cd4027c
ML
877 (format port "~a~2%"
878 (string->recutils
879 (string-trim-right
880 (parameterize ((%text-width width))
881 (texi->plain-text
882 (string-append "description: "
883 (or (and=> (package-description p) P_)
884 ""))))
885 #\newline))))
299112d3 886
2cd09108
NK
887(define (string->generations str)
888 "Return the list of generations matching a pattern in STR. This function
889accepts the following patterns: \"1\", \"1,2,3\", \"1..9\", \"1..\", \"..9\"."
890 (define (maybe-integer)
891 (let ((x (string->number str)))
892 (and (integer? x)
893 x)))
894
895 (define (maybe-comma-separated-integers)
896 (let ((lst (delete-duplicates
897 (map string->number
898 (string-split str #\,)))))
899 (and (every integer? lst)
900 lst)))
901
902 (cond ((maybe-integer)
903 =>
904 list)
905 ((maybe-comma-separated-integers)
906 =>
907 identity)
908 ((string-match "^([0-9]+)\\.\\.([0-9]+)$" str)
909 =>
910 (lambda (match)
911 (let ((s (string->number (match:substring match 1)))
912 (e (string->number (match:substring match 2))))
913 (and (every integer? (list s e))
914 (<= s e)
915 (iota (1+ (- e s)) s)))))
916 ((string-match "^([0-9]+)\\.\\.$" str)
917 =>
918 (lambda (match)
919 (let ((s (string->number (match:substring match 1))))
920 (and (integer? s)
921 `(>= ,s)))))
922 ((string-match "^\\.\\.([0-9]+)$" str)
923 =>
924 (lambda (match)
925 (let ((e (string->number (match:substring match 1))))
926 (and (integer? e)
927 `(<= ,e)))))
928 (else #f)))
929
930(define (string->duration str)
931 "Return the duration matching a pattern in STR. This function accepts the
932following patterns: \"1d\", \"1w\", \"1m\"."
933 (define (hours->duration hours match)
934 (make-time time-duration 0
935 (* 3600 hours (string->number (match:substring match 1)))))
936
937 (cond ((string-match "^([0-9]+)d$" str)
938 =>
939 (lambda (match)
940 (hours->duration 24 match)))
941 ((string-match "^([0-9]+)w$" str)
942 =>
943 (lambda (match)
944 (hours->duration (* 24 7) match)))
945 ((string-match "^([0-9]+)m$" str)
946 =>
947 (lambda (match)
948 (hours->duration (* 24 30) match)))
949 (else #f)))
950
2876b989
LC
951(define* (package-specification->name+version+output spec
952 #:optional (output "out"))
953 "Parse package specification SPEC and return three value: the specified
954package name, version number (or #f), and output name (or OUTPUT). SPEC may
955optionally contain a version number and an output name, as in these examples:
956
957 guile
958 guile-2.0.9
959 guile:debug
960 guile-2.0.9:debug
961"
962 (let*-values (((name sub-drv)
963 (match (string-rindex spec #\:)
964 (#f (values spec output))
965 (colon (values (substring spec 0 colon)
966 (substring spec (+ 1 colon))))))
967 ((name version)
968 (package-name->name+version name)))
969 (values name version sub-drv)))
970
f535dcbe
DT
971(define (specification->file-system-mapping spec writable?)
972 "Read the SPEC and return the corresponding <file-system-mapping>. SPEC is
973a string of the form \"SOURCE\" or \"SOURCE=TARGET\". The former specifies
974that SOURCE from the host should be mounted at SOURCE in the other system.
975The latter format specifies that SOURCE from the host should be mounted at
976TARGET in the other system."
977 (let ((index (string-index spec #\=)))
978 (if index
979 (file-system-mapping
980 (source (substring spec 0 index))
981 (target (substring spec (+ 1 index)))
982 (writable? writable?))
983 (file-system-mapping
984 (source spec)
985 (target spec)
986 (writable? writable?)))))
987
2876b989
LC
988\f
989;;;
990;;; Command-line option processing.
991;;;
992
e49951eb 993(define (show-guix-usage)
e49951eb 994 (format (current-error-port)
25c93676
LC
995 (_ "Try `guix --help' for more information.~%"))
996 (exit 1))
e49951eb 997
e31ff8b8
LC
998(define (command-files)
999 "Return the list of source files that define Guix sub-commands."
1000 (define directory
1001 (and=> (search-path %load-path "guix.scm")
1002 (compose (cut string-append <> "/guix/scripts")
1003 dirname)))
1004
2b8cf44f
LC
1005 (define dot-scm?
1006 (cut string-suffix? ".scm" <>))
1007
e31ff8b8 1008 (if directory
09d809db 1009 (scandir directory dot-scm?)
e31ff8b8
LC
1010 '()))
1011
1012(define (commands)
1013 "Return the list of Guix command names."
1014 (map (compose (cut string-drop-right <> 4)
1015 basename)
1016 (command-files)))
1017
1018(define (show-guix-help)
59f734f3 1019 (define (internal? command)
2c74fde0 1020 (member command '("substitute" "authenticate" "offload")))
59f734f3 1021
e31ff8b8
LC
1022 (format #t (_ "Usage: guix COMMAND ARGS...
1023Run COMMAND with ARGS.\n"))
1024 (newline)
1025 (format #t (_ "COMMAND must be one of the sub-commands listed below:\n"))
1026 (newline)
1027 ;; TODO: Display a synopsis of each command.
59f734f3
LC
1028 (format #t "~{ ~a~%~}" (sort (remove internal? (commands))
1029 string<?))
e31ff8b8
LC
1030 (show-bug-report-information))
1031
a2011be5
LC
1032(define program-name
1033 ;; Name of the command-line program currently executing, or #f.
1034 (make-parameter #f))
1035
ec5d0a85
LC
1036(define (run-guix-command command . args)
1037 "Run COMMAND with the given ARGS. Report an error when COMMAND is not
1038found."
1039 (define module
1040 (catch 'misc-error
1041 (lambda ()
1042 (resolve-interface `(guix scripts ,command)))
1043 (lambda -
25c93676
LC
1044 (format (current-error-port)
1045 (_ "guix: ~a: command not found~%") command)
1046 (show-guix-usage))))
ec5d0a85
LC
1047
1048 (let ((command-main (module-ref module
1049 (symbol-append 'guix- command))))
1050 (parameterize ((program-name command))
1051 (apply command-main args))))
1052
caa6732e
AK
1053(define (run-guix . args)
1054 "Run the 'guix' command defined by command line ARGS.
1055Unlike 'guix-main', this procedure assumes that locale, i18n support,
1056and signal handling has already been set up."
1057 (define option? (cut string-prefix? "-" <>))
1058
1059 (match args
1060 (()
1061 (format (current-error-port)
1062 (_ "guix: missing command name~%"))
1063 (show-guix-usage))
1064 ((or ("-h") ("--help"))
1065 (show-guix-help))
1066 (("--version")
1067 (show-version-and-exit "guix"))
1068 (((? option? o) args ...)
1069 (format (current-error-port)
1070 (_ "guix: unrecognized option '~a'~%") o)
1071 (show-guix-usage))
1072 (("help" args ...)
1073 (show-guix-help))
1074 ((command args ...)
1075 (apply run-guix-command
1076 (string->symbol command)
1077 args))))
1078
a2011be5
LC
1079(define guix-warning-port
1080 (make-parameter (current-warning-port)))
1081
e49951eb
MW
1082(define (guix-main arg0 . args)
1083 (initialize-guix)
caa6732e 1084 (apply run-guix args))
e49951eb 1085
073c34d7 1086;;; ui.scm ends here