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