2013-01-05 18:47:50 -05:00
|
|
|
|
;;; GNU Guix --- Functional package management for GNU
|
2023-01-03 06:19:48 -05:00
|
|
|
|
;;; Copyright © 2012-2023 Ludovic Courtès <ludo@gnu.org>
|
2018-03-16 18:29:31 -04:00
|
|
|
|
;;; Copyright © 2013, 2018 Mark H Weaver <mhw@netris.org>
|
2013-04-21 04:08:40 -04:00
|
|
|
|
;;; Copyright © 2013 Nikita Karetnikov <nikita@karetnikov.org>
|
2015-09-10 05:37:36 -04:00
|
|
|
|
;;; Copyright © 2014 Cyril Roelandt <tipecaml@gmail.com>
|
|
|
|
|
;;; Copyright © 2014 Cyrill Schenkel <cyrill.schenkel@gmail.com>
|
2017-03-20 06:41:41 -04:00
|
|
|
|
;;; Copyright © 2014, 2015, 2017 Alex Kost <alezost@gmail.com>
|
2015-09-10 05:37:36 -04:00
|
|
|
|
;;; Copyright © 2015 David Thompson <davet@gnu.org>
|
2016-05-16 11:55:38 -04:00
|
|
|
|
;;; Copyright © 2015, 2016 Mathieu Lirzin <mthl@gnu.org>
|
2016-10-26 08:53:29 -04:00
|
|
|
|
;;; Copyright © 2016 Roel Janssen <roel@gnu.org>
|
|
|
|
|
;;; Copyright © 2016 Benz Schenk <benz.schenk@uzh.ch>
|
2018-07-07 00:41:35 -04:00
|
|
|
|
;;; Copyright © 2018 Kyle Meyer <kyle@kyleam.com>
|
2018-09-04 11:32:27 -04:00
|
|
|
|
;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net>
|
2019-05-06 04:51:30 -04:00
|
|
|
|
;;; Copyright © 2019 Chris Marusich <cmmarusich@gmail.com>
|
2020-11-15 13:25:00 -05:00
|
|
|
|
;;; Copyright © 2019, 2020 Tobias Geerinckx-Rice <me@tobias.gr>
|
2021-01-07 12:08:47 -05:00
|
|
|
|
;;; Copyright © 2019, 2021 Simon Tournier <zimon.toutoune@gmail.com>
|
2020-05-31 19:18:01 -04:00
|
|
|
|
;;; Copyright © 2020 Arun Isaac <arunisaac@systemreboot.net>
|
2020-09-02 11:52:16 -04:00
|
|
|
|
;;; Copyright © 2020 Maxim Cournoyer <maxim.cournoyer@gmail.com>
|
2018-01-09 17:20:12 -05:00
|
|
|
|
;;; Copyright © 2018 Steve Sprang <scs@stevesprang.com>
|
2022-06-08 05:50:28 -04:00
|
|
|
|
;;; Copyright © 2022 Taiju HIGASHI <higashi@taiju.info>
|
2022-06-26 08:37:56 -04:00
|
|
|
|
;;; Copyright © 2022 Liliana Marie Prikler <liliana.prikler@gmail.com>
|
2012-10-31 19:50:01 -04:00
|
|
|
|
;;;
|
2013-01-05 18:47:50 -05:00
|
|
|
|
;;; This file is part of GNU Guix.
|
2012-10-31 19:50:01 -04:00
|
|
|
|
;;;
|
2013-01-05 18:47:50 -05:00
|
|
|
|
;;; GNU Guix is free software; you can redistribute it and/or modify it
|
2012-10-31 19:50:01 -04:00
|
|
|
|
;;; under the terms of the GNU General Public License as published by
|
|
|
|
|
;;; the Free Software Foundation; either version 3 of the License, or (at
|
|
|
|
|
;;; your option) any later version.
|
|
|
|
|
;;;
|
2013-01-05 18:47:50 -05:00
|
|
|
|
;;; GNU Guix is distributed in the hope that it will be useful, but
|
2012-10-31 19:50:01 -04:00
|
|
|
|
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
;;; GNU General Public License for more details.
|
|
|
|
|
;;;
|
|
|
|
|
;;; You should have received a copy of the GNU General Public License
|
2013-01-05 18:47:50 -05:00
|
|
|
|
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
2012-10-31 19:50:01 -04:00
|
|
|
|
|
|
|
|
|
(define-module (guix ui)
|
2017-11-08 04:13:45 -05:00
|
|
|
|
#:use-module (guix i18n)
|
2019-04-10 06:00:55 -04:00
|
|
|
|
#:use-module (guix colors)
|
2019-06-03 16:58:36 -04:00
|
|
|
|
#:use-module (guix diagnostics)
|
2017-04-03 17:52:19 -04:00
|
|
|
|
#:use-module (guix gexp)
|
2017-11-24 12:16:43 -05:00
|
|
|
|
#:use-module (guix sets)
|
2012-10-31 19:50:01 -04:00
|
|
|
|
#:use-module (guix utils)
|
|
|
|
|
#:use-module (guix store)
|
2012-11-03 16:19:43 -04:00
|
|
|
|
#:use-module (guix config)
|
2012-10-31 19:50:01 -04:00
|
|
|
|
#:use-module (guix packages)
|
2014-10-08 09:15:49 -04:00
|
|
|
|
#:use-module (guix profiles)
|
2013-02-20 17:41:24 -05:00
|
|
|
|
#:use-module (guix derivations)
|
2015-02-08 12:30:20 -05:00
|
|
|
|
#:use-module (guix build-system)
|
|
|
|
|
#:use-module (guix serialization)
|
2019-11-08 17:23:01 -05:00
|
|
|
|
#:use-module ((guix licenses)
|
|
|
|
|
#:select (license? license-name license-uri))
|
2017-05-31 09:26:21 -04:00
|
|
|
|
#:use-module ((guix build syscalls)
|
2019-11-29 08:53:22 -05:00
|
|
|
|
#:select (free-disk-space terminal-columns terminal-rows
|
|
|
|
|
with-file-lock/no-wait))
|
2018-03-16 18:29:31 -04:00
|
|
|
|
#:use-module ((guix build utils)
|
2018-06-09 04:21:26 -04:00
|
|
|
|
;; XXX: All we need are the bindings related to
|
|
|
|
|
;; '&invoke-error'. However, to work around the bug described
|
|
|
|
|
;; in 5d669883ecc104403c5d3ba7d172e9c02234577c, #:hide
|
|
|
|
|
;; unwanted bindings instead of #:select'ing the needed
|
|
|
|
|
;; bindings.
|
2020-01-15 09:03:08 -05:00
|
|
|
|
#:hide (package-name->name+version
|
|
|
|
|
;; Avoid "overrides core binding" warning.
|
|
|
|
|
delete))
|
2013-02-01 07:16:27 -05:00
|
|
|
|
#:use-module (srfi srfi-1)
|
2020-09-01 16:13:11 -04:00
|
|
|
|
#:use-module (srfi srfi-9 gnu)
|
2013-02-01 07:16:27 -05:00
|
|
|
|
#:use-module (srfi srfi-11)
|
2013-09-19 07:07:39 -04:00
|
|
|
|
#:use-module (srfi srfi-19)
|
2012-10-31 19:50:01 -04:00
|
|
|
|
#:use-module (srfi srfi-26)
|
2015-05-25 12:25:19 -04:00
|
|
|
|
#:use-module (srfi srfi-31)
|
2012-10-31 19:50:01 -04:00
|
|
|
|
#:use-module (srfi srfi-34)
|
2014-02-21 11:45:04 -05:00
|
|
|
|
#:use-module (srfi srfi-35)
|
2013-05-10 06:33:18 -04:00
|
|
|
|
#:autoload (ice-9 ftw) (scandir)
|
2012-11-19 17:02:59 -05:00
|
|
|
|
#:use-module (ice-9 match)
|
2013-02-20 17:41:24 -05:00
|
|
|
|
#:use-module (ice-9 format)
|
2013-09-19 07:07:39 -04:00
|
|
|
|
#:use-module (ice-9 regex)
|
2020-06-06 17:17:02 -04:00
|
|
|
|
#:autoload (ice-9 popen) (open-pipe* close-pipe)
|
2015-05-25 16:52:41 -04:00
|
|
|
|
#:autoload (system repl repl) (start-repl)
|
|
|
|
|
#:autoload (system repl debug) (make-debug stack->vector)
|
2015-08-06 18:10:43 -04:00
|
|
|
|
#:use-module (texinfo)
|
|
|
|
|
#:use-module (texinfo plain-text)
|
|
|
|
|
#:use-module (texinfo string-utils)
|
2019-06-03 16:58:36 -04:00
|
|
|
|
|
|
|
|
|
;; Re-exports for backward compatibility.
|
|
|
|
|
#:re-export (G_ N_ P_ ;now in (guix i18n)
|
|
|
|
|
|
|
|
|
|
warning info report-error leave ;now in (guix diagnostics)
|
|
|
|
|
location->string
|
|
|
|
|
guix-warning-port program-name)
|
|
|
|
|
#:export (display-hint
|
2015-05-18 07:49:44 -04:00
|
|
|
|
make-user-module
|
|
|
|
|
load*
|
2015-04-07 16:27:45 -04:00
|
|
|
|
warn-about-load-error
|
2012-11-03 16:19:43 -04:00
|
|
|
|
show-version-and-exit
|
2013-01-05 09:55:47 -05:00
|
|
|
|
show-bug-report-information
|
2015-10-28 10:53:17 -04:00
|
|
|
|
make-regexp*
|
2013-05-20 12:14:55 -04:00
|
|
|
|
string->number*
|
2014-04-08 16:01:44 -04:00
|
|
|
|
size->number
|
2015-07-23 09:08:39 -04:00
|
|
|
|
show-derivation-outputs
|
2020-03-18 17:19:05 -04:00
|
|
|
|
build-notifier
|
2013-02-20 17:41:24 -05:00
|
|
|
|
show-what-to-build
|
2015-05-20 18:42:35 -04:00
|
|
|
|
show-what-to-build*
|
2014-10-08 09:15:49 -04:00
|
|
|
|
show-manifest-transaction
|
2020-11-26 16:53:08 -05:00
|
|
|
|
guard*
|
2012-10-31 19:50:01 -04:00
|
|
|
|
call-with-error-handling
|
2012-11-19 17:02:59 -05:00
|
|
|
|
with-error-handling
|
2018-05-04 09:05:05 -04:00
|
|
|
|
with-unbound-variable-handling
|
2015-07-15 12:01:05 -04:00
|
|
|
|
leave-on-EPIPE
|
2013-11-18 17:08:20 -05:00
|
|
|
|
read/eval
|
2013-03-01 15:55:42 -05:00
|
|
|
|
read/eval-package-expression
|
2018-07-02 17:51:20 -04:00
|
|
|
|
check-available-space
|
2020-03-20 07:44:43 -04:00
|
|
|
|
indented-string
|
2013-02-01 07:16:27 -05:00
|
|
|
|
fill-paragraph
|
2017-09-13 10:07:30 -04:00
|
|
|
|
%text-width
|
2015-09-20 06:27:23 -04:00
|
|
|
|
texi->plain-text
|
2015-08-06 18:10:43 -04:00
|
|
|
|
package-description-string
|
2017-03-20 06:41:41 -04:00
|
|
|
|
package-synopsis-string
|
2013-02-01 07:16:27 -05:00
|
|
|
|
string->recutils
|
Replace individual scripts with master 'guix' script.
* scripts/guix.in: New script.
* Makefile.am (bin_SCRIPTS): Add 'scripts/guix'. Remove 'guix-build',
'guix-download', 'guix-import', 'guix-package', and 'guix-gc'.
(MODULES): Add 'guix/scripts/build.scm', 'guix/scripts/download.scm',
'guix/scripts/import.scm', 'guix/scripts/package.scm', and
'guix/scripts/gc.scm'.
* configure.ac (AC_CONFIG_FILES): Add 'scripts/guix'. Remove 'guix-build',
'guix-download', 'guix-import', 'guix-package', and 'guix-gc'.
* guix-build.in, guix-download.in, guix-gc.in, guix-import.in,
guix-package.in: Remove shell script boilerplate. Move to guix-COMMAND.in
to guix/scripts/COMMAND.scm. Rename module from (guix-COMMAND) to
(guix scripts COMMAND). Change "guix-COMMAND" to "guix COMMAND" in
usage help string.
* pre-inst-env.in: Add "@abs_top_builddir@/scripts" to the front of $PATH.
Export $GUIX_UNINSTALLED.
* tests/guix-build.sh, tests/guix-daemon.sh, tests/guix-download.sh,
tests/guix-gc.sh, tests/guix-package.sh: Use "guix COMMAND" instead of
"guix-COMMAND".
* doc/guix.texi: Replace all occurrences of "guix-COMMAND" with
"guix COMMAND".
* po/POTFILES.in: Update.
2013-02-14 04:15:25 -05:00
|
|
|
|
package->recutils
|
2013-11-01 11:57:48 -04:00
|
|
|
|
package-specification->name+version+output
|
2019-06-25 17:37:32 -04:00
|
|
|
|
|
2022-02-09 16:21:58 -05:00
|
|
|
|
pager-wrapped-port
|
2020-06-28 16:36:43 -04:00
|
|
|
|
with-paginated-output-port
|
2017-09-13 09:07:17 -04:00
|
|
|
|
relevance
|
|
|
|
|
package-relevance
|
2019-06-25 17:37:32 -04:00
|
|
|
|
display-search-results
|
|
|
|
|
|
2019-11-29 08:53:22 -05:00
|
|
|
|
with-profile-lock
|
2013-09-19 07:07:39 -04:00
|
|
|
|
string->generations
|
|
|
|
|
string->duration
|
2015-10-26 14:03:56 -04:00
|
|
|
|
matching-generations
|
2015-10-26 16:16:20 -04:00
|
|
|
|
display-generation
|
|
|
|
|
display-profile-content
|
2016-10-26 08:53:29 -04:00
|
|
|
|
display-profile-content-diff
|
2015-10-26 18:01:06 -04:00
|
|
|
|
roll-back*
|
|
|
|
|
switch-to-generation*
|
|
|
|
|
delete-generation*
|
2019-09-15 11:54:05 -04:00
|
|
|
|
|
|
|
|
|
%default-message-language
|
|
|
|
|
current-message-language
|
|
|
|
|
|
Replace individual scripts with master 'guix' script.
* scripts/guix.in: New script.
* Makefile.am (bin_SCRIPTS): Add 'scripts/guix'. Remove 'guix-build',
'guix-download', 'guix-import', 'guix-package', and 'guix-gc'.
(MODULES): Add 'guix/scripts/build.scm', 'guix/scripts/download.scm',
'guix/scripts/import.scm', 'guix/scripts/package.scm', and
'guix/scripts/gc.scm'.
* configure.ac (AC_CONFIG_FILES): Add 'scripts/guix'. Remove 'guix-build',
'guix-download', 'guix-import', 'guix-package', and 'guix-gc'.
* guix-build.in, guix-download.in, guix-gc.in, guix-import.in,
guix-package.in: Remove shell script boilerplate. Move to guix-COMMAND.in
to guix/scripts/COMMAND.scm. Rename module from (guix-COMMAND) to
(guix scripts COMMAND). Change "guix-COMMAND" to "guix COMMAND" in
usage help string.
* pre-inst-env.in: Add "@abs_top_builddir@/scripts" to the front of $PATH.
Export $GUIX_UNINSTALLED.
* tests/guix-build.sh, tests/guix-daemon.sh, tests/guix-download.sh,
tests/guix-gc.sh, tests/guix-package.sh: Use "guix COMMAND" instead of
"guix-COMMAND".
* doc/guix.texi: Replace all occurrences of "guix-COMMAND" with
"guix COMMAND".
* po/POTFILES.in: Update.
2013-02-14 04:15:25 -05:00
|
|
|
|
run-guix-command
|
2015-08-16 03:28:04 -04:00
|
|
|
|
run-guix
|
2019-04-09 16:39:26 -04:00
|
|
|
|
guix-main))
|
2012-10-31 19:50:01 -04:00
|
|
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
|
;;;
|
|
|
|
|
;;; User interface facilities for command-line tools.
|
|
|
|
|
;;;
|
|
|
|
|
;;; Code:
|
|
|
|
|
|
2017-11-09 17:31:18 -05:00
|
|
|
|
(define (print-unbound-variable-error port key args default-printer)
|
|
|
|
|
;; Print unbound variable errors more nicely, and in the right language.
|
|
|
|
|
(match args
|
|
|
|
|
((proc message (variable) _ ...)
|
|
|
|
|
;; We can always omit PROC because when it's useful (i.e., different from
|
|
|
|
|
;; "module-lookup"), it gets displayed before.
|
2018-05-04 09:05:05 -04:00
|
|
|
|
(format port (G_ "error: ~a: unbound variable") variable))
|
2017-11-09 17:31:18 -05:00
|
|
|
|
(_
|
|
|
|
|
(default-printer))))
|
|
|
|
|
|
|
|
|
|
(set-exception-printer! 'unbound-variable print-unbound-variable-error)
|
|
|
|
|
|
2015-05-18 07:49:44 -04:00
|
|
|
|
(define (make-user-module modules)
|
|
|
|
|
"Return a new user module with the additional MODULES loaded."
|
|
|
|
|
;; Module in which the machine description file is loaded.
|
|
|
|
|
(let ((module (make-fresh-user-module)))
|
|
|
|
|
(for-each (lambda (iface)
|
|
|
|
|
(module-use! module (resolve-interface iface)))
|
|
|
|
|
modules)
|
|
|
|
|
module))
|
|
|
|
|
|
2018-05-04 06:13:53 -04:00
|
|
|
|
(define (last-frame-with-source stack)
|
|
|
|
|
"Walk stack upwards and return the last frame that has source location
|
|
|
|
|
information, or #f if it could not be found."
|
2015-05-25 12:25:19 -04:00
|
|
|
|
(define (frame-with-source frame)
|
|
|
|
|
;; Walk from FRAME upwards until source location information is found.
|
|
|
|
|
(let loop ((frame frame)
|
|
|
|
|
(previous frame))
|
|
|
|
|
(if (not frame)
|
|
|
|
|
previous
|
2020-01-17 11:11:34 -05:00
|
|
|
|
|
|
|
|
|
;; On Guile 3, the latest frame with source may be that of
|
|
|
|
|
;; 'raise-exception' in boot-9.scm. Skip it.
|
|
|
|
|
(if (and (frame-source frame)
|
|
|
|
|
(not (eq? 'raise-exception (frame-procedure-name frame))))
|
2015-05-25 12:25:19 -04:00
|
|
|
|
frame
|
|
|
|
|
(loop (frame-previous frame) frame)))))
|
|
|
|
|
|
2018-05-04 06:13:53 -04:00
|
|
|
|
(let* ((depth (stack-length stack))
|
|
|
|
|
(last (and (> depth 0) (stack-ref stack 0))))
|
|
|
|
|
(frame-with-source (if (> depth 1)
|
|
|
|
|
(stack-ref stack 1) ;skip the 'throw' frame
|
|
|
|
|
last))))
|
|
|
|
|
|
2021-05-26 16:30:31 -04:00
|
|
|
|
(define-syntax-rule (without-compiler-optimizations exp)
|
|
|
|
|
;; Compile with the baseline compiler (-O1), which is much less expensive
|
|
|
|
|
;; than -O2.
|
|
|
|
|
(parameterize (((@ (system base compile) default-optimization-level) 1))
|
|
|
|
|
exp))
|
2021-05-17 17:16:40 -04:00
|
|
|
|
|
2023-08-11 11:20:06 -04:00
|
|
|
|
(define (try-canonicalize-path file)
|
|
|
|
|
"Like 'canonicalize-path', but return FILE as-is if 'canonicalize-path'
|
|
|
|
|
throws.
|
|
|
|
|
|
|
|
|
|
This is necessary for corner cases where 'canonicalize-path' fails. One
|
|
|
|
|
example is on Linux when a /dev/fd/N file denotes a pipe, represented as a
|
|
|
|
|
symlink to a non-existent file like 'pipe:[1234]', as in this example:
|
|
|
|
|
|
|
|
|
|
sh -c 'stat $(readlink -f /dev/fd/1)' | cat"
|
|
|
|
|
(catch 'system-error
|
|
|
|
|
(lambda ()
|
|
|
|
|
(canonicalize-path file))
|
|
|
|
|
(const file)))
|
|
|
|
|
|
2018-05-04 06:13:53 -04:00
|
|
|
|
(define* (load* file user-module
|
|
|
|
|
#:key (on-error 'nothing-special))
|
|
|
|
|
"Load the user provided Scheme source code FILE."
|
2015-05-25 16:52:41 -04:00
|
|
|
|
(define (error-string frame args)
|
|
|
|
|
(call-with-output-string
|
2018-03-05 04:52:32 -05:00
|
|
|
|
(lambda (port)
|
|
|
|
|
(apply display-error frame port (cdr args)))))
|
2015-05-25 16:52:41 -04:00
|
|
|
|
|
|
|
|
|
(define tag
|
|
|
|
|
(make-prompt-tag "user-code"))
|
|
|
|
|
|
2015-05-18 07:49:44 -04:00
|
|
|
|
(catch #t
|
|
|
|
|
(lambda ()
|
2015-05-25 12:25:19 -04:00
|
|
|
|
;; XXX: Force a recompilation to avoid ABI issues.
|
2021-05-17 16:47:18 -04:00
|
|
|
|
(set! %fresh-auto-compile #t)
|
2015-05-25 12:25:19 -04:00
|
|
|
|
(set! %load-should-auto-compile #t)
|
2015-05-18 07:49:44 -04:00
|
|
|
|
|
|
|
|
|
(save-module-excursion
|
|
|
|
|
(lambda ()
|
|
|
|
|
(set-current-module user-module)
|
|
|
|
|
|
2015-05-25 12:25:19 -04:00
|
|
|
|
;; Hide the "auto-compiling" messages.
|
|
|
|
|
(parameterize ((current-warning-port (%make-void-port "w")))
|
2015-05-25 16:52:41 -04:00
|
|
|
|
(call-with-prompt tag
|
|
|
|
|
(lambda ()
|
|
|
|
|
;; Give 'load' an absolute file name so that it doesn't try to
|
|
|
|
|
;; search for FILE in %LOAD-PATH. Note: use 'load', not
|
2020-04-16 17:17:16 -04:00
|
|
|
|
;; 'primitive-load', so that FILE is compiled, which then allows
|
|
|
|
|
;; us to provide better error reporting with source line numbers.
|
2021-05-17 17:16:40 -04:00
|
|
|
|
(without-compiler-optimizations
|
2023-08-11 11:20:06 -04:00
|
|
|
|
(load (try-canonicalize-path file))))
|
2015-05-25 16:52:41 -04:00
|
|
|
|
(const #f))))))
|
2015-05-25 12:25:19 -04:00
|
|
|
|
(lambda _
|
|
|
|
|
;; XXX: Errors are reported from the pre-unwind handler below, but
|
|
|
|
|
;; calling 'exit' from there has no effect, so we call it here.
|
|
|
|
|
(exit 1))
|
|
|
|
|
(rec (handle-error . args)
|
|
|
|
|
;; Capture the stack up to this procedure call, excluded, and pass
|
|
|
|
|
;; the faulty stack frame to 'report-load-error'.
|
2015-05-25 16:52:41 -04:00
|
|
|
|
(let* ((stack (make-stack #t handle-error tag))
|
2018-05-04 06:13:53 -04:00
|
|
|
|
(frame (last-frame-with-source stack)))
|
2015-05-25 16:52:41 -04:00
|
|
|
|
|
|
|
|
|
(report-load-error file args frame)
|
|
|
|
|
|
|
|
|
|
(case on-error
|
|
|
|
|
((debug)
|
|
|
|
|
(newline)
|
ui: Rename '_' to 'G_'.
This avoids collisions with '_' when the latter is used as a 'match'
pattern for instance. See
<https://lists.gnu.org/archive/html/guix-devel/2017-04/msg00464.html>.
* guix/ui.scm: Rename '_' to 'G_'.
* po/guix/Makevars (XGETTEXT_OPTIONS): Adjust accordingly.
* build-aux/compile-all.scm (warnings): Remove 'format'.
* gnu/packages.scm,
gnu/services.scm,
gnu/services/shepherd.scm,
gnu/system.scm,
gnu/system/shadow.scm,
guix/gnupg.scm,
guix/http-client.scm,
guix/import/cpan.scm,
guix/import/elpa.scm,
guix/import/pypi.scm,
guix/nar.scm,
guix/scripts.scm,
guix/scripts/archive.scm,
guix/scripts/authenticate.scm,
guix/scripts/build.scm,
guix/scripts/challenge.scm,
guix/scripts/container.scm,
guix/scripts/container/exec.scm,
guix/scripts/copy.scm,
guix/scripts/download.scm,
guix/scripts/edit.scm,
guix/scripts/environment.scm,
guix/scripts/gc.scm,
guix/scripts/graph.scm,
guix/scripts/hash.scm,
guix/scripts/import.scm,
guix/scripts/import/cpan.scm,
guix/scripts/import/cran.scm,
guix/scripts/import/crate.scm,
guix/scripts/import/elpa.scm,
guix/scripts/import/gem.scm,
guix/scripts/import/gnu.scm,
guix/scripts/import/hackage.scm,
guix/scripts/import/nix.scm,
guix/scripts/import/pypi.scm,
guix/scripts/import/stackage.scm,
guix/scripts/lint.scm,
guix/scripts/offload.scm,
guix/scripts/pack.scm,
guix/scripts/package.scm,
guix/scripts/perform-download.scm,
guix/scripts/publish.scm,
guix/scripts/pull.scm,
guix/scripts/refresh.scm,
guix/scripts/size.scm,
guix/scripts/substitute.scm,
guix/scripts/system.scm,
guix/ssh.scm,
guix/upstream.scm: Use 'G_' instead of '_'. Most of this change was
obtained by running: "sed -i -e's/(_ "/(G_ "/g' `find -name \*.scm`".
2017-05-03 09:57:02 -04:00
|
|
|
|
(display (G_ "entering debugger; type ',bt' for a backtrace\n"))
|
2015-05-25 16:52:41 -04:00
|
|
|
|
(start-repl #:debug (make-debug (stack->vector stack) 0
|
|
|
|
|
(error-string frame args)
|
|
|
|
|
#f)))
|
|
|
|
|
((backtrace)
|
|
|
|
|
(newline (current-error-port))
|
|
|
|
|
(display-backtrace stack (current-error-port)))
|
|
|
|
|
(else
|
|
|
|
|
#t))))))
|
2015-05-25 12:25:19 -04:00
|
|
|
|
|
2017-11-09 17:29:39 -05:00
|
|
|
|
(define (known-variable-definition variable)
|
|
|
|
|
"Search among the currently loaded modules one that defines a variable named
|
|
|
|
|
VARIABLE and return it, or #f if none was found."
|
|
|
|
|
(define (module<? m1 m2)
|
|
|
|
|
(match (module-name m2)
|
|
|
|
|
(('gnu _ ...) #t)
|
|
|
|
|
(('guix _ ...)
|
|
|
|
|
(match (module-name m1)
|
|
|
|
|
(('gnu _ ...) #f)
|
|
|
|
|
(_ #t)))
|
|
|
|
|
(_ #f)))
|
|
|
|
|
|
2017-11-24 12:16:43 -05:00
|
|
|
|
(let loop ((modules (list (resolve-module '() #f #f #:ensure #f)))
|
|
|
|
|
(suggestions '())
|
|
|
|
|
(visited (setq)))
|
2017-11-09 17:29:39 -05:00
|
|
|
|
(match modules
|
|
|
|
|
(()
|
|
|
|
|
;; Pick the "best" suggestion.
|
|
|
|
|
(match (sort suggestions module<?)
|
|
|
|
|
(() #f)
|
|
|
|
|
((first _ ...) first)))
|
|
|
|
|
((head tail ...)
|
2017-11-24 12:16:43 -05:00
|
|
|
|
(if (set-contains? visited head)
|
|
|
|
|
(loop tail suggestions visited)
|
|
|
|
|
(let ((visited (set-insert head visited))
|
|
|
|
|
(next (append tail
|
|
|
|
|
(hash-map->list (lambda (name module)
|
|
|
|
|
module)
|
|
|
|
|
(module-submodules head)))))
|
2020-10-15 10:41:14 -04:00
|
|
|
|
(match (and=> (module-public-interface head)
|
|
|
|
|
(cut module-local-variable <> variable))
|
2017-11-24 12:16:43 -05:00
|
|
|
|
(#f (loop next suggestions visited))
|
|
|
|
|
(_
|
|
|
|
|
(match (module-name head)
|
|
|
|
|
(('gnu _ ...) head) ;must be that one
|
|
|
|
|
(_ (loop next (cons head suggestions) visited)))))))))))
|
2017-11-09 17:29:39 -05:00
|
|
|
|
|
2019-06-03 16:58:36 -04:00
|
|
|
|
(define %hint-color (color BOLD CYAN))
|
|
|
|
|
|
2023-02-24 05:15:45 -05:00
|
|
|
|
(define (texinfo-quote str)
|
|
|
|
|
"Quote at signs and braces in STR to obtain its Texinfo represention."
|
|
|
|
|
(list->string
|
|
|
|
|
(string-fold-right (lambda (chr result)
|
|
|
|
|
(if (memq chr '(#\@ #\{ #\}))
|
|
|
|
|
(cons* #\@ chr result)
|
|
|
|
|
(cons chr result)))
|
|
|
|
|
'()
|
|
|
|
|
str)))
|
|
|
|
|
|
|
|
|
|
(define* (display-hint message
|
|
|
|
|
#:key (port (current-error-port))
|
|
|
|
|
#:rest arguments)
|
|
|
|
|
"Display MESSAGE, a l10n message possibly containing Texinfo markup and
|
|
|
|
|
'format' escape, to PORT. ARGUMENTS is a (possibly empty) list of strings or
|
|
|
|
|
other objects that must match the 'format' escapes in MESSAGE."
|
2019-04-10 06:55:23 -04:00
|
|
|
|
(define colorize
|
|
|
|
|
(if (color-output? port)
|
|
|
|
|
(lambda (str)
|
2019-04-11 10:57:38 -04:00
|
|
|
|
(colorize-string str %hint-color))
|
2019-04-10 06:55:23 -04:00
|
|
|
|
identity))
|
|
|
|
|
|
|
|
|
|
(display (colorize (G_ "hint: ")) port)
|
|
|
|
|
(display
|
|
|
|
|
;; XXX: We should arrange so that the initial indent is wider.
|
|
|
|
|
(parameterize ((%text-width (max 15 (- (terminal-columns) 5))))
|
2023-02-24 05:15:45 -05:00
|
|
|
|
(texi->plain-text (match arguments
|
2023-03-16 12:11:20 -04:00
|
|
|
|
(() (format #f message))
|
2023-02-24 05:15:45 -05:00
|
|
|
|
(_ (apply format #f message
|
|
|
|
|
(map (match-lambda
|
|
|
|
|
((? string? str)
|
|
|
|
|
(texinfo-quote str))
|
|
|
|
|
(obj
|
|
|
|
|
(texinfo-quote
|
|
|
|
|
(object->string obj))))
|
|
|
|
|
arguments))))))
|
2019-04-10 06:55:23 -04:00
|
|
|
|
port))
|
2017-11-09 17:27:56 -05:00
|
|
|
|
|
2018-05-04 09:05:05 -04:00
|
|
|
|
(define* (report-unbound-variable-error args #:key frame)
|
|
|
|
|
"Return the given unbound-variable error, where ARGS is the list of 'throw'
|
|
|
|
|
arguments."
|
|
|
|
|
(match args
|
|
|
|
|
((key . args)
|
|
|
|
|
(print-exception (current-error-port) frame key args)))
|
|
|
|
|
(match args
|
|
|
|
|
(('unbound-variable proc message (variable) _ ...)
|
|
|
|
|
(match (known-variable-definition variable)
|
|
|
|
|
(#f
|
|
|
|
|
(display-hint (G_ "Did you forget a @code{use-modules} form?")))
|
|
|
|
|
((? module? module)
|
2023-02-24 05:15:45 -05:00
|
|
|
|
(display-hint (G_ "Did you forget @code{(use-modules ~a)}?")
|
|
|
|
|
(module-name module)))))))
|
2018-05-04 09:05:05 -04:00
|
|
|
|
|
2019-07-19 17:48:09 -04:00
|
|
|
|
(define (check-module-matches-file module file)
|
|
|
|
|
"Check whether FILE starts with 'define-module MODULE' and print a hint if
|
|
|
|
|
it doesn't."
|
|
|
|
|
;; This is a common mistake when people start writing their own package
|
|
|
|
|
;; definitions and try loading them with 'guix build -L …', so help them
|
|
|
|
|
;; diagnose the problem.
|
|
|
|
|
(define (hint)
|
2023-02-24 05:15:45 -05:00
|
|
|
|
(display-hint (G_ "File @file{~a} should probably start with:
|
2019-07-19 17:48:09 -04:00
|
|
|
|
|
|
|
|
|
@example\n(define-module ~a)\n@end example")
|
2023-02-24 05:15:45 -05:00
|
|
|
|
file module))
|
2019-07-19 17:48:09 -04:00
|
|
|
|
|
|
|
|
|
(catch 'system-error
|
|
|
|
|
(lambda ()
|
|
|
|
|
(let* ((sexp (call-with-input-file file read))
|
|
|
|
|
(loc (and (pair? sexp)
|
|
|
|
|
(source-properties->location (source-properties sexp)))))
|
|
|
|
|
(match sexp
|
|
|
|
|
(('define-module (names ...) _ ...)
|
|
|
|
|
(unless (equal? module names)
|
|
|
|
|
(warning loc
|
|
|
|
|
(G_ "module name ~a does not match file name '~a'~%")
|
|
|
|
|
names (module->source-file-name module))
|
|
|
|
|
(hint)))
|
|
|
|
|
((? eof-object?)
|
|
|
|
|
(warning (G_ "~a: file is empty~%") file))
|
|
|
|
|
(else
|
|
|
|
|
(hint)))))
|
|
|
|
|
(const #f)))
|
|
|
|
|
|
2015-05-25 12:25:19 -04:00
|
|
|
|
(define* (report-load-error file args #:optional frame)
|
2015-05-25 16:52:41 -04:00
|
|
|
|
"Report the failure to load FILE, a user-provided Scheme file.
|
2015-04-07 16:07:25 -04:00
|
|
|
|
ARGS is the list of arguments received by the 'throw' handler."
|
|
|
|
|
(match args
|
2016-09-20 04:51:39 -04:00
|
|
|
|
(('system-error . rest)
|
2015-04-07 16:07:25 -04:00
|
|
|
|
(let ((err (system-error-errno args)))
|
ui: Rename '_' to 'G_'.
This avoids collisions with '_' when the latter is used as a 'match'
pattern for instance. See
<https://lists.gnu.org/archive/html/guix-devel/2017-04/msg00464.html>.
* guix/ui.scm: Rename '_' to 'G_'.
* po/guix/Makevars (XGETTEXT_OPTIONS): Adjust accordingly.
* build-aux/compile-all.scm (warnings): Remove 'format'.
* gnu/packages.scm,
gnu/services.scm,
gnu/services/shepherd.scm,
gnu/system.scm,
gnu/system/shadow.scm,
guix/gnupg.scm,
guix/http-client.scm,
guix/import/cpan.scm,
guix/import/elpa.scm,
guix/import/pypi.scm,
guix/nar.scm,
guix/scripts.scm,
guix/scripts/archive.scm,
guix/scripts/authenticate.scm,
guix/scripts/build.scm,
guix/scripts/challenge.scm,
guix/scripts/container.scm,
guix/scripts/container/exec.scm,
guix/scripts/copy.scm,
guix/scripts/download.scm,
guix/scripts/edit.scm,
guix/scripts/environment.scm,
guix/scripts/gc.scm,
guix/scripts/graph.scm,
guix/scripts/hash.scm,
guix/scripts/import.scm,
guix/scripts/import/cpan.scm,
guix/scripts/import/cran.scm,
guix/scripts/import/crate.scm,
guix/scripts/import/elpa.scm,
guix/scripts/import/gem.scm,
guix/scripts/import/gnu.scm,
guix/scripts/import/hackage.scm,
guix/scripts/import/nix.scm,
guix/scripts/import/pypi.scm,
guix/scripts/import/stackage.scm,
guix/scripts/lint.scm,
guix/scripts/offload.scm,
guix/scripts/pack.scm,
guix/scripts/package.scm,
guix/scripts/perform-download.scm,
guix/scripts/publish.scm,
guix/scripts/pull.scm,
guix/scripts/refresh.scm,
guix/scripts/size.scm,
guix/scripts/substitute.scm,
guix/scripts/system.scm,
guix/ssh.scm,
guix/upstream.scm: Use 'G_' instead of '_'. Most of this change was
obtained by running: "sed -i -e's/(_ "/(G_ "/g' `find -name \*.scm`".
2017-05-03 09:57:02 -04:00
|
|
|
|
(report-error (G_ "failed to load '~a': ~a~%") file (strerror err))))
|
2021-04-28 18:38:03 -04:00
|
|
|
|
(('read-error _ message args ...)
|
2017-10-10 04:22:43 -04:00
|
|
|
|
;; Guile's missing-paren messages are obscure so we make them more
|
|
|
|
|
;; intelligible here.
|
2021-04-28 18:38:03 -04:00
|
|
|
|
(if (or (string-suffix? "end of file" message) ;Guile < 3.0.6
|
|
|
|
|
(and (string-contains message "unexpected end of input")
|
|
|
|
|
(member '(#\)) args)))
|
|
|
|
|
(let ((location (string-take message
|
|
|
|
|
(+ 2 (string-contains message ": ")))))
|
2017-10-10 04:22:43 -04:00
|
|
|
|
(format (current-error-port) (G_ "~amissing closing parenthesis~%")
|
|
|
|
|
location))
|
2021-11-07 09:56:19 -05:00
|
|
|
|
(report-error (G_ "read error while loading '~a': ~a~%")
|
|
|
|
|
file (apply format #f message args))))
|
2020-01-16 09:00:18 -05:00
|
|
|
|
(('syntax-error proc message properties form subform . rest)
|
2015-04-07 16:07:25 -04:00
|
|
|
|
(let ((loc (source-properties->location properties)))
|
2020-01-16 09:00:18 -05:00
|
|
|
|
(report-error loc (G_ "~s: ~a~%")
|
|
|
|
|
(or subform form) message)))
|
2018-05-04 09:05:05 -04:00
|
|
|
|
(('unbound-variable _ ...)
|
|
|
|
|
(report-unbound-variable-error args #:frame frame))
|
2019-11-26 06:21:26 -05:00
|
|
|
|
(((or 'srfi-34 '%exception) obj)
|
2020-07-25 11:59:13 -04:00
|
|
|
|
(cond ((message-condition? obj)
|
|
|
|
|
(report-error (and (error-location? obj)
|
|
|
|
|
(error-location obj))
|
|
|
|
|
(G_ "~a~%")
|
|
|
|
|
(gettext (condition-message obj) %gettext-domain)))
|
|
|
|
|
((formatted-message? obj)
|
|
|
|
|
(apply report-error
|
|
|
|
|
(and (error-location? obj) (error-location obj))
|
|
|
|
|
(gettext (formatted-message-string obj) %gettext-domain)
|
|
|
|
|
(formatted-message-arguments obj)))
|
|
|
|
|
(else
|
|
|
|
|
(report-error (G_ "exception thrown: ~s~%") obj)))
|
2017-11-08 05:16:25 -05:00
|
|
|
|
(when (fix-hint? obj)
|
2017-11-09 17:27:56 -05:00
|
|
|
|
(display-hint (condition-fix-hint obj))))
|
2019-02-11 16:48:24 -05:00
|
|
|
|
((key args ...)
|
ui: Rename '_' to 'G_'.
This avoids collisions with '_' when the latter is used as a 'match'
pattern for instance. See
<https://lists.gnu.org/archive/html/guix-devel/2017-04/msg00464.html>.
* guix/ui.scm: Rename '_' to 'G_'.
* po/guix/Makevars (XGETTEXT_OPTIONS): Adjust accordingly.
* build-aux/compile-all.scm (warnings): Remove 'format'.
* gnu/packages.scm,
gnu/services.scm,
gnu/services/shepherd.scm,
gnu/system.scm,
gnu/system/shadow.scm,
guix/gnupg.scm,
guix/http-client.scm,
guix/import/cpan.scm,
guix/import/elpa.scm,
guix/import/pypi.scm,
guix/nar.scm,
guix/scripts.scm,
guix/scripts/archive.scm,
guix/scripts/authenticate.scm,
guix/scripts/build.scm,
guix/scripts/challenge.scm,
guix/scripts/container.scm,
guix/scripts/container/exec.scm,
guix/scripts/copy.scm,
guix/scripts/download.scm,
guix/scripts/edit.scm,
guix/scripts/environment.scm,
guix/scripts/gc.scm,
guix/scripts/graph.scm,
guix/scripts/hash.scm,
guix/scripts/import.scm,
guix/scripts/import/cpan.scm,
guix/scripts/import/cran.scm,
guix/scripts/import/crate.scm,
guix/scripts/import/elpa.scm,
guix/scripts/import/gem.scm,
guix/scripts/import/gnu.scm,
guix/scripts/import/hackage.scm,
guix/scripts/import/nix.scm,
guix/scripts/import/pypi.scm,
guix/scripts/import/stackage.scm,
guix/scripts/lint.scm,
guix/scripts/offload.scm,
guix/scripts/pack.scm,
guix/scripts/package.scm,
guix/scripts/perform-download.scm,
guix/scripts/publish.scm,
guix/scripts/pull.scm,
guix/scripts/refresh.scm,
guix/scripts/size.scm,
guix/scripts/substitute.scm,
guix/scripts/system.scm,
guix/ssh.scm,
guix/upstream.scm: Use 'G_' instead of '_'. Most of this change was
obtained by running: "sed -i -e's/(_ "/(G_ "/g' `find -name \*.scm`".
2017-05-03 09:57:02 -04:00
|
|
|
|
(report-error (G_ "failed to load '~a':~%") file)
|
2019-02-11 16:48:24 -05:00
|
|
|
|
(match args
|
|
|
|
|
(((? symbol? proc) (? string? message) (args ...) . rest)
|
|
|
|
|
(display-error frame (current-error-port) proc message
|
|
|
|
|
args rest))
|
|
|
|
|
(_
|
|
|
|
|
;; Some exceptions like 'git-error' do not follow Guile's convention
|
|
|
|
|
;; above and need to be printed with 'print-exception'.
|
|
|
|
|
(print-exception (current-error-port) frame key args))))))
|
2015-04-07 16:07:25 -04:00
|
|
|
|
|
2019-07-19 17:48:09 -04:00
|
|
|
|
(define (warn-about-load-error file module args) ;FIXME: factorize with ↑
|
2015-04-07 16:27:45 -04:00
|
|
|
|
"Report the failure to load FILE, a user-provided Scheme file, without
|
|
|
|
|
exiting. ARGS is the list of arguments received by the 'throw' handler."
|
|
|
|
|
(match args
|
2016-09-20 04:51:39 -04:00
|
|
|
|
(('system-error . rest)
|
2015-04-07 16:27:45 -04:00
|
|
|
|
(let ((err (system-error-errno args)))
|
2019-07-19 17:48:09 -04:00
|
|
|
|
(warning (G_ "failed to load '~a': ~a~%") module (strerror err))))
|
2015-04-07 16:27:45 -04:00
|
|
|
|
(('syntax-error proc message properties form . rest)
|
|
|
|
|
(let ((loc (source-properties->location properties)))
|
2019-04-10 05:14:25 -04:00
|
|
|
|
(warning loc (G_ "~a~%") message)))
|
2019-07-19 18:33:50 -04:00
|
|
|
|
(('unbound-variable _ ...)
|
|
|
|
|
(report-unbound-variable-error args))
|
2019-11-26 06:21:26 -05:00
|
|
|
|
(((or 'srfi-34 '%exception) obj)
|
2020-07-25 11:59:13 -04:00
|
|
|
|
(cond ((message-condition? obj)
|
|
|
|
|
(warning (G_ "failed to load '~a': ~a~%")
|
|
|
|
|
file
|
|
|
|
|
(gettext (condition-message obj) %gettext-domain)))
|
|
|
|
|
((formatted-message? obj)
|
|
|
|
|
(warning (G_ "failed to load '~a': ~a~%")
|
2020-11-06 15:42:39 -05:00
|
|
|
|
file
|
2020-07-25 11:59:13 -04:00
|
|
|
|
(apply format #f
|
|
|
|
|
(gettext (formatted-message-string obj)
|
|
|
|
|
%gettext-domain)
|
|
|
|
|
(formatted-message-arguments obj))))
|
|
|
|
|
(else
|
|
|
|
|
(warning (G_ "failed to load '~a': exception thrown: ~s~%")
|
|
|
|
|
file obj))))
|
2015-04-07 16:27:45 -04:00
|
|
|
|
((error args ...)
|
2019-07-19 17:48:09 -04:00
|
|
|
|
(warning (G_ "failed to load '~a':~%") module)
|
|
|
|
|
(apply display-error #f (current-error-port) args)
|
|
|
|
|
(check-module-matches-file module file))))
|
2015-04-07 16:27:45 -04:00
|
|
|
|
|
2018-05-04 09:05:05 -04:00
|
|
|
|
(define (call-with-unbound-variable-handling thunk)
|
|
|
|
|
(define tag
|
|
|
|
|
(make-prompt-tag "user-code"))
|
|
|
|
|
|
|
|
|
|
(catch 'unbound-variable
|
|
|
|
|
(lambda ()
|
|
|
|
|
(call-with-prompt tag
|
|
|
|
|
thunk
|
|
|
|
|
(const #f)))
|
|
|
|
|
(const #t)
|
|
|
|
|
(rec (handle-error . args)
|
|
|
|
|
(let* ((stack (make-stack #t handle-error tag))
|
|
|
|
|
(frame (and stack (last-frame-with-source stack))))
|
|
|
|
|
(report-unbound-variable-error args #:frame frame)
|
|
|
|
|
(exit 1)))))
|
|
|
|
|
|
|
|
|
|
(define-syntax-rule (with-unbound-variable-handling exp ...)
|
|
|
|
|
"Capture 'unbound-variable' exceptions in the dynamic extent of EXP... and
|
|
|
|
|
report them in a user-friendly way."
|
|
|
|
|
(call-with-unbound-variable-handling (lambda () exp ...)))
|
|
|
|
|
|
2019-09-15 11:54:05 -04:00
|
|
|
|
(define %default-message-language
|
|
|
|
|
;; Default language to use for messages.
|
|
|
|
|
(make-parameter "en"))
|
|
|
|
|
|
|
|
|
|
(define (current-message-language)
|
|
|
|
|
"Return the language used for messages according to the current locale.
|
|
|
|
|
Return %DEFAULT-MESSAGE-LANGUAGE if that information could not be obtained. The
|
|
|
|
|
result is an ISO-639-2 language code such as \"ar\", without the territory
|
|
|
|
|
part."
|
|
|
|
|
(let ((locale (setlocale LC_MESSAGES)))
|
|
|
|
|
(match (string-index locale #\_)
|
|
|
|
|
(#f locale)
|
|
|
|
|
(index (string-take locale index)))))
|
|
|
|
|
|
2013-04-22 07:24:16 -04:00
|
|
|
|
(define (install-locale)
|
|
|
|
|
"Install the current locale settings."
|
|
|
|
|
(catch 'system-error
|
|
|
|
|
(lambda _
|
|
|
|
|
(setlocale LC_ALL ""))
|
|
|
|
|
(lambda args
|
2021-05-03 15:57:24 -04:00
|
|
|
|
(display-hint (G_ "Consider installing the @code{glibc-locales} package
|
|
|
|
|
and defining @code{GUIX_LOCPATH}, along these lines:
|
2018-06-27 09:36:03 -04:00
|
|
|
|
|
|
|
|
|
@example
|
2021-05-03 15:57:24 -04:00
|
|
|
|
guix install glibc-locales
|
2018-06-27 09:36:03 -04:00
|
|
|
|
export GUIX_LOCPATH=\"$HOME/.guix-profile/lib/locale\"
|
|
|
|
|
@end example
|
|
|
|
|
|
2020-09-02 09:59:09 -04:00
|
|
|
|
See the \"Application Setup\" section in the manual, for more info.\n"))
|
|
|
|
|
;; We're now running in the "C" locale. Try to install a UTF-8 locale
|
|
|
|
|
;; instead. This one is guaranteed to be available in 'guix' from 'guix
|
|
|
|
|
;; pull'.
|
|
|
|
|
(false-if-exception (setlocale LC_ALL "en_US.utf8")))))
|
2013-04-22 07:24:16 -04:00
|
|
|
|
|
Replace individual scripts with master 'guix' script.
* scripts/guix.in: New script.
* Makefile.am (bin_SCRIPTS): Add 'scripts/guix'. Remove 'guix-build',
'guix-download', 'guix-import', 'guix-package', and 'guix-gc'.
(MODULES): Add 'guix/scripts/build.scm', 'guix/scripts/download.scm',
'guix/scripts/import.scm', 'guix/scripts/package.scm', and
'guix/scripts/gc.scm'.
* configure.ac (AC_CONFIG_FILES): Add 'scripts/guix'. Remove 'guix-build',
'guix-download', 'guix-import', 'guix-package', and 'guix-gc'.
* guix-build.in, guix-download.in, guix-gc.in, guix-import.in,
guix-package.in: Remove shell script boilerplate. Move to guix-COMMAND.in
to guix/scripts/COMMAND.scm. Rename module from (guix-COMMAND) to
(guix scripts COMMAND). Change "guix-COMMAND" to "guix COMMAND" in
usage help string.
* pre-inst-env.in: Add "@abs_top_builddir@/scripts" to the front of $PATH.
Export $GUIX_UNINSTALLED.
* tests/guix-build.sh, tests/guix-daemon.sh, tests/guix-download.sh,
tests/guix-gc.sh, tests/guix-package.sh: Use "guix COMMAND" instead of
"guix-COMMAND".
* doc/guix.texi: Replace all occurrences of "guix-COMMAND" with
"guix COMMAND".
* po/POTFILES.in: Update.
2013-02-14 04:15:25 -05:00
|
|
|
|
(define (initialize-guix)
|
2013-02-17 09:38:02 -05:00
|
|
|
|
"Perform the usual initialization for stand-alone Guix commands."
|
2017-05-16 08:31:37 -04:00
|
|
|
|
;; By default don't annoy users with deprecation warnings. In practice,
|
|
|
|
|
;; 'define-deprecated' in (ice-9 deprecated) arranges so that those warnings
|
|
|
|
|
;; are emitted at expansion-time only, but there are cases where they could
|
|
|
|
|
;; slip through, for instance when interpreting code.
|
|
|
|
|
(unless (getenv "GUILE_WARN_DEPRECATED")
|
|
|
|
|
(debug-disable 'warn-deprecated))
|
|
|
|
|
|
Replace individual scripts with master 'guix' script.
* scripts/guix.in: New script.
* Makefile.am (bin_SCRIPTS): Add 'scripts/guix'. Remove 'guix-build',
'guix-download', 'guix-import', 'guix-package', and 'guix-gc'.
(MODULES): Add 'guix/scripts/build.scm', 'guix/scripts/download.scm',
'guix/scripts/import.scm', 'guix/scripts/package.scm', and
'guix/scripts/gc.scm'.
* configure.ac (AC_CONFIG_FILES): Add 'scripts/guix'. Remove 'guix-build',
'guix-download', 'guix-import', 'guix-package', and 'guix-gc'.
* guix-build.in, guix-download.in, guix-gc.in, guix-import.in,
guix-package.in: Remove shell script boilerplate. Move to guix-COMMAND.in
to guix/scripts/COMMAND.scm. Rename module from (guix-COMMAND) to
(guix scripts COMMAND). Change "guix-COMMAND" to "guix COMMAND" in
usage help string.
* pre-inst-env.in: Add "@abs_top_builddir@/scripts" to the front of $PATH.
Export $GUIX_UNINSTALLED.
* tests/guix-build.sh, tests/guix-daemon.sh, tests/guix-download.sh,
tests/guix-gc.sh, tests/guix-package.sh: Use "guix COMMAND" instead of
"guix-COMMAND".
* doc/guix.texi: Replace all occurrences of "guix-COMMAND" with
"guix COMMAND".
* po/POTFILES.in: Update.
2013-02-14 04:15:25 -05:00
|
|
|
|
(install-locale)
|
2013-10-12 10:37:28 -04:00
|
|
|
|
(textdomain %gettext-domain)
|
2013-07-12 17:01:07 -04:00
|
|
|
|
|
|
|
|
|
;; Ignore SIGPIPE. If the daemon closes the connection, we prefer to be
|
|
|
|
|
;; notified via an EPIPE later.
|
|
|
|
|
(sigaction SIGPIPE SIG_IGN)
|
|
|
|
|
|
2019-01-07 04:57:18 -05:00
|
|
|
|
(setvbuf (current-output-port) 'line)
|
|
|
|
|
(setvbuf (current-error-port) 'line))
|
Replace individual scripts with master 'guix' script.
* scripts/guix.in: New script.
* Makefile.am (bin_SCRIPTS): Add 'scripts/guix'. Remove 'guix-build',
'guix-download', 'guix-import', 'guix-package', and 'guix-gc'.
(MODULES): Add 'guix/scripts/build.scm', 'guix/scripts/download.scm',
'guix/scripts/import.scm', 'guix/scripts/package.scm', and
'guix/scripts/gc.scm'.
* configure.ac (AC_CONFIG_FILES): Add 'scripts/guix'. Remove 'guix-build',
'guix-download', 'guix-import', 'guix-package', and 'guix-gc'.
* guix-build.in, guix-download.in, guix-gc.in, guix-import.in,
guix-package.in: Remove shell script boilerplate. Move to guix-COMMAND.in
to guix/scripts/COMMAND.scm. Rename module from (guix-COMMAND) to
(guix scripts COMMAND). Change "guix-COMMAND" to "guix COMMAND" in
usage help string.
* pre-inst-env.in: Add "@abs_top_builddir@/scripts" to the front of $PATH.
Export $GUIX_UNINSTALLED.
* tests/guix-build.sh, tests/guix-daemon.sh, tests/guix-download.sh,
tests/guix-gc.sh, tests/guix-package.sh: Use "guix COMMAND" instead of
"guix-COMMAND".
* doc/guix.texi: Replace all occurrences of "guix-COMMAND" with
"guix COMMAND".
* po/POTFILES.in: Update.
2013-02-14 04:15:25 -05:00
|
|
|
|
|
2012-11-03 16:19:43 -04:00
|
|
|
|
(define* (show-version-and-exit #:optional (command (car (command-line))))
|
|
|
|
|
"Display version information for COMMAND and `(exit 0)'."
|
2023-10-12 09:39:03 -04:00
|
|
|
|
(leave-on-EPIPE
|
|
|
|
|
(simple-format #t "~a (~a) ~a~%"
|
|
|
|
|
command %guix-package-name %guix-version)
|
|
|
|
|
(format #t "Copyright ~a 2023 ~a"
|
|
|
|
|
;; TRANSLATORS: Translate "(C)" to the copyright symbol
|
|
|
|
|
;; (C-in-a-circle), if this symbol is available in the user's
|
|
|
|
|
;; locale. Otherwise, do not translate "(C)"; leave it as-is. */
|
|
|
|
|
(G_ "(C)")
|
|
|
|
|
(G_ "the Guix authors\n"))
|
|
|
|
|
(display (G_"\
|
2013-11-03 17:09:30 -05:00
|
|
|
|
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
|
|
|
|
|
This is free software: you are free to change and redistribute it.
|
|
|
|
|
There is NO WARRANTY, to the extent permitted by law.
|
2023-10-12 09:39:03 -04:00
|
|
|
|
")))
|
2012-11-03 16:19:43 -04:00
|
|
|
|
(exit 0))
|
|
|
|
|
|
2013-01-05 09:55:47 -05:00
|
|
|
|
(define (show-bug-report-information)
|
2016-05-16 11:55:38 -04:00
|
|
|
|
;; TRANSLATORS: The placeholder indicates the bug-reporting address for this
|
|
|
|
|
;; package. Please add another line saying "Report translation bugs to
|
|
|
|
|
;; ...\n" with the address for translation bugs (typically your translation
|
|
|
|
|
;; team's web or email address).
|
ui: Rename '_' to 'G_'.
This avoids collisions with '_' when the latter is used as a 'match'
pattern for instance. See
<https://lists.gnu.org/archive/html/guix-devel/2017-04/msg00464.html>.
* guix/ui.scm: Rename '_' to 'G_'.
* po/guix/Makevars (XGETTEXT_OPTIONS): Adjust accordingly.
* build-aux/compile-all.scm (warnings): Remove 'format'.
* gnu/packages.scm,
gnu/services.scm,
gnu/services/shepherd.scm,
gnu/system.scm,
gnu/system/shadow.scm,
guix/gnupg.scm,
guix/http-client.scm,
guix/import/cpan.scm,
guix/import/elpa.scm,
guix/import/pypi.scm,
guix/nar.scm,
guix/scripts.scm,
guix/scripts/archive.scm,
guix/scripts/authenticate.scm,
guix/scripts/build.scm,
guix/scripts/challenge.scm,
guix/scripts/container.scm,
guix/scripts/container/exec.scm,
guix/scripts/copy.scm,
guix/scripts/download.scm,
guix/scripts/edit.scm,
guix/scripts/environment.scm,
guix/scripts/gc.scm,
guix/scripts/graph.scm,
guix/scripts/hash.scm,
guix/scripts/import.scm,
guix/scripts/import/cpan.scm,
guix/scripts/import/cran.scm,
guix/scripts/import/crate.scm,
guix/scripts/import/elpa.scm,
guix/scripts/import/gem.scm,
guix/scripts/import/gnu.scm,
guix/scripts/import/hackage.scm,
guix/scripts/import/nix.scm,
guix/scripts/import/pypi.scm,
guix/scripts/import/stackage.scm,
guix/scripts/lint.scm,
guix/scripts/offload.scm,
guix/scripts/pack.scm,
guix/scripts/package.scm,
guix/scripts/perform-download.scm,
guix/scripts/publish.scm,
guix/scripts/pull.scm,
guix/scripts/refresh.scm,
guix/scripts/size.scm,
guix/scripts/substitute.scm,
guix/scripts/system.scm,
guix/ssh.scm,
guix/upstream.scm: Use 'G_' instead of '_'. Most of this change was
obtained by running: "sed -i -e's/(_ "/(G_ "/g' `find -name \*.scm`".
2017-05-03 09:57:02 -04:00
|
|
|
|
(format #t (G_ "
|
2013-01-05 09:55:47 -05:00
|
|
|
|
Report bugs to: ~a.") %guix-bug-report-address)
|
ui: Rename '_' to 'G_'.
This avoids collisions with '_' when the latter is used as a 'match'
pattern for instance. See
<https://lists.gnu.org/archive/html/guix-devel/2017-04/msg00464.html>.
* guix/ui.scm: Rename '_' to 'G_'.
* po/guix/Makevars (XGETTEXT_OPTIONS): Adjust accordingly.
* build-aux/compile-all.scm (warnings): Remove 'format'.
* gnu/packages.scm,
gnu/services.scm,
gnu/services/shepherd.scm,
gnu/system.scm,
gnu/system/shadow.scm,
guix/gnupg.scm,
guix/http-client.scm,
guix/import/cpan.scm,
guix/import/elpa.scm,
guix/import/pypi.scm,
guix/nar.scm,
guix/scripts.scm,
guix/scripts/archive.scm,
guix/scripts/authenticate.scm,
guix/scripts/build.scm,
guix/scripts/challenge.scm,
guix/scripts/container.scm,
guix/scripts/container/exec.scm,
guix/scripts/copy.scm,
guix/scripts/download.scm,
guix/scripts/edit.scm,
guix/scripts/environment.scm,
guix/scripts/gc.scm,
guix/scripts/graph.scm,
guix/scripts/hash.scm,
guix/scripts/import.scm,
guix/scripts/import/cpan.scm,
guix/scripts/import/cran.scm,
guix/scripts/import/crate.scm,
guix/scripts/import/elpa.scm,
guix/scripts/import/gem.scm,
guix/scripts/import/gnu.scm,
guix/scripts/import/hackage.scm,
guix/scripts/import/nix.scm,
guix/scripts/import/pypi.scm,
guix/scripts/import/stackage.scm,
guix/scripts/lint.scm,
guix/scripts/offload.scm,
guix/scripts/pack.scm,
guix/scripts/package.scm,
guix/scripts/perform-download.scm,
guix/scripts/publish.scm,
guix/scripts/pull.scm,
guix/scripts/refresh.scm,
guix/scripts/size.scm,
guix/scripts/substitute.scm,
guix/scripts/system.scm,
guix/ssh.scm,
guix/upstream.scm: Use 'G_' instead of '_'. Most of this change was
obtained by running: "sed -i -e's/(_ "/(G_ "/g' `find -name \*.scm`".
2017-05-03 09:57:02 -04:00
|
|
|
|
(format #t (G_ "
|
2013-01-05 09:55:47 -05:00
|
|
|
|
~a home page: <~a>") %guix-package-name %guix-home-page-url)
|
2020-09-01 16:23:50 -04:00
|
|
|
|
(format #t (G_ "
|
|
|
|
|
General help using Guix and GNU software: <~a>")
|
2021-02-23 11:00:32 -05:00
|
|
|
|
;; TRANSLATORS: Change the "/en" bit of this URL appropriately if
|
|
|
|
|
;; the web site is translated in your language.
|
|
|
|
|
(G_ "https://guix.gnu.org/en/help/"))
|
2013-01-05 09:55:47 -05:00
|
|
|
|
(newline))
|
|
|
|
|
|
2017-01-13 06:07:10 -05:00
|
|
|
|
(define (augmented-system-error-handler file)
|
|
|
|
|
"Return a 'system-error' handler that mentions FILE in its message."
|
|
|
|
|
(lambda (key proc fmt args errno)
|
|
|
|
|
;; Augment the FMT and ARGS with information about TARGET (this
|
|
|
|
|
;; information is missing as of Guile 2.0.11, making the exception
|
|
|
|
|
;; uninformative.)
|
|
|
|
|
(apply throw key proc "~A: ~S"
|
|
|
|
|
(list (strerror (car errno)) file)
|
|
|
|
|
(list errno))))
|
|
|
|
|
|
2018-12-16 23:12:13 -05:00
|
|
|
|
(define-syntax apply-formals
|
|
|
|
|
(syntax-rules ()
|
|
|
|
|
((_ proc (args ...)) (proc args ...))
|
|
|
|
|
((_ proc (arg1 args ... . rest)) (apply proc arg1 args ... rest))))
|
|
|
|
|
|
|
|
|
|
(define-syntax-rule (error-reporting-wrapper proc formals file)
|
2017-01-13 06:07:10 -05:00
|
|
|
|
"Wrap PROC such that its 'system-error' exceptions are augmented to mention
|
|
|
|
|
FILE."
|
|
|
|
|
(let ((real-proc (@ (guile) proc)))
|
2018-12-16 23:12:13 -05:00
|
|
|
|
(lambda formals
|
2017-01-13 06:07:10 -05:00
|
|
|
|
(catch 'system-error
|
|
|
|
|
(lambda ()
|
2018-12-16 23:12:13 -05:00
|
|
|
|
(apply-formals real-proc formals))
|
2017-01-13 06:07:10 -05:00
|
|
|
|
(augmented-system-error-handler file)))))
|
|
|
|
|
|
2015-06-10 04:25:16 -04:00
|
|
|
|
(set! symlink
|
|
|
|
|
;; We 'set!' the global binding because (gnu build ...) modules and similar
|
|
|
|
|
;; typically don't use (guix ui).
|
2017-01-13 06:07:10 -05:00
|
|
|
|
(error-reporting-wrapper symlink (source target) target))
|
2015-04-20 16:37:20 -04:00
|
|
|
|
|
2015-05-24 11:22:43 -04:00
|
|
|
|
(set! copy-file
|
|
|
|
|
;; Note: here we use 'set!', not #:replace, because UIs typically use
|
|
|
|
|
;; 'copy-recursively', which doesn't use (guix ui).
|
2017-01-13 06:07:10 -05:00
|
|
|
|
(error-reporting-wrapper copy-file (source target) target))
|
|
|
|
|
|
2017-01-13 06:09:01 -05:00
|
|
|
|
(set! canonicalize-path
|
|
|
|
|
(error-reporting-wrapper canonicalize-path (file) file))
|
|
|
|
|
|
2018-07-03 05:02:54 -04:00
|
|
|
|
(set! delete-file
|
|
|
|
|
(error-reporting-wrapper delete-file (file) file))
|
|
|
|
|
|
2018-12-16 23:12:13 -05:00
|
|
|
|
(set! execlp
|
|
|
|
|
(error-reporting-wrapper execlp (filename . args) filename))
|
2015-05-24 11:22:43 -04:00
|
|
|
|
|
2023-01-25 13:48:39 -05:00
|
|
|
|
(set! mkdir
|
|
|
|
|
(error-reporting-wrapper mkdir (directory . args) directory))
|
|
|
|
|
|
2015-10-28 10:53:17 -04:00
|
|
|
|
(define (make-regexp* regexp . flags)
|
|
|
|
|
"Like 'make-regexp' but error out if REGEXP is invalid, reporting the error
|
|
|
|
|
nicely."
|
|
|
|
|
(catch 'regular-expression-syntax
|
|
|
|
|
(lambda ()
|
|
|
|
|
(apply make-regexp regexp flags))
|
|
|
|
|
(lambda (key proc message . rest)
|
ui: Rename '_' to 'G_'.
This avoids collisions with '_' when the latter is used as a 'match'
pattern for instance. See
<https://lists.gnu.org/archive/html/guix-devel/2017-04/msg00464.html>.
* guix/ui.scm: Rename '_' to 'G_'.
* po/guix/Makevars (XGETTEXT_OPTIONS): Adjust accordingly.
* build-aux/compile-all.scm (warnings): Remove 'format'.
* gnu/packages.scm,
gnu/services.scm,
gnu/services/shepherd.scm,
gnu/system.scm,
gnu/system/shadow.scm,
guix/gnupg.scm,
guix/http-client.scm,
guix/import/cpan.scm,
guix/import/elpa.scm,
guix/import/pypi.scm,
guix/nar.scm,
guix/scripts.scm,
guix/scripts/archive.scm,
guix/scripts/authenticate.scm,
guix/scripts/build.scm,
guix/scripts/challenge.scm,
guix/scripts/container.scm,
guix/scripts/container/exec.scm,
guix/scripts/copy.scm,
guix/scripts/download.scm,
guix/scripts/edit.scm,
guix/scripts/environment.scm,
guix/scripts/gc.scm,
guix/scripts/graph.scm,
guix/scripts/hash.scm,
guix/scripts/import.scm,
guix/scripts/import/cpan.scm,
guix/scripts/import/cran.scm,
guix/scripts/import/crate.scm,
guix/scripts/import/elpa.scm,
guix/scripts/import/gem.scm,
guix/scripts/import/gnu.scm,
guix/scripts/import/hackage.scm,
guix/scripts/import/nix.scm,
guix/scripts/import/pypi.scm,
guix/scripts/import/stackage.scm,
guix/scripts/lint.scm,
guix/scripts/offload.scm,
guix/scripts/pack.scm,
guix/scripts/package.scm,
guix/scripts/perform-download.scm,
guix/scripts/publish.scm,
guix/scripts/pull.scm,
guix/scripts/refresh.scm,
guix/scripts/size.scm,
guix/scripts/substitute.scm,
guix/scripts/system.scm,
guix/ssh.scm,
guix/upstream.scm: Use 'G_' instead of '_'. Most of this change was
obtained by running: "sed -i -e's/(_ "/(G_ "/g' `find -name \*.scm`".
2017-05-03 09:57:02 -04:00
|
|
|
|
(leave (G_ "'~a' is not a valid regular expression: ~a~%")
|
2015-10-28 10:53:17 -04:00
|
|
|
|
regexp message))))
|
|
|
|
|
|
2013-05-20 12:14:55 -04:00
|
|
|
|
(define (string->number* str)
|
|
|
|
|
"Like `string->number', but error out with an error message on failure."
|
|
|
|
|
(or (string->number str)
|
ui: Rename '_' to 'G_'.
This avoids collisions with '_' when the latter is used as a 'match'
pattern for instance. See
<https://lists.gnu.org/archive/html/guix-devel/2017-04/msg00464.html>.
* guix/ui.scm: Rename '_' to 'G_'.
* po/guix/Makevars (XGETTEXT_OPTIONS): Adjust accordingly.
* build-aux/compile-all.scm (warnings): Remove 'format'.
* gnu/packages.scm,
gnu/services.scm,
gnu/services/shepherd.scm,
gnu/system.scm,
gnu/system/shadow.scm,
guix/gnupg.scm,
guix/http-client.scm,
guix/import/cpan.scm,
guix/import/elpa.scm,
guix/import/pypi.scm,
guix/nar.scm,
guix/scripts.scm,
guix/scripts/archive.scm,
guix/scripts/authenticate.scm,
guix/scripts/build.scm,
guix/scripts/challenge.scm,
guix/scripts/container.scm,
guix/scripts/container/exec.scm,
guix/scripts/copy.scm,
guix/scripts/download.scm,
guix/scripts/edit.scm,
guix/scripts/environment.scm,
guix/scripts/gc.scm,
guix/scripts/graph.scm,
guix/scripts/hash.scm,
guix/scripts/import.scm,
guix/scripts/import/cpan.scm,
guix/scripts/import/cran.scm,
guix/scripts/import/crate.scm,
guix/scripts/import/elpa.scm,
guix/scripts/import/gem.scm,
guix/scripts/import/gnu.scm,
guix/scripts/import/hackage.scm,
guix/scripts/import/nix.scm,
guix/scripts/import/pypi.scm,
guix/scripts/import/stackage.scm,
guix/scripts/lint.scm,
guix/scripts/offload.scm,
guix/scripts/pack.scm,
guix/scripts/package.scm,
guix/scripts/perform-download.scm,
guix/scripts/publish.scm,
guix/scripts/pull.scm,
guix/scripts/refresh.scm,
guix/scripts/size.scm,
guix/scripts/substitute.scm,
guix/scripts/system.scm,
guix/ssh.scm,
guix/upstream.scm: Use 'G_' instead of '_'. Most of this change was
obtained by running: "sed -i -e's/(_ "/(G_ "/g' `find -name \*.scm`".
2017-05-03 09:57:02 -04:00
|
|
|
|
(leave (G_ "~a: invalid number~%") str)))
|
2013-05-20 12:14:55 -04:00
|
|
|
|
|
2014-04-08 16:01:44 -04:00
|
|
|
|
(define (size->number str)
|
|
|
|
|
"Convert STR, a storage measurement representation such as \"1024\" or
|
|
|
|
|
\"1MiB\", to a number of bytes. Raise an error if STR could not be
|
|
|
|
|
interpreted."
|
|
|
|
|
(define unit-pos
|
2020-02-23 06:42:58 -05:00
|
|
|
|
(string-rindex str
|
|
|
|
|
(char-set-union (char-set #\.) char-set:digit)))
|
2014-04-08 16:01:44 -04:00
|
|
|
|
|
|
|
|
|
(define unit
|
|
|
|
|
(and unit-pos (substring str (+ 1 unit-pos))))
|
|
|
|
|
|
|
|
|
|
(let* ((numstr (if unit-pos
|
|
|
|
|
(substring str 0 (+ 1 unit-pos))
|
|
|
|
|
str))
|
|
|
|
|
(num (string->number numstr)))
|
|
|
|
|
(unless num
|
ui: Rename '_' to 'G_'.
This avoids collisions with '_' when the latter is used as a 'match'
pattern for instance. See
<https://lists.gnu.org/archive/html/guix-devel/2017-04/msg00464.html>.
* guix/ui.scm: Rename '_' to 'G_'.
* po/guix/Makevars (XGETTEXT_OPTIONS): Adjust accordingly.
* build-aux/compile-all.scm (warnings): Remove 'format'.
* gnu/packages.scm,
gnu/services.scm,
gnu/services/shepherd.scm,
gnu/system.scm,
gnu/system/shadow.scm,
guix/gnupg.scm,
guix/http-client.scm,
guix/import/cpan.scm,
guix/import/elpa.scm,
guix/import/pypi.scm,
guix/nar.scm,
guix/scripts.scm,
guix/scripts/archive.scm,
guix/scripts/authenticate.scm,
guix/scripts/build.scm,
guix/scripts/challenge.scm,
guix/scripts/container.scm,
guix/scripts/container/exec.scm,
guix/scripts/copy.scm,
guix/scripts/download.scm,
guix/scripts/edit.scm,
guix/scripts/environment.scm,
guix/scripts/gc.scm,
guix/scripts/graph.scm,
guix/scripts/hash.scm,
guix/scripts/import.scm,
guix/scripts/import/cpan.scm,
guix/scripts/import/cran.scm,
guix/scripts/import/crate.scm,
guix/scripts/import/elpa.scm,
guix/scripts/import/gem.scm,
guix/scripts/import/gnu.scm,
guix/scripts/import/hackage.scm,
guix/scripts/import/nix.scm,
guix/scripts/import/pypi.scm,
guix/scripts/import/stackage.scm,
guix/scripts/lint.scm,
guix/scripts/offload.scm,
guix/scripts/pack.scm,
guix/scripts/package.scm,
guix/scripts/perform-download.scm,
guix/scripts/publish.scm,
guix/scripts/pull.scm,
guix/scripts/refresh.scm,
guix/scripts/size.scm,
guix/scripts/substitute.scm,
guix/scripts/system.scm,
guix/ssh.scm,
guix/upstream.scm: Use 'G_' instead of '_'. Most of this change was
obtained by running: "sed -i -e's/(_ "/(G_ "/g' `find -name \*.scm`".
2017-05-03 09:57:02 -04:00
|
|
|
|
(leave (G_ "invalid number: ~a~%") numstr))
|
2014-04-08 16:01:44 -04:00
|
|
|
|
|
|
|
|
|
((compose inexact->exact round)
|
|
|
|
|
(* num
|
|
|
|
|
(match unit
|
2014-10-03 07:35:14 -04:00
|
|
|
|
((or "KiB" "K" "k") (expt 2 10))
|
|
|
|
|
((or "MiB" "M") (expt 2 20))
|
|
|
|
|
((or "GiB" "G") (expt 2 30))
|
|
|
|
|
((or "TiB" "T") (expt 2 40))
|
|
|
|
|
((or "PiB" "P") (expt 2 50))
|
|
|
|
|
((or "EiB" "E") (expt 2 60))
|
|
|
|
|
((or "ZiB" "Z") (expt 2 70))
|
|
|
|
|
((or "YiB" "Y") (expt 2 80))
|
|
|
|
|
("kB" (expt 10 3))
|
2014-04-08 16:01:44 -04:00
|
|
|
|
("MB" (expt 10 6))
|
|
|
|
|
("GB" (expt 10 9))
|
|
|
|
|
("TB" (expt 10 12))
|
2014-10-03 07:35:14 -04:00
|
|
|
|
("PB" (expt 10 15))
|
|
|
|
|
("EB" (expt 10 18))
|
|
|
|
|
("ZB" (expt 10 21))
|
|
|
|
|
("YB" (expt 10 24))
|
2014-04-08 16:01:44 -04:00
|
|
|
|
("" 1)
|
2016-09-20 04:51:39 -04:00
|
|
|
|
(x
|
ui: Rename '_' to 'G_'.
This avoids collisions with '_' when the latter is used as a 'match'
pattern for instance. See
<https://lists.gnu.org/archive/html/guix-devel/2017-04/msg00464.html>.
* guix/ui.scm: Rename '_' to 'G_'.
* po/guix/Makevars (XGETTEXT_OPTIONS): Adjust accordingly.
* build-aux/compile-all.scm (warnings): Remove 'format'.
* gnu/packages.scm,
gnu/services.scm,
gnu/services/shepherd.scm,
gnu/system.scm,
gnu/system/shadow.scm,
guix/gnupg.scm,
guix/http-client.scm,
guix/import/cpan.scm,
guix/import/elpa.scm,
guix/import/pypi.scm,
guix/nar.scm,
guix/scripts.scm,
guix/scripts/archive.scm,
guix/scripts/authenticate.scm,
guix/scripts/build.scm,
guix/scripts/challenge.scm,
guix/scripts/container.scm,
guix/scripts/container/exec.scm,
guix/scripts/copy.scm,
guix/scripts/download.scm,
guix/scripts/edit.scm,
guix/scripts/environment.scm,
guix/scripts/gc.scm,
guix/scripts/graph.scm,
guix/scripts/hash.scm,
guix/scripts/import.scm,
guix/scripts/import/cpan.scm,
guix/scripts/import/cran.scm,
guix/scripts/import/crate.scm,
guix/scripts/import/elpa.scm,
guix/scripts/import/gem.scm,
guix/scripts/import/gnu.scm,
guix/scripts/import/hackage.scm,
guix/scripts/import/nix.scm,
guix/scripts/import/pypi.scm,
guix/scripts/import/stackage.scm,
guix/scripts/lint.scm,
guix/scripts/offload.scm,
guix/scripts/pack.scm,
guix/scripts/package.scm,
guix/scripts/perform-download.scm,
guix/scripts/publish.scm,
guix/scripts/pull.scm,
guix/scripts/refresh.scm,
guix/scripts/size.scm,
guix/scripts/substitute.scm,
guix/scripts/system.scm,
guix/ssh.scm,
guix/upstream.scm: Use 'G_' instead of '_'. Most of this change was
obtained by running: "sed -i -e's/(_ "/(G_ "/g' `find -name \*.scm`".
2017-05-03 09:57:02 -04:00
|
|
|
|
(leave (G_ "unknown unit: ~a~%") unit)))))))
|
2014-04-08 16:01:44 -04:00
|
|
|
|
|
2017-12-10 17:41:21 -05:00
|
|
|
|
(define (display-collision-resolution-hint collision)
|
|
|
|
|
"Display hints on how to resolve COLLISION, a &profile-collistion-error."
|
|
|
|
|
(define (top-most-entry entry)
|
|
|
|
|
(let loop ((entry entry))
|
|
|
|
|
(match (force (manifest-entry-parent entry))
|
|
|
|
|
(#f entry)
|
|
|
|
|
(parent (loop parent)))))
|
|
|
|
|
|
|
|
|
|
(let* ((first (profile-collision-error-entry collision))
|
|
|
|
|
(second (profile-collision-error-conflict collision))
|
|
|
|
|
(name1 (manifest-entry-name (top-most-entry first)))
|
|
|
|
|
(name2 (manifest-entry-name (top-most-entry second))))
|
|
|
|
|
(if (string=? name1 name2)
|
2023-02-24 05:15:45 -05:00
|
|
|
|
(display-hint (G_ "You cannot have two different versions
|
2017-12-10 17:41:21 -05:00
|
|
|
|
or variants of @code{~a} in the same profile.")
|
2023-02-24 05:15:45 -05:00
|
|
|
|
name1)
|
|
|
|
|
(display-hint (G_ "Try upgrading both @code{~a} and @code{~a},
|
2017-12-10 17:41:21 -05:00
|
|
|
|
or remove one of them from the profile.")
|
2023-02-24 05:15:45 -05:00
|
|
|
|
name1 name2))))
|
2017-12-10 17:41:21 -05:00
|
|
|
|
|
2021-05-26 16:30:31 -04:00
|
|
|
|
;; On Guile 3.0, in 'call-with-error-handling' we need to re-raise. To
|
|
|
|
|
;; preserve useful backtraces in case of unhandled errors, we want that to
|
|
|
|
|
;; happen before the stack has been unwound, hence 'guard*'.
|
|
|
|
|
(define-syntax-rule (guard* (var clauses ...) exp ...)
|
|
|
|
|
"This variant of SRFI-34 'guard' does not unwind the stack before
|
2020-07-14 19:11:00 -04:00
|
|
|
|
evaluating the tests and bodies of CLAUSES."
|
2021-05-26 16:30:31 -04:00
|
|
|
|
(with-exception-handler
|
|
|
|
|
(lambda (var)
|
|
|
|
|
(cond clauses ... (else (raise var))))
|
|
|
|
|
(lambda () exp ...)
|
|
|
|
|
#:unwind? #f))
|
2020-07-14 19:11:00 -04:00
|
|
|
|
|
2012-10-31 19:50:01 -04:00
|
|
|
|
(define (call-with-error-handling thunk)
|
|
|
|
|
"Call THUNK within a user-friendly error handler."
|
2016-03-09 17:37:12 -05:00
|
|
|
|
(define (port-filename* port)
|
|
|
|
|
;; 'port-filename' returns #f for non-file ports, but it raises an
|
|
|
|
|
;; exception for file ports that are closed. Work around that.
|
|
|
|
|
(and (not (port-closed? port))
|
|
|
|
|
(port-filename port)))
|
|
|
|
|
|
2020-07-14 19:11:00 -04:00
|
|
|
|
(guard* (c ((package-input-error? c)
|
|
|
|
|
(let* ((package (package-error-package c))
|
|
|
|
|
(input (package-error-invalid-input c))
|
|
|
|
|
(location (package-location package))
|
|
|
|
|
(file (location-file location))
|
|
|
|
|
(line (location-line location))
|
|
|
|
|
(column (location-column location)))
|
|
|
|
|
(leave (G_ "~a:~a:~a: package `~a' has an invalid input: ~s~%")
|
|
|
|
|
file line column
|
|
|
|
|
(package-full-name package) input)))
|
2023-06-05 17:41:37 -04:00
|
|
|
|
((package-cyclic-dependency-error? c)
|
|
|
|
|
(let ((package (package-error-package c)))
|
|
|
|
|
(leave (package-location package)
|
|
|
|
|
(G_ "~a: dependency cycle detected:
|
|
|
|
|
~a~{ -> ~a~}~%")
|
|
|
|
|
(package-full-name package)
|
|
|
|
|
(package-full-name package)
|
|
|
|
|
(map package-full-name
|
|
|
|
|
(package-error-dependency-cycle c)))))
|
2020-07-14 19:11:00 -04:00
|
|
|
|
((package-cross-build-system-error? c)
|
|
|
|
|
(let* ((package (package-error-package c))
|
|
|
|
|
(loc (package-location package))
|
|
|
|
|
(system (package-build-system package)))
|
|
|
|
|
(leave (G_ "~a: ~a: build system `~a' does not support cross builds~%")
|
|
|
|
|
(location->string loc)
|
|
|
|
|
(package-full-name package)
|
|
|
|
|
(build-system-name system))))
|
|
|
|
|
((gexp-input-error? c)
|
2020-11-10 08:40:20 -05:00
|
|
|
|
(let ((input (gexp-error-invalid-input c)))
|
2020-07-14 19:11:00 -04:00
|
|
|
|
(leave (G_ "~s: invalid G-expression input~%")
|
|
|
|
|
(gexp-error-invalid-input c))))
|
|
|
|
|
((profile-not-found-error? c)
|
|
|
|
|
(leave (G_ "profile '~a' does not exist~%")
|
|
|
|
|
(profile-error-profile c)))
|
|
|
|
|
((missing-generation-error? c)
|
|
|
|
|
(leave (G_ "generation ~a of profile '~a' does not exist~%")
|
|
|
|
|
(missing-generation-error-generation c)
|
|
|
|
|
(profile-error-profile c)))
|
|
|
|
|
((unmatched-pattern-error? c)
|
|
|
|
|
(let ((pattern (unmatched-pattern-error-pattern c)))
|
|
|
|
|
(leave (G_ "package '~a~@[@~a~]~@[:~a~]' not found in profile~%")
|
|
|
|
|
(manifest-pattern-name pattern)
|
|
|
|
|
(manifest-pattern-version pattern)
|
|
|
|
|
(match (manifest-pattern-output pattern)
|
|
|
|
|
("out" #f)
|
|
|
|
|
(output output)))))
|
|
|
|
|
((profile-collision-error? c)
|
|
|
|
|
(let ((entry (profile-collision-error-entry c))
|
|
|
|
|
(conflict (profile-collision-error-conflict c)))
|
|
|
|
|
(define (report-parent-entries entry)
|
|
|
|
|
(let ((parent (force (manifest-entry-parent entry))))
|
|
|
|
|
(when (manifest-entry? parent)
|
|
|
|
|
(report-error (G_ " ... propagated from ~a@~a~%")
|
|
|
|
|
(manifest-entry-name parent)
|
|
|
|
|
(manifest-entry-version parent))
|
|
|
|
|
(report-parent-entries parent))))
|
|
|
|
|
|
|
|
|
|
(define (manifest-entry-output* entry)
|
|
|
|
|
(match (manifest-entry-output entry)
|
|
|
|
|
("out" "")
|
|
|
|
|
(output (string-append ":" output))))
|
|
|
|
|
|
|
|
|
|
(report-error (G_ "profile contains conflicting entries for ~a~a~%")
|
|
|
|
|
(manifest-entry-name entry)
|
|
|
|
|
(manifest-entry-output* entry))
|
|
|
|
|
(report-error (G_ " first entry: ~a@~a~a ~a~%")
|
|
|
|
|
(manifest-entry-name entry)
|
|
|
|
|
(manifest-entry-version entry)
|
|
|
|
|
(manifest-entry-output* entry)
|
|
|
|
|
(manifest-entry-item entry))
|
|
|
|
|
(report-parent-entries entry)
|
|
|
|
|
(report-error (G_ " second entry: ~a@~a~a ~a~%")
|
|
|
|
|
(manifest-entry-name conflict)
|
|
|
|
|
(manifest-entry-version conflict)
|
|
|
|
|
(manifest-entry-output* conflict)
|
|
|
|
|
(manifest-entry-item conflict))
|
|
|
|
|
(report-parent-entries conflict)
|
|
|
|
|
(display-collision-resolution-hint c)
|
|
|
|
|
(exit 1)))
|
|
|
|
|
((nar-error? c)
|
|
|
|
|
(let ((file (nar-error-file c))
|
|
|
|
|
(port (nar-error-port c)))
|
|
|
|
|
(if file
|
|
|
|
|
(leave (G_ "corrupt input while restoring '~a' from ~s~%")
|
|
|
|
|
file (or (port-filename* port) port))
|
|
|
|
|
(leave (G_ "corrupt input while restoring archive from ~s~%")
|
|
|
|
|
(or (port-filename* port) port)))))
|
|
|
|
|
((store-connection-error? c)
|
|
|
|
|
(leave (G_ "failed to connect to `~a': ~a~%")
|
|
|
|
|
(store-connection-error-file c)
|
|
|
|
|
(strerror (store-connection-error-code c))))
|
|
|
|
|
((store-protocol-error? c)
|
|
|
|
|
;; FIXME: Server-provided error messages aren't i18n'd.
|
|
|
|
|
(leave (G_ "~a~%")
|
|
|
|
|
(store-protocol-error-message c)))
|
|
|
|
|
((derivation-missing-output-error? c)
|
|
|
|
|
(leave (G_ "reference to invalid output '~a' of derivation '~a'~%")
|
|
|
|
|
(derivation-missing-output c)
|
|
|
|
|
(derivation-file-name (derivation-error-derivation c))))
|
|
|
|
|
((file-search-error? c)
|
|
|
|
|
(leave (G_ "file '~a' could not be found in these \
|
2016-03-22 10:00:53 -04:00
|
|
|
|
directories:~{ ~a~}~%")
|
2020-07-14 19:11:00 -04:00
|
|
|
|
(file-search-error-file-name c)
|
|
|
|
|
(file-search-error-search-path c)))
|
|
|
|
|
((invoke-error? c)
|
|
|
|
|
(leave (G_ "program exited\
|
2018-03-16 18:29:31 -04:00
|
|
|
|
~@[ with non-zero exit status ~a~]\
|
|
|
|
|
~@[ terminated by signal ~a~]\
|
|
|
|
|
~@[ stopped by signal ~a~]: ~s~%")
|
2020-07-14 19:11:00 -04:00
|
|
|
|
(invoke-error-exit-status c)
|
|
|
|
|
(invoke-error-term-signal c)
|
|
|
|
|
(invoke-error-stop-signal c)
|
|
|
|
|
(cons (invoke-error-program c)
|
|
|
|
|
(invoke-error-arguments c))))
|
|
|
|
|
|
2020-07-25 11:59:13 -04:00
|
|
|
|
((formatted-message? c)
|
|
|
|
|
(apply report-error
|
|
|
|
|
(and (error-location? c) (error-location c))
|
|
|
|
|
(gettext (formatted-message-string c) %gettext-domain)
|
|
|
|
|
(formatted-message-arguments c))
|
|
|
|
|
(when (fix-hint? c)
|
|
|
|
|
(display-hint (condition-fix-hint c)))
|
|
|
|
|
(exit 1))
|
|
|
|
|
|
2020-07-14 19:11:00 -04:00
|
|
|
|
;; On Guile 3.0.0, exceptions such as 'unbound-variable' are
|
|
|
|
|
;; compound and include a '&message'. However, that message only
|
|
|
|
|
;; contains the format string. Thus, special-case it here to
|
|
|
|
|
;; avoid displaying a bare format string.
|
|
|
|
|
;;
|
|
|
|
|
;; Furthermore, use of 'guard*' ensures that the stack has not
|
|
|
|
|
;; been unwound when we re-raise, since that would otherwise show
|
|
|
|
|
;; useless backtraces.
|
2021-05-26 16:30:31 -04:00
|
|
|
|
(((exception-predicate &exception-with-kind-and-args) c)
|
2021-05-26 17:06:13 -04:00
|
|
|
|
(if (eq? 'system-error (exception-kind c)) ;EPIPE & co.
|
|
|
|
|
(match (exception-args c)
|
|
|
|
|
((proc format-string format-args . _)
|
|
|
|
|
(leave (G_ "~a: ~a~%") proc
|
|
|
|
|
(apply format #f format-string format-args))))
|
|
|
|
|
(raise c)))
|
2020-08-04 15:27:30 -04:00
|
|
|
|
|
|
|
|
|
((message-condition? c)
|
|
|
|
|
;; Normally '&message' error conditions have an i18n'd message.
|
|
|
|
|
(report-error (and (error-location? c) (error-location c))
|
|
|
|
|
(G_ "~a~%")
|
|
|
|
|
(gettext (condition-message c) %gettext-domain))
|
|
|
|
|
(when (fix-hint? c)
|
|
|
|
|
(display-hint (condition-fix-hint c)))
|
|
|
|
|
(exit 1)))
|
2021-05-26 17:06:13 -04:00
|
|
|
|
(thunk)))
|
2012-10-31 19:50:01 -04:00
|
|
|
|
|
2015-07-15 12:01:05 -04:00
|
|
|
|
(define-syntax-rule (leave-on-EPIPE exp ...)
|
2020-04-16 17:17:16 -04:00
|
|
|
|
"Run EXP... in a context where EPIPE errors are caught and lead to 'exit'
|
2015-07-15 12:01:05 -04:00
|
|
|
|
with successful exit code. This is useful when writing to the standard output
|
|
|
|
|
may lead to EPIPE, because the standard output is piped through 'head' or
|
|
|
|
|
similar."
|
|
|
|
|
(catch 'system-error
|
|
|
|
|
(lambda ()
|
|
|
|
|
exp ...)
|
|
|
|
|
(lambda args
|
|
|
|
|
;; We really have to exit this brutally, otherwise Guile eventually
|
|
|
|
|
;; attempts to flush all the ports, leading to an uncaught EPIPE down
|
|
|
|
|
;; the path.
|
|
|
|
|
(if (= EPIPE (system-error-errno args))
|
|
|
|
|
(primitive-_exit 0)
|
|
|
|
|
(apply throw args)))))
|
|
|
|
|
|
2014-06-14 16:37:24 -04:00
|
|
|
|
(define %guix-user-module
|
|
|
|
|
;; Module in which user expressions are evaluated.
|
2014-06-14 17:23:56 -04:00
|
|
|
|
;; Compute lazily to avoid circularity with (guix gexp).
|
|
|
|
|
(delay
|
|
|
|
|
(let ((module (make-module)))
|
|
|
|
|
(beautify-user-module! module)
|
|
|
|
|
;; Use (guix gexp) so that one can use #~ & co.
|
|
|
|
|
(module-use! module (resolve-interface '(guix gexp)))
|
|
|
|
|
module)))
|
2014-06-14 16:37:24 -04:00
|
|
|
|
|
2013-11-18 17:08:20 -05:00
|
|
|
|
(define (read/eval str)
|
|
|
|
|
"Read and evaluate STR, raising an error if something goes wrong."
|
2013-03-01 15:55:42 -05:00
|
|
|
|
(let ((exp (catch #t
|
|
|
|
|
(lambda ()
|
|
|
|
|
(call-with-input-string str read))
|
|
|
|
|
(lambda args
|
ui: Rename '_' to 'G_'.
This avoids collisions with '_' when the latter is used as a 'match'
pattern for instance. See
<https://lists.gnu.org/archive/html/guix-devel/2017-04/msg00464.html>.
* guix/ui.scm: Rename '_' to 'G_'.
* po/guix/Makevars (XGETTEXT_OPTIONS): Adjust accordingly.
* build-aux/compile-all.scm (warnings): Remove 'format'.
* gnu/packages.scm,
gnu/services.scm,
gnu/services/shepherd.scm,
gnu/system.scm,
gnu/system/shadow.scm,
guix/gnupg.scm,
guix/http-client.scm,
guix/import/cpan.scm,
guix/import/elpa.scm,
guix/import/pypi.scm,
guix/nar.scm,
guix/scripts.scm,
guix/scripts/archive.scm,
guix/scripts/authenticate.scm,
guix/scripts/build.scm,
guix/scripts/challenge.scm,
guix/scripts/container.scm,
guix/scripts/container/exec.scm,
guix/scripts/copy.scm,
guix/scripts/download.scm,
guix/scripts/edit.scm,
guix/scripts/environment.scm,
guix/scripts/gc.scm,
guix/scripts/graph.scm,
guix/scripts/hash.scm,
guix/scripts/import.scm,
guix/scripts/import/cpan.scm,
guix/scripts/import/cran.scm,
guix/scripts/import/crate.scm,
guix/scripts/import/elpa.scm,
guix/scripts/import/gem.scm,
guix/scripts/import/gnu.scm,
guix/scripts/import/hackage.scm,
guix/scripts/import/nix.scm,
guix/scripts/import/pypi.scm,
guix/scripts/import/stackage.scm,
guix/scripts/lint.scm,
guix/scripts/offload.scm,
guix/scripts/pack.scm,
guix/scripts/package.scm,
guix/scripts/perform-download.scm,
guix/scripts/publish.scm,
guix/scripts/pull.scm,
guix/scripts/refresh.scm,
guix/scripts/size.scm,
guix/scripts/substitute.scm,
guix/scripts/system.scm,
guix/ssh.scm,
guix/upstream.scm: Use 'G_' instead of '_'. Most of this change was
obtained by running: "sed -i -e's/(_ "/(G_ "/g' `find -name \*.scm`".
2017-05-03 09:57:02 -04:00
|
|
|
|
(leave (G_ "failed to read expression ~s: ~s~%")
|
2013-03-01 15:55:42 -05:00
|
|
|
|
str args)))))
|
2013-11-18 17:08:20 -05:00
|
|
|
|
(catch #t
|
|
|
|
|
(lambda ()
|
2014-06-14 17:23:56 -04:00
|
|
|
|
(eval exp (force %guix-user-module)))
|
2013-11-18 17:08:20 -05:00
|
|
|
|
(lambda args
|
ui: Rename '_' to 'G_'.
This avoids collisions with '_' when the latter is used as a 'match'
pattern for instance. See
<https://lists.gnu.org/archive/html/guix-devel/2017-04/msg00464.html>.
* guix/ui.scm: Rename '_' to 'G_'.
* po/guix/Makevars (XGETTEXT_OPTIONS): Adjust accordingly.
* build-aux/compile-all.scm (warnings): Remove 'format'.
* gnu/packages.scm,
gnu/services.scm,
gnu/services/shepherd.scm,
gnu/system.scm,
gnu/system/shadow.scm,
guix/gnupg.scm,
guix/http-client.scm,
guix/import/cpan.scm,
guix/import/elpa.scm,
guix/import/pypi.scm,
guix/nar.scm,
guix/scripts.scm,
guix/scripts/archive.scm,
guix/scripts/authenticate.scm,
guix/scripts/build.scm,
guix/scripts/challenge.scm,
guix/scripts/container.scm,
guix/scripts/container/exec.scm,
guix/scripts/copy.scm,
guix/scripts/download.scm,
guix/scripts/edit.scm,
guix/scripts/environment.scm,
guix/scripts/gc.scm,
guix/scripts/graph.scm,
guix/scripts/hash.scm,
guix/scripts/import.scm,
guix/scripts/import/cpan.scm,
guix/scripts/import/cran.scm,
guix/scripts/import/crate.scm,
guix/scripts/import/elpa.scm,
guix/scripts/import/gem.scm,
guix/scripts/import/gnu.scm,
guix/scripts/import/hackage.scm,
guix/scripts/import/nix.scm,
guix/scripts/import/pypi.scm,
guix/scripts/import/stackage.scm,
guix/scripts/lint.scm,
guix/scripts/offload.scm,
guix/scripts/pack.scm,
guix/scripts/package.scm,
guix/scripts/perform-download.scm,
guix/scripts/publish.scm,
guix/scripts/pull.scm,
guix/scripts/refresh.scm,
guix/scripts/size.scm,
guix/scripts/substitute.scm,
guix/scripts/system.scm,
guix/ssh.scm,
guix/upstream.scm: Use 'G_' instead of '_'. Most of this change was
obtained by running: "sed -i -e's/(_ "/(G_ "/g' `find -name \*.scm`".
2017-05-03 09:57:02 -04:00
|
|
|
|
(report-error (G_ "failed to evaluate expression '~a':~%") exp)
|
2015-05-26 16:38:17 -04:00
|
|
|
|
(match args
|
|
|
|
|
(('syntax-error proc message properties form . rest)
|
ui: Rename '_' to 'G_'.
This avoids collisions with '_' when the latter is used as a 'match'
pattern for instance. See
<https://lists.gnu.org/archive/html/guix-devel/2017-04/msg00464.html>.
* guix/ui.scm: Rename '_' to 'G_'.
* po/guix/Makevars (XGETTEXT_OPTIONS): Adjust accordingly.
* build-aux/compile-all.scm (warnings): Remove 'format'.
* gnu/packages.scm,
gnu/services.scm,
gnu/services/shepherd.scm,
gnu/system.scm,
gnu/system/shadow.scm,
guix/gnupg.scm,
guix/http-client.scm,
guix/import/cpan.scm,
guix/import/elpa.scm,
guix/import/pypi.scm,
guix/nar.scm,
guix/scripts.scm,
guix/scripts/archive.scm,
guix/scripts/authenticate.scm,
guix/scripts/build.scm,
guix/scripts/challenge.scm,
guix/scripts/container.scm,
guix/scripts/container/exec.scm,
guix/scripts/copy.scm,
guix/scripts/download.scm,
guix/scripts/edit.scm,
guix/scripts/environment.scm,
guix/scripts/gc.scm,
guix/scripts/graph.scm,
guix/scripts/hash.scm,
guix/scripts/import.scm,
guix/scripts/import/cpan.scm,
guix/scripts/import/cran.scm,
guix/scripts/import/crate.scm,
guix/scripts/import/elpa.scm,
guix/scripts/import/gem.scm,
guix/scripts/import/gnu.scm,
guix/scripts/import/hackage.scm,
guix/scripts/import/nix.scm,
guix/scripts/import/pypi.scm,
guix/scripts/import/stackage.scm,
guix/scripts/lint.scm,
guix/scripts/offload.scm,
guix/scripts/pack.scm,
guix/scripts/package.scm,
guix/scripts/perform-download.scm,
guix/scripts/publish.scm,
guix/scripts/pull.scm,
guix/scripts/refresh.scm,
guix/scripts/size.scm,
guix/scripts/substitute.scm,
guix/scripts/system.scm,
guix/ssh.scm,
guix/upstream.scm: Use 'G_' instead of '_'. Most of this change was
obtained by running: "sed -i -e's/(_ "/(G_ "/g' `find -name \*.scm`".
2017-05-03 09:57:02 -04:00
|
|
|
|
(report-error (G_ "syntax error: ~a~%") message))
|
2019-11-26 06:21:26 -05:00
|
|
|
|
(((or 'srfi-34 '%exception) obj)
|
2020-07-25 11:59:13 -04:00
|
|
|
|
(cond ((message-condition? obj)
|
|
|
|
|
(report-error (G_ "~a~%")
|
|
|
|
|
(gettext (condition-message obj)
|
|
|
|
|
%gettext-domain)))
|
|
|
|
|
((formatted-message? obj)
|
|
|
|
|
(apply report-error #f
|
|
|
|
|
(gettext (formatted-message-string obj)
|
|
|
|
|
%gettext-domain)
|
|
|
|
|
(formatted-message-arguments obj)))
|
|
|
|
|
(else
|
|
|
|
|
(report-error (G_ "exception thrown: ~s~%") obj))))
|
2015-05-26 16:38:17 -04:00
|
|
|
|
((error args ...)
|
|
|
|
|
(apply display-error #f (current-error-port) args))
|
|
|
|
|
(what? #f))
|
|
|
|
|
(exit 1)))))
|
2013-11-18 17:08:20 -05:00
|
|
|
|
|
|
|
|
|
(define (read/eval-package-expression str)
|
|
|
|
|
"Read and evaluate STR and return the package it refers to, or exit an
|
|
|
|
|
error."
|
|
|
|
|
(match (read/eval str)
|
|
|
|
|
((? package? p) p)
|
2016-09-20 04:51:39 -04:00
|
|
|
|
(x
|
ui: Rename '_' to 'G_'.
This avoids collisions with '_' when the latter is used as a 'match'
pattern for instance. See
<https://lists.gnu.org/archive/html/guix-devel/2017-04/msg00464.html>.
* guix/ui.scm: Rename '_' to 'G_'.
* po/guix/Makevars (XGETTEXT_OPTIONS): Adjust accordingly.
* build-aux/compile-all.scm (warnings): Remove 'format'.
* gnu/packages.scm,
gnu/services.scm,
gnu/services/shepherd.scm,
gnu/system.scm,
gnu/system/shadow.scm,
guix/gnupg.scm,
guix/http-client.scm,
guix/import/cpan.scm,
guix/import/elpa.scm,
guix/import/pypi.scm,
guix/nar.scm,
guix/scripts.scm,
guix/scripts/archive.scm,
guix/scripts/authenticate.scm,
guix/scripts/build.scm,
guix/scripts/challenge.scm,
guix/scripts/container.scm,
guix/scripts/container/exec.scm,
guix/scripts/copy.scm,
guix/scripts/download.scm,
guix/scripts/edit.scm,
guix/scripts/environment.scm,
guix/scripts/gc.scm,
guix/scripts/graph.scm,
guix/scripts/hash.scm,
guix/scripts/import.scm,
guix/scripts/import/cpan.scm,
guix/scripts/import/cran.scm,
guix/scripts/import/crate.scm,
guix/scripts/import/elpa.scm,
guix/scripts/import/gem.scm,
guix/scripts/import/gnu.scm,
guix/scripts/import/hackage.scm,
guix/scripts/import/nix.scm,
guix/scripts/import/pypi.scm,
guix/scripts/import/stackage.scm,
guix/scripts/lint.scm,
guix/scripts/offload.scm,
guix/scripts/pack.scm,
guix/scripts/package.scm,
guix/scripts/perform-download.scm,
guix/scripts/publish.scm,
guix/scripts/pull.scm,
guix/scripts/refresh.scm,
guix/scripts/size.scm,
guix/scripts/substitute.scm,
guix/scripts/system.scm,
guix/ssh.scm,
guix/upstream.scm: Use 'G_' instead of '_'. Most of this change was
obtained by running: "sed -i -e's/(_ "/(G_ "/g' `find -name \*.scm`".
2017-05-03 09:57:02 -04:00
|
|
|
|
(leave (G_ "expression ~s does not evaluate to a package~%")
|
2013-11-18 17:08:20 -05:00
|
|
|
|
str))))
|
2013-03-01 15:55:42 -05:00
|
|
|
|
|
2015-07-23 09:08:39 -04:00
|
|
|
|
(define (show-derivation-outputs derivation)
|
2019-06-23 12:46:53 -04:00
|
|
|
|
"Show the output file names of DERIVATION, which can be a derivation or a
|
|
|
|
|
derivation input."
|
|
|
|
|
(define (show-outputs derivation outputs)
|
|
|
|
|
(format #t "~{~a~%~}"
|
|
|
|
|
(map (cut derivation->output-path derivation <>)
|
|
|
|
|
outputs)))
|
|
|
|
|
|
|
|
|
|
(match derivation
|
|
|
|
|
((? derivation?)
|
|
|
|
|
(show-outputs derivation (derivation-output-names derivation)))
|
|
|
|
|
((? derivation-input? input)
|
|
|
|
|
(show-outputs (derivation-input-derivation input)
|
|
|
|
|
(derivation-input-sub-derivations input)))))
|
2015-07-23 09:08:39 -04:00
|
|
|
|
|
2018-07-02 17:51:20 -04:00
|
|
|
|
(define* (check-available-space need
|
|
|
|
|
#:optional (directory (%store-prefix)))
|
|
|
|
|
"Make sure at least NEED bytes are available in DIRECTORY. Otherwise emit a
|
2017-05-31 09:26:21 -04:00
|
|
|
|
warning."
|
|
|
|
|
(let ((free (catch 'system-error
|
|
|
|
|
(lambda ()
|
2018-07-02 17:51:20 -04:00
|
|
|
|
(free-disk-space directory))
|
2017-05-31 09:26:21 -04:00
|
|
|
|
(const #f))))
|
|
|
|
|
(when (and free (>= need free))
|
|
|
|
|
(warning (G_ "at least ~,1h MB needed but only ~,1h MB available in ~a~%")
|
2018-07-02 17:51:20 -04:00
|
|
|
|
(/ need 1e6) (/ free 1e6) directory))))
|
2017-05-31 09:26:21 -04:00
|
|
|
|
|
2018-11-26 16:31:09 -05:00
|
|
|
|
(define (graft-derivation? drv)
|
|
|
|
|
"Return true if DRV is definitely a graft derivation, false otherwise."
|
|
|
|
|
(match (assq-ref (derivation-properties drv) 'type)
|
|
|
|
|
('graft #t)
|
|
|
|
|
(_ #f)))
|
|
|
|
|
|
2018-12-19 08:36:29 -05:00
|
|
|
|
(define (profile-hook-derivation? drv)
|
|
|
|
|
"Return true if DRV is definitely a profile hook derivation, false otherwise."
|
|
|
|
|
(match (assq-ref (derivation-properties drv) 'type)
|
|
|
|
|
('profile-hook #t)
|
|
|
|
|
(_ #f)))
|
|
|
|
|
|
2019-10-01 04:45:05 -04:00
|
|
|
|
(define (colorize-store-file-name file)
|
|
|
|
|
"Colorize FILE, a store file name, such that the hash part is less prominent
|
2022-01-21 22:46:36 -05:00
|
|
|
|
than the rest."
|
2019-10-01 04:45:05 -04:00
|
|
|
|
(let ((len (string-length file))
|
|
|
|
|
(prefix (+ (string-length (%store-prefix)) 32 2)))
|
|
|
|
|
(if (< len prefix)
|
|
|
|
|
file
|
|
|
|
|
(string-append (colorize-string (string-take file prefix)
|
|
|
|
|
(color DARK))
|
|
|
|
|
(string-drop file prefix)))))
|
|
|
|
|
|
2020-07-22 17:11:56 -04:00
|
|
|
|
(define %default-verbosity
|
|
|
|
|
;; Default verbosity level for 'show-what-to-build'.
|
|
|
|
|
2)
|
|
|
|
|
|
2013-04-16 18:06:59 -04:00
|
|
|
|
(define* (show-what-to-build store drv
|
2015-12-09 04:30:03 -05:00
|
|
|
|
#:key dry-run? (use-substitutes? #t)
|
2020-07-22 17:11:56 -04:00
|
|
|
|
(verbosity %default-verbosity)
|
2015-12-09 04:30:03 -05:00
|
|
|
|
(mode (build-mode normal)))
|
2013-02-20 17:41:24 -05:00
|
|
|
|
"Show what will or would (depending on DRY-RUN?) be built in realizing the
|
2019-06-23 12:35:26 -04:00
|
|
|
|
derivations listed in DRV using MODE, a 'build-mode' value. The elements of
|
|
|
|
|
DRV can be either derivations or derivation inputs.
|
|
|
|
|
|
2020-03-22 06:52:41 -04:00
|
|
|
|
Return two values: a Boolean indicating whether there's something to build,
|
2020-07-22 17:11:56 -04:00
|
|
|
|
and a Boolean indicating whether there's something to download.
|
|
|
|
|
|
|
|
|
|
When USE-SUBSTITUTES?, check and report what is prerequisites are available
|
|
|
|
|
for download. VERBOSITY is an integer indicating the level of details to be
|
|
|
|
|
shown: level 2 and higher provide all the details, level 1 shows a high-level
|
|
|
|
|
summary, and level 0 shows nothing."
|
2019-06-23 12:35:26 -04:00
|
|
|
|
(define inputs
|
|
|
|
|
(map (match-lambda
|
|
|
|
|
((? derivation? drv) (derivation-input drv))
|
|
|
|
|
((? derivation-input? input) input))
|
|
|
|
|
drv))
|
|
|
|
|
|
2017-05-31 05:06:42 -04:00
|
|
|
|
(define substitutable-info
|
2020-04-16 17:17:16 -04:00
|
|
|
|
;; Call 'substitution-oracle' upfront so we don't end up launching the
|
2015-01-09 18:39:59 -05:00
|
|
|
|
;; substituter many times. This makes a big difference, especially when
|
|
|
|
|
;; DRV is a long list as is the case with 'guix environment'.
|
|
|
|
|
(if use-substitutes?
|
2019-07-04 18:09:27 -04:00
|
|
|
|
(substitution-oracle store inputs #:mode mode)
|
2015-01-09 18:39:59 -05:00
|
|
|
|
(const #f)))
|
|
|
|
|
|
2019-10-01 04:45:05 -04:00
|
|
|
|
(define colorized-store-item
|
|
|
|
|
(if (color-output? (current-error-port))
|
|
|
|
|
colorize-store-file-name
|
|
|
|
|
identity))
|
|
|
|
|
|
2020-03-22 06:50:40 -04:00
|
|
|
|
(let*-values (((build/full download)
|
2019-06-23 12:35:26 -04:00
|
|
|
|
(derivation-build-plan store inputs
|
2019-06-19 16:21:28 -04:00
|
|
|
|
#:mode mode
|
|
|
|
|
#:substitutable-info
|
|
|
|
|
substitutable-info))
|
2018-12-19 08:36:29 -05:00
|
|
|
|
((graft hook build)
|
2019-06-19 16:21:28 -04:00
|
|
|
|
(match (fold (lambda (drv acc)
|
|
|
|
|
(let ((file (derivation-file-name drv)))
|
2018-12-19 08:36:29 -05:00
|
|
|
|
(match acc
|
|
|
|
|
((#:graft graft #:hook hook #:build build)
|
|
|
|
|
(cond
|
|
|
|
|
((graft-derivation? drv)
|
|
|
|
|
`(#:graft ,(cons file graft)
|
|
|
|
|
#:hook ,hook
|
|
|
|
|
#:build ,build))
|
|
|
|
|
((profile-hook-derivation? drv)
|
|
|
|
|
`(#:graft ,graft
|
|
|
|
|
#:hook ,(cons file hook)
|
|
|
|
|
#:build ,build))
|
|
|
|
|
(else
|
|
|
|
|
`(#:graft ,graft
|
|
|
|
|
#:hook ,hook
|
|
|
|
|
#:build ,(cons file build))))))))
|
|
|
|
|
'(#:graft () #:hook () #:build ())
|
2020-03-22 06:50:40 -04:00
|
|
|
|
build/full)
|
2018-12-19 08:36:29 -05:00
|
|
|
|
((#:graft graft #:hook hook #:build build)
|
|
|
|
|
(values graft hook build)))))
|
2017-05-31 09:26:21 -04:00
|
|
|
|
(define installed-size
|
|
|
|
|
(reduce + 0 (map substitutable-nar-size download)))
|
|
|
|
|
|
2017-05-31 09:06:28 -04:00
|
|
|
|
(define download-size
|
|
|
|
|
(/ (reduce + 0 (map substitutable-download-size download))
|
|
|
|
|
1e6))
|
|
|
|
|
|
|
|
|
|
(define display-download-size?
|
|
|
|
|
;; Sometimes narinfos lack information about the download size. Only
|
|
|
|
|
;; display when we have information for all of DOWNLOAD.
|
|
|
|
|
(not (any (compose zero? substitutable-download-size) download)))
|
|
|
|
|
|
2020-07-22 17:11:56 -04:00
|
|
|
|
;; Combinatorial explosion ahead along two axes: DRY-RUN? and VERBOSITY.
|
|
|
|
|
;; Unfortunately, this is hardly avoidable for proper i18n.
|
2013-02-20 17:41:24 -05:00
|
|
|
|
(if dry-run?
|
2013-04-16 18:06:59 -04:00
|
|
|
|
(begin
|
2022-03-09 04:36:28 -05:00
|
|
|
|
(unless (or (zero? verbosity) (null? build))
|
2020-07-22 17:11:56 -04:00
|
|
|
|
(format (current-error-port)
|
2022-03-09 04:36:28 -05:00
|
|
|
|
(highlight/warn
|
|
|
|
|
(N_ "The following derivation would be built:~%"
|
|
|
|
|
"The following derivations would be built:~%"
|
|
|
|
|
(length build))))
|
|
|
|
|
(format (current-error-port) "~{ ~a~%~}"
|
|
|
|
|
(map colorized-store-item build)))
|
2020-07-22 17:11:56 -04:00
|
|
|
|
(cond ((>= verbosity 2)
|
|
|
|
|
(if display-download-size?
|
2022-03-09 04:47:52 -05:00
|
|
|
|
(begin
|
|
|
|
|
(format (current-error-port)
|
|
|
|
|
(highlight
|
|
|
|
|
;; TRANSLATORS: "MB" is for "megabyte"; it
|
|
|
|
|
;; should be translated to the corresponding
|
|
|
|
|
;; abbreviation.
|
|
|
|
|
(G_ "~:[~,1h MB would be downloaded:~%~;~]"))
|
|
|
|
|
(null? download)
|
|
|
|
|
download-size)
|
|
|
|
|
(format (current-error-port) "~{ ~a~%~}"
|
|
|
|
|
(map (compose colorized-store-item substitutable-path)
|
|
|
|
|
download)))
|
|
|
|
|
(begin
|
|
|
|
|
(format (current-error-port)
|
|
|
|
|
(highlight
|
|
|
|
|
(N_ "~:[The following file would be downloaded:~%~;~]"
|
|
|
|
|
"~:[The following files would be downloaded:~%~;~]"
|
|
|
|
|
(length download)))
|
|
|
|
|
(null? download))
|
|
|
|
|
(format (current-error-port) "~{ ~a~%~}"
|
|
|
|
|
(map (compose colorized-store-item substitutable-path)
|
|
|
|
|
download))))
|
2020-07-22 17:11:56 -04:00
|
|
|
|
(format (current-error-port)
|
|
|
|
|
(N_ "~:[The following graft would be made:~%~{ ~a~%~}~;~]"
|
|
|
|
|
"~:[The following grafts would be made:~%~{ ~a~%~}~;~]"
|
|
|
|
|
(length graft))
|
|
|
|
|
(null? graft) (map colorized-store-item graft))
|
|
|
|
|
(format (current-error-port)
|
|
|
|
|
(N_ "~:[The following profile hook would be built:~%~{ ~a~%~}~;~]"
|
|
|
|
|
"~:[The following profile hooks would be built:~%~{ ~a~%~}~;~]"
|
|
|
|
|
(length hook))
|
|
|
|
|
(null? hook) (map colorized-store-item hook)))
|
|
|
|
|
((= verbosity 1)
|
|
|
|
|
;; Display the bare minimum; don't mention grafts and hooks.
|
2020-09-14 09:16:59 -04:00
|
|
|
|
(unless (null? build)
|
|
|
|
|
(newline (current-error-port)))
|
2020-07-22 17:11:56 -04:00
|
|
|
|
(if display-download-size?
|
|
|
|
|
(format (current-error-port)
|
|
|
|
|
;; TRANSLATORS: "MB" is for "megabyte"; it should be
|
|
|
|
|
;; translated to the corresponding abbreviation.
|
2020-09-14 09:16:59 -04:00
|
|
|
|
(highlight (G_ "~:[~,1h MB would be downloaded~%~;~]"))
|
2020-07-22 17:11:56 -04:00
|
|
|
|
(null? download) download-size)
|
|
|
|
|
(format (current-error-port)
|
2020-09-14 09:16:59 -04:00
|
|
|
|
(highlight
|
|
|
|
|
(N_ "~:[~h item would be downloaded~%~;~]"
|
|
|
|
|
"~:[~h items would be downloaded~%~;~]"
|
|
|
|
|
(length download)))
|
2020-07-22 17:11:56 -04:00
|
|
|
|
(null? download) (length download))))))
|
|
|
|
|
|
2013-04-16 18:06:59 -04:00
|
|
|
|
(begin
|
2022-03-09 04:36:28 -05:00
|
|
|
|
(unless (or (zero? verbosity) (null? build))
|
2020-07-22 17:11:56 -04:00
|
|
|
|
(format (current-error-port)
|
2022-03-09 04:36:28 -05:00
|
|
|
|
(highlight/warn
|
|
|
|
|
(N_ "The following derivation will be built:~%"
|
|
|
|
|
"The following derivations will be built:~%"
|
|
|
|
|
(length build))))
|
|
|
|
|
(format (current-error-port) "~{ ~a~%~}"
|
|
|
|
|
(map colorized-store-item build)))
|
2020-07-22 17:11:56 -04:00
|
|
|
|
(cond ((>= verbosity 2)
|
|
|
|
|
(if display-download-size?
|
2022-03-09 04:47:52 -05:00
|
|
|
|
(begin
|
|
|
|
|
(format (current-error-port)
|
|
|
|
|
(highlight
|
|
|
|
|
;; TRANSLATORS: "MB" is for "megabyte"; it
|
|
|
|
|
;; should be translated to the corresponding
|
|
|
|
|
;; abbreviation.
|
|
|
|
|
(G_ "~:[~,1h MB will be downloaded:~%~;~]"))
|
|
|
|
|
(null? download)
|
|
|
|
|
download-size)
|
|
|
|
|
(format (current-error-port) "~{ ~a~%~}"
|
|
|
|
|
(map (compose colorized-store-item substitutable-path)
|
|
|
|
|
download)))
|
|
|
|
|
(begin
|
|
|
|
|
(format (current-error-port)
|
|
|
|
|
(highlight
|
|
|
|
|
(N_ "~:[The following file will be downloaded:~%~;~]"
|
|
|
|
|
"~:[The following files will be downloaded:~%~;~]"
|
|
|
|
|
(length download)))
|
|
|
|
|
(null? download))
|
|
|
|
|
(format (current-error-port) "~{ ~a~%~}"
|
|
|
|
|
(map (compose colorized-store-item substitutable-path)
|
|
|
|
|
download))))
|
2020-07-22 17:11:56 -04:00
|
|
|
|
(format (current-error-port)
|
|
|
|
|
(N_ "~:[The following graft will be made:~%~{ ~a~%~}~;~]"
|
|
|
|
|
"~:[The following grafts will be made:~%~{ ~a~%~}~;~]"
|
|
|
|
|
(length graft))
|
|
|
|
|
(null? graft) (map colorized-store-item graft))
|
|
|
|
|
(format (current-error-port)
|
|
|
|
|
(N_ "~:[The following profile hook will be built:~%~{ ~a~%~}~;~]"
|
|
|
|
|
"~:[The following profile hooks will be built:~%~{ ~a~%~}~;~]"
|
|
|
|
|
(length hook))
|
|
|
|
|
(null? hook) (map colorized-store-item hook)))
|
|
|
|
|
((= verbosity 1)
|
|
|
|
|
;; Display the bare minimum; don't mention grafts and hooks.
|
2020-09-14 09:16:59 -04:00
|
|
|
|
(unless (null? build)
|
|
|
|
|
(newline (current-error-port)))
|
2020-07-22 17:11:56 -04:00
|
|
|
|
(if display-download-size?
|
|
|
|
|
(format (current-error-port)
|
|
|
|
|
;; TRANSLATORS: "MB" is for "megabyte"; it should be
|
|
|
|
|
;; translated to the corresponding abbreviation.
|
2020-09-14 09:16:59 -04:00
|
|
|
|
(highlight (G_ "~:[~,1h MB will be downloaded~%~;~]"))
|
2020-07-22 17:11:56 -04:00
|
|
|
|
(null? download) download-size)
|
|
|
|
|
(format (current-error-port)
|
2020-09-14 09:16:59 -04:00
|
|
|
|
(highlight
|
|
|
|
|
(N_ "~:[~h item will be downloaded~%~;~]"
|
|
|
|
|
"~:[~h items will be downloaded~%~;~]"
|
|
|
|
|
(length download)))
|
2020-07-22 17:11:56 -04:00
|
|
|
|
(null? download) (length download)))))))
|
2017-05-31 09:26:21 -04:00
|
|
|
|
|
|
|
|
|
(check-available-space installed-size)
|
|
|
|
|
|
2020-03-22 06:52:41 -04:00
|
|
|
|
(values (pair? build/full) (pair? download))))
|
2013-02-20 17:41:24 -05:00
|
|
|
|
|
2015-05-20 18:42:35 -04:00
|
|
|
|
(define show-what-to-build*
|
|
|
|
|
(store-lift show-what-to-build))
|
|
|
|
|
|
2020-07-22 17:11:56 -04:00
|
|
|
|
(define* (build-notifier #:key (dry-run? #f) (use-substitutes? #t)
|
|
|
|
|
(verbosity %default-verbosity))
|
2020-03-18 17:19:05 -04:00
|
|
|
|
"Return a procedure suitable for 'with-build-handler' that, when
|
|
|
|
|
'build-things' is called, invokes 'show-what-to-build' to display the build
|
|
|
|
|
plan. When DRY-RUN? is true, the 'with-build-handler' form returns without
|
|
|
|
|
any build happening."
|
|
|
|
|
(define not-comma
|
|
|
|
|
(char-set-complement (char-set #\,)))
|
|
|
|
|
|
|
|
|
|
(define (read-derivation-from-file* item)
|
|
|
|
|
(catch 'system-error
|
|
|
|
|
(lambda ()
|
|
|
|
|
(read-derivation-from-file item))
|
|
|
|
|
(const #f)))
|
|
|
|
|
|
|
|
|
|
(lambda (continue store things mode)
|
|
|
|
|
(define inputs
|
|
|
|
|
;; List of derivation inputs to build. Filter out non-existent '.drv'
|
|
|
|
|
;; files because the daemon transparently tries to substitute them.
|
|
|
|
|
(filter-map (match-lambda
|
|
|
|
|
(((? derivation-path? drv) . output)
|
|
|
|
|
(let ((drv (read-derivation-from-file* drv))
|
|
|
|
|
(outputs (string-tokenize output not-comma)))
|
|
|
|
|
(and drv (derivation-input drv outputs))))
|
|
|
|
|
((? derivation-path? drv)
|
|
|
|
|
(and=> (read-derivation-from-file* drv)
|
|
|
|
|
derivation-input))
|
|
|
|
|
(_
|
|
|
|
|
#f))
|
|
|
|
|
things))
|
|
|
|
|
|
2020-03-22 06:53:21 -04:00
|
|
|
|
(let-values (((build? download?)
|
|
|
|
|
(show-what-to-build store inputs
|
|
|
|
|
#:dry-run? dry-run?
|
|
|
|
|
#:use-substitutes? use-substitutes?
|
2020-07-22 17:11:56 -04:00
|
|
|
|
#:verbosity verbosity
|
2020-03-22 06:53:21 -04:00
|
|
|
|
#:mode mode)))
|
|
|
|
|
|
|
|
|
|
(unless (and (or build? download?)
|
|
|
|
|
dry-run?)
|
|
|
|
|
(continue #t)))))
|
2020-03-18 17:19:05 -04:00
|
|
|
|
|
2014-10-08 09:15:49 -04:00
|
|
|
|
(define (right-arrow port)
|
|
|
|
|
"Return either a string containing the 'RIGHT ARROW' character, or an ASCII
|
|
|
|
|
replacement if PORT is not Unicode-capable."
|
2017-03-08 16:21:31 -05:00
|
|
|
|
(let ((encoding (port-encoding port))
|
|
|
|
|
(arrow "→"))
|
|
|
|
|
(catch 'encoding-error
|
|
|
|
|
(lambda ()
|
|
|
|
|
(call-with-output-string
|
|
|
|
|
(lambda (port)
|
|
|
|
|
(set-port-encoding! port encoding)
|
|
|
|
|
(set-port-conversion-strategy! port 'error)
|
|
|
|
|
(display arrow port))))
|
|
|
|
|
(lambda (key . args)
|
|
|
|
|
"->"))))
|
2014-10-08 09:15:49 -04:00
|
|
|
|
|
2020-03-24 09:08:51 -04:00
|
|
|
|
(define* (tabulate rows #:key (initial-indent 0) (max-width 25)
|
|
|
|
|
(inter-column " "))
|
|
|
|
|
"Return a list of strings where each string is a tabulated representation of
|
|
|
|
|
an element of ROWS. All the ROWS must be lists of the same number of cells.
|
|
|
|
|
|
|
|
|
|
Add INITIAL-INDENT white space at the beginning of each row. Ensure that
|
|
|
|
|
columns are at most MAX-WIDTH characters wide. Use INTER-COLUMN as a
|
|
|
|
|
separator between subsequent columns."
|
|
|
|
|
(define column-widths
|
|
|
|
|
;; List of column widths.
|
|
|
|
|
(let loop ((rows rows)
|
|
|
|
|
(widths '()))
|
|
|
|
|
(match rows
|
|
|
|
|
(((? null?) ...)
|
|
|
|
|
(reverse widths))
|
|
|
|
|
(((column rest ...) ...)
|
|
|
|
|
(loop rest
|
|
|
|
|
(cons (min (apply max (map string-length column))
|
|
|
|
|
max-width)
|
|
|
|
|
widths))))))
|
|
|
|
|
|
|
|
|
|
(define indent
|
|
|
|
|
(make-string initial-indent #\space))
|
|
|
|
|
|
|
|
|
|
(define (string-pad-right* str len)
|
|
|
|
|
(if (> (string-length str) len)
|
|
|
|
|
str
|
|
|
|
|
(string-pad-right str len)))
|
|
|
|
|
|
|
|
|
|
(map (lambda (row)
|
|
|
|
|
(string-trim-right
|
|
|
|
|
(string-append indent
|
|
|
|
|
(string-join
|
|
|
|
|
(map string-pad-right* row column-widths)
|
|
|
|
|
inter-column))))
|
|
|
|
|
rows))
|
|
|
|
|
|
2014-10-08 09:15:49 -04:00
|
|
|
|
(define* (show-manifest-transaction store manifest transaction
|
|
|
|
|
#:key dry-run?)
|
|
|
|
|
"Display what will/would be installed/removed from MANIFEST by TRANSACTION."
|
2020-09-02 11:52:16 -04:00
|
|
|
|
(define* (package-strings names versions outputs #:key old-versions)
|
2020-09-02 13:08:46 -04:00
|
|
|
|
(tabulate (stable-sort
|
|
|
|
|
(zip (map (lambda (name output)
|
|
|
|
|
(if (string=? output "out")
|
|
|
|
|
name
|
|
|
|
|
(string-append name ":" output)))
|
|
|
|
|
names outputs)
|
|
|
|
|
(if old-versions
|
|
|
|
|
(map (lambda (old new)
|
|
|
|
|
(if (string=? old new)
|
|
|
|
|
(G_ "(dependencies or package changed)")
|
|
|
|
|
(string-append old " " → " " new)))
|
|
|
|
|
old-versions versions)
|
|
|
|
|
versions))
|
|
|
|
|
(lambda (x y)
|
|
|
|
|
(string<? (first x) (first y))))
|
2020-03-24 09:08:51 -04:00
|
|
|
|
#:initial-indent 3))
|
2014-10-08 09:15:49 -04:00
|
|
|
|
|
2020-09-02 11:52:16 -04:00
|
|
|
|
(define → ;an arrow that can be represented on stderr
|
|
|
|
|
(right-arrow (current-error-port)))
|
|
|
|
|
|
2015-02-08 12:52:00 -05:00
|
|
|
|
(let-values (((remove install upgrade downgrade)
|
2014-10-08 09:15:49 -04:00
|
|
|
|
(manifest-transaction-effects manifest transaction)))
|
|
|
|
|
(match remove
|
|
|
|
|
((($ <manifest-entry> name version output item) ..1)
|
|
|
|
|
(let ((len (length name))
|
2020-03-24 09:38:28 -04:00
|
|
|
|
(remove (package-strings name version output)))
|
2014-10-08 09:15:49 -04:00
|
|
|
|
(if dry-run?
|
|
|
|
|
(format (current-error-port)
|
|
|
|
|
(N_ "The following package would be removed:~%~{~a~%~}~%"
|
|
|
|
|
"The following packages would be removed:~%~{~a~%~}~%"
|
|
|
|
|
len)
|
|
|
|
|
remove)
|
|
|
|
|
(format (current-error-port)
|
|
|
|
|
(N_ "The following package will be removed:~%~{~a~%~}~%"
|
|
|
|
|
"The following packages will be removed:~%~{~a~%~}~%"
|
|
|
|
|
len)
|
|
|
|
|
remove))))
|
2017-03-08 15:36:54 -05:00
|
|
|
|
(x #f))
|
2015-02-08 12:52:00 -05:00
|
|
|
|
(match downgrade
|
|
|
|
|
(((($ <manifest-entry> name old-version)
|
|
|
|
|
. ($ <manifest-entry> _ new-version output item)) ..1)
|
|
|
|
|
(let ((len (length name))
|
2020-09-02 11:52:16 -04:00
|
|
|
|
(downgrade (package-strings name new-version output
|
|
|
|
|
#:old-versions old-version)))
|
2015-02-08 12:52:00 -05:00
|
|
|
|
(if dry-run?
|
|
|
|
|
(format (current-error-port)
|
|
|
|
|
(N_ "The following package would be downgraded:~%~{~a~%~}~%"
|
|
|
|
|
"The following packages would be downgraded:~%~{~a~%~}~%"
|
|
|
|
|
len)
|
|
|
|
|
downgrade)
|
|
|
|
|
(format (current-error-port)
|
|
|
|
|
(N_ "The following package will be downgraded:~%~{~a~%~}~%"
|
|
|
|
|
"The following packages will be downgraded:~%~{~a~%~}~%"
|
|
|
|
|
len)
|
|
|
|
|
downgrade))))
|
2017-03-08 15:36:54 -05:00
|
|
|
|
(x #f))
|
2014-10-08 09:15:49 -04:00
|
|
|
|
(match upgrade
|
|
|
|
|
(((($ <manifest-entry> name old-version)
|
|
|
|
|
. ($ <manifest-entry> _ new-version output item)) ..1)
|
|
|
|
|
(let ((len (length name))
|
2020-09-02 11:52:16 -04:00
|
|
|
|
(upgrade (package-strings name new-version output
|
|
|
|
|
#:old-versions old-version)))
|
2014-10-08 09:15:49 -04:00
|
|
|
|
(if dry-run?
|
|
|
|
|
(format (current-error-port)
|
|
|
|
|
(N_ "The following package would be upgraded:~%~{~a~%~}~%"
|
|
|
|
|
"The following packages would be upgraded:~%~{~a~%~}~%"
|
|
|
|
|
len)
|
|
|
|
|
upgrade)
|
|
|
|
|
(format (current-error-port)
|
|
|
|
|
(N_ "The following package will be upgraded:~%~{~a~%~}~%"
|
|
|
|
|
"The following packages will be upgraded:~%~{~a~%~}~%"
|
|
|
|
|
len)
|
|
|
|
|
upgrade))))
|
2017-03-08 15:36:54 -05:00
|
|
|
|
(x #f))
|
2014-10-08 09:15:49 -04:00
|
|
|
|
(match install
|
|
|
|
|
((($ <manifest-entry> name version output item _) ..1)
|
|
|
|
|
(let ((len (length name))
|
2020-03-24 09:38:28 -04:00
|
|
|
|
(install (package-strings name version output)))
|
2014-10-08 09:15:49 -04:00
|
|
|
|
(if dry-run?
|
|
|
|
|
(format (current-error-port)
|
|
|
|
|
(N_ "The following package would be installed:~%~{~a~%~}~%"
|
|
|
|
|
"The following packages would be installed:~%~{~a~%~}~%"
|
|
|
|
|
len)
|
|
|
|
|
install)
|
|
|
|
|
(format (current-error-port)
|
|
|
|
|
(N_ "The following package will be installed:~%~{~a~%~}~%"
|
|
|
|
|
"The following packages will be installed:~%~{~a~%~}~%"
|
|
|
|
|
len)
|
|
|
|
|
install))))
|
2017-03-08 15:36:54 -05:00
|
|
|
|
(x #f))))
|
2014-10-08 09:15:49 -04:00
|
|
|
|
|
2012-10-31 19:50:01 -04:00
|
|
|
|
(define-syntax with-error-handling
|
|
|
|
|
(syntax-rules ()
|
|
|
|
|
"Run BODY within a user-friendly error condition handler."
|
|
|
|
|
((_ body ...)
|
|
|
|
|
(call-with-error-handling
|
|
|
|
|
(lambda ()
|
|
|
|
|
body ...)))))
|
|
|
|
|
|
2020-03-20 07:44:43 -04:00
|
|
|
|
(define* (indented-string str indent
|
|
|
|
|
#:key (initial-indent? #t))
|
2020-04-16 17:17:16 -04:00
|
|
|
|
"Return STR with each newline preceded by INDENT spaces. When
|
2020-03-20 07:44:43 -04:00
|
|
|
|
INITIAL-INDENT? is true, the first line is also indented."
|
|
|
|
|
(define indent-string
|
|
|
|
|
(make-list indent #\space))
|
|
|
|
|
|
|
|
|
|
(list->string
|
|
|
|
|
(string-fold-right (lambda (chr result)
|
|
|
|
|
(if (eqv? chr #\newline)
|
|
|
|
|
(cons chr (append indent-string result))
|
|
|
|
|
(cons chr result)))
|
|
|
|
|
'()
|
|
|
|
|
(if initial-indent?
|
|
|
|
|
(string-append (list->string indent-string) str)
|
|
|
|
|
str))))
|
|
|
|
|
|
2013-02-01 07:16:27 -05:00
|
|
|
|
(define* (fill-paragraph str width #:optional (column 0))
|
|
|
|
|
"Fill STR such that each line contains at most WIDTH characters, assuming
|
|
|
|
|
that the first character is at COLUMN.
|
|
|
|
|
|
|
|
|
|
When STR contains a single line break surrounded by other characters, it is
|
|
|
|
|
converted to a space; sequences of more than one line break are preserved."
|
|
|
|
|
(define (maybe-break chr result)
|
|
|
|
|
(match result
|
|
|
|
|
((column newlines chars)
|
|
|
|
|
(case chr
|
|
|
|
|
((#\newline)
|
|
|
|
|
`(,column ,(+ 1 newlines) ,chars))
|
|
|
|
|
(else
|
2014-07-26 18:53:16 -04:00
|
|
|
|
(let* ((spaces (if (and (pair? chars) (eqv? (car chars) #\.)) 2 1))
|
|
|
|
|
(chars (case newlines
|
|
|
|
|
((0) chars)
|
|
|
|
|
((1)
|
|
|
|
|
(append (make-list spaces #\space) chars))
|
|
|
|
|
(else
|
|
|
|
|
(append (make-list newlines #\newline) chars))))
|
|
|
|
|
(column (case newlines
|
|
|
|
|
((0) column)
|
|
|
|
|
((1) (+ spaces column))
|
|
|
|
|
(else 0))))
|
2013-02-01 07:16:27 -05:00
|
|
|
|
(let ((chars (cons chr chars))
|
|
|
|
|
(column (+ 1 column)))
|
|
|
|
|
(if (> column width)
|
|
|
|
|
(let*-values (((before after)
|
|
|
|
|
(break (cut eqv? #\space <>) chars))
|
|
|
|
|
((len)
|
|
|
|
|
(length before)))
|
|
|
|
|
(if (<= len width)
|
|
|
|
|
`(,len
|
|
|
|
|
0
|
|
|
|
|
,(if (null? after)
|
|
|
|
|
before
|
2014-07-26 18:53:16 -04:00
|
|
|
|
(append before
|
|
|
|
|
(cons #\newline
|
|
|
|
|
(drop-while (cut eqv? #\space <>)
|
|
|
|
|
after)))))
|
2013-02-01 07:16:27 -05:00
|
|
|
|
`(,column 0 ,chars))) ; unbreakable
|
|
|
|
|
`(,column 0 ,chars)))))))))
|
|
|
|
|
|
|
|
|
|
(match (string-fold maybe-break
|
|
|
|
|
`(,column 0 ())
|
|
|
|
|
str)
|
2017-03-08 15:36:54 -05:00
|
|
|
|
((column newlines chars)
|
2013-02-01 07:16:27 -05:00
|
|
|
|
(list->string (reverse chars)))))
|
|
|
|
|
|
2013-11-01 11:57:48 -04:00
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
;;; Packages.
|
|
|
|
|
;;;
|
|
|
|
|
|
2015-08-06 18:10:43 -04:00
|
|
|
|
(define %text-width
|
2020-03-11 11:07:04 -04:00
|
|
|
|
;; '*line-width*' was introduced in Guile 2.2.7/3.0.1. On older versions of
|
|
|
|
|
;; Guile, monkey-patch 'wrap*' below.
|
|
|
|
|
(if (defined? '*line-width*)
|
|
|
|
|
(let ((parameter (fluid->parameter *line-width*)))
|
|
|
|
|
(parameter (terminal-columns))
|
|
|
|
|
parameter)
|
|
|
|
|
(make-parameter (terminal-columns))))
|
|
|
|
|
|
|
|
|
|
(unless (defined? '*line-width*) ;Guile < 2.2.7
|
|
|
|
|
(set! (@@ (texinfo plain-text) wrap*)
|
|
|
|
|
;; XXX: Monkey patch this private procedure to let 'package->recutils'
|
|
|
|
|
;; parameterize the fill of description field correctly.
|
|
|
|
|
(lambda strings
|
|
|
|
|
(let ((indent (fluid-ref (@@ (texinfo plain-text) *indent*))))
|
|
|
|
|
(fill-string (string-concatenate strings)
|
|
|
|
|
#:line-width (%text-width) #:initial-indent indent
|
|
|
|
|
#:subsequent-indent indent)))))
|
2015-08-06 18:10:43 -04:00
|
|
|
|
|
|
|
|
|
(define (texi->plain-text str)
|
|
|
|
|
"Return a plain-text representation of texinfo fragment STR."
|
2015-09-24 15:56:42 -04:00
|
|
|
|
;; 'texi-fragment->stexi' uses a string port so make sure it's a
|
|
|
|
|
;; Unicode-capable one (see <http://bugs.gnu.org/11197>.)
|
|
|
|
|
(with-fluids ((%default-port-encoding "UTF-8"))
|
|
|
|
|
(stexi->plain-text (texi-fragment->stexi str))))
|
2015-08-06 18:10:43 -04:00
|
|
|
|
|
2021-10-18 07:37:56 -04:00
|
|
|
|
(define (texi->plain-text* package str)
|
|
|
|
|
"Same as 'texi->plain-text', but gracefully handle Texinfo errors."
|
|
|
|
|
(catch 'parser-error
|
|
|
|
|
(lambda ()
|
|
|
|
|
(texi->plain-text str))
|
|
|
|
|
(lambda args
|
|
|
|
|
(warning (package-location package)
|
|
|
|
|
(G_ "~a: invalid Texinfo markup~%")
|
|
|
|
|
(package-full-name package))
|
|
|
|
|
str)))
|
|
|
|
|
|
2017-03-20 06:41:41 -04:00
|
|
|
|
(define (package-field-string package field-accessor)
|
|
|
|
|
"Return a plain-text representation of PACKAGE field."
|
|
|
|
|
(and=> (field-accessor package)
|
2021-10-18 07:37:56 -04:00
|
|
|
|
(lambda (str)
|
|
|
|
|
(texi->plain-text* package (P_ str)))))
|
2017-03-20 06:41:41 -04:00
|
|
|
|
|
2015-08-06 18:10:43 -04:00
|
|
|
|
(define (package-description-string package)
|
|
|
|
|
"Return a plain-text representation of PACKAGE description field."
|
2017-03-20 06:41:41 -04:00
|
|
|
|
(package-field-string package package-description))
|
|
|
|
|
|
|
|
|
|
(define (package-synopsis-string package)
|
|
|
|
|
"Return a plain-text representation of PACKAGE synopsis field."
|
|
|
|
|
(package-field-string package package-synopsis))
|
2015-08-06 18:10:43 -04:00
|
|
|
|
|
2013-02-01 07:16:27 -05:00
|
|
|
|
(define (string->recutils str)
|
|
|
|
|
"Return a version of STR where newlines have been replaced by newlines
|
|
|
|
|
followed by \"+ \", which makes for a valid multi-line field value in the
|
|
|
|
|
`recutils' syntax."
|
|
|
|
|
(list->string
|
|
|
|
|
(string-fold-right (lambda (chr result)
|
|
|
|
|
(if (eqv? chr #\newline)
|
|
|
|
|
(cons* chr #\+ #\space result)
|
|
|
|
|
(cons chr result)))
|
|
|
|
|
'()
|
|
|
|
|
str)))
|
|
|
|
|
|
2017-06-13 12:09:30 -04:00
|
|
|
|
(define* (package->recutils p port #:optional (width (%text-width))
|
2019-11-08 17:19:07 -05:00
|
|
|
|
#:key
|
|
|
|
|
(hyperlinks? (supports-hyperlinks? port))
|
2022-04-09 14:26:45 -04:00
|
|
|
|
(extra-fields '())
|
|
|
|
|
(highlighting identity))
|
2013-02-01 07:16:27 -05:00
|
|
|
|
"Write to PORT a `recutils' record of package P, arranging to fit within
|
2019-11-08 17:19:07 -05:00
|
|
|
|
WIDTH columns. EXTRA-FIELDS is a list of symbol/value pairs to emit. When
|
2022-04-09 14:26:45 -04:00
|
|
|
|
HYPERLINKS? is true, emit hyperlink escape sequences when appropriate. Pass
|
|
|
|
|
the synopsis and description through HIGHLIGHTING, a one-argument procedure
|
|
|
|
|
that may return a colorized version of its argument."
|
2022-04-09 14:07:17 -04:00
|
|
|
|
(define port*
|
|
|
|
|
(or (pager-wrapped-port port) port))
|
|
|
|
|
|
2016-04-14 17:43:31 -04:00
|
|
|
|
(define width*
|
|
|
|
|
;; The available number of columns once we've taken into account space for
|
|
|
|
|
;; the initial "+ " prefix.
|
|
|
|
|
(if (> width 2) (- width 2) width))
|
|
|
|
|
|
2022-01-11 11:32:45 -05:00
|
|
|
|
(define (split-lines str indent)
|
|
|
|
|
(string->recutils
|
|
|
|
|
(fill-paragraph str width* indent)))
|
|
|
|
|
|
2014-07-24 18:29:47 -04:00
|
|
|
|
(define (dependencies->recutils packages)
|
2017-07-02 01:14:16 -04:00
|
|
|
|
(let ((list (string-join (delete-duplicates
|
|
|
|
|
(map package-full-name
|
|
|
|
|
(sort packages package<?))) " ")))
|
2022-01-11 11:32:45 -05:00
|
|
|
|
(split-lines list (string-length "dependencies: "))))
|
2014-07-24 18:29:47 -04:00
|
|
|
|
|
2022-11-02 16:01:30 -04:00
|
|
|
|
(define %default-output-synopses
|
|
|
|
|
`(("bin" . ,(G_ "executable programs and scripts"))
|
|
|
|
|
("debug" . ,(G_ "debug information"))
|
2022-11-02 16:16:07 -04:00
|
|
|
|
("doc" . ,(G_ "documentation"))
|
2022-11-02 16:01:30 -04:00
|
|
|
|
("lib" . ,(G_ "shared libraries"))
|
|
|
|
|
("static" . ,(G_ "static libraries"))
|
|
|
|
|
("out" . ,(G_ "everything else"))))
|
|
|
|
|
|
|
|
|
|
(define* (output->recutils package output #:optional
|
|
|
|
|
(default-synopses %default-output-synopses))
|
2022-06-26 08:37:56 -04:00
|
|
|
|
(string-append
|
|
|
|
|
"+ " output ": "
|
|
|
|
|
(or
|
|
|
|
|
(any
|
|
|
|
|
(match-lambda
|
|
|
|
|
(('output-synopsis key synopsis)
|
|
|
|
|
(and (string=? key output) (P_ synopsis)))
|
|
|
|
|
(_ #f))
|
|
|
|
|
(package-properties package))
|
2022-11-02 16:01:30 -04:00
|
|
|
|
(assoc-ref default-synopses output)
|
2022-11-02 16:10:50 -04:00
|
|
|
|
(G_ "[description missing]"))))
|
2022-06-26 08:37:56 -04:00
|
|
|
|
|
|
|
|
|
(define (package-outputs/out-last package)
|
|
|
|
|
((compose append partition)
|
|
|
|
|
(negate (cut string=? "out" <>))
|
|
|
|
|
(package-outputs package)))
|
|
|
|
|
|
2014-07-16 09:38:34 -04:00
|
|
|
|
(define (package<? p1 p2)
|
|
|
|
|
(string<? (package-full-name p1) (package-full-name p2)))
|
|
|
|
|
|
2022-04-09 14:26:45 -04:00
|
|
|
|
(define highlighting*
|
|
|
|
|
(if (color-output? port*)
|
|
|
|
|
highlighting
|
|
|
|
|
identity))
|
|
|
|
|
|
2013-02-01 07:16:27 -05:00
|
|
|
|
;; Note: Don't i18n field names so that people can post-process it.
|
2022-04-09 14:07:17 -04:00
|
|
|
|
(format port "name: ~a~%" (highlight (package-name p) port*))
|
|
|
|
|
(format port "version: ~a~%" (highlight (package-version p) port*))
|
2022-11-02 16:01:30 -04:00
|
|
|
|
(match (package-outputs/out-last p)
|
|
|
|
|
(("out") ; one output has everything
|
|
|
|
|
(format port "outputs:~%~a~%"
|
|
|
|
|
(output->recutils p "out"
|
|
|
|
|
(alist-cons "out" (G_ "everything")
|
|
|
|
|
%default-output-synopses))))
|
|
|
|
|
(outputs ; multiple outputs
|
|
|
|
|
(format port "outputs:~%~{~a~%~}"
|
|
|
|
|
(map (cut output->recutils p <>) (package-outputs/out-last p)))))
|
|
|
|
|
|
2015-04-19 13:12:22 -04:00
|
|
|
|
(format port "systems: ~a~%"
|
2022-01-11 11:32:45 -05:00
|
|
|
|
(split-lines (string-join (package-transitive-supported-systems p))
|
|
|
|
|
(string-length "systems: ")))
|
2014-07-16 09:38:34 -04:00
|
|
|
|
(format port "dependencies: ~a~%"
|
|
|
|
|
(match (package-direct-inputs p)
|
2014-07-25 08:38:20 -04:00
|
|
|
|
(((labels inputs . _) ...)
|
|
|
|
|
(dependencies->recutils (filter package? inputs)))))
|
2013-02-01 07:16:27 -05:00
|
|
|
|
(format port "location: ~a~%"
|
2019-11-08 17:19:07 -05:00
|
|
|
|
(or (and=> (package-location p)
|
|
|
|
|
(if hyperlinks? location->hyperlink location->string))
|
ui: Rename '_' to 'G_'.
This avoids collisions with '_' when the latter is used as a 'match'
pattern for instance. See
<https://lists.gnu.org/archive/html/guix-devel/2017-04/msg00464.html>.
* guix/ui.scm: Rename '_' to 'G_'.
* po/guix/Makevars (XGETTEXT_OPTIONS): Adjust accordingly.
* build-aux/compile-all.scm (warnings): Remove 'format'.
* gnu/packages.scm,
gnu/services.scm,
gnu/services/shepherd.scm,
gnu/system.scm,
gnu/system/shadow.scm,
guix/gnupg.scm,
guix/http-client.scm,
guix/import/cpan.scm,
guix/import/elpa.scm,
guix/import/pypi.scm,
guix/nar.scm,
guix/scripts.scm,
guix/scripts/archive.scm,
guix/scripts/authenticate.scm,
guix/scripts/build.scm,
guix/scripts/challenge.scm,
guix/scripts/container.scm,
guix/scripts/container/exec.scm,
guix/scripts/copy.scm,
guix/scripts/download.scm,
guix/scripts/edit.scm,
guix/scripts/environment.scm,
guix/scripts/gc.scm,
guix/scripts/graph.scm,
guix/scripts/hash.scm,
guix/scripts/import.scm,
guix/scripts/import/cpan.scm,
guix/scripts/import/cran.scm,
guix/scripts/import/crate.scm,
guix/scripts/import/elpa.scm,
guix/scripts/import/gem.scm,
guix/scripts/import/gnu.scm,
guix/scripts/import/hackage.scm,
guix/scripts/import/nix.scm,
guix/scripts/import/pypi.scm,
guix/scripts/import/stackage.scm,
guix/scripts/lint.scm,
guix/scripts/offload.scm,
guix/scripts/pack.scm,
guix/scripts/package.scm,
guix/scripts/perform-download.scm,
guix/scripts/publish.scm,
guix/scripts/pull.scm,
guix/scripts/refresh.scm,
guix/scripts/size.scm,
guix/scripts/substitute.scm,
guix/scripts/system.scm,
guix/ssh.scm,
guix/upstream.scm: Use 'G_' instead of '_'. Most of this change was
obtained by running: "sed -i -e's/(_ "/(G_ "/g' `find -name \*.scm`".
2017-05-03 09:57:02 -04:00
|
|
|
|
(G_ "unknown")))
|
2014-01-13 12:49:26 -05:00
|
|
|
|
|
|
|
|
|
;; Note: Starting from version 1.6 or recutils, hyphens are not allowed in
|
|
|
|
|
;; field identifiers.
|
|
|
|
|
(format port "homepage: ~a~%" (package-home-page p))
|
|
|
|
|
|
2013-02-01 07:16:27 -05:00
|
|
|
|
(format port "license: ~a~%"
|
|
|
|
|
(match (package-license p)
|
|
|
|
|
(((? license? licenses) ...)
|
|
|
|
|
(string-join (map license-name licenses)
|
|
|
|
|
", "))
|
|
|
|
|
((? license? license)
|
2019-11-08 17:23:01 -05:00
|
|
|
|
(let ((text (license-name license))
|
|
|
|
|
(uri (license-uri license)))
|
|
|
|
|
(if (and hyperlinks? uri (string-prefix? "http" uri))
|
|
|
|
|
(hyperlink uri text)
|
|
|
|
|
text)))
|
2013-02-01 07:16:27 -05:00
|
|
|
|
(x
|
ui: Rename '_' to 'G_'.
This avoids collisions with '_' when the latter is used as a 'match'
pattern for instance. See
<https://lists.gnu.org/archive/html/guix-devel/2017-04/msg00464.html>.
* guix/ui.scm: Rename '_' to 'G_'.
* po/guix/Makevars (XGETTEXT_OPTIONS): Adjust accordingly.
* build-aux/compile-all.scm (warnings): Remove 'format'.
* gnu/packages.scm,
gnu/services.scm,
gnu/services/shepherd.scm,
gnu/system.scm,
gnu/system/shadow.scm,
guix/gnupg.scm,
guix/http-client.scm,
guix/import/cpan.scm,
guix/import/elpa.scm,
guix/import/pypi.scm,
guix/nar.scm,
guix/scripts.scm,
guix/scripts/archive.scm,
guix/scripts/authenticate.scm,
guix/scripts/build.scm,
guix/scripts/challenge.scm,
guix/scripts/container.scm,
guix/scripts/container/exec.scm,
guix/scripts/copy.scm,
guix/scripts/download.scm,
guix/scripts/edit.scm,
guix/scripts/environment.scm,
guix/scripts/gc.scm,
guix/scripts/graph.scm,
guix/scripts/hash.scm,
guix/scripts/import.scm,
guix/scripts/import/cpan.scm,
guix/scripts/import/cran.scm,
guix/scripts/import/crate.scm,
guix/scripts/import/elpa.scm,
guix/scripts/import/gem.scm,
guix/scripts/import/gnu.scm,
guix/scripts/import/hackage.scm,
guix/scripts/import/nix.scm,
guix/scripts/import/pypi.scm,
guix/scripts/import/stackage.scm,
guix/scripts/lint.scm,
guix/scripts/offload.scm,
guix/scripts/pack.scm,
guix/scripts/package.scm,
guix/scripts/perform-download.scm,
guix/scripts/publish.scm,
guix/scripts/pull.scm,
guix/scripts/refresh.scm,
guix/scripts/size.scm,
guix/scripts/substitute.scm,
guix/scripts/system.scm,
guix/ssh.scm,
guix/upstream.scm: Use 'G_' instead of '_'. Most of this change was
obtained by running: "sed -i -e's/(_ "/(G_ "/g' `find -name \*.scm`".
2017-05-03 09:57:02 -04:00
|
|
|
|
(G_ "unknown"))))
|
2013-02-01 07:16:27 -05:00
|
|
|
|
(format port "synopsis: ~a~%"
|
2022-04-09 14:26:45 -04:00
|
|
|
|
(highlighting*
|
|
|
|
|
(string-map (match-lambda
|
|
|
|
|
(#\newline #\space)
|
|
|
|
|
(chr chr))
|
|
|
|
|
(or (package-synopsis-string p) ""))))
|
2017-06-13 12:09:30 -04:00
|
|
|
|
(format port "~a~%"
|
2022-04-09 14:26:45 -04:00
|
|
|
|
(highlighting*
|
|
|
|
|
(string->recutils
|
|
|
|
|
(string-trim-right
|
|
|
|
|
(parameterize ((%text-width width*))
|
|
|
|
|
;; Call 'texi->plain-text' on the concatenated string to account
|
|
|
|
|
;; for the width of "description:" in paragraph filling.
|
|
|
|
|
(texi->plain-text*
|
|
|
|
|
p
|
|
|
|
|
(string-append "description: "
|
|
|
|
|
(or (and=> (package-description p) P_)
|
|
|
|
|
""))))
|
|
|
|
|
#\newline))))
|
2017-06-13 12:09:30 -04:00
|
|
|
|
(for-each (match-lambda
|
|
|
|
|
((field . value)
|
|
|
|
|
(let ((field (symbol->string field)))
|
|
|
|
|
(format port "~a: ~a~%"
|
|
|
|
|
field
|
|
|
|
|
(fill-paragraph (object->string value) width*
|
|
|
|
|
(string-length field))))))
|
|
|
|
|
extra-fields)
|
|
|
|
|
(newline port))
|
2013-02-01 07:16:27 -05:00
|
|
|
|
|
2019-06-25 17:37:32 -04:00
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
;;; Searching.
|
|
|
|
|
;;;
|
|
|
|
|
|
2017-09-13 09:07:17 -04:00
|
|
|
|
(define (relevance obj regexps metrics)
|
|
|
|
|
"Compute a \"relevance score\" for OBJ as a function of its number of
|
|
|
|
|
matches of REGEXPS and accordingly to METRICS. METRICS is list of
|
2019-05-06 04:51:30 -04:00
|
|
|
|
field/weight pairs, where FIELD is a procedure that returns a string or list
|
|
|
|
|
of strings describing OBJ, and WEIGHT is a positive integer denoting the
|
|
|
|
|
weight of this field in the final score.
|
2017-09-13 09:07:17 -04:00
|
|
|
|
|
|
|
|
|
A score of zero means that OBJ does not match any of REGEXPS. The higher the
|
|
|
|
|
score, the more relevant OBJ is to REGEXPS."
|
2019-09-18 11:57:57 -04:00
|
|
|
|
(define (score regexp str)
|
|
|
|
|
(fold-matches regexp str 0
|
|
|
|
|
(lambda (m score)
|
|
|
|
|
(+ score
|
|
|
|
|
(if (string=? (match:substring m) str)
|
|
|
|
|
5 ;exact match
|
|
|
|
|
1)))))
|
|
|
|
|
|
|
|
|
|
(define (regexp->score regexp)
|
|
|
|
|
(let ((score-regexp (lambda (str) (score regexp str))))
|
|
|
|
|
(fold (lambda (metric relevance)
|
|
|
|
|
(match metric
|
|
|
|
|
((field . weight)
|
|
|
|
|
(match (field obj)
|
|
|
|
|
(#f relevance)
|
|
|
|
|
((? string? str)
|
|
|
|
|
(+ relevance (* (score-regexp str) weight)))
|
|
|
|
|
((lst ...)
|
|
|
|
|
(+ relevance (* weight (apply + (map score-regexp lst)))))))))
|
|
|
|
|
0 metrics)))
|
|
|
|
|
|
2020-05-31 19:18:01 -04:00
|
|
|
|
(let loop ((regexps regexps)
|
|
|
|
|
(total-score 0))
|
|
|
|
|
(match regexps
|
|
|
|
|
((head . tail)
|
|
|
|
|
(let ((score (regexp->score head)))
|
|
|
|
|
;; Return zero if one of PATTERNS doesn't match.
|
|
|
|
|
(if (zero? score)
|
|
|
|
|
0
|
|
|
|
|
(loop tail (+ total-score score)))))
|
|
|
|
|
(() total-score))))
|
2017-09-13 09:07:17 -04:00
|
|
|
|
|
|
|
|
|
(define %package-metrics
|
|
|
|
|
;; Metrics used to compute the "relevance score" of a package against a set
|
|
|
|
|
;; of regexps.
|
2017-11-15 11:38:21 -05:00
|
|
|
|
`((,package-name . 4)
|
2022-12-09 06:01:31 -05:00
|
|
|
|
(,package-upstream-name* . 2)
|
2019-03-23 18:53:55 -04:00
|
|
|
|
|
2019-05-06 04:51:30 -04:00
|
|
|
|
;; Match against uncommon outputs.
|
|
|
|
|
(,(lambda (package)
|
|
|
|
|
(filter (lambda (output)
|
|
|
|
|
(not (member output
|
2020-04-16 17:17:16 -04:00
|
|
|
|
;; Some common outputs shared by many packages.
|
2019-05-06 04:51:30 -04:00
|
|
|
|
'("out" "doc" "debug" "lib" "include" "bin"))))
|
|
|
|
|
(package-outputs package)))
|
|
|
|
|
. 1)
|
|
|
|
|
|
2019-03-23 18:53:55 -04:00
|
|
|
|
;; Match regexps on the raw Texinfo since formatting it is quite expensive
|
|
|
|
|
;; and doesn't have much of an effect on search results.
|
|
|
|
|
(,(lambda (package)
|
|
|
|
|
(and=> (package-synopsis package) P_)) . 3)
|
|
|
|
|
(,(lambda (package)
|
|
|
|
|
(and=> (package-description package) P_)) . 2)
|
|
|
|
|
|
2017-11-15 11:38:21 -05:00
|
|
|
|
(,(lambda (type)
|
|
|
|
|
(match (and=> (package-location type) location-file)
|
|
|
|
|
((? string? file) (basename file ".scm"))
|
|
|
|
|
(#f "")))
|
|
|
|
|
. 1)))
|
2017-09-13 09:07:17 -04:00
|
|
|
|
|
|
|
|
|
(define (package-relevance package regexps)
|
|
|
|
|
"Return a score denoting the relevance of PACKAGE for REGEXPS. A score of
|
|
|
|
|
zero means that PACKAGE does not match any of REGEXPS."
|
|
|
|
|
(relevance package regexps %package-metrics))
|
|
|
|
|
|
2022-02-09 16:21:58 -05:00
|
|
|
|
(define pager-port-mapping
|
|
|
|
|
;; If a pager is being used, via 'with-paginated-output-port', this maps the
|
|
|
|
|
;; pager port (pipe) to the underlying output port.
|
|
|
|
|
(make-parameter #f))
|
|
|
|
|
|
|
|
|
|
(define* (pager-wrapped-port #:optional (port (current-output-port)))
|
|
|
|
|
"If PORT is a pipe to a pager created by 'with-paginated-output-port',
|
|
|
|
|
return the underlying port. Otherwise return #f."
|
|
|
|
|
(match (pager-port-mapping)
|
|
|
|
|
((pager . wrapped)
|
|
|
|
|
(and (eq? pager port) wrapped))
|
|
|
|
|
(_
|
|
|
|
|
#f)))
|
|
|
|
|
|
2022-06-08 05:50:28 -04:00
|
|
|
|
(define (find-available-pager)
|
|
|
|
|
"Return the program name of an available pager or the empty string if none is
|
|
|
|
|
available."
|
|
|
|
|
(or (getenv "GUIX_PAGER")
|
|
|
|
|
(getenv "PAGER")
|
|
|
|
|
(which "less")
|
|
|
|
|
(which "more")
|
|
|
|
|
""))
|
|
|
|
|
|
2020-07-26 10:45:42 -04:00
|
|
|
|
(define* (call-with-paginated-output-port proc
|
|
|
|
|
#:key (less-options "FrX"))
|
2022-06-08 05:50:28 -04:00
|
|
|
|
(let ((pager-command-line (find-available-pager)))
|
2020-11-15 13:25:00 -05:00
|
|
|
|
;; Setting PAGER to the empty string conventionally disables paging.
|
|
|
|
|
(if (and (not (string-null? pager-command-line))
|
|
|
|
|
(isatty?* (current-output-port)))
|
|
|
|
|
;; Set 'LESS' so that 'less' exits if everything fits on the screen
|
|
|
|
|
;; (F), lets ANSI escapes through (r), does not send the termcap
|
|
|
|
|
;; initialization string (X). Set it unconditionally because some
|
|
|
|
|
;; distros set it to something that doesn't work here.
|
|
|
|
|
;;
|
|
|
|
|
;; For things that produce long lines, such as 'guix processes', use
|
|
|
|
|
;; 'R' instead of 'r': this strips hyperlinks but allows 'less' to
|
|
|
|
|
;; make a good estimate of the line length.
|
|
|
|
|
(let* ((pager (with-environment-variables `(("LESS" ,less-options))
|
|
|
|
|
(apply open-pipe* OPEN_WRITE
|
|
|
|
|
;; Split into arguments. Treat runs of multiple
|
|
|
|
|
;; whitespace characters as one. libpipeline-
|
|
|
|
|
;; style "cmd one\ arg" escaping is unsupported.
|
|
|
|
|
(remove (lambda (s) (string-null? s))
|
|
|
|
|
(string-split pager-command-line
|
|
|
|
|
char-set:whitespace))))))
|
|
|
|
|
(dynamic-wind
|
|
|
|
|
(const #t)
|
2022-02-09 16:21:58 -05:00
|
|
|
|
(lambda ()
|
|
|
|
|
(parameterize ((pager-port-mapping
|
|
|
|
|
(cons pager (current-output-port))))
|
|
|
|
|
(proc pager)))
|
2020-11-15 13:25:00 -05:00
|
|
|
|
(lambda () (close-pipe pager))))
|
|
|
|
|
(proc (current-output-port)))))
|
2020-06-06 17:17:02 -04:00
|
|
|
|
|
2020-07-26 10:45:42 -04:00
|
|
|
|
(define-syntax with-paginated-output-port
|
|
|
|
|
(syntax-rules ()
|
|
|
|
|
"Evaluate EXP... with PORT bound to a port that talks to the pager if
|
2020-06-06 17:17:02 -04:00
|
|
|
|
standard output is a tty, or with PORT set to the current output port."
|
2020-07-26 10:45:42 -04:00
|
|
|
|
((_ port exp ... #:less-options opts)
|
|
|
|
|
(call-with-paginated-output-port (lambda (port) exp ...)
|
|
|
|
|
#:less-options opts))
|
|
|
|
|
((_ port exp ...)
|
|
|
|
|
(call-with-paginated-output-port (lambda (port) exp ...)))))
|
2020-06-06 17:17:02 -04:00
|
|
|
|
|
2019-06-25 17:37:32 -04:00
|
|
|
|
(define* (display-search-results matches port
|
|
|
|
|
#:key
|
2022-04-09 14:26:45 -04:00
|
|
|
|
(regexps '())
|
2019-06-25 17:37:32 -04:00
|
|
|
|
(command "guix search")
|
|
|
|
|
(print package->recutils))
|
|
|
|
|
"Display MATCHES, a list of object/score pairs, by calling PRINT on each of
|
2022-04-09 14:26:45 -04:00
|
|
|
|
them. If PORT is a terminal, print at most a full screen of results. REGEXPS
|
|
|
|
|
is a list of regexps to highlight in search results."
|
2019-06-25 17:37:32 -04:00
|
|
|
|
(define first-line
|
|
|
|
|
(port-line port))
|
|
|
|
|
|
|
|
|
|
(define max-rows
|
|
|
|
|
(and first-line (isatty? port)
|
|
|
|
|
(terminal-rows port)))
|
|
|
|
|
|
|
|
|
|
(define (line-count str)
|
|
|
|
|
(string-count str #\newline))
|
|
|
|
|
|
2022-04-09 14:26:45 -04:00
|
|
|
|
(define highlighting
|
|
|
|
|
(let ((match-color (color ON-RED BOLD)))
|
|
|
|
|
(colorize-full-matches (map (lambda (regexp)
|
|
|
|
|
(cons regexp match-color))
|
|
|
|
|
regexps))))
|
|
|
|
|
|
2020-06-06 17:17:02 -04:00
|
|
|
|
(with-paginated-output-port paginated
|
|
|
|
|
(let loop ((matches matches))
|
|
|
|
|
(match matches
|
|
|
|
|
(((package . score) rest ...)
|
|
|
|
|
(let* ((links? (supports-hyperlinks? port)))
|
|
|
|
|
(print package paginated
|
|
|
|
|
#:hyperlinks? links?
|
2022-04-09 14:26:45 -04:00
|
|
|
|
#:extra-fields `((relevance . ,score))
|
|
|
|
|
#:highlighting highlighting)
|
2020-06-06 17:17:02 -04:00
|
|
|
|
(loop rest)))
|
|
|
|
|
(()
|
|
|
|
|
#t)))))
|
2019-06-25 17:37:32 -04:00
|
|
|
|
|
|
|
|
|
|
2013-09-19 07:07:39 -04:00
|
|
|
|
(define (string->generations str)
|
|
|
|
|
"Return the list of generations matching a pattern in STR. This function
|
|
|
|
|
accepts the following patterns: \"1\", \"1,2,3\", \"1..9\", \"1..\", \"..9\"."
|
|
|
|
|
(define (maybe-integer)
|
|
|
|
|
(let ((x (string->number str)))
|
|
|
|
|
(and (integer? x)
|
|
|
|
|
x)))
|
|
|
|
|
|
|
|
|
|
(define (maybe-comma-separated-integers)
|
|
|
|
|
(let ((lst (delete-duplicates
|
|
|
|
|
(map string->number
|
|
|
|
|
(string-split str #\,)))))
|
|
|
|
|
(and (every integer? lst)
|
|
|
|
|
lst)))
|
|
|
|
|
|
|
|
|
|
(cond ((maybe-integer)
|
|
|
|
|
=>
|
|
|
|
|
list)
|
|
|
|
|
((maybe-comma-separated-integers)
|
|
|
|
|
=>
|
|
|
|
|
identity)
|
|
|
|
|
((string-match "^([0-9]+)\\.\\.([0-9]+)$" str)
|
|
|
|
|
=>
|
|
|
|
|
(lambda (match)
|
|
|
|
|
(let ((s (string->number (match:substring match 1)))
|
|
|
|
|
(e (string->number (match:substring match 2))))
|
|
|
|
|
(and (every integer? (list s e))
|
|
|
|
|
(<= s e)
|
|
|
|
|
(iota (1+ (- e s)) s)))))
|
|
|
|
|
((string-match "^([0-9]+)\\.\\.$" str)
|
|
|
|
|
=>
|
|
|
|
|
(lambda (match)
|
|
|
|
|
(let ((s (string->number (match:substring match 1))))
|
|
|
|
|
(and (integer? s)
|
|
|
|
|
`(>= ,s)))))
|
|
|
|
|
((string-match "^\\.\\.([0-9]+)$" str)
|
|
|
|
|
=>
|
|
|
|
|
(lambda (match)
|
|
|
|
|
(let ((e (string->number (match:substring match 1))))
|
|
|
|
|
(and (integer? e)
|
|
|
|
|
`(<= ,e)))))
|
|
|
|
|
(else #f)))
|
|
|
|
|
|
|
|
|
|
(define (string->duration str)
|
|
|
|
|
"Return the duration matching a pattern in STR. This function accepts the
|
|
|
|
|
following patterns: \"1d\", \"1w\", \"1m\"."
|
|
|
|
|
(define (hours->duration hours match)
|
|
|
|
|
(make-time time-duration 0
|
|
|
|
|
(* 3600 hours (string->number (match:substring match 1)))))
|
|
|
|
|
|
2016-06-09 17:28:17 -04:00
|
|
|
|
(cond ((string-match "^([0-9]+)s$" str)
|
|
|
|
|
=>
|
|
|
|
|
(lambda (match)
|
|
|
|
|
(make-time time-duration 0
|
|
|
|
|
(string->number (match:substring match 1)))))
|
|
|
|
|
((string-match "^([0-9]+)h$" str)
|
2017-05-10 09:25:07 -04:00
|
|
|
|
=>
|
2016-06-09 17:28:17 -04:00
|
|
|
|
(lambda (match)
|
|
|
|
|
(hours->duration 1 match)))
|
|
|
|
|
((string-match "^([0-9]+)d$" str)
|
2013-09-19 07:07:39 -04:00
|
|
|
|
=>
|
|
|
|
|
(lambda (match)
|
|
|
|
|
(hours->duration 24 match)))
|
|
|
|
|
((string-match "^([0-9]+)w$" str)
|
|
|
|
|
=>
|
|
|
|
|
(lambda (match)
|
|
|
|
|
(hours->duration (* 24 7) match)))
|
|
|
|
|
((string-match "^([0-9]+)m$" str)
|
|
|
|
|
=>
|
|
|
|
|
(lambda (match)
|
|
|
|
|
(hours->duration (* 24 30) match)))
|
|
|
|
|
(else #f)))
|
|
|
|
|
|
2015-10-26 14:03:56 -04:00
|
|
|
|
(define* (matching-generations str profile
|
|
|
|
|
#:key (duration-relation <=))
|
|
|
|
|
"Return the list of available generations matching a pattern in STR. See
|
|
|
|
|
'string->generations' and 'string->duration' for the list of valid patterns.
|
|
|
|
|
When STR is a duration pattern, return all the generations whose ctime has
|
|
|
|
|
DURATION-RELATION with the current time."
|
|
|
|
|
(define (valid-generations lst)
|
|
|
|
|
(define (valid-generation? n)
|
|
|
|
|
(any (cut = n <>) (generation-numbers profile)))
|
|
|
|
|
|
|
|
|
|
(fold-right (lambda (x acc)
|
|
|
|
|
(if (valid-generation? x)
|
|
|
|
|
(cons x acc)
|
|
|
|
|
acc))
|
|
|
|
|
'()
|
|
|
|
|
lst))
|
|
|
|
|
|
|
|
|
|
(define (filter-generations generations)
|
|
|
|
|
(match generations
|
|
|
|
|
(() '())
|
|
|
|
|
(('>= n)
|
|
|
|
|
(drop-while (cut > n <>)
|
|
|
|
|
(generation-numbers profile)))
|
|
|
|
|
(('<= n)
|
|
|
|
|
(valid-generations (iota n 1)))
|
|
|
|
|
((lst ..1)
|
|
|
|
|
(valid-generations lst))
|
2017-03-08 15:36:54 -05:00
|
|
|
|
(x #f)))
|
2015-10-26 14:03:56 -04:00
|
|
|
|
|
|
|
|
|
(define (filter-by-duration duration)
|
|
|
|
|
(define (time-at-midnight time)
|
|
|
|
|
;; Return TIME at midnight by setting nanoseconds, seconds, minutes, and
|
|
|
|
|
;; hours to zeros.
|
|
|
|
|
(let ((d (time-utc->date time)))
|
|
|
|
|
(date->time-utc
|
|
|
|
|
(make-date 0 0 0 0
|
|
|
|
|
(date-day d) (date-month d)
|
|
|
|
|
(date-year d) (date-zone-offset d)))))
|
|
|
|
|
|
|
|
|
|
(define generation-ctime-alist
|
|
|
|
|
(map (lambda (number)
|
|
|
|
|
(cons number
|
|
|
|
|
(time-second
|
|
|
|
|
(time-at-midnight
|
|
|
|
|
(generation-time profile number)))))
|
|
|
|
|
(generation-numbers profile)))
|
|
|
|
|
|
|
|
|
|
(match duration
|
|
|
|
|
(#f #f)
|
|
|
|
|
(res
|
|
|
|
|
(let ((s (time-second
|
|
|
|
|
(subtract-duration (time-at-midnight (current-time))
|
|
|
|
|
duration))))
|
|
|
|
|
(delete #f (map (lambda (x)
|
|
|
|
|
(and (duration-relation s (cdr x))
|
|
|
|
|
(first x)))
|
|
|
|
|
generation-ctime-alist))))))
|
|
|
|
|
|
|
|
|
|
(cond ((string->generations str)
|
|
|
|
|
=>
|
|
|
|
|
filter-generations)
|
|
|
|
|
((string->duration str)
|
|
|
|
|
=>
|
|
|
|
|
filter-by-duration)
|
2019-07-10 13:58:30 -04:00
|
|
|
|
(else
|
|
|
|
|
(raise
|
2020-07-25 12:26:18 -04:00
|
|
|
|
(formatted-message (G_ "invalid syntax: ~a~%") str)))))
|
2015-10-26 14:03:56 -04:00
|
|
|
|
|
2015-10-26 16:16:20 -04:00
|
|
|
|
(define (display-generation profile number)
|
|
|
|
|
"Display a one-line summary of generation NUMBER of PROFILE."
|
|
|
|
|
(unless (zero? number)
|
2019-11-28 07:12:39 -05:00
|
|
|
|
(let* ((file (generation-file-name profile number))
|
|
|
|
|
(link (if (supports-hyperlinks?)
|
|
|
|
|
(cut file-hyperlink file <>)
|
2020-02-27 18:03:34 -05:00
|
|
|
|
identity))
|
2022-02-09 16:23:27 -05:00
|
|
|
|
(header (format #f (link (highlight (G_ "Generation ~a\t~a")
|
|
|
|
|
(or (pager-wrapped-port)
|
|
|
|
|
(current-output-port))))
|
2019-11-28 07:12:39 -05:00
|
|
|
|
number
|
|
|
|
|
(date->string
|
|
|
|
|
(time-utc->date
|
|
|
|
|
(generation-time profile number))
|
|
|
|
|
;; TRANSLATORS: This is a format-string for date->string.
|
|
|
|
|
;; Please choose a format that corresponds to the
|
|
|
|
|
;; usual way of presenting dates in your locale.
|
|
|
|
|
;; See https://www.gnu.org/software/guile/manual/html_node/SRFI_002d19-Date-to-string.html
|
|
|
|
|
;; for details.
|
|
|
|
|
(G_ "~b ~d ~Y ~T"))))
|
|
|
|
|
(current (generation-number profile)))
|
2015-10-26 16:16:20 -04:00
|
|
|
|
(if (= number current)
|
2016-03-30 09:00:25 -04:00
|
|
|
|
;; TRANSLATORS: The word "current" here is an adjective for
|
|
|
|
|
;; "Generation", as in "current generation". Use the appropriate
|
|
|
|
|
;; gender where applicable.
|
ui: Rename '_' to 'G_'.
This avoids collisions with '_' when the latter is used as a 'match'
pattern for instance. See
<https://lists.gnu.org/archive/html/guix-devel/2017-04/msg00464.html>.
* guix/ui.scm: Rename '_' to 'G_'.
* po/guix/Makevars (XGETTEXT_OPTIONS): Adjust accordingly.
* build-aux/compile-all.scm (warnings): Remove 'format'.
* gnu/packages.scm,
gnu/services.scm,
gnu/services/shepherd.scm,
gnu/system.scm,
gnu/system/shadow.scm,
guix/gnupg.scm,
guix/http-client.scm,
guix/import/cpan.scm,
guix/import/elpa.scm,
guix/import/pypi.scm,
guix/nar.scm,
guix/scripts.scm,
guix/scripts/archive.scm,
guix/scripts/authenticate.scm,
guix/scripts/build.scm,
guix/scripts/challenge.scm,
guix/scripts/container.scm,
guix/scripts/container/exec.scm,
guix/scripts/copy.scm,
guix/scripts/download.scm,
guix/scripts/edit.scm,
guix/scripts/environment.scm,
guix/scripts/gc.scm,
guix/scripts/graph.scm,
guix/scripts/hash.scm,
guix/scripts/import.scm,
guix/scripts/import/cpan.scm,
guix/scripts/import/cran.scm,
guix/scripts/import/crate.scm,
guix/scripts/import/elpa.scm,
guix/scripts/import/gem.scm,
guix/scripts/import/gnu.scm,
guix/scripts/import/hackage.scm,
guix/scripts/import/nix.scm,
guix/scripts/import/pypi.scm,
guix/scripts/import/stackage.scm,
guix/scripts/lint.scm,
guix/scripts/offload.scm,
guix/scripts/pack.scm,
guix/scripts/package.scm,
guix/scripts/perform-download.scm,
guix/scripts/publish.scm,
guix/scripts/pull.scm,
guix/scripts/refresh.scm,
guix/scripts/size.scm,
guix/scripts/substitute.scm,
guix/scripts/system.scm,
guix/ssh.scm,
guix/upstream.scm: Use 'G_' instead of '_'. Most of this change was
obtained by running: "sed -i -e's/(_ "/(G_ "/g' `find -name \*.scm`".
2017-05-03 09:57:02 -04:00
|
|
|
|
(format #t (G_ "~a\t(current)~%") header)
|
2015-10-26 16:16:20 -04:00
|
|
|
|
(format #t "~a~%" header)))))
|
|
|
|
|
|
2016-10-26 08:53:29 -04:00
|
|
|
|
(define (display-profile-content-diff profile gen1 gen2)
|
2018-07-10 18:53:04 -04:00
|
|
|
|
"Display the changed packages in PROFILE GEN2 compared to generation GEN1."
|
2016-10-26 08:53:29 -04:00
|
|
|
|
|
|
|
|
|
(define (equal-entry? first second)
|
|
|
|
|
(string= (manifest-entry-item first) (manifest-entry-item second)))
|
|
|
|
|
|
2018-01-09 17:20:12 -05:00
|
|
|
|
(define (make-row entry prefix)
|
2016-10-26 08:53:29 -04:00
|
|
|
|
(match entry
|
|
|
|
|
(($ <manifest-entry> name version output location _)
|
2018-01-09 17:20:12 -05:00
|
|
|
|
(list (format #f " ~a ~a" prefix name) version output location))))
|
2016-10-26 08:53:29 -04:00
|
|
|
|
|
|
|
|
|
(define (list-entries number)
|
|
|
|
|
(manifest-entries (profile-manifest (generation-file-name profile number))))
|
|
|
|
|
|
|
|
|
|
(define (display-diff profile old new)
|
|
|
|
|
(display-generation profile new)
|
|
|
|
|
(let ((added (lset-difference
|
|
|
|
|
equal-entry? (list-entries new) (list-entries old)))
|
|
|
|
|
(removed (lset-difference
|
|
|
|
|
equal-entry? (list-entries old) (list-entries new))))
|
2018-01-09 17:20:12 -05:00
|
|
|
|
(pretty-print-table (append (map (cut make-row <> "+") added)
|
|
|
|
|
(map (cut make-row <> "-") removed)))
|
2016-11-17 17:49:29 -05:00
|
|
|
|
(newline)))
|
2016-10-26 08:53:29 -04:00
|
|
|
|
|
|
|
|
|
(display-diff profile gen1 gen2))
|
|
|
|
|
|
2019-11-29 08:53:22 -05:00
|
|
|
|
(define (profile-lock-handler profile errno . _)
|
|
|
|
|
"Handle failure to acquire PROFILE's lock."
|
2019-11-29 09:11:51 -05:00
|
|
|
|
;; NFS mounts can return ENOLCK. When that happens, there's not much that
|
|
|
|
|
;; can be done, so warn the user and keep going.
|
|
|
|
|
(if (= errno ENOLCK)
|
|
|
|
|
(warning (G_ "cannot lock profile ~a: ~a~%")
|
|
|
|
|
profile (strerror errno))
|
|
|
|
|
(leave (G_ "profile ~a is locked by another process~%")
|
|
|
|
|
profile)))
|
2019-11-29 08:53:22 -05:00
|
|
|
|
|
|
|
|
|
(define profile-lock-file
|
|
|
|
|
(cut string-append <> ".lock"))
|
|
|
|
|
|
|
|
|
|
(define-syntax-rule (with-profile-lock profile exp ...)
|
|
|
|
|
"Grab PROFILE's lock and evaluate EXP... Call 'leave' if the lock is
|
|
|
|
|
already taken."
|
|
|
|
|
(with-file-lock/no-wait (profile-lock-file profile)
|
|
|
|
|
(cut profile-lock-handler profile <...>)
|
|
|
|
|
exp ...))
|
|
|
|
|
|
2015-10-26 16:16:20 -04:00
|
|
|
|
(define (display-profile-content profile number)
|
|
|
|
|
"Display the packages in PROFILE, generation NUMBER, in a human-readable
|
|
|
|
|
way."
|
2018-01-09 17:20:12 -05:00
|
|
|
|
|
|
|
|
|
(define entry->row
|
|
|
|
|
(match-lambda
|
|
|
|
|
(($ <manifest-entry> name version output location _)
|
|
|
|
|
(list (string-append " " name) version output location))))
|
|
|
|
|
|
|
|
|
|
(let* ((manifest (profile-manifest (generation-file-name profile number)))
|
|
|
|
|
(entries (manifest-entries manifest))
|
|
|
|
|
(rows (map entry->row entries)))
|
|
|
|
|
;; Show most recently installed packages last.
|
|
|
|
|
(pretty-print-table (reverse rows))))
|
2015-10-26 16:16:20 -04:00
|
|
|
|
|
2015-10-26 18:01:06 -04:00
|
|
|
|
(define (display-generation-change previous current)
|
ui: Rename '_' to 'G_'.
This avoids collisions with '_' when the latter is used as a 'match'
pattern for instance. See
<https://lists.gnu.org/archive/html/guix-devel/2017-04/msg00464.html>.
* guix/ui.scm: Rename '_' to 'G_'.
* po/guix/Makevars (XGETTEXT_OPTIONS): Adjust accordingly.
* build-aux/compile-all.scm (warnings): Remove 'format'.
* gnu/packages.scm,
gnu/services.scm,
gnu/services/shepherd.scm,
gnu/system.scm,
gnu/system/shadow.scm,
guix/gnupg.scm,
guix/http-client.scm,
guix/import/cpan.scm,
guix/import/elpa.scm,
guix/import/pypi.scm,
guix/nar.scm,
guix/scripts.scm,
guix/scripts/archive.scm,
guix/scripts/authenticate.scm,
guix/scripts/build.scm,
guix/scripts/challenge.scm,
guix/scripts/container.scm,
guix/scripts/container/exec.scm,
guix/scripts/copy.scm,
guix/scripts/download.scm,
guix/scripts/edit.scm,
guix/scripts/environment.scm,
guix/scripts/gc.scm,
guix/scripts/graph.scm,
guix/scripts/hash.scm,
guix/scripts/import.scm,
guix/scripts/import/cpan.scm,
guix/scripts/import/cran.scm,
guix/scripts/import/crate.scm,
guix/scripts/import/elpa.scm,
guix/scripts/import/gem.scm,
guix/scripts/import/gnu.scm,
guix/scripts/import/hackage.scm,
guix/scripts/import/nix.scm,
guix/scripts/import/pypi.scm,
guix/scripts/import/stackage.scm,
guix/scripts/lint.scm,
guix/scripts/offload.scm,
guix/scripts/pack.scm,
guix/scripts/package.scm,
guix/scripts/perform-download.scm,
guix/scripts/publish.scm,
guix/scripts/pull.scm,
guix/scripts/refresh.scm,
guix/scripts/size.scm,
guix/scripts/substitute.scm,
guix/scripts/system.scm,
guix/ssh.scm,
guix/upstream.scm: Use 'G_' instead of '_'. Most of this change was
obtained by running: "sed -i -e's/(_ "/(G_ "/g' `find -name \*.scm`".
2017-05-03 09:57:02 -04:00
|
|
|
|
(format #t (G_ "switched from generation ~a to ~a~%") previous current))
|
2015-10-26 18:01:06 -04:00
|
|
|
|
|
|
|
|
|
(define (roll-back* store profile)
|
|
|
|
|
"Like 'roll-back', but display what is happening."
|
|
|
|
|
(call-with-values
|
|
|
|
|
(lambda ()
|
|
|
|
|
(roll-back store profile))
|
|
|
|
|
display-generation-change))
|
|
|
|
|
|
|
|
|
|
(define (switch-to-generation* profile number)
|
2021-01-30 15:51:18 -05:00
|
|
|
|
"Like 'switch-to-generation', but display what is happening."
|
2015-10-26 18:01:06 -04:00
|
|
|
|
(let ((previous (switch-to-generation profile number)))
|
|
|
|
|
(display-generation-change previous number)))
|
|
|
|
|
|
|
|
|
|
(define (delete-generation* store profile generation)
|
|
|
|
|
"Like 'delete-generation', but display what is going on."
|
ui: Rename '_' to 'G_'.
This avoids collisions with '_' when the latter is used as a 'match'
pattern for instance. See
<https://lists.gnu.org/archive/html/guix-devel/2017-04/msg00464.html>.
* guix/ui.scm: Rename '_' to 'G_'.
* po/guix/Makevars (XGETTEXT_OPTIONS): Adjust accordingly.
* build-aux/compile-all.scm (warnings): Remove 'format'.
* gnu/packages.scm,
gnu/services.scm,
gnu/services/shepherd.scm,
gnu/system.scm,
gnu/system/shadow.scm,
guix/gnupg.scm,
guix/http-client.scm,
guix/import/cpan.scm,
guix/import/elpa.scm,
guix/import/pypi.scm,
guix/nar.scm,
guix/scripts.scm,
guix/scripts/archive.scm,
guix/scripts/authenticate.scm,
guix/scripts/build.scm,
guix/scripts/challenge.scm,
guix/scripts/container.scm,
guix/scripts/container/exec.scm,
guix/scripts/copy.scm,
guix/scripts/download.scm,
guix/scripts/edit.scm,
guix/scripts/environment.scm,
guix/scripts/gc.scm,
guix/scripts/graph.scm,
guix/scripts/hash.scm,
guix/scripts/import.scm,
guix/scripts/import/cpan.scm,
guix/scripts/import/cran.scm,
guix/scripts/import/crate.scm,
guix/scripts/import/elpa.scm,
guix/scripts/import/gem.scm,
guix/scripts/import/gnu.scm,
guix/scripts/import/hackage.scm,
guix/scripts/import/nix.scm,
guix/scripts/import/pypi.scm,
guix/scripts/import/stackage.scm,
guix/scripts/lint.scm,
guix/scripts/offload.scm,
guix/scripts/pack.scm,
guix/scripts/package.scm,
guix/scripts/perform-download.scm,
guix/scripts/publish.scm,
guix/scripts/pull.scm,
guix/scripts/refresh.scm,
guix/scripts/size.scm,
guix/scripts/substitute.scm,
guix/scripts/system.scm,
guix/ssh.scm,
guix/upstream.scm: Use 'G_' instead of '_'. Most of this change was
obtained by running: "sed -i -e's/(_ "/(G_ "/g' `find -name \*.scm`".
2017-05-03 09:57:02 -04:00
|
|
|
|
(format #t (G_ "deleting ~a~%")
|
2015-10-26 18:01:06 -04:00
|
|
|
|
(generation-file-name profile generation))
|
|
|
|
|
(delete-generation store profile generation))
|
|
|
|
|
|
2013-11-01 11:57:48 -04:00
|
|
|
|
(define* (package-specification->name+version+output spec
|
|
|
|
|
#:optional (output "out"))
|
|
|
|
|
"Parse package specification SPEC and return three value: the specified
|
|
|
|
|
package name, version number (or #f), and output name (or OUTPUT). SPEC may
|
|
|
|
|
optionally contain a version number and an output name, as in these examples:
|
|
|
|
|
|
|
|
|
|
guile
|
2016-02-28 17:11:36 -05:00
|
|
|
|
guile@2.0.9
|
2013-11-01 11:57:48 -04:00
|
|
|
|
guile:debug
|
2016-02-28 17:11:36 -05:00
|
|
|
|
guile@2.0.9:debug
|
2013-11-01 11:57:48 -04:00
|
|
|
|
"
|
|
|
|
|
(let*-values (((name sub-drv)
|
|
|
|
|
(match (string-rindex spec #\:)
|
|
|
|
|
(#f (values spec output))
|
|
|
|
|
(colon (values (substring spec 0 colon)
|
|
|
|
|
(substring spec (+ 1 colon))))))
|
|
|
|
|
((name version)
|
|
|
|
|
(package-name->name+version name)))
|
|
|
|
|
(values name version sub-drv)))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
;;; Command-line option processing.
|
|
|
|
|
;;;
|
|
|
|
|
|
Replace individual scripts with master 'guix' script.
* scripts/guix.in: New script.
* Makefile.am (bin_SCRIPTS): Add 'scripts/guix'. Remove 'guix-build',
'guix-download', 'guix-import', 'guix-package', and 'guix-gc'.
(MODULES): Add 'guix/scripts/build.scm', 'guix/scripts/download.scm',
'guix/scripts/import.scm', 'guix/scripts/package.scm', and
'guix/scripts/gc.scm'.
* configure.ac (AC_CONFIG_FILES): Add 'scripts/guix'. Remove 'guix-build',
'guix-download', 'guix-import', 'guix-package', and 'guix-gc'.
* guix-build.in, guix-download.in, guix-gc.in, guix-import.in,
guix-package.in: Remove shell script boilerplate. Move to guix-COMMAND.in
to guix/scripts/COMMAND.scm. Rename module from (guix-COMMAND) to
(guix scripts COMMAND). Change "guix-COMMAND" to "guix COMMAND" in
usage help string.
* pre-inst-env.in: Add "@abs_top_builddir@/scripts" to the front of $PATH.
Export $GUIX_UNINSTALLED.
* tests/guix-build.sh, tests/guix-daemon.sh, tests/guix-download.sh,
tests/guix-gc.sh, tests/guix-package.sh: Use "guix COMMAND" instead of
"guix-COMMAND".
* doc/guix.texi: Replace all occurrences of "guix-COMMAND" with
"guix COMMAND".
* po/POTFILES.in: Update.
2013-02-14 04:15:25 -05:00
|
|
|
|
(define (show-guix-usage)
|
|
|
|
|
(format (current-error-port)
|
ui: Rename '_' to 'G_'.
This avoids collisions with '_' when the latter is used as a 'match'
pattern for instance. See
<https://lists.gnu.org/archive/html/guix-devel/2017-04/msg00464.html>.
* guix/ui.scm: Rename '_' to 'G_'.
* po/guix/Makevars (XGETTEXT_OPTIONS): Adjust accordingly.
* build-aux/compile-all.scm (warnings): Remove 'format'.
* gnu/packages.scm,
gnu/services.scm,
gnu/services/shepherd.scm,
gnu/system.scm,
gnu/system/shadow.scm,
guix/gnupg.scm,
guix/http-client.scm,
guix/import/cpan.scm,
guix/import/elpa.scm,
guix/import/pypi.scm,
guix/nar.scm,
guix/scripts.scm,
guix/scripts/archive.scm,
guix/scripts/authenticate.scm,
guix/scripts/build.scm,
guix/scripts/challenge.scm,
guix/scripts/container.scm,
guix/scripts/container/exec.scm,
guix/scripts/copy.scm,
guix/scripts/download.scm,
guix/scripts/edit.scm,
guix/scripts/environment.scm,
guix/scripts/gc.scm,
guix/scripts/graph.scm,
guix/scripts/hash.scm,
guix/scripts/import.scm,
guix/scripts/import/cpan.scm,
guix/scripts/import/cran.scm,
guix/scripts/import/crate.scm,
guix/scripts/import/elpa.scm,
guix/scripts/import/gem.scm,
guix/scripts/import/gnu.scm,
guix/scripts/import/hackage.scm,
guix/scripts/import/nix.scm,
guix/scripts/import/pypi.scm,
guix/scripts/import/stackage.scm,
guix/scripts/lint.scm,
guix/scripts/offload.scm,
guix/scripts/pack.scm,
guix/scripts/package.scm,
guix/scripts/perform-download.scm,
guix/scripts/publish.scm,
guix/scripts/pull.scm,
guix/scripts/refresh.scm,
guix/scripts/size.scm,
guix/scripts/substitute.scm,
guix/scripts/system.scm,
guix/ssh.scm,
guix/upstream.scm: Use 'G_' instead of '_'. Most of this change was
obtained by running: "sed -i -e's/(_ "/(G_ "/g' `find -name \*.scm`".
2017-05-03 09:57:02 -04:00
|
|
|
|
(G_ "Try `guix --help' for more information.~%"))
|
2013-05-10 17:14:26 -04:00
|
|
|
|
(exit 1))
|
Replace individual scripts with master 'guix' script.
* scripts/guix.in: New script.
* Makefile.am (bin_SCRIPTS): Add 'scripts/guix'. Remove 'guix-build',
'guix-download', 'guix-import', 'guix-package', and 'guix-gc'.
(MODULES): Add 'guix/scripts/build.scm', 'guix/scripts/download.scm',
'guix/scripts/import.scm', 'guix/scripts/package.scm', and
'guix/scripts/gc.scm'.
* configure.ac (AC_CONFIG_FILES): Add 'scripts/guix'. Remove 'guix-build',
'guix-download', 'guix-import', 'guix-package', and 'guix-gc'.
* guix-build.in, guix-download.in, guix-gc.in, guix-import.in,
guix-package.in: Remove shell script boilerplate. Move to guix-COMMAND.in
to guix/scripts/COMMAND.scm. Rename module from (guix-COMMAND) to
(guix scripts COMMAND). Change "guix-COMMAND" to "guix COMMAND" in
usage help string.
* pre-inst-env.in: Add "@abs_top_builddir@/scripts" to the front of $PATH.
Export $GUIX_UNINSTALLED.
* tests/guix-build.sh, tests/guix-daemon.sh, tests/guix-download.sh,
tests/guix-gc.sh, tests/guix-package.sh: Use "guix COMMAND" instead of
"guix-COMMAND".
* doc/guix.texi: Replace all occurrences of "guix-COMMAND" with
"guix COMMAND".
* po/POTFILES.in: Update.
2013-02-14 04:15:25 -05:00
|
|
|
|
|
2020-09-01 16:13:11 -04:00
|
|
|
|
;; Representation of a 'guix' command.
|
|
|
|
|
(define-immutable-record-type <command>
|
|
|
|
|
(command name synopsis category)
|
|
|
|
|
command?
|
|
|
|
|
(name command-name)
|
|
|
|
|
(synopsis command-synopsis)
|
|
|
|
|
(category command-category))
|
|
|
|
|
|
|
|
|
|
(define (source-file-command file)
|
|
|
|
|
"Read FILE, a Scheme source file, and return either a <command> object based
|
|
|
|
|
on the 'define-command' top-level form found therein, or #f if FILE does not
|
|
|
|
|
contain a 'define-command' form."
|
|
|
|
|
(define command-name
|
2021-01-05 05:14:51 -05:00
|
|
|
|
(match (filter (negate string-null?)
|
|
|
|
|
(string-split file #\/))
|
|
|
|
|
((_ ... "guix" (or "scripts" "extensions") name)
|
2020-09-01 16:13:11 -04:00
|
|
|
|
(list (file-sans-extension name)))
|
2021-01-05 05:14:51 -05:00
|
|
|
|
((_ ... "guix" (or "scripts" "extensions") first second)
|
2020-09-01 16:13:11 -04:00
|
|
|
|
(list first (file-sans-extension second)))))
|
|
|
|
|
|
|
|
|
|
;; The strategy here is to parse FILE. This is much cheaper than a
|
|
|
|
|
;; technique based on run-time introspection where we'd load FILE and all
|
|
|
|
|
;; the modules it depends on.
|
|
|
|
|
(call-with-input-file file
|
|
|
|
|
(lambda (port)
|
|
|
|
|
(let loop ()
|
|
|
|
|
(match (read port)
|
|
|
|
|
(('define-command _ ('synopsis synopsis)
|
|
|
|
|
_ ...)
|
|
|
|
|
(command command-name synopsis 'main))
|
|
|
|
|
(('define-command _
|
|
|
|
|
('category category) ('synopsis synopsis)
|
|
|
|
|
_ ...)
|
|
|
|
|
(command command-name synopsis category))
|
|
|
|
|
((? eof-object?)
|
|
|
|
|
#f)
|
|
|
|
|
(_
|
|
|
|
|
(loop)))))))
|
|
|
|
|
|
2021-01-05 05:14:51 -05:00
|
|
|
|
(define* (command-files #:optional directory)
|
2013-05-10 06:33:18 -04:00
|
|
|
|
"Return the list of source files that define Guix sub-commands."
|
2021-01-05 05:14:51 -05:00
|
|
|
|
(define directory*
|
|
|
|
|
(or directory
|
|
|
|
|
(and=> (search-path %load-path "guix.scm")
|
|
|
|
|
(compose (cut string-append <> "/guix/scripts")
|
|
|
|
|
dirname))))
|
2013-05-10 06:33:18 -04:00
|
|
|
|
|
2013-05-14 07:37:21 -04:00
|
|
|
|
(define dot-scm?
|
|
|
|
|
(cut string-suffix? ".scm" <>))
|
|
|
|
|
|
2021-01-05 05:14:51 -05:00
|
|
|
|
(if directory*
|
|
|
|
|
(map (cut string-append directory* "/" <>)
|
|
|
|
|
(scandir directory* dot-scm?))
|
2013-05-10 06:33:18 -04:00
|
|
|
|
'()))
|
|
|
|
|
|
2021-01-05 05:14:51 -05:00
|
|
|
|
(define (extension-directories)
|
|
|
|
|
"Return the list of directories containing Guix extensions."
|
|
|
|
|
(filter file-exists?
|
|
|
|
|
(parse-path
|
|
|
|
|
(getenv "GUIX_EXTENSIONS_PATH"))))
|
|
|
|
|
|
2013-05-10 06:33:18 -04:00
|
|
|
|
(define (commands)
|
2020-09-01 16:13:11 -04:00
|
|
|
|
"Return the list of commands, alphabetically sorted."
|
2021-01-05 05:14:51 -05:00
|
|
|
|
(filter-map source-file-command
|
|
|
|
|
(append (command-files)
|
|
|
|
|
(append-map command-files
|
|
|
|
|
(extension-directories)))))
|
2013-05-10 06:33:18 -04:00
|
|
|
|
|
|
|
|
|
(define (show-guix-help)
|
2014-01-06 17:31:17 -05:00
|
|
|
|
(define (internal? command)
|
2015-07-19 22:30:16 -04:00
|
|
|
|
(member command '("substitute" "authenticate" "offload"
|
|
|
|
|
"perform-download")))
|
2014-01-06 17:31:17 -05:00
|
|
|
|
|
2020-09-01 16:13:11 -04:00
|
|
|
|
(define (display-commands commands)
|
|
|
|
|
(let* ((names (map (lambda (command)
|
|
|
|
|
(string-join (command-name command)))
|
|
|
|
|
commands))
|
|
|
|
|
(max-width (reduce max 0 (map string-length names))))
|
|
|
|
|
(for-each (lambda (name command)
|
|
|
|
|
(format #t " ~a ~a~%"
|
|
|
|
|
(string-pad-right name max-width)
|
|
|
|
|
(G_ (command-synopsis command))))
|
|
|
|
|
names
|
|
|
|
|
commands)))
|
|
|
|
|
|
|
|
|
|
(define (category-predicate category)
|
|
|
|
|
(lambda (command)
|
|
|
|
|
(eq? category (command-category command))))
|
|
|
|
|
|
2021-10-30 10:07:14 -04:00
|
|
|
|
(display (G_ "Usage: guix OPTION | COMMAND ARGS...
|
2021-10-30 09:48:48 -04:00
|
|
|
|
Run COMMAND with ARGS, if given.\n"))
|
|
|
|
|
|
|
|
|
|
(display (G_ "
|
|
|
|
|
-h, --help display this helpful text again and exit"))
|
|
|
|
|
(display (G_ "
|
|
|
|
|
-V, --version display version and copyright information and exit"))
|
|
|
|
|
(newline)
|
|
|
|
|
|
2013-05-10 06:33:18 -04:00
|
|
|
|
(newline)
|
2021-10-30 10:07:14 -04:00
|
|
|
|
(display (G_ "COMMAND must be one of the sub-commands listed below:\n"))
|
2020-09-01 16:13:11 -04:00
|
|
|
|
|
|
|
|
|
(let ((commands (commands))
|
|
|
|
|
(categories (module-ref (resolve-interface '(guix scripts))
|
|
|
|
|
'%command-categories)))
|
|
|
|
|
(for-each (match-lambda
|
|
|
|
|
(('internal . _)
|
|
|
|
|
#t) ;hide internal commands
|
|
|
|
|
((category . synopsis)
|
2021-01-05 05:14:51 -05:00
|
|
|
|
(let ((relevant-commands (filter (category-predicate category)
|
|
|
|
|
commands)))
|
|
|
|
|
;; Only print categories that contain commands.
|
|
|
|
|
(match relevant-commands
|
|
|
|
|
((one . more)
|
|
|
|
|
(format #t "~% ~a~%" (G_ synopsis))
|
|
|
|
|
(display-commands relevant-commands))
|
|
|
|
|
(_ #f)))))
|
2020-09-01 16:13:11 -04:00
|
|
|
|
categories))
|
2013-05-10 06:33:18 -04:00
|
|
|
|
(show-bug-report-information))
|
|
|
|
|
|
2013-05-10 06:14:01 -04:00
|
|
|
|
(define (run-guix-command command . args)
|
|
|
|
|
"Run COMMAND with the given ARGS. Report an error when COMMAND is not
|
|
|
|
|
found."
|
2021-01-19 16:28:10 -05:00
|
|
|
|
(define (command-hint guess commands)
|
|
|
|
|
(define command-names
|
|
|
|
|
(map (lambda (command)
|
|
|
|
|
(match (command-name command)
|
|
|
|
|
((head tail ...) head)))
|
|
|
|
|
commands))
|
|
|
|
|
(string-closest (symbol->string guess) command-names #:threshold 3))
|
|
|
|
|
|
2013-05-10 06:14:01 -04:00
|
|
|
|
(define module
|
2021-01-15 19:57:08 -05:00
|
|
|
|
;; Check if there is a matching extension.
|
|
|
|
|
(match (search-path (extension-directories)
|
|
|
|
|
(format #f "~a.scm" command))
|
|
|
|
|
(#f
|
|
|
|
|
(catch 'misc-error
|
|
|
|
|
(lambda ()
|
|
|
|
|
(resolve-interface `(guix scripts ,command)))
|
|
|
|
|
(lambda _
|
2021-01-19 16:28:10 -05:00
|
|
|
|
(let ((hint (command-hint command (commands))))
|
|
|
|
|
(format (current-error-port)
|
|
|
|
|
(G_ "guix: ~a: command not found~%") command)
|
|
|
|
|
(when hint
|
2023-02-24 05:15:45 -05:00
|
|
|
|
(display-hint (G_ "Did you mean @code{~a}?") hint))
|
2021-01-19 16:28:10 -05:00
|
|
|
|
(show-guix-usage)))))
|
2021-01-15 19:57:08 -05:00
|
|
|
|
(file
|
|
|
|
|
(load file)
|
|
|
|
|
(resolve-interface `(guix extensions ,command)))))
|
2013-05-10 06:14:01 -04:00
|
|
|
|
|
|
|
|
|
(let ((command-main (module-ref module
|
|
|
|
|
(symbol-append 'guix- command))))
|
|
|
|
|
(parameterize ((program-name command))
|
2021-06-28 16:52:16 -04:00
|
|
|
|
(dynamic-wind
|
|
|
|
|
(const #f)
|
|
|
|
|
(lambda ()
|
|
|
|
|
(apply command-main args))
|
|
|
|
|
(lambda ()
|
|
|
|
|
;; Abuse 'exit-hook' (which is normally meant to be used by the
|
|
|
|
|
;; REPL) to run things like profiling hooks upon completion.
|
|
|
|
|
(run-hook exit-hook))))))
|
2013-05-10 06:14:01 -04:00
|
|
|
|
|
2015-08-16 03:28:04 -04:00
|
|
|
|
(define (run-guix . args)
|
|
|
|
|
"Run the 'guix' command defined by command line ARGS.
|
|
|
|
|
Unlike 'guix-main', this procedure assumes that locale, i18n support,
|
2020-04-16 17:17:16 -04:00
|
|
|
|
and signal handling have already been set up."
|
2015-08-16 03:28:04 -04:00
|
|
|
|
(define option? (cut string-prefix? "-" <>))
|
|
|
|
|
|
2017-06-15 15:58:17 -04:00
|
|
|
|
;; The default %LOAD-EXTENSIONS includes the empty string, which doubles the
|
|
|
|
|
;; number of 'stat' calls per entry in %LOAD-PATH. Shamelessly remove it.
|
|
|
|
|
(set! %load-extensions '(".scm"))
|
|
|
|
|
|
2021-06-28 16:52:16 -04:00
|
|
|
|
;; Disable canonicalization so we don't don't stat unreasonably.
|
|
|
|
|
(with-fluids ((%file-port-name-canonicalization #f))
|
|
|
|
|
(match args
|
|
|
|
|
(()
|
|
|
|
|
(format (current-error-port)
|
|
|
|
|
(G_ "guix: missing command name~%"))
|
|
|
|
|
(show-guix-usage))
|
|
|
|
|
((or ("-h") ("--help"))
|
|
|
|
|
(leave-on-EPIPE (show-guix-help)))
|
|
|
|
|
((or ("-V") ("--version"))
|
|
|
|
|
(show-version-and-exit "guix"))
|
|
|
|
|
(((? option? o) args ...)
|
|
|
|
|
(format (current-error-port)
|
|
|
|
|
(G_ "guix: unrecognized option '~a'~%") o)
|
|
|
|
|
(show-guix-usage))
|
|
|
|
|
(("help" command)
|
|
|
|
|
(apply run-guix-command (string->symbol command)
|
|
|
|
|
'("--help")))
|
|
|
|
|
(("help" args ...)
|
|
|
|
|
(leave-on-EPIPE (show-guix-help)))
|
|
|
|
|
((command args ...)
|
|
|
|
|
(apply run-guix-command
|
|
|
|
|
(string->symbol command)
|
|
|
|
|
args)))))
|
2015-08-16 03:28:04 -04:00
|
|
|
|
|
Replace individual scripts with master 'guix' script.
* scripts/guix.in: New script.
* Makefile.am (bin_SCRIPTS): Add 'scripts/guix'. Remove 'guix-build',
'guix-download', 'guix-import', 'guix-package', and 'guix-gc'.
(MODULES): Add 'guix/scripts/build.scm', 'guix/scripts/download.scm',
'guix/scripts/import.scm', 'guix/scripts/package.scm', and
'guix/scripts/gc.scm'.
* configure.ac (AC_CONFIG_FILES): Add 'scripts/guix'. Remove 'guix-build',
'guix-download', 'guix-import', 'guix-package', and 'guix-gc'.
* guix-build.in, guix-download.in, guix-gc.in, guix-import.in,
guix-package.in: Remove shell script boilerplate. Move to guix-COMMAND.in
to guix/scripts/COMMAND.scm. Rename module from (guix-COMMAND) to
(guix scripts COMMAND). Change "guix-COMMAND" to "guix COMMAND" in
usage help string.
* pre-inst-env.in: Add "@abs_top_builddir@/scripts" to the front of $PATH.
Export $GUIX_UNINSTALLED.
* tests/guix-build.sh, tests/guix-daemon.sh, tests/guix-download.sh,
tests/guix-gc.sh, tests/guix-package.sh: Use "guix COMMAND" instead of
"guix-COMMAND".
* doc/guix.texi: Replace all occurrences of "guix-COMMAND" with
"guix COMMAND".
* po/POTFILES.in: Update.
2013-02-14 04:15:25 -05:00
|
|
|
|
(define (guix-main arg0 . args)
|
|
|
|
|
(initialize-guix)
|
2015-08-16 03:28:04 -04:00
|
|
|
|
(apply run-guix args))
|
Replace individual scripts with master 'guix' script.
* scripts/guix.in: New script.
* Makefile.am (bin_SCRIPTS): Add 'scripts/guix'. Remove 'guix-build',
'guix-download', 'guix-import', 'guix-package', and 'guix-gc'.
(MODULES): Add 'guix/scripts/build.scm', 'guix/scripts/download.scm',
'guix/scripts/import.scm', 'guix/scripts/package.scm', and
'guix/scripts/gc.scm'.
* configure.ac (AC_CONFIG_FILES): Add 'scripts/guix'. Remove 'guix-build',
'guix-download', 'guix-import', 'guix-package', and 'guix-gc'.
* guix-build.in, guix-download.in, guix-gc.in, guix-import.in,
guix-package.in: Remove shell script boilerplate. Move to guix-COMMAND.in
to guix/scripts/COMMAND.scm. Rename module from (guix-COMMAND) to
(guix scripts COMMAND). Change "guix-COMMAND" to "guix COMMAND" in
usage help string.
* pre-inst-env.in: Add "@abs_top_builddir@/scripts" to the front of $PATH.
Export $GUIX_UNINSTALLED.
* tests/guix-build.sh, tests/guix-daemon.sh, tests/guix-download.sh,
tests/guix-gc.sh, tests/guix-package.sh: Use "guix COMMAND" instead of
"guix-COMMAND".
* doc/guix.texi: Replace all occurrences of "guix-COMMAND" with
"guix COMMAND".
* po/POTFILES.in: Update.
2013-02-14 04:15:25 -05:00
|
|
|
|
|
2020-07-14 19:11:00 -04:00
|
|
|
|
;;; Local Variables:
|
|
|
|
|
;;; eval: (put 'guard* 'scheme-indent-function 2)
|
|
|
|
|
;;; End:
|
|
|
|
|
|
2012-10-31 19:50:01 -04:00
|
|
|
|
;;; ui.scm ends here
|