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