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