ui: Add 'display-search-results' and use it.
[jackhill/guix/guix.git] / guix / ui.scm
1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Ludovic Courtès <ludo@gnu.org>
3 ;;; Copyright © 2013, 2018 Mark H Weaver <mhw@netris.org>
4 ;;; Copyright © 2013 Nikita Karetnikov <nikita@karetnikov.org>
5 ;;; Copyright © 2014 Cyril Roelandt <tipecaml@gmail.com>
6 ;;; Copyright © 2014 Cyrill Schenkel <cyrill.schenkel@gmail.com>
7 ;;; Copyright © 2014, 2015, 2017 Alex Kost <alezost@gmail.com>
8 ;;; Copyright © 2015 David Thompson <davet@gnu.org>
9 ;;; Copyright © 2015, 2016 Mathieu Lirzin <mthl@gnu.org>
10 ;;; Copyright © 2016 Roel Janssen <roel@gnu.org>
11 ;;; Copyright © 2016 Benz Schenk <benz.schenk@uzh.ch>
12 ;;; Copyright © 2018 Kyle Meyer <kyle@kyleam.com>
13 ;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net>
14 ;;; Copyright © 2019 Chris Marusich <cmmarusich@gmail.com>
15 ;;; Copyright © 2019 Tobias Geerinckx-Rice <me@tobias.gr>
16 ;;;
17 ;;; This file is part of GNU Guix.
18 ;;;
19 ;;; GNU Guix is free software; you can redistribute it and/or modify it
20 ;;; under the terms of the GNU General Public License as published by
21 ;;; the Free Software Foundation; either version 3 of the License, or (at
22 ;;; your option) any later version.
23 ;;;
24 ;;; GNU Guix is distributed in the hope that it will be useful, but
25 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
26 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 ;;; GNU General Public License for more details.
28 ;;;
29 ;;; You should have received a copy of the GNU General Public License
30 ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
31
32 (define-module (guix ui)
33 #:use-module (guix i18n)
34 #:use-module (guix colors)
35 #:use-module (guix diagnostics)
36 #:use-module (guix gexp)
37 #:use-module (guix sets)
38 #:use-module (guix utils)
39 #:use-module (guix store)
40 #:use-module (guix config)
41 #:use-module (guix packages)
42 #:use-module (guix profiles)
43 #:use-module (guix derivations)
44 #:use-module (guix combinators)
45 #:use-module (guix build-system)
46 #:use-module (guix serialization)
47 #:use-module ((guix licenses) #:select (license? license-name))
48 #:use-module ((guix build syscalls)
49 #:select (free-disk-space terminal-columns
50 terminal-rows))
51 #:use-module ((guix build utils)
52 ;; XXX: All we need are the bindings related to
53 ;; '&invoke-error'. However, to work around the bug described
54 ;; in 5d669883ecc104403c5d3ba7d172e9c02234577c, #:hide
55 ;; unwanted bindings instead of #:select'ing the needed
56 ;; bindings.
57 #:hide (package-name->name+version))
58 #:use-module (srfi srfi-1)
59 #:use-module (srfi srfi-11)
60 #:use-module (srfi srfi-19)
61 #:use-module (srfi srfi-26)
62 #:use-module (srfi srfi-31)
63 #:use-module (srfi srfi-34)
64 #:use-module (srfi srfi-35)
65 #:autoload (ice-9 ftw) (scandir)
66 #:use-module (ice-9 match)
67 #:use-module (ice-9 format)
68 #:use-module (ice-9 regex)
69 #:autoload (system base compile) (compile-file)
70 #:autoload (system repl repl) (start-repl)
71 #:autoload (system repl debug) (make-debug stack->vector)
72 #:use-module (texinfo)
73 #:use-module (texinfo plain-text)
74 #:use-module (texinfo string-utils)
75
76 ;; Re-exports for backward compatibility.
77 #:re-export (G_ N_ P_ ;now in (guix i18n)
78
79 warning info report-error leave ;now in (guix diagnostics)
80 location->string
81 guix-warning-port program-name)
82 #:export (display-hint
83 make-user-module
84 load*
85 warn-about-load-error
86 show-version-and-exit
87 show-bug-report-information
88 make-regexp*
89 string->number*
90 size->number
91 show-derivation-outputs
92 show-what-to-build
93 show-what-to-build*
94 show-manifest-transaction
95 call-with-error-handling
96 with-error-handling
97 with-unbound-variable-handling
98 leave-on-EPIPE
99 read/eval
100 read/eval-package-expression
101 check-available-space
102 fill-paragraph
103 %text-width
104 texi->plain-text
105 package-description-string
106 package-synopsis-string
107 string->recutils
108 package->recutils
109 package-specification->name+version+output
110
111 relevance
112 package-relevance
113 display-search-results
114
115 string->generations
116 string->duration
117 matching-generations
118 display-generation
119 display-profile-content
120 display-profile-content-diff
121 roll-back*
122 switch-to-generation*
123 delete-generation*
124 run-guix-command
125 run-guix
126 guix-main))
127
128 ;;; Commentary:
129 ;;;
130 ;;; User interface facilities for command-line tools.
131 ;;;
132 ;;; Code:
133
134 (define (print-unbound-variable-error port key args default-printer)
135 ;; Print unbound variable errors more nicely, and in the right language.
136 (match args
137 ((proc message (variable) _ ...)
138 ;; We can always omit PROC because when it's useful (i.e., different from
139 ;; "module-lookup"), it gets displayed before.
140 (format port (G_ "error: ~a: unbound variable") variable))
141 (_
142 (default-printer))))
143
144 (set-exception-printer! 'unbound-variable print-unbound-variable-error)
145
146 (define (make-user-module modules)
147 "Return a new user module with the additional MODULES loaded."
148 ;; Module in which the machine description file is loaded.
149 (let ((module (make-fresh-user-module)))
150 (for-each (lambda (iface)
151 (module-use! module (resolve-interface iface)))
152 modules)
153 module))
154
155 (define (last-frame-with-source stack)
156 "Walk stack upwards and return the last frame that has source location
157 information, or #f if it could not be found."
158 (define (frame-with-source frame)
159 ;; Walk from FRAME upwards until source location information is found.
160 (let loop ((frame frame)
161 (previous frame))
162 (if (not frame)
163 previous
164 (if (frame-source frame)
165 frame
166 (loop (frame-previous frame) frame)))))
167
168 (let* ((depth (stack-length stack))
169 (last (and (> depth 0) (stack-ref stack 0))))
170 (frame-with-source (if (> depth 1)
171 (stack-ref stack 1) ;skip the 'throw' frame
172 last))))
173
174 (define* (load* file user-module
175 #:key (on-error 'nothing-special))
176 "Load the user provided Scheme source code FILE."
177 (define (error-string frame args)
178 (call-with-output-string
179 (lambda (port)
180 (apply display-error frame port (cdr args)))))
181
182 (define tag
183 (make-prompt-tag "user-code"))
184
185 (catch #t
186 (lambda ()
187 ;; XXX: Force a recompilation to avoid ABI issues.
188 ;;
189 ;; In 2.2.3, the bogus answer to <https://bugs.gnu.org/29226> was to
190 ;; ignore all available .go, not just those from ~/.cache, which in turn
191 ;; meant that we had to rebuild *everything*. Since this is too costly,
192 ;; we have to turn off '%fresh-auto-compile' with that version, so to
193 ;; avoid ABI breakage in the user's config file, we explicitly compile
194 ;; it (the problem remains if the user's config is spread on several
195 ;; modules.) See <https://bugs.gnu.org/29881>.
196 (unless (string=? (version) "2.2.3")
197 (set! %fresh-auto-compile #t))
198
199 (set! %load-should-auto-compile #t)
200
201 (save-module-excursion
202 (lambda ()
203 (set-current-module user-module)
204
205 ;; Hide the "auto-compiling" messages.
206 (parameterize ((current-warning-port (%make-void-port "w")))
207 (call-with-prompt tag
208 (lambda ()
209 (when (string=? (version) "2.2.3")
210 (catch 'system-error
211 (lambda ()
212 (compile-file file #:env user-module))
213 (const #f))) ;EACCES maybe, let's interpret it
214
215 ;; Give 'load' an absolute file name so that it doesn't try to
216 ;; search for FILE in %LOAD-PATH. Note: use 'load', not
217 ;; 'primitive-load', so that FILE is compiled, which then allows us
218 ;; to provide better error reporting with source line numbers.
219 (load (canonicalize-path file)))
220 (const #f))))))
221 (lambda _
222 ;; XXX: Errors are reported from the pre-unwind handler below, but
223 ;; calling 'exit' from there has no effect, so we call it here.
224 (exit 1))
225 (rec (handle-error . args)
226 ;; Capture the stack up to this procedure call, excluded, and pass
227 ;; the faulty stack frame to 'report-load-error'.
228 (let* ((stack (make-stack #t handle-error tag))
229 (frame (last-frame-with-source stack)))
230
231 (report-load-error file args frame)
232
233 (case on-error
234 ((debug)
235 (newline)
236 (display (G_ "entering debugger; type ',bt' for a backtrace\n"))
237 (start-repl #:debug (make-debug (stack->vector stack) 0
238 (error-string frame args)
239 #f)))
240 ((backtrace)
241 (newline (current-error-port))
242 (display-backtrace stack (current-error-port)))
243 (else
244 #t))))))
245
246 (define (known-variable-definition variable)
247 "Search among the currently loaded modules one that defines a variable named
248 VARIABLE and return it, or #f if none was found."
249 (define (module<? m1 m2)
250 (match (module-name m2)
251 (('gnu _ ...) #t)
252 (('guix _ ...)
253 (match (module-name m1)
254 (('gnu _ ...) #f)
255 (_ #t)))
256 (_ #f)))
257
258 (let loop ((modules (list (resolve-module '() #f #f #:ensure #f)))
259 (suggestions '())
260 (visited (setq)))
261 (match modules
262 (()
263 ;; Pick the "best" suggestion.
264 (match (sort suggestions module<?)
265 (() #f)
266 ((first _ ...) first)))
267 ((head tail ...)
268 (if (set-contains? visited head)
269 (loop tail suggestions visited)
270 (let ((visited (set-insert head visited))
271 (next (append tail
272 (hash-map->list (lambda (name module)
273 module)
274 (module-submodules head)))))
275 (match (module-local-variable head variable)
276 (#f (loop next suggestions visited))
277 (_
278 (match (module-name head)
279 (('gnu _ ...) head) ;must be that one
280 (_ (loop next (cons head suggestions) visited)))))))))))
281
282 (define %hint-color (color BOLD CYAN))
283
284 (define* (display-hint message #:optional (port (current-error-port)))
285 "Display MESSAGE, a l10n message possibly containing Texinfo markup, to
286 PORT."
287 (define colorize
288 (if (color-output? port)
289 (lambda (str)
290 (colorize-string str %hint-color))
291 identity))
292
293 (display (colorize (G_ "hint: ")) port)
294 (display
295 ;; XXX: We should arrange so that the initial indent is wider.
296 (parameterize ((%text-width (max 15 (- (terminal-columns) 5))))
297 (texi->plain-text message))
298 port))
299
300 (define* (report-unbound-variable-error args #:key frame)
301 "Return the given unbound-variable error, where ARGS is the list of 'throw'
302 arguments."
303 (match args
304 ((key . args)
305 (print-exception (current-error-port) frame key args)))
306 (match args
307 (('unbound-variable proc message (variable) _ ...)
308 (match (known-variable-definition variable)
309 (#f
310 (display-hint (G_ "Did you forget a @code{use-modules} form?")))
311 ((? module? module)
312 (display-hint (format #f (G_ "Did you forget @code{(use-modules ~a)}?")
313 (module-name module))))))))
314
315 (define* (report-load-error file args #:optional frame)
316 "Report the failure to load FILE, a user-provided Scheme file.
317 ARGS is the list of arguments received by the 'throw' handler."
318 (match args
319 (('system-error . rest)
320 (let ((err (system-error-errno args)))
321 (report-error (G_ "failed to load '~a': ~a~%") file (strerror err))))
322 (('read-error "scm_i_lreadparen" message _ ...)
323 ;; Guile's missing-paren messages are obscure so we make them more
324 ;; intelligible here.
325 (if (string-suffix? "end of file" message)
326 (let ((location (string-drop-right message
327 (string-length "end of file"))))
328 (format (current-error-port) (G_ "~amissing closing parenthesis~%")
329 location))
330 (apply throw args)))
331 (('syntax-error proc message properties form . rest)
332 (let ((loc (source-properties->location properties)))
333 (report-error loc (G_ "~a~%") message)))
334 (('unbound-variable _ ...)
335 (report-unbound-variable-error args #:frame frame))
336 (('srfi-34 obj)
337 (if (message-condition? obj)
338 (report-error (and (error-location? obj)
339 (error-location obj))
340 (G_ "~a~%")
341 (gettext (condition-message obj) %gettext-domain))
342 (report-error (G_ "exception thrown: ~s~%") obj))
343 (when (fix-hint? obj)
344 (display-hint (condition-fix-hint obj))))
345 ((key args ...)
346 (report-error (G_ "failed to load '~a':~%") file)
347 (match args
348 (((? symbol? proc) (? string? message) (args ...) . rest)
349 (display-error frame (current-error-port) proc message
350 args rest))
351 (_
352 ;; Some exceptions like 'git-error' do not follow Guile's convention
353 ;; above and need to be printed with 'print-exception'.
354 (print-exception (current-error-port) frame key args))))))
355
356 (define (warn-about-load-error file args) ;FIXME: factorize with ↑
357 "Report the failure to load FILE, a user-provided Scheme file, without
358 exiting. ARGS is the list of arguments received by the 'throw' handler."
359 (match args
360 (('system-error . rest)
361 (let ((err (system-error-errno args)))
362 (warning (G_ "failed to load '~a': ~a~%") file (strerror err))))
363 (('syntax-error proc message properties form . rest)
364 (let ((loc (source-properties->location properties)))
365 (warning loc (G_ "~a~%") message)))
366 (('srfi-34 obj)
367 (if (message-condition? obj)
368 (warning (G_ "failed to load '~a': ~a~%")
369 file
370 (gettext (condition-message obj) %gettext-domain))
371 (warning (G_ "failed to load '~a': exception thrown: ~s~%")
372 file obj)))
373 ((error args ...)
374 (warning (G_ "failed to load '~a':~%") file)
375 (apply display-error #f (current-error-port) args))))
376
377 (define (call-with-unbound-variable-handling thunk)
378 (define tag
379 (make-prompt-tag "user-code"))
380
381 (catch 'unbound-variable
382 (lambda ()
383 (call-with-prompt tag
384 thunk
385 (const #f)))
386 (const #t)
387 (rec (handle-error . args)
388 (let* ((stack (make-stack #t handle-error tag))
389 (frame (and stack (last-frame-with-source stack))))
390 (report-unbound-variable-error args #:frame frame)
391 (exit 1)))))
392
393 (define-syntax-rule (with-unbound-variable-handling exp ...)
394 "Capture 'unbound-variable' exceptions in the dynamic extent of EXP... and
395 report them in a user-friendly way."
396 (call-with-unbound-variable-handling (lambda () exp ...)))
397
398 (define (install-locale)
399 "Install the current locale settings."
400 (catch 'system-error
401 (lambda _
402 (setlocale LC_ALL ""))
403 (lambda args
404 (display-hint (G_ "Consider installing the @code{glibc-utf8-locales} or
405 @code{glibc-locales} package and defining @code{GUIX_LOCPATH}, along these
406 lines:
407
408 @example
409 guix package -i glibc-utf8-locales
410 export GUIX_LOCPATH=\"$HOME/.guix-profile/lib/locale\"
411 @end example
412
413 See the \"Application Setup\" section in the manual, for more info.\n")))))
414
415 (define (initialize-guix)
416 "Perform the usual initialization for stand-alone Guix commands."
417 ;; By default don't annoy users with deprecation warnings. In practice,
418 ;; 'define-deprecated' in (ice-9 deprecated) arranges so that those warnings
419 ;; are emitted at expansion-time only, but there are cases where they could
420 ;; slip through, for instance when interpreting code.
421 (unless (getenv "GUILE_WARN_DEPRECATED")
422 (debug-disable 'warn-deprecated))
423
424 (install-locale)
425 (textdomain %gettext-domain)
426
427 ;; Ignore SIGPIPE. If the daemon closes the connection, we prefer to be
428 ;; notified via an EPIPE later.
429 (sigaction SIGPIPE SIG_IGN)
430
431 (setvbuf (current-output-port) 'line)
432 (setvbuf (current-error-port) 'line))
433
434 (define* (show-version-and-exit #:optional (command (car (command-line))))
435 "Display version information for COMMAND and `(exit 0)'."
436 (simple-format #t "~a (~a) ~a~%"
437 command %guix-package-name %guix-version)
438 (format #t "Copyright ~a 2019 ~a"
439 ;; TRANSLATORS: Translate "(C)" to the copyright symbol
440 ;; (C-in-a-circle), if this symbol is available in the user's
441 ;; locale. Otherwise, do not translate "(C)"; leave it as-is. */
442 (G_ "(C)")
443 (G_ "the Guix authors\n"))
444 (display (G_"\
445 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
446 This is free software: you are free to change and redistribute it.
447 There is NO WARRANTY, to the extent permitted by law.
448 "))
449 (exit 0))
450
451 (define (show-bug-report-information)
452 ;; TRANSLATORS: The placeholder indicates the bug-reporting address for this
453 ;; package. Please add another line saying "Report translation bugs to
454 ;; ...\n" with the address for translation bugs (typically your translation
455 ;; team's web or email address).
456 (format #t (G_ "
457 Report bugs to: ~a.") %guix-bug-report-address)
458 (format #t (G_ "
459 ~a home page: <~a>") %guix-package-name %guix-home-page-url)
460 (display (G_ "
461 General help using GNU software: <http://www.gnu.org/gethelp/>"))
462 (newline))
463
464 (define (augmented-system-error-handler file)
465 "Return a 'system-error' handler that mentions FILE in its message."
466 (lambda (key proc fmt args errno)
467 ;; Augment the FMT and ARGS with information about TARGET (this
468 ;; information is missing as of Guile 2.0.11, making the exception
469 ;; uninformative.)
470 (apply throw key proc "~A: ~S"
471 (list (strerror (car errno)) file)
472 (list errno))))
473
474 (define-syntax apply-formals
475 (syntax-rules ()
476 ((_ proc (args ...)) (proc args ...))
477 ((_ proc (arg1 args ... . rest)) (apply proc arg1 args ... rest))))
478
479 (define-syntax-rule (error-reporting-wrapper proc formals file)
480 "Wrap PROC such that its 'system-error' exceptions are augmented to mention
481 FILE."
482 (let ((real-proc (@ (guile) proc)))
483 (lambda formals
484 (catch 'system-error
485 (lambda ()
486 (apply-formals real-proc formals))
487 (augmented-system-error-handler file)))))
488
489 (set! symlink
490 ;; We 'set!' the global binding because (gnu build ...) modules and similar
491 ;; typically don't use (guix ui).
492 (error-reporting-wrapper symlink (source target) target))
493
494 (set! copy-file
495 ;; Note: here we use 'set!', not #:replace, because UIs typically use
496 ;; 'copy-recursively', which doesn't use (guix ui).
497 (error-reporting-wrapper copy-file (source target) target))
498
499 (set! canonicalize-path
500 (error-reporting-wrapper canonicalize-path (file) file))
501
502 (set! delete-file
503 (error-reporting-wrapper delete-file (file) file))
504
505 (set! execlp
506 (error-reporting-wrapper execlp (filename . args) filename))
507
508 (define (make-regexp* regexp . flags)
509 "Like 'make-regexp' but error out if REGEXP is invalid, reporting the error
510 nicely."
511 (catch 'regular-expression-syntax
512 (lambda ()
513 (apply make-regexp regexp flags))
514 (lambda (key proc message . rest)
515 (leave (G_ "'~a' is not a valid regular expression: ~a~%")
516 regexp message))))
517
518 (define (string->number* str)
519 "Like `string->number', but error out with an error message on failure."
520 (or (string->number str)
521 (leave (G_ "~a: invalid number~%") str)))
522
523 (define (size->number str)
524 "Convert STR, a storage measurement representation such as \"1024\" or
525 \"1MiB\", to a number of bytes. Raise an error if STR could not be
526 interpreted."
527 (define unit-pos
528 (string-rindex str char-set:digit))
529
530 (define unit
531 (and unit-pos (substring str (+ 1 unit-pos))))
532
533 (let* ((numstr (if unit-pos
534 (substring str 0 (+ 1 unit-pos))
535 str))
536 (num (string->number numstr)))
537 (unless num
538 (leave (G_ "invalid number: ~a~%") numstr))
539
540 ((compose inexact->exact round)
541 (* num
542 (match unit
543 ((or "KiB" "K" "k") (expt 2 10))
544 ((or "MiB" "M") (expt 2 20))
545 ((or "GiB" "G") (expt 2 30))
546 ((or "TiB" "T") (expt 2 40))
547 ((or "PiB" "P") (expt 2 50))
548 ((or "EiB" "E") (expt 2 60))
549 ((or "ZiB" "Z") (expt 2 70))
550 ((or "YiB" "Y") (expt 2 80))
551 ("kB" (expt 10 3))
552 ("MB" (expt 10 6))
553 ("GB" (expt 10 9))
554 ("TB" (expt 10 12))
555 ("PB" (expt 10 15))
556 ("EB" (expt 10 18))
557 ("ZB" (expt 10 21))
558 ("YB" (expt 10 24))
559 ("" 1)
560 (x
561 (leave (G_ "unknown unit: ~a~%") unit)))))))
562
563 (define (display-collision-resolution-hint collision)
564 "Display hints on how to resolve COLLISION, a &profile-collistion-error."
565 (define (top-most-entry entry)
566 (let loop ((entry entry))
567 (match (force (manifest-entry-parent entry))
568 (#f entry)
569 (parent (loop parent)))))
570
571 (let* ((first (profile-collision-error-entry collision))
572 (second (profile-collision-error-conflict collision))
573 (name1 (manifest-entry-name (top-most-entry first)))
574 (name2 (manifest-entry-name (top-most-entry second))))
575 (if (string=? name1 name2)
576 (display-hint (format #f (G_ "You cannot have two different versions
577 or variants of @code{~a} in the same profile.")
578 name1))
579 (display-hint (format #f (G_ "Try upgrading both @code{~a} and @code{~a},
580 or remove one of them from the profile.")
581 name1 name2)))))
582
583 (define (call-with-error-handling thunk)
584 "Call THUNK within a user-friendly error handler."
585 (define (port-filename* port)
586 ;; 'port-filename' returns #f for non-file ports, but it raises an
587 ;; exception for file ports that are closed. Work around that.
588 (and (not (port-closed? port))
589 (port-filename port)))
590
591 (guard (c ((package-input-error? c)
592 (let* ((package (package-error-package c))
593 (input (package-error-invalid-input c))
594 (location (package-location package))
595 (file (location-file location))
596 (line (location-line location))
597 (column (location-column location)))
598 (leave (G_ "~a:~a:~a: package `~a' has an invalid input: ~s~%")
599 file line column
600 (package-full-name package) input)))
601 ((package-cross-build-system-error? c)
602 (let* ((package (package-error-package c))
603 (loc (package-location package))
604 (system (package-build-system package)))
605 (leave (G_ "~a: ~a: build system `~a' does not support cross builds~%")
606 (location->string loc)
607 (package-full-name package)
608 (build-system-name system))))
609 ((gexp-input-error? c)
610 (let ((input (package-error-invalid-input c)))
611 (leave (G_ "~s: invalid G-expression input~%")
612 (gexp-error-invalid-input c))))
613 ((profile-not-found-error? c)
614 (leave (G_ "profile '~a' does not exist~%")
615 (profile-error-profile c)))
616 ((missing-generation-error? c)
617 (leave (G_ "generation ~a of profile '~a' does not exist~%")
618 (missing-generation-error-generation c)
619 (profile-error-profile c)))
620 ((unmatched-pattern-error? c)
621 (let ((pattern (unmatched-pattern-error-pattern c)))
622 (leave (G_ "package '~a~@[@~a~]~@[:~a~]' not found in profile~%")
623 (manifest-pattern-name pattern)
624 (manifest-pattern-version pattern)
625 (match (manifest-pattern-output pattern)
626 ("out" #f)
627 (output output)))))
628 ((profile-collision-error? c)
629 (let ((entry (profile-collision-error-entry c))
630 (conflict (profile-collision-error-conflict c)))
631 (define (report-parent-entries entry)
632 (let ((parent (force (manifest-entry-parent entry))))
633 (when (manifest-entry? parent)
634 (report-error (G_ " ... propagated from ~a@~a~%")
635 (manifest-entry-name parent)
636 (manifest-entry-version parent))
637 (report-parent-entries parent))))
638
639 (define (manifest-entry-output* entry)
640 (match (manifest-entry-output entry)
641 ("out" "")
642 (output (string-append ":" output))))
643
644 (report-error (G_ "profile contains conflicting entries for ~a~a~%")
645 (manifest-entry-name entry)
646 (manifest-entry-output* entry))
647 (report-error (G_ " first entry: ~a@~a~a ~a~%")
648 (manifest-entry-name entry)
649 (manifest-entry-version entry)
650 (manifest-entry-output* entry)
651 (manifest-entry-item entry))
652 (report-parent-entries entry)
653 (report-error (G_ " second entry: ~a@~a~a ~a~%")
654 (manifest-entry-name conflict)
655 (manifest-entry-version conflict)
656 (manifest-entry-output* conflict)
657 (manifest-entry-item conflict))
658 (report-parent-entries conflict)
659 (display-collision-resolution-hint c)
660 (exit 1)))
661 ((nar-error? c)
662 (let ((file (nar-error-file c))
663 (port (nar-error-port c)))
664 (if file
665 (leave (G_ "corrupt input while restoring '~a' from ~s~%")
666 file (or (port-filename* port) port))
667 (leave (G_ "corrupt input while restoring archive from ~s~%")
668 (or (port-filename* port) port)))))
669 ((store-connection-error? c)
670 (leave (G_ "failed to connect to `~a': ~a~%")
671 (store-connection-error-file c)
672 (strerror (store-connection-error-code c))))
673 ((store-protocol-error? c)
674 ;; FIXME: Server-provided error messages aren't i18n'd.
675 (leave (G_ "~a~%")
676 (store-protocol-error-message c)))
677 ((derivation-missing-output-error? c)
678 (leave (G_ "reference to invalid output '~a' of derivation '~a'~%")
679 (derivation-missing-output c)
680 (derivation-file-name (derivation-error-derivation c))))
681 ((file-search-error? c)
682 (leave (G_ "file '~a' could not be found in these \
683 directories:~{ ~a~}~%")
684 (file-search-error-file-name c)
685 (file-search-error-search-path c)))
686 ((invoke-error? c)
687 (leave (G_ "program exited\
688 ~@[ with non-zero exit status ~a~]\
689 ~@[ terminated by signal ~a~]\
690 ~@[ stopped by signal ~a~]: ~s~%")
691 (invoke-error-exit-status c)
692 (invoke-error-term-signal c)
693 (invoke-error-stop-signal c)
694 (cons (invoke-error-program c)
695 (invoke-error-arguments c))))
696 ((and (error-location? c) (message-condition? c))
697 (report-error (error-location c) (G_ "~a~%")
698 (gettext (condition-message c) %gettext-domain))
699 (when (fix-hint? c)
700 (display-hint (condition-fix-hint c)))
701 (exit 1))
702 ((and (message-condition? c) (fix-hint? c))
703 (report-error (G_ "~a~%")
704 (gettext (condition-message c) %gettext-domain))
705 (display-hint (condition-fix-hint c))
706 (exit 1))
707 ((message-condition? c)
708 ;; Normally '&message' error conditions have an i18n'd message.
709 (leave (G_ "~a~%")
710 (gettext (condition-message c) %gettext-domain))))
711 ;; Catch EPIPE and the likes.
712 (catch 'system-error
713 thunk
714 (lambda (key proc format-string format-args . rest)
715 (leave (G_ "~a: ~a~%") proc
716 (apply format #f format-string format-args))))))
717
718 (define-syntax-rule (leave-on-EPIPE exp ...)
719 "Run EXP... in a context when EPIPE errors are caught and lead to 'exit'
720 with successful exit code. This is useful when writing to the standard output
721 may lead to EPIPE, because the standard output is piped through 'head' or
722 similar."
723 (catch 'system-error
724 (lambda ()
725 exp ...)
726 (lambda args
727 ;; We really have to exit this brutally, otherwise Guile eventually
728 ;; attempts to flush all the ports, leading to an uncaught EPIPE down
729 ;; the path.
730 (if (= EPIPE (system-error-errno args))
731 (primitive-_exit 0)
732 (apply throw args)))))
733
734 (define %guix-user-module
735 ;; Module in which user expressions are evaluated.
736 ;; Compute lazily to avoid circularity with (guix gexp).
737 (delay
738 (let ((module (make-module)))
739 (beautify-user-module! module)
740 ;; Use (guix gexp) so that one can use #~ & co.
741 (module-use! module (resolve-interface '(guix gexp)))
742 module)))
743
744 (define (read/eval str)
745 "Read and evaluate STR, raising an error if something goes wrong."
746 (let ((exp (catch #t
747 (lambda ()
748 (call-with-input-string str read))
749 (lambda args
750 (leave (G_ "failed to read expression ~s: ~s~%")
751 str args)))))
752 (catch #t
753 (lambda ()
754 (eval exp (force %guix-user-module)))
755 (lambda args
756 (report-error (G_ "failed to evaluate expression '~a':~%") exp)
757 (match args
758 (('syntax-error proc message properties form . rest)
759 (report-error (G_ "syntax error: ~a~%") message))
760 (('srfi-34 obj)
761 (if (message-condition? obj)
762 (report-error (G_ "~a~%")
763 (gettext (condition-message obj)
764 %gettext-domain))
765 (report-error (G_ "exception thrown: ~s~%") obj)))
766 ((error args ...)
767 (apply display-error #f (current-error-port) args))
768 (what? #f))
769 (exit 1)))))
770
771 (define (read/eval-package-expression str)
772 "Read and evaluate STR and return the package it refers to, or exit an
773 error."
774 (match (read/eval str)
775 ((? package? p) p)
776 (x
777 (leave (G_ "expression ~s does not evaluate to a package~%")
778 str))))
779
780 (define (show-derivation-outputs derivation)
781 "Show the output file names of DERIVATION."
782 (format #t "~{~a~%~}"
783 (map (match-lambda
784 ((out-name . out)
785 (derivation->output-path derivation out-name)))
786 (derivation-outputs derivation))))
787
788 (define* (check-available-space need
789 #:optional (directory (%store-prefix)))
790 "Make sure at least NEED bytes are available in DIRECTORY. Otherwise emit a
791 warning."
792 (let ((free (catch 'system-error
793 (lambda ()
794 (free-disk-space directory))
795 (const #f))))
796 (when (and free (>= need free))
797 (warning (G_ "at least ~,1h MB needed but only ~,1h MB available in ~a~%")
798 (/ need 1e6) (/ free 1e6) directory))))
799
800 (define (graft-derivation? drv)
801 "Return true if DRV is definitely a graft derivation, false otherwise."
802 (match (assq-ref (derivation-properties drv) 'type)
803 ('graft #t)
804 (_ #f)))
805
806 (define (profile-hook-derivation? drv)
807 "Return true if DRV is definitely a profile hook derivation, false otherwise."
808 (match (assq-ref (derivation-properties drv) 'type)
809 ('profile-hook #t)
810 (_ #f)))
811
812 (define* (show-what-to-build store drv
813 #:key dry-run? (use-substitutes? #t)
814 (mode (build-mode normal)))
815 "Show what will or would (depending on DRY-RUN?) be built in realizing the
816 derivations listed in DRV using MODE, a 'build-mode' value. Return #t if
817 there's something to build, #f otherwise. When USE-SUBSTITUTES?, check and
818 report what is prerequisites are available for download."
819 (define substitutable-info
820 ;; Call 'substitutation-oracle' upfront so we don't end up launching the
821 ;; substituter many times. This makes a big difference, especially when
822 ;; DRV is a long list as is the case with 'guix environment'.
823 (if use-substitutes?
824 (substitution-oracle store drv #:mode mode)
825 (const #f)))
826
827 (define (built-or-substitutable? drv)
828 (or (null? (derivation-outputs drv))
829 (let ((out (derivation->output-path drv))) ;XXX: assume "out" exists
830 (or (valid-path? store out)
831 (substitutable-info out)))))
832
833 (let*-values (((build download)
834 (fold2 (lambda (drv build download)
835 (let-values (((b d)
836 (derivation-prerequisites-to-build
837 store drv
838 #:mode mode
839 #:substitutable-info
840 substitutable-info)))
841 (values (append b build)
842 (append d download))))
843 '() '()
844 drv))
845 ((build) ; add the DRV themselves
846 (delete-duplicates
847 (append (map derivation-file-name
848 (remove built-or-substitutable? drv))
849 (map derivation-input-path build))))
850 ((download) ; add the references of DOWNLOAD
851 (if use-substitutes?
852 (delete-duplicates
853 (append download
854 (filter-map (lambda (item)
855 (if (valid-path? store item)
856 #f
857 (substitutable-info item)))
858 (append-map
859 substitutable-references
860 download))))
861 download))
862 ((graft hook build)
863 (match (fold (lambda (file acc)
864 (let ((drv (read-derivation-from-file file)))
865 (match acc
866 ((#:graft graft #:hook hook #:build build)
867 (cond
868 ((graft-derivation? drv)
869 `(#:graft ,(cons file graft)
870 #:hook ,hook
871 #:build ,build))
872 ((profile-hook-derivation? drv)
873 `(#:graft ,graft
874 #:hook ,(cons file hook)
875 #:build ,build))
876 (else
877 `(#:graft ,graft
878 #:hook ,hook
879 #:build ,(cons file build))))))))
880 '(#:graft () #:hook () #:build ())
881 build)
882 ((#:graft graft #:hook hook #:build build)
883 (values graft hook build)))))
884 (define installed-size
885 (reduce + 0 (map substitutable-nar-size download)))
886
887 (define download-size
888 (/ (reduce + 0 (map substitutable-download-size download))
889 1e6))
890
891 (define display-download-size?
892 ;; Sometimes narinfos lack information about the download size. Only
893 ;; display when we have information for all of DOWNLOAD.
894 (not (any (compose zero? substitutable-download-size) download)))
895
896 (if dry-run?
897 (begin
898 (format (current-error-port)
899 (N_ "~:[The following derivation would be built:~%~{ ~a~%~}~;~]"
900 "~:[The following derivations would be built:~%~{ ~a~%~}~;~]"
901 (length build))
902 (null? build) build)
903 (if display-download-size?
904 (format (current-error-port)
905 ;; TRANSLATORS: "MB" is for "megabyte"; it should be
906 ;; translated to the corresponding abbreviation.
907 (G_ "~:[~,1h MB would be downloaded:~%~{ ~a~%~}~;~]")
908 (null? download)
909 download-size
910 (map substitutable-path download))
911 (format (current-error-port)
912 (N_ "~:[The following file would be downloaded:~%~{ ~a~%~}~;~]"
913 "~:[The following files would be downloaded:~%~{ ~a~%~}~;~]"
914 (length download))
915 (null? download)
916 (map substitutable-path download)))
917 (format (current-error-port)
918 (N_ "~:[The following graft would be made:~%~{ ~a~%~}~;~]"
919 "~:[The following grafts would be made:~%~{ ~a~%~}~;~]"
920 (length graft))
921 (null? graft) graft)
922 (format (current-error-port)
923 (N_ "~:[The following profile hook would be built:~%~{ ~a~%~}~;~]"
924 "~:[The following profile hooks would be built:~%~{ ~a~%~}~;~]"
925 (length hook))
926 (null? hook) hook))
927 (begin
928 (format (current-error-port)
929 (N_ "~:[The following derivation will be built:~%~{ ~a~%~}~;~]"
930 "~:[The following derivations will be built:~%~{ ~a~%~}~;~]"
931 (length build))
932 (null? build) build)
933 (if display-download-size?
934 (format (current-error-port)
935 ;; TRANSLATORS: "MB" is for "megabyte"; it should be
936 ;; translated to the corresponding abbreviation.
937 (G_ "~:[~,1h MB will be downloaded:~%~{ ~a~%~}~;~]")
938 (null? download)
939 download-size
940 (map substitutable-path download))
941 (format (current-error-port)
942 (N_ "~:[The following file will be downloaded:~%~{ ~a~%~}~;~]"
943 "~:[The following files will be downloaded:~%~{ ~a~%~}~;~]"
944 (length download))
945 (null? download)
946 (map substitutable-path download)))
947 (format (current-error-port)
948 (N_ "~:[The following graft will be made:~%~{ ~a~%~}~;~]"
949 "~:[The following grafts will be made:~%~{ ~a~%~}~;~]"
950 (length graft))
951 (null? graft) graft)
952 (format (current-error-port)
953 (N_ "~:[The following profile hook will be built:~%~{ ~a~%~}~;~]"
954 "~:[The following profile hooks will be built:~%~{ ~a~%~}~;~]"
955 (length hook))
956 (null? hook) hook)))
957
958 (check-available-space installed-size)
959
960 (pair? build)))
961
962 (define show-what-to-build*
963 (store-lift show-what-to-build))
964
965 (define (right-arrow port)
966 "Return either a string containing the 'RIGHT ARROW' character, or an ASCII
967 replacement if PORT is not Unicode-capable."
968 (let ((encoding (port-encoding port))
969 (arrow "→"))
970 (catch 'encoding-error
971 (lambda ()
972 (call-with-output-string
973 (lambda (port)
974 (set-port-encoding! port encoding)
975 (set-port-conversion-strategy! port 'error)
976 (display arrow port))))
977 (lambda (key . args)
978 "->"))))
979
980 (define* (show-manifest-transaction store manifest transaction
981 #:key dry-run?)
982 "Display what will/would be installed/removed from MANIFEST by TRANSACTION."
983 (define (package-strings name version output item)
984 (map (lambda (name version output item)
985 (format #f " ~a~:[:~a~;~*~]\t~a\t~a"
986 name
987 (equal? output "out") output version
988 (if (package? item)
989 (package-output store item output)
990 item)))
991 name version output item))
992
993 (define → ;an arrow that can be represented on stderr
994 (right-arrow (current-error-port)))
995
996 (define (upgrade-string name old-version new-version output item)
997 (format #f " ~a~:[:~a~;~*~]\t~a ~a ~a\t~a"
998 name (equal? output "out") output
999 old-version → new-version
1000 (if (package? item)
1001 (package-output store item output)
1002 item)))
1003
1004 (let-values (((remove install upgrade downgrade)
1005 (manifest-transaction-effects manifest transaction)))
1006 (match remove
1007 ((($ <manifest-entry> name version output item) ..1)
1008 (let ((len (length name))
1009 (remove (package-strings name version output item)))
1010 (if dry-run?
1011 (format (current-error-port)
1012 (N_ "The following package would be removed:~%~{~a~%~}~%"
1013 "The following packages would be removed:~%~{~a~%~}~%"
1014 len)
1015 remove)
1016 (format (current-error-port)
1017 (N_ "The following package will be removed:~%~{~a~%~}~%"
1018 "The following packages will be removed:~%~{~a~%~}~%"
1019 len)
1020 remove))))
1021 (x #f))
1022 (match downgrade
1023 (((($ <manifest-entry> name old-version)
1024 . ($ <manifest-entry> _ new-version output item)) ..1)
1025 (let ((len (length name))
1026 (downgrade (map upgrade-string
1027 name old-version new-version output item)))
1028 (if dry-run?
1029 (format (current-error-port)
1030 (N_ "The following package would be downgraded:~%~{~a~%~}~%"
1031 "The following packages would be downgraded:~%~{~a~%~}~%"
1032 len)
1033 downgrade)
1034 (format (current-error-port)
1035 (N_ "The following package will be downgraded:~%~{~a~%~}~%"
1036 "The following packages will be downgraded:~%~{~a~%~}~%"
1037 len)
1038 downgrade))))
1039 (x #f))
1040 (match upgrade
1041 (((($ <manifest-entry> name old-version)
1042 . ($ <manifest-entry> _ new-version output item)) ..1)
1043 (let ((len (length name))
1044 (upgrade (map upgrade-string
1045 name old-version new-version output item)))
1046 (if dry-run?
1047 (format (current-error-port)
1048 (N_ "The following package would be upgraded:~%~{~a~%~}~%"
1049 "The following packages would be upgraded:~%~{~a~%~}~%"
1050 len)
1051 upgrade)
1052 (format (current-error-port)
1053 (N_ "The following package will be upgraded:~%~{~a~%~}~%"
1054 "The following packages will be upgraded:~%~{~a~%~}~%"
1055 len)
1056 upgrade))))
1057 (x #f))
1058 (match install
1059 ((($ <manifest-entry> name version output item _) ..1)
1060 (let ((len (length name))
1061 (install (package-strings name version output item)))
1062 (if dry-run?
1063 (format (current-error-port)
1064 (N_ "The following package would be installed:~%~{~a~%~}~%"
1065 "The following packages would be installed:~%~{~a~%~}~%"
1066 len)
1067 install)
1068 (format (current-error-port)
1069 (N_ "The following package will be installed:~%~{~a~%~}~%"
1070 "The following packages will be installed:~%~{~a~%~}~%"
1071 len)
1072 install))))
1073 (x #f))))
1074
1075 (define-syntax with-error-handling
1076 (syntax-rules ()
1077 "Run BODY within a user-friendly error condition handler."
1078 ((_ body ...)
1079 (call-with-error-handling
1080 (lambda ()
1081 body ...)))))
1082
1083 (define* (fill-paragraph str width #:optional (column 0))
1084 "Fill STR such that each line contains at most WIDTH characters, assuming
1085 that the first character is at COLUMN.
1086
1087 When STR contains a single line break surrounded by other characters, it is
1088 converted to a space; sequences of more than one line break are preserved."
1089 (define (maybe-break chr result)
1090 (match result
1091 ((column newlines chars)
1092 (case chr
1093 ((#\newline)
1094 `(,column ,(+ 1 newlines) ,chars))
1095 (else
1096 (let* ((spaces (if (and (pair? chars) (eqv? (car chars) #\.)) 2 1))
1097 (chars (case newlines
1098 ((0) chars)
1099 ((1)
1100 (append (make-list spaces #\space) chars))
1101 (else
1102 (append (make-list newlines #\newline) chars))))
1103 (column (case newlines
1104 ((0) column)
1105 ((1) (+ spaces column))
1106 (else 0))))
1107 (let ((chars (cons chr chars))
1108 (column (+ 1 column)))
1109 (if (> column width)
1110 (let*-values (((before after)
1111 (break (cut eqv? #\space <>) chars))
1112 ((len)
1113 (length before)))
1114 (if (<= len width)
1115 `(,len
1116 0
1117 ,(if (null? after)
1118 before
1119 (append before
1120 (cons #\newline
1121 (drop-while (cut eqv? #\space <>)
1122 after)))))
1123 `(,column 0 ,chars))) ; unbreakable
1124 `(,column 0 ,chars)))))))))
1125
1126 (match (string-fold maybe-break
1127 `(,column 0 ())
1128 str)
1129 ((column newlines chars)
1130 (list->string (reverse chars)))))
1131
1132 \f
1133 ;;;
1134 ;;; Packages.
1135 ;;;
1136
1137 (define %text-width
1138 (make-parameter (terminal-columns)))
1139
1140 (set! (@@ (texinfo plain-text) wrap*)
1141 ;; XXX: Monkey patch this private procedure to let 'package->recutils'
1142 ;; parameterize the fill of description field correctly.
1143 (lambda strings
1144 (let ((indent (fluid-ref (@@ (texinfo plain-text) *indent*))))
1145 (fill-string (string-concatenate strings)
1146 #:line-width (%text-width) #:initial-indent indent
1147 #:subsequent-indent indent))))
1148
1149 (define (texi->plain-text str)
1150 "Return a plain-text representation of texinfo fragment STR."
1151 ;; 'texi-fragment->stexi' uses a string port so make sure it's a
1152 ;; Unicode-capable one (see <http://bugs.gnu.org/11197>.)
1153 (with-fluids ((%default-port-encoding "UTF-8"))
1154 (stexi->plain-text (texi-fragment->stexi str))))
1155
1156 (define (package-field-string package field-accessor)
1157 "Return a plain-text representation of PACKAGE field."
1158 (and=> (field-accessor package)
1159 (compose texi->plain-text P_)))
1160
1161 (define (package-description-string package)
1162 "Return a plain-text representation of PACKAGE description field."
1163 (package-field-string package package-description))
1164
1165 (define (package-synopsis-string package)
1166 "Return a plain-text representation of PACKAGE synopsis field."
1167 (package-field-string package package-synopsis))
1168
1169 (define (string->recutils str)
1170 "Return a version of STR where newlines have been replaced by newlines
1171 followed by \"+ \", which makes for a valid multi-line field value in the
1172 `recutils' syntax."
1173 (list->string
1174 (string-fold-right (lambda (chr result)
1175 (if (eqv? chr #\newline)
1176 (cons* chr #\+ #\space result)
1177 (cons chr result)))
1178 '()
1179 str)))
1180
1181 (define* (package->recutils p port #:optional (width (%text-width))
1182 #:key (extra-fields '()))
1183 "Write to PORT a `recutils' record of package P, arranging to fit within
1184 WIDTH columns. EXTRA-FIELDS is a list of symbol/value pairs to emit."
1185 (define width*
1186 ;; The available number of columns once we've taken into account space for
1187 ;; the initial "+ " prefix.
1188 (if (> width 2) (- width 2) width))
1189
1190 (define (dependencies->recutils packages)
1191 (let ((list (string-join (delete-duplicates
1192 (map package-full-name
1193 (sort packages package<?))) " ")))
1194 (string->recutils
1195 (fill-paragraph list width*
1196 (string-length "dependencies: ")))))
1197
1198 (define (package<? p1 p2)
1199 (string<? (package-full-name p1) (package-full-name p2)))
1200
1201 ;; Note: Don't i18n field names so that people can post-process it.
1202 (format port "name: ~a~%" (package-name p))
1203 (format port "version: ~a~%" (package-version p))
1204 (format port "outputs: ~a~%" (string-join (package-outputs p)))
1205 (format port "systems: ~a~%"
1206 (string-join (package-transitive-supported-systems p)))
1207 (format port "dependencies: ~a~%"
1208 (match (package-direct-inputs p)
1209 (((labels inputs . _) ...)
1210 (dependencies->recutils (filter package? inputs)))))
1211 (format port "location: ~a~%"
1212 (or (and=> (package-location p) location->string)
1213 (G_ "unknown")))
1214
1215 ;; Note: Starting from version 1.6 or recutils, hyphens are not allowed in
1216 ;; field identifiers.
1217 (format port "homepage: ~a~%" (package-home-page p))
1218
1219 (format port "license: ~a~%"
1220 (match (package-license p)
1221 (((? license? licenses) ...)
1222 (string-join (map license-name licenses)
1223 ", "))
1224 ((? license? license)
1225 (license-name license))
1226 (x
1227 (G_ "unknown"))))
1228 (format port "synopsis: ~a~%"
1229 (string-map (match-lambda
1230 (#\newline #\space)
1231 (chr chr))
1232 (or (and=> (package-synopsis-string p) P_)
1233 "")))
1234 (format port "~a~%"
1235 (string->recutils
1236 (string-trim-right
1237 (parameterize ((%text-width width*))
1238 (texi->plain-text
1239 (string-append "description: "
1240 (or (and=> (package-description p) P_)
1241 ""))))
1242 #\newline)))
1243 (for-each (match-lambda
1244 ((field . value)
1245 (let ((field (symbol->string field)))
1246 (format port "~a: ~a~%"
1247 field
1248 (fill-paragraph (object->string value) width*
1249 (string-length field))))))
1250 extra-fields)
1251 (newline port))
1252
1253 \f
1254 ;;;
1255 ;;; Searching.
1256 ;;;
1257
1258 (define (relevance obj regexps metrics)
1259 "Compute a \"relevance score\" for OBJ as a function of its number of
1260 matches of REGEXPS and accordingly to METRICS. METRICS is list of
1261 field/weight pairs, where FIELD is a procedure that returns a string or list
1262 of strings describing OBJ, and WEIGHT is a positive integer denoting the
1263 weight of this field in the final score.
1264
1265 A score of zero means that OBJ does not match any of REGEXPS. The higher the
1266 score, the more relevant OBJ is to REGEXPS."
1267 (define (score str)
1268 (define scores
1269 (map (lambda (regexp)
1270 (fold-matches regexp str 0
1271 (lambda (m score)
1272 (+ score
1273 (if (string=? (match:substring m) str)
1274 5 ;exact match
1275 1)))))
1276 regexps))
1277
1278 ;; Return zero if one of REGEXPS doesn't match.
1279 (if (any zero? scores)
1280 0
1281 (reduce + 0 scores)))
1282
1283 (fold (lambda (metric relevance)
1284 (match metric
1285 ((field . weight)
1286 (match (field obj)
1287 (#f relevance)
1288 ((? string? str)
1289 (+ relevance (* (score str) weight)))
1290 ((lst ...)
1291 (+ relevance (* weight (apply + (map score lst)))))))))
1292 0
1293 metrics))
1294
1295 (define %package-metrics
1296 ;; Metrics used to compute the "relevance score" of a package against a set
1297 ;; of regexps.
1298 `((,package-name . 4)
1299
1300 ;; Match against uncommon outputs.
1301 (,(lambda (package)
1302 (filter (lambda (output)
1303 (not (member output
1304 ;; Some common outpus shared by many packages.
1305 '("out" "doc" "debug" "lib" "include" "bin"))))
1306 (package-outputs package)))
1307 . 1)
1308
1309 ;; Match regexps on the raw Texinfo since formatting it is quite expensive
1310 ;; and doesn't have much of an effect on search results.
1311 (,(lambda (package)
1312 (and=> (package-synopsis package) P_)) . 3)
1313 (,(lambda (package)
1314 (and=> (package-description package) P_)) . 2)
1315
1316 (,(lambda (type)
1317 (match (and=> (package-location type) location-file)
1318 ((? string? file) (basename file ".scm"))
1319 (#f "")))
1320 . 1)))
1321
1322 (define (package-relevance package regexps)
1323 "Return a score denoting the relevance of PACKAGE for REGEXPS. A score of
1324 zero means that PACKAGE does not match any of REGEXPS."
1325 (relevance package regexps %package-metrics))
1326
1327 (define* (display-search-results matches port
1328 #:key
1329 (command "guix search")
1330 (print package->recutils))
1331 "Display MATCHES, a list of object/score pairs, by calling PRINT on each of
1332 them. If PORT is a terminal, print at most a full screen of results."
1333 (define first-line
1334 (port-line port))
1335
1336 (define max-rows
1337 (and first-line (isatty? port)
1338 (terminal-rows port)))
1339
1340 (define (line-count str)
1341 (string-count str #\newline))
1342
1343 (let loop ((matches matches))
1344 (match matches
1345 (((package . score) rest ...)
1346 (let ((text (call-with-output-string
1347 (lambda (port)
1348 (print package port
1349 #:extra-fields
1350 `((relevance . ,score)))))))
1351 (if (and max-rows
1352 (> (port-line port) first-line) ;print at least one result
1353 (> (+ 4 (line-count text) (port-line port))
1354 max-rows))
1355 (unless (null? rest)
1356 (display-hint (format #f (G_ "Run @code{~a ... | less} \
1357 to view all the results.")
1358 command)))
1359 (begin
1360 (display text port)
1361 (loop rest)))))
1362 (()
1363 #t))))
1364
1365 \f
1366 (define (string->generations str)
1367 "Return the list of generations matching a pattern in STR. This function
1368 accepts the following patterns: \"1\", \"1,2,3\", \"1..9\", \"1..\", \"..9\"."
1369 (define (maybe-integer)
1370 (let ((x (string->number str)))
1371 (and (integer? x)
1372 x)))
1373
1374 (define (maybe-comma-separated-integers)
1375 (let ((lst (delete-duplicates
1376 (map string->number
1377 (string-split str #\,)))))
1378 (and (every integer? lst)
1379 lst)))
1380
1381 (cond ((maybe-integer)
1382 =>
1383 list)
1384 ((maybe-comma-separated-integers)
1385 =>
1386 identity)
1387 ((string-match "^([0-9]+)\\.\\.([0-9]+)$" str)
1388 =>
1389 (lambda (match)
1390 (let ((s (string->number (match:substring match 1)))
1391 (e (string->number (match:substring match 2))))
1392 (and (every integer? (list s e))
1393 (<= s e)
1394 (iota (1+ (- e s)) s)))))
1395 ((string-match "^([0-9]+)\\.\\.$" str)
1396 =>
1397 (lambda (match)
1398 (let ((s (string->number (match:substring match 1))))
1399 (and (integer? s)
1400 `(>= ,s)))))
1401 ((string-match "^\\.\\.([0-9]+)$" str)
1402 =>
1403 (lambda (match)
1404 (let ((e (string->number (match:substring match 1))))
1405 (and (integer? e)
1406 `(<= ,e)))))
1407 (else #f)))
1408
1409 (define (string->duration str)
1410 "Return the duration matching a pattern in STR. This function accepts the
1411 following patterns: \"1d\", \"1w\", \"1m\"."
1412 (define (hours->duration hours match)
1413 (make-time time-duration 0
1414 (* 3600 hours (string->number (match:substring match 1)))))
1415
1416 (cond ((string-match "^([0-9]+)s$" str)
1417 =>
1418 (lambda (match)
1419 (make-time time-duration 0
1420 (string->number (match:substring match 1)))))
1421 ((string-match "^([0-9]+)h$" str)
1422 =>
1423 (lambda (match)
1424 (hours->duration 1 match)))
1425 ((string-match "^([0-9]+)d$" str)
1426 =>
1427 (lambda (match)
1428 (hours->duration 24 match)))
1429 ((string-match "^([0-9]+)w$" str)
1430 =>
1431 (lambda (match)
1432 (hours->duration (* 24 7) match)))
1433 ((string-match "^([0-9]+)m$" str)
1434 =>
1435 (lambda (match)
1436 (hours->duration (* 24 30) match)))
1437 (else #f)))
1438
1439 (define* (matching-generations str profile
1440 #:key (duration-relation <=))
1441 "Return the list of available generations matching a pattern in STR. See
1442 'string->generations' and 'string->duration' for the list of valid patterns.
1443 When STR is a duration pattern, return all the generations whose ctime has
1444 DURATION-RELATION with the current time."
1445 (define (valid-generations lst)
1446 (define (valid-generation? n)
1447 (any (cut = n <>) (generation-numbers profile)))
1448
1449 (fold-right (lambda (x acc)
1450 (if (valid-generation? x)
1451 (cons x acc)
1452 acc))
1453 '()
1454 lst))
1455
1456 (define (filter-generations generations)
1457 (match generations
1458 (() '())
1459 (('>= n)
1460 (drop-while (cut > n <>)
1461 (generation-numbers profile)))
1462 (('<= n)
1463 (valid-generations (iota n 1)))
1464 ((lst ..1)
1465 (valid-generations lst))
1466 (x #f)))
1467
1468 (define (filter-by-duration duration)
1469 (define (time-at-midnight time)
1470 ;; Return TIME at midnight by setting nanoseconds, seconds, minutes, and
1471 ;; hours to zeros.
1472 (let ((d (time-utc->date time)))
1473 (date->time-utc
1474 (make-date 0 0 0 0
1475 (date-day d) (date-month d)
1476 (date-year d) (date-zone-offset d)))))
1477
1478 (define generation-ctime-alist
1479 (map (lambda (number)
1480 (cons number
1481 (time-second
1482 (time-at-midnight
1483 (generation-time profile number)))))
1484 (generation-numbers profile)))
1485
1486 (match duration
1487 (#f #f)
1488 (res
1489 (let ((s (time-second
1490 (subtract-duration (time-at-midnight (current-time))
1491 duration))))
1492 (delete #f (map (lambda (x)
1493 (and (duration-relation s (cdr x))
1494 (first x)))
1495 generation-ctime-alist))))))
1496
1497 (cond ((string->generations str)
1498 =>
1499 filter-generations)
1500 ((string->duration str)
1501 =>
1502 filter-by-duration)
1503 (else #f)))
1504
1505 (define (display-generation profile number)
1506 "Display a one-line summary of generation NUMBER of PROFILE."
1507 (unless (zero? number)
1508 (let ((header (format #f (highlight (G_ "Generation ~a\t~a")) number
1509 (date->string
1510 (time-utc->date
1511 (generation-time profile number))
1512 ;; TRANSLATORS: This is a format-string for date->string.
1513 ;; Please choose a format that corresponds to the
1514 ;; usual way of presenting dates in your locale.
1515 ;; See https://www.gnu.org/software/guile/manual/html_node/SRFI_002d19-Date-to-string.html
1516 ;; for details.
1517 (G_ "~b ~d ~Y ~T"))))
1518 (current (generation-number profile)))
1519 (if (= number current)
1520 ;; TRANSLATORS: The word "current" here is an adjective for
1521 ;; "Generation", as in "current generation". Use the appropriate
1522 ;; gender where applicable.
1523 (format #t (G_ "~a\t(current)~%") header)
1524 (format #t "~a~%" header)))))
1525
1526 (define (display-profile-content-diff profile gen1 gen2)
1527 "Display the changed packages in PROFILE GEN2 compared to generation GEN1."
1528
1529 (define (equal-entry? first second)
1530 (string= (manifest-entry-item first) (manifest-entry-item second)))
1531
1532 (define (display-entry entry prefix)
1533 (match entry
1534 (($ <manifest-entry> name version output location _)
1535 (format #t " ~a ~a\t~a\t~a\t~a~%" prefix name version output location))))
1536
1537 (define (list-entries number)
1538 (manifest-entries (profile-manifest (generation-file-name profile number))))
1539
1540 (define (display-diff profile old new)
1541 (display-generation profile new)
1542 (let ((added (lset-difference
1543 equal-entry? (list-entries new) (list-entries old)))
1544 (removed (lset-difference
1545 equal-entry? (list-entries old) (list-entries new))))
1546 (for-each (cut display-entry <> "+") added)
1547 (for-each (cut display-entry <> "-") removed)
1548 (newline)))
1549
1550 (display-diff profile gen1 gen2))
1551
1552 (define (display-profile-content profile number)
1553 "Display the packages in PROFILE, generation NUMBER, in a human-readable
1554 way."
1555 (for-each (match-lambda
1556 (($ <manifest-entry> name version output location _)
1557 (format #t " ~a\t~a\t~a\t~a~%"
1558 name version output location)))
1559
1560 ;; Show most recently installed packages last.
1561 (reverse
1562 (manifest-entries
1563 (profile-manifest (generation-file-name profile number))))))
1564
1565 (define (display-generation-change previous current)
1566 (format #t (G_ "switched from generation ~a to ~a~%") previous current))
1567
1568 (define (roll-back* store profile)
1569 "Like 'roll-back', but display what is happening."
1570 (call-with-values
1571 (lambda ()
1572 (roll-back store profile))
1573 display-generation-change))
1574
1575 (define (switch-to-generation* profile number)
1576 "Like 'switch-generation', but display what is happening."
1577 (let ((previous (switch-to-generation profile number)))
1578 (display-generation-change previous number)))
1579
1580 (define (delete-generation* store profile generation)
1581 "Like 'delete-generation', but display what is going on."
1582 (format #t (G_ "deleting ~a~%")
1583 (generation-file-name profile generation))
1584 (delete-generation store profile generation))
1585
1586 (define* (package-specification->name+version+output spec
1587 #:optional (output "out"))
1588 "Parse package specification SPEC and return three value: the specified
1589 package name, version number (or #f), and output name (or OUTPUT). SPEC may
1590 optionally contain a version number and an output name, as in these examples:
1591
1592 guile
1593 guile@2.0.9
1594 guile:debug
1595 guile@2.0.9:debug
1596 "
1597 (let*-values (((name sub-drv)
1598 (match (string-rindex spec #\:)
1599 (#f (values spec output))
1600 (colon (values (substring spec 0 colon)
1601 (substring spec (+ 1 colon))))))
1602 ((name version)
1603 (package-name->name+version name)))
1604 (values name version sub-drv)))
1605
1606 \f
1607 ;;;
1608 ;;; Command-line option processing.
1609 ;;;
1610
1611 (define (show-guix-usage)
1612 (format (current-error-port)
1613 (G_ "Try `guix --help' for more information.~%"))
1614 (exit 1))
1615
1616 (define (command-files)
1617 "Return the list of source files that define Guix sub-commands."
1618 (define directory
1619 (and=> (search-path %load-path "guix.scm")
1620 (compose (cut string-append <> "/guix/scripts")
1621 dirname)))
1622
1623 (define dot-scm?
1624 (cut string-suffix? ".scm" <>))
1625
1626 (if directory
1627 (scandir directory dot-scm?)
1628 '()))
1629
1630 (define (commands)
1631 "Return the list of Guix command names."
1632 (map (compose (cut string-drop-right <> 4)
1633 basename)
1634 (command-files)))
1635
1636 (define (show-guix-help)
1637 (define (internal? command)
1638 (member command '("substitute" "authenticate" "offload"
1639 "perform-download")))
1640
1641 (format #t (G_ "Usage: guix COMMAND ARGS...
1642 Run COMMAND with ARGS.\n"))
1643 (newline)
1644 (format #t (G_ "COMMAND must be one of the sub-commands listed below:\n"))
1645 (newline)
1646 ;; TODO: Display a synopsis of each command.
1647 (format #t "~{ ~a~%~}" (sort (remove internal? (commands))
1648 string<?))
1649 (show-bug-report-information))
1650
1651 (define (run-guix-command command . args)
1652 "Run COMMAND with the given ARGS. Report an error when COMMAND is not
1653 found."
1654 (define module
1655 (catch 'misc-error
1656 (lambda ()
1657 (resolve-interface `(guix scripts ,command)))
1658 (lambda -
1659 (format (current-error-port)
1660 (G_ "guix: ~a: command not found~%") command)
1661 (show-guix-usage))))
1662
1663 (let ((command-main (module-ref module
1664 (symbol-append 'guix- command))))
1665 (parameterize ((program-name command))
1666 ;; Disable canonicalization so we don't don't stat unreasonably.
1667 (with-fluids ((%file-port-name-canonicalization #f))
1668 (dynamic-wind
1669 (const #f)
1670 (lambda ()
1671 (apply command-main args))
1672 (lambda ()
1673 ;; Abuse 'exit-hook' (which is normally meant to be used by the
1674 ;; REPL) to run things like profiling hooks upon completion.
1675 (run-hook exit-hook)))))))
1676
1677 (define (run-guix . args)
1678 "Run the 'guix' command defined by command line ARGS.
1679 Unlike 'guix-main', this procedure assumes that locale, i18n support,
1680 and signal handling has already been set up."
1681 (define option? (cut string-prefix? "-" <>))
1682
1683 ;; The default %LOAD-EXTENSIONS includes the empty string, which doubles the
1684 ;; number of 'stat' calls per entry in %LOAD-PATH. Shamelessly remove it.
1685 (set! %load-extensions '(".scm"))
1686
1687 (match args
1688 (()
1689 (format (current-error-port)
1690 (G_ "guix: missing command name~%"))
1691 (show-guix-usage))
1692 ((or ("-h") ("--help"))
1693 (show-guix-help))
1694 ((or ("-V") ("--version"))
1695 (show-version-and-exit "guix"))
1696 (((? option? o) args ...)
1697 (format (current-error-port)
1698 (G_ "guix: unrecognized option '~a'~%") o)
1699 (show-guix-usage))
1700 (("help" command)
1701 (apply run-guix-command (string->symbol command)
1702 '("--help")))
1703 (("help" args ...)
1704 (show-guix-help))
1705 ((command args ...)
1706 (apply run-guix-command
1707 (string->symbol command)
1708 args))))
1709
1710 (define (guix-main arg0 . args)
1711 (initialize-guix)
1712 (apply run-guix args))
1713
1714 ;;; ui.scm ends here