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