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