[PATCH 0/2] Make 'guix help' helpful

  • Done
  • quality assurance status badge
Details
5 participants
  • Efraim Flashner
  • Ludovic Courtès
  • Maxim Cournoyer
  • Ricardo Wurmus
  • zimoun
Owner
unassigned
Submitted by
Ludovic Courtès
Severity
normal
L
L
Ludovic Courtès wrote on 1 Sep 2020 22:35
(address . guix-patches@gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
20200901203520.21103-1-ludo@gnu.org
Hey Guix!

Here’s another long-overdue change that was brought to my
attention: making ‘guix help’ show a synopsis of each command.
While at it, it also groups them in categories (I more or
less followed the manual, but there’s prolly room for
improvement, like a ‘packaging’ category maybe?):

Toggle snippet (50 lines)
$ ./pre-inst-env guix help
Usage: guix COMMAND ARGS...
Run COMMAND with ARGS.

COMMAND must be one of the sub-commands listed below:

main commands:
deploy deploy operating systems on a set of machines
describe describe the channel revisions currently used
gc invoke the garbage collector
install install packages
package manage packages and profiles
pull pull the latest revision of Guix
remove removed installed packages
search search for packages
show show information about packages
system build and deploy full operating systems
time-machine run commands from a different revision
upgrade upgrade packages to their latest version
weather report on the available of pre-built package binaries

commands for developers:
build build packages or derivations without installing them
container run code in containers created by 'guix environment -C'
edit view and edit package definitions
environment spawn one-off software environments
import import a package definition from an external repository
pack create application bundles
refresh update existing package definitions

advanced usage:
archive manipulate, export, and import normalized archives (nars)
challenge challenge substitute servers, comparing their binaries
copy copy store items remotely over SSH
download download a file to the store and print its hash
git operate on Git repositories
graph view and query package dependency graphs
hash compute the cryptographic hash of a file
lint validate package definitions
offload set up and operate build offloading
processes list currently running sessions
publish publish build results over HTTP
repl read-eval-print loop (REPL) for interactive programming
size profile the on-disk size of packages

Report bugs to: bug-guix@gnu.org.
GNU Guix home page: <https://www.gnu.org/software/guix/>
General help using Guix and GNU software: <https://guix.gnu.org/help/>

Much more… helpful than what we currently have, no? :-)

This works by introducing a new ‘define-command’ macro that each
command now uses and where it defines its synopsis. ‘guix help’
actually reads files in search of ‘define-command’, which is cheaper
than loading each module and doing some sort of introspection.

The URL shown at the end (“General help”) is also changed, as was
rightfully suggested by zimoun a while back.

Thoughts?

Ludo’.

PS: We can talk about categories, but make sure to turn on the
bikeshedding limitation mode of your mail client. :-)

Ludovic Courtès (2):
scripts: Use 'define-command' and have 'guix help' use that.
ui: '--help' output links to https://guix.gnu.org/help/.

guix/scripts.scm | 29 ++++++++++-
guix/scripts/archive.scm | 5 +-
guix/scripts/authenticate.scm | 8 ++-
guix/scripts/build.scm | 5 +-
guix/scripts/challenge.scm | 5 +-
guix/scripts/container.scm | 6 ++-
guix/scripts/copy.scm | 5 +-
guix/scripts/deploy.scm | 3 +-
guix/scripts/describe.scm | 3 +-
guix/scripts/download.scm | 5 +-
guix/scripts/edit.scm | 7 ++-
guix/scripts/environment.scm | 5 +-
guix/scripts/gc.scm | 4 +-
guix/scripts/git.scm | 6 ++-
guix/scripts/graph.scm | 5 +-
guix/scripts/hash.scm | 5 +-
guix/scripts/import.scm | 8 ++-
guix/scripts/install.scm | 6 ++-
guix/scripts/lint.scm | 5 +-
guix/scripts/offload.scm | 6 ++-
guix/scripts/pack.scm | 5 +-
guix/scripts/package.scm | 4 +-
guix/scripts/perform-download.scm | 18 ++++---
guix/scripts/processes.scm | 4 +-
guix/scripts/publish.scm | 5 +-
guix/scripts/pull.scm | 4 +-
guix/scripts/refresh.scm | 7 ++-
guix/scripts/remove.scm | 6 ++-
guix/scripts/repl.scm | 5 +-
guix/scripts/search.scm | 6 ++-
guix/scripts/show.scm | 4 +-
guix/scripts/size.scm | 7 ++-
guix/scripts/substitute.scm | 7 ++-
guix/scripts/system.scm | 4 +-
guix/scripts/time-machine.scm | 4 +-
guix/scripts/upgrade.scm | 6 ++-
guix/scripts/weather.scm | 4 +-
guix/ui.scm | 82 +++++++++++++++++++++++++++----
38 files changed, 249 insertions(+), 64 deletions(-)

--
2.28.0
L
L
Ludovic Courtès wrote on 1 Sep 2020 22:41
[PATCH 2/2] ui: '--help' output links to <https://guix.gnu.org/help/>.
(address . 43159@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
20200901204136.21375-2-ludo@gnu.org
* guix/ui.scm (show-bug-report-information): Link to
https://guix.gnu.org/help/ instead of https://www.gnu.org/gethelp/ .
The former is much more useful and includes links to GNU manuals.
---
guix/ui.scm | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

Toggle diff (18 lines)
diff --git a/guix/ui.scm b/guix/ui.scm
index 4d90a47bb9..87a1925a4b 100644
--- a/guix/ui.scm
+++ b/guix/ui.scm
@@ -542,8 +542,9 @@ There is NO WARRANTY, to the extent permitted by law.
Report bugs to: ~a.") %guix-bug-report-address)
(format #t (G_ "
~a home page: <~a>") %guix-package-name %guix-home-page-url)
- (display (G_ "
-General help using GNU software: <http://www.gnu.org/gethelp/>"))
+ (format #t (G_ "
+General help using Guix and GNU software: <~a>")
+ "https://guix.gnu.org/help/")
(newline))
(define (augmented-system-error-handler file)
--
2.28.0
L
L
Ludovic Courtès wrote on 1 Sep 2020 22:41
[PATCH 1/2] scripts: Use 'define-command' and have 'guix help' use that.
(address . 43159@debbugs.gnu.org)(name . Ludovic Courtès)(address . ludo@gnu.org)
20200901204136.21375-1-ludo@gnu.org
This changes 'guix help' to print a short synopsis for each command and
to group commands by category.

* guix/scripts.scm (synopsis, category): New variables.
(define-command): New macro.
* guix/ui.scm (<command>): New record type.
(source-file-command): New procedure.
(command-files): Return absolute file names.
(commands): Return a list of <command> records.
(show-guix-help)[display-commands, category-predicate]: New procedures.
Display commands grouped in three categories.
* guix/scripts/archive.scm (guix-archive): Use 'define-command'.
* guix/scripts/authenticate.scm (guix-authenticate): Likewise.
* guix/scripts/build.scm (guix-build): Likewise.
* guix/scripts/challenge.scm (guix-challenge): Likewise.
* guix/scripts/container.scm (guix-container): Likewise.
* guix/scripts/copy.scm (guix-copy): Likewise.
* guix/scripts/deploy.scm (guix-deploy): Likewise.
* guix/scripts/describe.scm (guix-describe): Likewise.
* guix/scripts/download.scm (guix-download): Likewise.
* guix/scripts/edit.scm (guix-edit): Likewise.
* guix/scripts/environment.scm (guix-environment): Likewise.
* guix/scripts/gc.scm (guix-gc): Likewise.
* guix/scripts/git.scm (guix-git): Likewise.
* guix/scripts/graph.scm (guix-graph): Likewise.
* guix/scripts/hash.scm (guix-hash): Likewise.
* guix/scripts/import.scm (guix-import): Likewise.
* guix/scripts/install.scm (guix-install): Likewise.
* guix/scripts/lint.scm (guix-lint): Likewise.
* guix/scripts/offload.scm (guix-offload): Likewise.
* guix/scripts/pack.scm (guix-pack): Likewise.
* guix/scripts/package.scm (guix-package): Likewise.
* guix/scripts/perform-download.scm (guix-perform-download): Likewise.
* guix/scripts/processes.scm (guix-processes): Likewise.
* guix/scripts/publish.scm (guix-publish): Likewise.
* guix/scripts/pull.scm (guix-pull): Likewise.
* guix/scripts/refresh.scm (guix-refresh): Likewise.
* guix/scripts/remove.scm (guix-remove): Likewise.
* guix/scripts/repl.scm (guix-repl): Likewise.
* guix/scripts/search.scm (guix-search): Likewise.
* guix/scripts/show.scm (guix-show): Likewise.
* guix/scripts/size.scm (guix-size): Likewise.
* guix/scripts/substitute.scm (guix-substitute): Likewise.
* guix/scripts/system.scm (guix-system): Likewise.
* guix/scripts/time-machine.scm (guix-time-machine): Likewise.
* guix/scripts/upgrade.scm (guix-upgrade): Likewise.
* guix/scripts/weather.scm (guix-weather): Likewise.
---
guix/scripts.scm | 29 +++++++++++-
guix/scripts/archive.scm | 5 +-
guix/scripts/authenticate.scm | 8 +++-
guix/scripts/build.scm | 5 +-
guix/scripts/challenge.scm | 5 +-
guix/scripts/container.scm | 6 ++-
guix/scripts/copy.scm | 5 +-
guix/scripts/deploy.scm | 3 +-
guix/scripts/describe.scm | 3 +-
guix/scripts/download.scm | 5 +-
guix/scripts/edit.scm | 7 ++-
guix/scripts/environment.scm | 5 +-
guix/scripts/gc.scm | 4 +-
guix/scripts/git.scm | 6 ++-
guix/scripts/graph.scm | 5 +-
guix/scripts/hash.scm | 5 +-
guix/scripts/import.scm | 8 +++-
guix/scripts/install.scm | 6 ++-
guix/scripts/lint.scm | 5 +-
guix/scripts/offload.scm | 6 ++-
guix/scripts/pack.scm | 5 +-
guix/scripts/package.scm | 4 +-
guix/scripts/perform-download.scm | 18 ++++----
guix/scripts/processes.scm | 4 +-
guix/scripts/publish.scm | 5 +-
guix/scripts/pull.scm | 4 +-
guix/scripts/refresh.scm | 7 ++-
guix/scripts/remove.scm | 6 ++-
guix/scripts/repl.scm | 5 +-
guix/scripts/search.scm | 6 ++-
guix/scripts/show.scm | 4 +-
guix/scripts/size.scm | 7 ++-
guix/scripts/substitute.scm | 7 ++-
guix/scripts/system.scm | 4 +-
guix/scripts/time-machine.scm | 4 +-
guix/scripts/upgrade.scm | 6 ++-
guix/scripts/weather.scm | 4 +-
guix/ui.scm | 77 +++++++++++++++++++++++++++----
38 files changed, 246 insertions(+), 62 deletions(-)

Toggle diff (472 lines)
diff --git a/guix/scripts.scm b/guix/scripts.scm
index 8534948892..013b775818 100644
--- a/guix/scripts.scm
+++ b/guix/scripts.scm
@@ -34,7 +34,10 @@
#:use-module (srfi srfi-19)
#:use-module (srfi srfi-37)
#:use-module (ice-9 match)
- #:export (args-fold*
+ #:export (synopsis
+ category
+ define-command
+ args-fold*
parse-command-line
maybe-build
build-package
@@ -50,6 +53,30 @@
;;;
;;; Code:
+;; Syntactic keywords.
+(define synopsis 'command-synopsis)
+(define category 'command-category)
+
+(define-syntax define-command
+ (syntax-rules (category synopsis)
+ "Define the given command as a procedure along with its synopsis and,
+optionally, its category. The synopsis becomes the docstring of the
+procedure, but both the category and synopsis are meant to be read (parsed) by
+'guix help'."
+ ;; The (synopsis ...) form is here so that xgettext sees those strings as
+ ;; translatable.
+ ((_ (name . args)
+ (synopsis doc) body ...)
+ (define (name . args)
+ doc
+ body ...))
+ ((_ (name . args)
+ (category _)
+ (synopsis doc) body ...)
+ (define (name . args)
+ doc
+ body ...))))
+
(define (args-fold* args options unrecognized-option-proc operand-proc . seeds)
"A wrapper on top of `args-fold' that does proper user-facing error
reporting."
diff --git a/guix/scripts/archive.scm b/guix/scripts/archive.scm
index f3b86fba14..8796774a01 100644
--- a/guix/scripts/archive.scm
+++ b/guix/scripts/archive.scm
@@ -355,7 +355,10 @@ output port."
;;; Entry point.
;;;
-(define (guix-archive . args)
+(define-command (guix-archive . args)
+ (category advanced)
+ (synopsis "manipulate, export, and import normalized archives (nars)")
+
(define (lines port)
;; Return lines read from PORT.
(let loop ((line (read-line port))
diff --git a/guix/scripts/authenticate.scm b/guix/scripts/authenticate.scm
index f1fd8ee895..a4b9171fc7 100644
--- a/guix/scripts/authenticate.scm
+++ b/guix/scripts/authenticate.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2013, 2014, 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2020 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -18,6 +18,7 @@
(define-module (guix scripts authenticate)
#:use-module (guix config)
+ #:use-module (guix scripts)
#:use-module (guix base16)
#:use-module (gcrypt pk-crypto)
#:use-module (guix pki)
@@ -90,7 +91,10 @@ to stdout upon success."
;;; unmodified currently.
;;;
-(define (guix-authenticate . args)
+(define-command (guix-authenticate . args)
+ (category internal)
+ (synopsis "sign or verify signatures on normalized archives (nars)")
+
;; Signature sexps written to stdout may contain binary data, so force
;; ISO-8859-1 encoding so that things are not mangled. See
;; <http://bugs.gnu.org/17312> for details.
diff --git a/guix/scripts/build.scm b/guix/scripts/build.scm
index 6286a43c02..37b8d82fd5 100644
--- a/guix/scripts/build.scm
+++ b/guix/scripts/build.scm
@@ -945,7 +945,10 @@ needed."
;;; Entry point.
;;;
-(define (guix-build . args)
+(define-command (guix-build . args)
+ (category development)
+ (synopsis "build packages or derivations without installing them")
+
(define opts
(parse-command-line args %options
(list %default-options)))
diff --git a/guix/scripts/challenge.scm b/guix/scripts/challenge.scm
index 624f51b200..6aab53152e 100644
--- a/guix/scripts/challenge.scm
+++ b/guix/scripts/challenge.scm
@@ -475,7 +475,10 @@ Challenge the substitutes for PACKAGE... provided by one or more servers.\n"))
;;; Entry point.
;;;
-(define (guix-challenge . args)
+(define-command (guix-challenge . args)
+ (category advanced)
+ (synopsis "challenge substitute servers, comparing their binaries")
+
(with-error-handling
(let* ((opts (parse-command-line args %options (list %default-options)
#:build-options? #f))
diff --git a/guix/scripts/container.scm b/guix/scripts/container.scm
index 8041d64b6b..2369437043 100644
--- a/guix/scripts/container.scm
+++ b/guix/scripts/container.scm
@@ -20,6 +20,7 @@
(define-module (guix scripts container)
#:use-module (ice-9 match)
#:use-module (guix ui)
+ #:use-module (guix scripts)
#:export (guix-container))
(define (show-help)
@@ -46,7 +47,10 @@ Build and manipulate Linux containers.\n"))
(proc (string->symbol (string-append "guix-container-" name))))
(module-ref module proc)))
-(define (guix-container . args)
+(define-command (guix-container . args)
+ (category development)
+ (synopsis "run code in containers created by 'guix environment -C'")
+
(with-error-handling
(match args
(()
diff --git a/guix/scripts/copy.scm b/guix/scripts/copy.scm
index 274620fc1e..b2eccae7a6 100644
--- a/guix/scripts/copy.scm
+++ b/guix/scripts/copy.scm
@@ -170,7 +170,10 @@ Copy ITEMS to or from the specified host over SSH.\n"))
;;; Entry point.
;;;
-(define (guix-copy . args)
+(define-command (guix-copy . args)
+ (category advanced)
+ (synopsis "copy store items remotely over SSH")
+
(with-error-handling
(let* ((opts (parse-command-line args %options (list %default-options)))
(source (assoc-ref opts 'source))
diff --git a/guix/scripts/deploy.scm b/guix/scripts/deploy.scm
index 4a68197620..1b5be307be 100644
--- a/guix/scripts/deploy.scm
+++ b/guix/scripts/deploy.scm
@@ -136,7 +136,8 @@ Perform the deployment specified by FILE.\n"))
(machine-display-name machine))))
-(define (guix-deploy . args)
+(define-command (guix-deploy . args)
+ (synopsis "deploy operating systems on a set of machines")
(define (handle-argument arg result)
(alist-cons 'file arg result))
diff --git a/guix/scripts/describe.scm b/guix/scripts/describe.scm
index bc868ffbbf..c3667516eb 100644
--- a/guix/scripts/describe.scm
+++ b/guix/scripts/describe.scm
@@ -304,7 +304,8 @@ text. The hyperlink links to a web view of COMMIT, when available."
;;; Entry point.
;;;
-(define (guix-describe . args)
+(define-command (guix-describe . args)
+ (synopsis "describe the channel revisions currently used")
(let* ((opts (args-fold* args %options
(lambda (opt name arg result)
(leave (G_ "~A: unrecognized option~%")
diff --git a/guix/scripts/download.scm b/guix/scripts/download.scm
index 589f62da9d..7192aa14d0 100644
--- a/guix/scripts/download.scm
+++ b/guix/scripts/download.scm
@@ -156,7 +156,10 @@ and 'base16' ('hex' and 'hexadecimal' can be used as well).\n"))
;;; Entry point.
;;;
-(define (guix-download . args)
+(define-command (guix-download . args)
+ (category advanced)
+ (synopsis "download a file to the store and print its hash")
+
(define (parse-options)
;; Return the alist of option values.
(args-fold* args %options
diff --git a/guix/scripts/edit.scm b/guix/scripts/edit.scm
index 43f3011869..39bd4f8a6c 100644
--- a/guix/scripts/edit.scm
+++ b/guix/scripts/edit.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2015, 2016, 2019 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2015, 2016, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2015 Mathieu Lirzin <mthl@gnu.org>
;;; Copyright © 2020 Simon Tournier <zimon.toutoune@gmail.com>
;;;
@@ -78,7 +78,10 @@ line."
(search-path* %load-path (location-file location))))
-(define (guix-edit . args)
+(define-command (guix-edit . args)
+ (category development)
+ (synopsis "view and edit package definitions")
+
(define (parse-arguments)
;; Return the list of package names.
(args-fold* args %options
diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm
index 1fb3505307..ad50281eb2 100644
--- a/guix/scripts/environment.scm
+++ b/guix/scripts/environment.scm
@@ -678,7 +678,10 @@ message if any test fails."
;;; Entry point.
;;;
-(define (guix-environment . args)
+(define-command (guix-environment . args)
+ (category development)
+ (synopsis "spawn one-off software environments")
+
(with-error-handling
(let* ((opts (parse-args args))
(pure? (assoc-ref opts 'pure))
diff --git a/guix/scripts/gc.scm b/guix/scripts/gc.scm
index ab7c13315f..043273f491 100644
--- a/guix/scripts/gc.scm
+++ b/guix/scripts/gc.scm
@@ -220,7 +220,9 @@ is deprecated; use '-D'~%"))
;;; Entry point.
;;;
-(define (guix-gc . args)
+(define-command (guix-gc . args)
+ (synopsis "invoke the garbage collector")
+
(define (parse-options)
;; Return the alist of option values.
(parse-command-line args %options (list %default-options)
diff --git a/guix/scripts/git.scm b/guix/scripts/git.scm
index bc829cbe99..58a496a1b2 100644
--- a/guix/scripts/git.scm
+++ b/guix/scripts/git.scm
@@ -19,6 +19,7 @@
(define-module (guix scripts git)
#:use-module (ice-9 match)
#:use-module (guix ui)
+ #:use-module (guix scripts)
#:export (guix-git))
(define (show-help)
@@ -45,7 +46,10 @@ Operate on Git repositories.\n"))
(proc (string->symbol (string-append "guix-git-" name))))
(module-ref module proc)))
-(define (guix-git . args)
+(define-command (guix-git . args)
+ (category advanced)
+ (synopsis "operate on Git repositories")
+
(with-error-handling
(match args
(()
diff --git a/guix/scripts/graph.scm b/guix/scripts/graph.scm
index 73d9269de2..bfeda4f61b 100644
--- a/guix/scripts/graph.scm
+++ b/guix/scripts/graph.scm
@@ -565,7 +565,10 @@ Emit a representation of the dependency graph of PACKAGE...\n"))
;;; Entry point.
;;;
-(define (guix-graph . args)
+(define-command (guix-graph . args)
+ (category advanced)
+ (synopsis "view and query package dependency graphs")
+
(with-error-handling
(define opts
(parse-command-line args %options
diff --git a/guix/scripts/hash.scm b/guix/scripts/hash.scm
index 9b4f419a24..480814df20 100644
--- a/guix/scripts/hash.scm
+++ b/guix/scripts/hash.scm
@@ -116,7 +116,10 @@ and 'base16' ('hex' and 'hexadecimal' can be used as well).\n"))
;;; Entry point.
;;;
-(define (guix-hash . args)
+(define-command (guix-hash . args)
+ (category advanced)
+ (synopsis "compute the cryptographic hash of a file")
+
(define (parse-options)
;; Return the alist of option values.
(parse-command-line args %options (list %default-options)
diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm
index c6cc93fad8..6e972561fb 100644
--- a/guix/scripts/import.scm
+++ b/guix/scripts/import.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012, 2013, 2014 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2012, 2013, 2014, 2020 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2014 David Thompson <davet@gnu.org>
;;; Copyright © 2018 Kyle Meyer <kyle@kyleam.com>
;;; Copyright © 2019 Ricardo Wurmus <rekado@elephly.net>
@@ -21,6 +21,7 @@
(define-module (guix scripts import)
#:use-module (guix ui)
+ #:use-module (guix scripts)
#:use-module (guix utils)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-11)
@@ -98,7 +99,10 @@ Run IMPORTER with ARGS.\n"))
(newline)
(show-bug-report-information))
-(define (guix-import . args)
+(define-command (guix-import . args)
+ (category development)
+ (synopsis "import a package definition from an external repository")
+
(match args
(()
(format (current-error-port)
diff --git a/guix/scripts/install.scm b/guix/scripts/install.scm
index d88e86e77a..894e60f9da 100644
--- a/guix/scripts/install.scm
+++ b/guix/scripts/install.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2019 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2019, 2020 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -66,7 +66,9 @@ This is an alias for 'guix package -i'.\n"))
%transformation-options
%standard-build-options)))
-(define (guix-install . args)
+(define-command (guix-install . args)
+ (synopsis "install packages")
+
(define (handle-argument arg result arg-handler)
;; Treat all non-option arguments as package specs.
(values (alist-cons 'install arg result)
diff --git a/guix/scripts/lint.scm b/guix/scripts/lint.scm
index 5168a1ca17..76bf18220a 100644
--- a/guix/scripts/lint.scm
+++ b/guix/scripts/lint.scm
@@ -157,7 +157,10 @@ run the checkers on all packages.\n"))
;;; Entry Point
;;;
-(define (guix-lint . args)
+(define-command (guix-lint . args)
+ (category advanced)
+ (synopsis "validate package definitions")
+
(define (parse-options)
;; Return the alist of option values.
(parse-command-line args %options (list %default-options)
diff --git a/guix/scripts/offload.scm b/guix/scripts/offload.scm
index 1e0e9d7905..4afdb9396d 100644
--- a/guix/scripts/offload.scm
+++ b/guix/scripts/offload.scm
@@ -39,6 +39,7 @@
#:select (fcntl-flock set-thread-name))
#:use-module ((guix build utils) #:select (which mkdir-p))
#:use-module (guix ui)
+ #:use-module (guix scripts)
#:use-module (guix diagnostics)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-11)
@@ -725,7 +726,10 @@ machine."
;;; Entry point.
;;;
-(define (guix-offload . args)
+(define-command (guix-offload . args)
+ (category advanced)
+ (synopsis "set up and operate build offloading")
+
(define request-line-rx
;; The request format. See 'tryBuildHook' method in build.cc.
(make-regexp "([01]) ([a-z0-9_-]+) (/[[:graph:]]+.drv) ([[:graph:]]*)"))
diff --git a/guix/scripts/pack.scm b/guix/scripts/pack.scm
index 9d6881fdaf..379e6a3ac6 100644
--- a/guix/scripts/pack.scm
+++ b/guix/scripts/pack.scm
@@ -1089,7 +1089,10 @@ Create a bundle of PACKAGE.\n"))
;;; Entry point.
;;;
-(define (guix-pack . args)
+(define-command (guix-pack . args)
+ (category development)
+ (synopsis "create application bundles")
+
(define opts
(parse-command-line args %options (list %default-options)))
diff --git a/guix/scripts/package.scm b/guix/scripts/package.scm
index ac8dedb5f3..4eb968a49b 100644
--- a/guix/scripts/package.scm
+++ b/guix/scripts/package.scm
@@ -941,7 +941,9 @@ processed, #f otherwise."
;;; Entry point.
;;;
-(define (guix-package . args)
+(define-command (guix-package . args)
+ (synopsis "manage packages and profiles")
+
(define (handle-argument arg result arg-handler)
;; Process non-option argument ARG by calling back ARG-HANDLER.
(if arg-handler
diff --git a/guix/scripts/perform-download.scm b/guix/scripts/perform-download.scm
index df787a9940..8d409092ba 100644
--- a/guix/scripts/perform-download.scm
+++ b/guix/scripts/perform-download.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2016, 2017, 2018 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2016, 2017, 2018, 2020 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -18,6 +18,7 @@
(define-module (guix scripts perform-download)
#:use-module (guix ui)
+ #:use-module (guix scripts)
#:use-module (guix derivations)
#:use-module ((guix store) #:select (derivation-path? store-path?))
#:use-module (guix build download)
@@ -91,14 +92,15 @@ actual output is different from that when we're doing a 'bmCheck' or
(leave (G_ "refusing to run with elevated privileges (UID ~a)~%")
(getuid))))
-(define (guix-perform-download . args)
- "Perform the download described by the given fixed-output derivation.
+(define-command (guix-perform-download . args)
+ (category internal)
+ (synopsis "perform download described by fixed-output
This message was truncated. Download the full message here.
E
E
Efraim Flashner wrote on 2 Sep 2020 10:06
Re: [bug#43159] [PATCH 0/2] Make 'guix help' helpful
(name . Ludovic Courtès)(address . ludo@gnu.org)(address . 43159@debbugs.gnu.org)
20200902080622.GI856@E5400
Attachment: file
-----BEGIN PGP SIGNATURE-----

iQIzBAABCgAdFiEEoov0DD5VE3JmLRT3Qarn3Mo9g1EFAl9PUnsACgkQQarn3Mo9
g1FDuxAAkbQQSp9tou8KxdrlxF2CoEKt+XsKsBaPwSf+jV0N6bneve9QuI8cvsRb
dzjYdbOvF09t32HrDexCv/uytGrPxF/ldQHzejxevObqPJyPjnbc2KHaGg15FWZu
yU12/SMkXLqIW+JRjjWFsLbH8gQlWmG4r6Q17RYY/IT22TExJWn7uHTUiwcWbh/p
MeVc1KwLGx0TwEv5eU7n/jJNyoSg9ABB2c8njmqoAbCI+10f1NoTcKFIWFeOhq70
Bd1of3CXZ2MUm0TFVK8rLEs8IfuPVLkok6tbKZIKBKdOob3zuQaexFQQkI7hvCLL
HTI85GeIj73rEZQni2DeLe/+4RkIIt1k1KrvC7HDVmXRNBd8QwMyJ3vF7YFE1NGZ
am64YA6rJwwyYsrLLFD/WgvPW3Hf2HaprmiGSr4sup4lDjToCwQUJvYcbHQtNJjF
S1tcqRKtlejKKEKi86cpDA1arCxgKPeXOTya9O593cz0KADz1AZ2kA/yP0Zx6W32
4G0485+3QzRtdVh3R3/94GEqXr0Fvd5ZqvNwgabweOwDIfYjkdKCkH9khS4XeNgL
fLHSdEOnDQ/JOcAxKGHi3yThT0kf+BRkEj4zG5qi9j+No7Dv+mHEchiW3vDpWpY5
n6zHiPicgPiyaaGc//fOliwUAmUgfdYI9nuNBR73AJrVbN26Lrw=
=xtBQ
-----END PGP SIGNATURE-----


L
L
Ludovic Courtès wrote on 2 Sep 2020 11:50
(name . Efraim Flashner)(address . efraim@flashner.co.il)(address . 43159@debbugs.gnu.org)
87a6y87bja.fsf@gnu.org
Hi,

Efraim Flashner <efraim@flashner.co.il> skribis:

Toggle quote (13 lines)
> On Tue, Sep 01, 2020 at 10:35:20PM +0200, Ludovic Courtès wrote:
>> Hey Guix!
>>
>> Here’s another long-overdue change that was brought to my
>> attention: making ‘guix help’ show a synopsis of each command.
>> While at it, it also groups them in categories (I more or
>> less followed the manual, but there’s prolly room for
>> improvement, like a ‘packaging’ category maybe?):
>>
>
> I dislike the idea that some commands are only for developers and some
> commands are "too advanced for the common user" (my words, not yours).

Yeah, I’m ambivalent about this as well.

Toggle quote (3 lines)
> Before bikeshedding about where the options should be, how about:
> commands for developers -> commands related to building

Rather, “commands for development“, because that’s really what ‘guix
environment’ is about, for instance, but saying ‘development’ rather
than ‘developers’ is probably wise.

Toggle quote (2 lines)
> advanced usage -> commands related to verification

Well that only works for ‘challenge’ (which I’d like to put in the hands
of ‘normal’ users, so I’m not comfortable with the ‘advanced’ label, but
OTOH, it’s clearly not one of the commands you’d begin with.)

What about archive, copy, download, etc.?

Toggle quote (3 lines)
> This way they're still "commands for everybody" and they're more
> descriptive than just "advanced" "expert" and "debug" style headers.

Understood.

Thanks for your feedback!

Ludo’.
E
E
Efraim Flashner wrote on 2 Sep 2020 13:09
(name . Ludovic Courtès)(address . ludo@gnu.org)(address . 43159@debbugs.gnu.org)
20200902110953.GB24305@E5400
On Wed, Sep 02, 2020 at 11:50:17AM +0200, Ludovic Courtès wrote:
Toggle quote (35 lines)
> Hi,
>
> Efraim Flashner <efraim@flashner.co.il> skribis:
>
> > On Tue, Sep 01, 2020 at 10:35:20PM +0200, Ludovic Courtès wrote:
> >> Hey Guix!
> >>
> >> Here’s another long-overdue change that was brought to my
> >> attention: making ‘guix help’ show a synopsis of each command.
> >> While at it, it also groups them in categories (I more or
> >> less followed the manual, but there’s prolly room for
> >> improvement, like a ‘packaging’ category maybe?):
> >>
> >
> > I dislike the idea that some commands are only for developers and some
> > commands are "too advanced for the common user" (my words, not yours).
>
> Yeah, I’m ambivalent about this as well.
>
> > Before bikeshedding about where the options should be, how about:
> > commands for developers -> commands related to building
>
> Rather, “commands for development“, because that’s really what ‘guix
> environment’ is about, for instance, but saying ‘development’ rather
> than ‘developers’ is probably wise.
>
> > advanced usage -> commands related to verification
>
> Well that only works for ‘challenge’ (which I’d like to put in the hands
> of ‘normal’ users, so I’m not comfortable with the ‘advanced’ label, but
> OTOH, it’s clearly not one of the commands you’d begin with.)
>
> What about archive, copy, download, etc.?
>

It seemed loosely related. If you're running 'guix pull; guix upgrade'
you're not first running 'guix download https://path/to/source.tar.xz'
or copying packages between machines or challenging the reproducibility
of the packages. That's for after you have the packages you want in your
profile or environment.

Toggle quote (9 lines)
> > This way they're still "commands for everybody" and they're more
> > descriptive than just "advanced" "expert" and "debug" style headers.
>
> Understood.
>
> Thanks for your feedback!
>
> Ludo’.

--
Efraim Flashner <efraim@flashner.co.il> ????? ?????
GPG key = A28B F40C 3E55 1372 662D 14F7 41AA E7DC CA3D 8351
Confidentiality cannot be guaranteed on emails sent or received unencrypted
-----BEGIN PGP SIGNATURE-----

iQIzBAABCgAdFiEEoov0DD5VE3JmLRT3Qarn3Mo9g1EFAl9PfXwACgkQQarn3Mo9
g1HJjQ//Z2rWEJhi8x0bG4hr0TZ6wQHuRkMaXBAh3SypSk3QEmn6LeGC96qBDnh1
N2oVpg519U5lVkOsnbwQWy8XiKq72Itd04+DE07mfoqn3JpzaVRdQz2Mc+l0MOZM
A2/ZqO1Ikw5GinoPnq441WlI+XkkbN4tB0pdeNv83P4QTv1AIZIq4fj6SLCRi41D
k61l7mcUUEjniLniUmFQOi6ge7e6iscgs6j/cG2oL6dvH0cL/LNAnz4aQ877DswA
Pop2anp3MzPrK1EMKpuUfIu9cKI2C8i1kNByGGvdBnCA6yr31Sfd9wCa8/qQf/6i
sfsb3CAxjp2fJL4Q5hEGQ73kR0r5mfgwbw35wAVMF0hA4p8VOCIiiO5n5nOqZLGh
k6ylLE4wY7KPgDAo2zZRrFb+NM5SKFwpZlYI/l1/lkeGBL0DVKcnRy/NDpjGrqnO
Ee2C2jeCyQrIbZaZvPbLoXRA3bR99A2i5tvVDSp5bFXHug7fi8fqWwiW/RiwPxef
LaAnfgLXQMck2iUG8YCeMuz2acRaPctYItPIuYdU1ci5VIVzM6Y0O5aynWQBaDvR
gYH2Z189p98/ye+dkGNPdx7wX8yAwrtW2Ef740qmWouc4T14g8iPY76MfelzBe9O
QeFGpl04RRweZgFgeGD4woFrCkZP3DGt58VLwIusav3Zveg1Dgk=
=iORf
-----END PGP SIGNATURE-----


M
M
Maxim Cournoyer wrote on 2 Sep 2020 20:24
Re: [bug#43159] [PATCH 1/2] scripts: Use 'define-command' and have 'guix help' use that.
(name . Ludovic Courtès)(address . ludo@gnu.org)(address . 43159@debbugs.gnu.org)
87r1rk595p.fsf@gmail.com
Ludovic Courtès <ludo@gnu.org> writes:

Toggle quote (3 lines)
> This changes 'guix help' to print a short synopsis for each command and
> to group commands by category.

[...]

Toggle quote (24 lines)
> diff --git a/guix/scripts.scm b/guix/scripts.scm
> index 8534948892..013b775818 100644
> --- a/guix/scripts.scm
> +++ b/guix/scripts.scm
> @@ -34,7 +34,10 @@
> #:use-module (srfi srfi-19)
> #:use-module (srfi srfi-37)
> #:use-module (ice-9 match)
> - #:export (args-fold*
> + #:export (synopsis
> + category
> + define-command
> + args-fold*
> parse-command-line
> maybe-build
> build-package
> @@ -50,6 +53,30 @@
> ;;;
> ;;; Code:
>
> +;; Syntactic keywords.
> +(define synopsis 'command-synopsis)
> +(define category 'command-category)

Are these definition really necessary/useful? I would have thought
having category and synopsis understood as literals in the
define-command syntax was enough?

Toggle quote (35 lines)
> +(define-syntax define-command
> + (syntax-rules (category synopsis)
> + "Define the given command as a procedure along with its synopsis and,
> +optionally, its category. The synopsis becomes the docstring of the
> +procedure, but both the category and synopsis are meant to be read (parsed) by
> +'guix help'."
> + ;; The (synopsis ...) form is here so that xgettext sees those strings as
> + ;; translatable.
> + ((_ (name . args)
> + (synopsis doc) body ...)
> + (define (name . args)
> + doc
> + body ...))
> + ((_ (name . args)
> + (category _)
> + (synopsis doc) body ...)
> + (define (name . args)
> + doc
> + body ...))))
> +
> (define (args-fold* args options unrecognized-option-proc operand-proc . seeds)
> "A wrapper on top of `args-fold' that does proper user-facing error
> reporting."
> diff --git a/guix/scripts/archive.scm b/guix/scripts/archive.scm
> index f3b86fba14..8796774a01 100644
> --- a/guix/scripts/archive.scm
> +++ b/guix/scripts/archive.scm
> @@ -355,7 +355,10 @@ output port."
> ;;; Entry point.
> ;;;
>
> -(define (guix-archive . args)
> +(define-command (guix-archive . args)
> + (category advanced)

It'd be helpful if the category was an enum to keep the set of
categories focused and helpful.

[...]

Toggle quote (10 lines)
> --- a/guix/scripts/weather.scm
> +++ b/guix/scripts/weather.scm
> @@ -495,7 +495,9 @@ SERVER. Display information for packages with at least THRESHOLD dependents."
> ;;; Entry point.
> ;;;
>
> -(define (guix-weather . args)
> +(define-command (guix-weather . args)
> + (synopsis "report on the available of pre-built package binaries")

^ availability

[...]

Toggle quote (11 lines)
> +(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
> + (match (string-split file #\/)
> + ((_ ... "guix" "scripts" name)
> + (list (file-sans-extension name)))
> + ((_ ... "guix" "scripts" first second)
> + (list first (file-sans-extension second)))))

It'd be better if an else clause threw an informative error, especially
since the restriction on file name is not otherwise documented.

Toggle quote (4 lines)
> + ;; 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.

Interesting! Have you measure it? I would have thought loading a couple
optimized byte code modules could have been nearly as fast as parsing
files manually. If so, I think it'd be preferable to use introspection
rather than implement a custom parser.

Toggle quote (17 lines)
> + (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)))))))
> +

[...]

Toggle quote (6 lines)
> + (define (display-commands commands)
> + (let* ((names (map (lambda (command)
> + (string-join (command-name command)))
> + commands))
> + (max-width (reduce max 0 (map string-length names))))

You can drop reduce and use (max (map string-length names)) instead.

Maxim
M
M
Maxim Cournoyer wrote on 2 Sep 2020 20:27
Re: [bug#43159] [PATCH 2/2] ui: '--help' output links to <https://guix.gnu.org/help/>.
(name . Ludovic Courtès)(address . ludo@gnu.org)(address . 43159@debbugs.gnu.org)
87mu28590r.fsf@gmail.com
Ludovic Courtès <ludo@gnu.org> writes:

Toggle quote (22 lines)
> * guix/ui.scm (show-bug-report-information): Link to
> <https://guix.gnu.org/help/> instead of <https://www.gnu.org/gethelp/>.
> The former is much more useful and includes links to GNU manuals.
> ---
> guix/ui.scm | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/guix/ui.scm b/guix/ui.scm
> index 4d90a47bb9..87a1925a4b 100644
> --- a/guix/ui.scm
> +++ b/guix/ui.scm
> @@ -542,8 +542,9 @@ There is NO WARRANTY, to the extent permitted by law.
> Report bugs to: ~a.") %guix-bug-report-address)
> (format #t (G_ "
> ~a home page: <~a>") %guix-package-name %guix-home-page-url)
> - (display (G_ "
> -General help using GNU software: <http://www.gnu.org/gethelp/>"))
> + (format #t (G_ "
> +General help using Guix and GNU software: <~a>")
> + "https://guix.gnu.org/help/")
> (newline))

LGTM!

Maxim
L
L
Ludovic Courtès wrote on 3 Sep 2020 15:41
Re: [bug#43159] [PATCH 1/2] scripts: Use 'define-command' and have 'guix help' use that.
(name . Maxim Cournoyer)(address . maxim.cournoyer@gmail.com)(address . 43159@debbugs.gnu.org)
87blinx9ii.fsf@gnu.org
Hi Maxim,

Maxim Cournoyer <maxim.cournoyer@gmail.com> skribis:

Toggle quote (2 lines)
> Ludovic Courtès <ludo@gnu.org> writes:

[...]

Toggle quote (8 lines)
>> +;; Syntactic keywords.
>> +(define synopsis 'command-synopsis)
>> +(define category 'command-category)
>
> Are these definition really necessary/useful? I would have thought
> having category and synopsis understood as literals in the
> define-command syntax was enough?

It’s not strictly necessary but it’s been considered “good practice”.
That allows users to detect name clashes, to rename/hide/etc. syntactic
keywords and so on.

Toggle quote (3 lines)
>> +(define-syntax define-command
>> + (syntax-rules (category synopsis)

[...]

Toggle quote (7 lines)
>> -(define (guix-archive . args)
>> +(define-command (guix-archive . args)
>> + (category advanced)
>
> It'd be helpful if the category was an enum to keep the set of
> categories focused and helpful.

Yes, I thought about making it a syntactic keyword; let’s see.

Toggle quote (9 lines)
>> + ;; 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.
>
> Interesting! Have you measure it? I would have thought loading a couple
> optimized byte code modules could have been nearly as fast as parsing
> files manually. If so, I think it'd be preferable to use introspection
> rather than implement a custom parser.

On a fast recent laptop with an SSD, a load of 0, hot cache, etc., we’d
still be below 1s. But see:

Toggle snippet (26 lines)
$ strace -c guix help >/dev/null
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ------------------
62.69 0.002698 1 2266 2043 stat
10.94 0.000471 2 161 2 lstat
4.55 0.000196 0 246 mmap
4.51 0.000194 0 330 172 openat

[...]

------ ----------- ----------- --------- --------- ------------------
100.00 0.004304 1 3748 2235 total
$ strace -c guile -c '(use-modules (guix scripts system) (guix scripts authenticate))'
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ------------------
54.27 0.007799 1 5735 4518 stat
12.00 0.001724 11 149 27 futex
9.06 0.001302 0 1328 651 openat
7.24 0.001040 1 822 mmap

[...]

------ ----------- ----------- --------- --------- ------------------
100.00 0.014371 1 10334 5202 total

(The 1st run is the current ‘guix help’; the 2nd run +/- emulates what
you propose.)

Loading all the modules translates into a lot more I/O, roughly an order
of magnitude. We’re talking about loading tens of modules just to get
at that synopsis:

Toggle snippet (7 lines)
scheme@(guile-user)> ,use(guix modules)
scheme@(guile-user)> (length (source-module-closure '((guix scripts system) (guix scripts authenticate))))
$10 = 439
scheme@(guile-user)> (length (source-module-closure '((guix scripts) (guix ui))))
$11 = 31

Memory usage would also be very different:

Toggle snippet (8 lines)
$ \time guix help >/dev/null
0.07user 0.01system 0:00.06elapsed 128%CPU (0avgtext+0avgdata 35348maxresident)k
0inputs+0outputs (0major+3906minor)pagefaults 0swaps
$ \time guile -c '(use-modules (guix scripts system) (guix scripts authenticate))'
0.42user 0.05system 0:00.37elapsed 128%CPU (0avgtext+0avgdata 166916maxresident)k
0inputs+0outputs (0major+15148minor)pagefaults 0swaps

In summary, while this approach undoubtedly looks awkward to any Lisper,
I think it’s a good way to not contribute to the general impression of
sluggishness and resource-hungriness of ‘guix’ commands. :-)

Toggle quote (8 lines)
>> + (define (display-commands commands)
>> + (let* ((names (map (lambda (command)
>> + (string-join (command-name command)))
>> + commands))
>> + (max-width (reduce max 0 (map string-length names))))
>
> You can drop reduce and use (max (map string-length names)) instead.

I could do (apply max (map …)) but I don’t like the idea of abusing
variadic argument lists in that way—I know, it’s very subjective. ;-)

Thanks for your feedback, I’ll send a v2!

Ludo’.
Z
Z
zimoun wrote on 3 Sep 2020 18:40
Re: [bug#43159] [PATCH 0/2] Make 'guix help' helpful
(name . Ludovic Courtès)(address . ludo@gnu.org)(address . 43159@debbugs.gnu.org)
CAJ3okZ1W1Ztrh13SHWrOttgz+r61t=n-m+6caLqPNmyaYmWeLA@mail.gmail.com
Hi Ludo,

On Tue, 1 Sep 2020 at 22:36, Ludovic Courtès <ludo@gnu.org> wrote:

Toggle quote (2 lines)
> remove removed installed packages

s/removed/remove

Toggle quote (2 lines)
> environment spawn one-off software environments

spawn one-off?


Toggle quote (3 lines)
> PS: We can talk about categories, but make sure to turn on the
> bikeshedding limitation mode of your mail client. :-)

Looking for "bikeshedder"? ;-)
Category theory is always complicated. :-)

It depends what do you mean by developers (or development)? To me,
download, hash, lint, repl and size are also commands used on a daily
basis for developing.
On the other hand, container is claimed to be "experimental" in the
manual so it should go in the "advanced" section.

Well, instead of "advanced usage", I propose "plumbing commands"


Thank you for this change.

Cheers,
simon
L
L
Ludovic Courtès wrote on 7 Sep 2020 14:56
[PATCHES v2] scripts: Use 'define-command' and have 'guix help' use that.
(address . 43159@debbugs.gnu.org)
87tuw9iw34.fsf_-_@gnu.org
Hi all!

Here’s a v2 of the patches, where I tried to take your feedback into
account. Changes:

• Categories that appear in uses of ‘define-command’ are now validated
at macro-expansion time.

• (guix scripts) contains an alist of the known categories and
‘show-help’ traverses it.

• Changed the label for development commands to “commands for
development”, and changed “advanced” to “plumbing”.

• Added a “packaging” category.

• Fixed the typos you reported.

The end result is:

Toggle snippet (51 lines)
Usage: guix COMMAND ARGS...
Run COMMAND with ARGS.

COMMAND must be one of the sub-commands listed below:

main commands
deploy deploy operating systems on a set of machines
describe describe the channel revisions currently used
gc invoke the garbage collector
install install packages
package manage packages and profiles
pull pull the latest revision of Guix
remove remove installed packages
search search for packages
show show information about packages
system build and deploy full operating systems
time-machine run commands from a different revision
upgrade upgrade packages to their latest version
weather report on the availability of pre-built package binaries

software development commands
container run code in containers created by 'guix environment -C'
environment spawn one-off software environments
pack create application bundles

packaging commands
build build packages or derivations without installing them
challenge challenge substitute servers, comparing their binaries
download download a file to the store and print its hash
edit view and edit package definitions
graph view and query package dependency graphs
hash compute the cryptographic hash of a file
import import a package definition from an external repository
lint validate package definitions
publish publish build results over HTTP
refresh update existing package definitions
size profile the on-disk size of packages

plumbing commands
archive manipulate, export, and import normalized archives (nars)
copy copy store items remotely over SSH
git operate on Git repositories
offload set up and operate build offloading
processes list currently running sessions
repl read-eval-print loop (REPL) for interactive programming

Report bugs to: bug-guix@gnu.org.
GNU Guix home page: <https://www.gnu.org/software/guix/>
General help using Guix and GNU software: <https://guix.gnu.org/help/>

Let me know what you think!

Thanks,
Ludo’.
From b3494f3cd670e0d1e5842b9b022c2606a520d34a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@gnu.org>
Date: Tue, 1 Sep 2020 22:23:50 +0200
Subject: [PATCH 1/2] ui: '--help' output links to

* guix/ui.scm (show-bug-report-information): Link to
https://guix.gnu.org/help/ instead of https://www.gnu.org/gethelp/ .
The former is much more useful and includes links to GNU manuals.
---
guix/ui.scm | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

Toggle diff (18 lines)
diff --git a/guix/ui.scm b/guix/ui.scm
index efc3f39186..981e133aaf 100644
--- a/guix/ui.scm
+++ b/guix/ui.scm
@@ -541,8 +541,9 @@ There is NO WARRANTY, to the extent permitted by law.
Report bugs to: ~a.") %guix-bug-report-address)
(format #t (G_ "
~a home page: <~a>") %guix-package-name %guix-home-page-url)
- (display (G_ "
-General help using GNU software: <http://www.gnu.org/gethelp/>"))
+ (format #t (G_ "
+General help using Guix and GNU software: <~a>")
+ "https://guix.gnu.org/help/")
(newline))
(define (augmented-system-error-handler file)
--
2.28.0
L
L
Ludovic Courtès wrote on 7 Sep 2020 14:58
Re: [bug#43159] [PATCH 0/2] Make 'guix help' helpful
(name . zimoun)(address . zimon.toutoune@gmail.com)(address . 43159@debbugs.gnu.org)
87o8mhiw0c.fsf@gnu.org
Hi,

zimoun <zimon.toutoune@gmail.com> skribis:

Toggle quote (4 lines)
>> environment spawn one-off software environments
>
> spawn one-off?

“One-off” is used as an adjective to mean a software environment that is
used once and then thrown away. Per WordNet:

Toggle snippet (7 lines)
Overview of noun one-off

The noun one-off has 1 sense (no senses from tagged texts)
1. one-off -- (a happening that occurs only once and is not repeated)

Thanks for your suggestions!

Ludo’.
L
L
Ludovic Courtès wrote on 10 Sep 2020 12:34
Re: [bug#43159] [PATCHES v2] scripts: Use 'define-command' and have 'guix help' use that.
(name . Maxim Cournoyer)(address . maxim.cournoyer@gmail.com)
874ko5hqd5.fsf@gnu.org
Ludovic Courtès <ludo@gnu.org> skribis:

Toggle quote (16 lines)
> Here’s a v2 of the patches, where I tried to take your feedback into
> account. Changes:
>
> • Categories that appear in uses of ‘define-command’ are now validated
> at macro-expansion time.
>
> • (guix scripts) contains an alist of the known categories and
> ‘show-help’ traverses it.
>
> • Changed the label for development commands to “commands for
> development”, and changed “advanced” to “plumbing”.
>
> • Added a “packaging” category.
>
> • Fixed the typos you reported.

I pushed this v2 as 3794ce93be8216d8378df7b808ce7f53b1e05a53.

Let’s iterate from here if people have ideas about better categorization
or things like that.

Thanks,
Ludo’.
Closed
R
R
Ricardo Wurmus wrote on 10 Sep 2020 12:55
Re: bug#43159: [PATCHES v2] scripts: Use 'define-command' and have 'guix help' use that.
(name . Ludovic Courtès)(address . ludo@gnu.org)
87h7s56gvr.fsf@elephly.net
I’m a bit late, but I’m very happy to see that “for developers” has
become “for development”!

Ludovic Courtès <ludo@gnu.org> writes:

Toggle quote (8 lines)
> Ludovic Courtès <ludo@gnu.org> skribis:
>
>> Here’s a v2 of the patches, where I tried to take your feedback into
>> account. Changes:
>>
>> • Categories that appear in uses of ‘define-command’ are now validated
>> at macro-expansion time.

Neat!

Toggle quote (3 lines)
>> • (guix scripts) contains an alist of the known categories and
>> ‘show-help’ traverses it.

Knowing that guile-config exists for automatically generating help
screens, configuration files, command line options, and all that I
wonder if there’s anything here that could become part of guile-config
and move out of Guix.

I had been in that situation myself where I felt that guile-config may
not be a great fit for my help texts because of minor quibbles about the
format or the way things are presented by default. In the end I decided
to use guile-config, because I prefer to have this handled by someone
else who keeps thinking about the problems relating to argument parsing,
configuration files, and help texts.

It may not be a great fit for Guix now, but I wonder if it could. In
the long run I think it would be good for Guix to become a little less
special — no matter if that’s monad macros, records, argparsing, or
configuration files.

This is not a recommendation either way. I just wonder if in the long
term we could benefit from moving all this to a separate package.

Toggle quote (9 lines)
>> • Changed the label for development commands to “commands for
>> development”, and changed “advanced” to “plumbing”.
>>
>> • Added a “packaging” category.
>>
>> • Fixed the typos you reported.
>
> I pushed this v2 as 3794ce93be8216d8378df7b808ce7f53b1e05a53.

Excellent! Thank you!

--
Ricardo
M
M
Maxim Cournoyer wrote on 11 Sep 2020 20:58
Re: [bug#43159] [PATCH 1/2] scripts: Use 'define-command' and have 'guix help' use that.
(name . Ludovic Courtès)(address . ludo@gnu.org)(address . 43159@debbugs.gnu.org)
878sdg6sz8.fsf@gmail.com
Hi Ludovic,

Sorry I couldn't reply faster.

Ludovic Courtès <ludo@gnu.org> writes:

[...]

Toggle quote (12 lines)
>>> +;; Syntactic keywords.
>>> +(define synopsis 'command-synopsis)
>>> +(define category 'command-category)
>>
>> Are these definition really necessary/useful? I would have thought
>> having category and synopsis understood as literals in the
>> define-command syntax was enough?
>
> It’s not strictly necessary but it’s been considered “good practice”.
> That allows users to detect name clashes, to rename/hide/etc. syntactic
> keywords and so on.

I see! Thank you for explaining.

[...]

Toggle quote (60 lines)
>>> + ;; 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.
>>
>> Interesting! Have you measure it? I would have thought loading a couple
>> optimized byte code modules could have been nearly as fast as parsing
>> files manually. If so, I think it'd be preferable to use introspection
>> rather than implement a custom parser.
>
> On a fast recent laptop with an SSD, a load of 0, hot cache, etc., we’d
> still be below 1s. But see:
>
> $ strace -c guix help >/dev/null
> % time seconds usecs/call calls errors syscall
> ------ ----------- ----------- --------- --------- ------------------
> 62.69 0.002698 1 2266 2043 stat
> 10.94 0.000471 2 161 2 lstat
> 4.55 0.000196 0 246 mmap
> 4.51 0.000194 0 330 172 openat
>
> [...]
>
> ------ ----------- ----------- --------- --------- ------------------
> 100.00 0.004304 1 3748 2235 total
> $ strace -c guile -c '(use-modules (guix scripts system) (guix scripts authenticate))'
> % time seconds usecs/call calls errors syscall
> ------ ----------- ----------- --------- --------- ------------------
> 54.27 0.007799 1 5735 4518 stat
> 12.00 0.001724 11 149 27 futex
> 9.06 0.001302 0 1328 651 openat
> 7.24 0.001040 1 822 mmap
>
> [...]
>
> ------ ----------- ----------- --------- --------- ------------------
> 100.00 0.014371 1 10334 5202 total
>
>
> (The 1st run is the current ‘guix help’; the 2nd run +/- emulates what
> you propose.)
>
> Loading all the modules translates into a lot more I/O, roughly an order
> of magnitude. We’re talking about loading tens of modules just to get
> at that synopsis:
>
> scheme@(guile-user)> ,use(guix modules)
> scheme@(guile-user)> (length (source-module-closure '((guix scripts system) (guix scripts authenticate))))
> $10 = 439
> scheme@(guile-user)> (length (source-module-closure '((guix scripts) (guix ui))))
> $11 = 31
>
> Memory usage would also be very different:
>
> $ \time guix help >/dev/null
> 0.07user 0.01system 0:00.06elapsed 128%CPU (0avgtext+0avgdata 35348maxresident)k
> 0inputs+0outputs (0major+3906minor)pagefaults 0swaps
> $ \time guile -c '(use-modules (guix scripts system) (guix scripts authenticate))'
> 0.42user 0.05system 0:00.37elapsed 128%CPU (0avgtext+0avgdata 166916maxresident)k
> 0inputs+0outputs (0major+15148minor)pagefaults 0swaps

Thanks for the detailed measurements! It does indeed seem your approach
is better, especially considering memory usage. Perhaps the commands
could have been moved to dedicated modules not using much dependency at
all so that their closure would have been small hence fast to load, but
keeping the commands definitions local to where they are useful is
definitely a nice property.

Toggle quote (15 lines)
> In summary, while this approach undoubtedly looks awkward to any Lisper,
> I think it’s a good way to not contribute to the general impression of
> sluggishness and resource-hungriness of ‘guix’ commands. :-)
>
>>> + (define (display-commands commands)
>>> + (let* ((names (map (lambda (command)
>>> + (string-join (command-name command)))
>>> + commands))
>>> + (max-width (reduce max 0 (map string-length names))))
>>
>> You can drop reduce and use (max (map string-length names)) instead.
>
> I could do (apply max (map …)) but I don’t like the idea of abusing
> variadic argument lists in that way—I know, it’s very subjective. ;-)

Eh, I wonder why? I may be missing something, but if max allows it,
doesn't it mean it's a valid use? Anyway, just curious to know what are
the grounds for this personal preference :-).

Toggle quote (2 lines)
> Thanks for your feedback, I’ll send a v2!

Thanks! I'm late, but LGTM, thank you.

Maxim
L
L
Ludovic Courtès wrote on 13 Sep 2020 15:03
(name . Maxim Cournoyer)(address . maxim.cournoyer@gmail.com)(address . 43159@debbugs.gnu.org)
87lfhd7rsn.fsf@gnu.org
Hi,

Maxim Cournoyer <maxim.cournoyer@gmail.com> skribis:

Toggle quote (2 lines)
> Sorry I couldn't reply faster.

No problem. I went ahead with this patch series, but nothing’s set in
stone and I’m open to further changes.

Toggle quote (7 lines)
> Thanks for the detailed measurements! It does indeed seem your approach
> is better, especially considering memory usage. Perhaps the commands
> could have been moved to dedicated modules not using much dependency at
> all so that their closure would have been small hence fast to load, but
> keeping the commands definitions local to where they are useful is
> definitely a nice property.

We can’t really reduce the closure of commands. In particular, (guix
scripts system) has to load pretty much “everything”.

What we could do is use #:autoload aggressively in the (guix scripts …)
modules, such that startup time would be as small as possible—e.g.,
‘--help’ would not trigger loading of a zillion modules.

It’s a bit tedious though and not necessarily helpful in the general
case where one is doing something non-trivial with the command. Well
dunno, we could try!

Toggle quote (19 lines)
>> In summary, while this approach undoubtedly looks awkward to any Lisper,
>> I think it’s a good way to not contribute to the general impression of
>> sluggishness and resource-hungriness of ‘guix’ commands. :-)
>>
>>>> + (define (display-commands commands)
>>>> + (let* ((names (map (lambda (command)
>>>> + (string-join (command-name command)))
>>>> + commands))
>>>> + (max-width (reduce max 0 (map string-length names))))
>>>
>>> You can drop reduce and use (max (map string-length names)) instead.
>>
>> I could do (apply max (map …)) but I don’t like the idea of abusing
>> variadic argument lists in that way—I know, it’s very subjective. ;-)
>
> Eh, I wonder why? I may be missing something, but if max allows it,
> doesn't it mean it's a valid use? Anyway, just curious to know what are
> the grounds for this personal preference :-).

It’s mostly aesthetic, but it comes from the idea that there could be
limitations on the maximum number of arguments a procedure can take, or
inefficiencies with dealing with many arguments. Now, in today’s Guile,
there are no such issues… (And now I look really silly!) :-)

Ludo’.
M
M
Maxim Cournoyer wrote on 14 Sep 2020 01:33
(name . Ludovic Courtès)(address . ludo@gnu.org)(address . 43159@debbugs.gnu.org)
87wo0x5k1n.fsf@gmail.com
Hi Ludovic!

Ludovic Courtès <ludo@gnu.org> writes:

Toggle quote (9 lines)
> Hi,
>
> Maxim Cournoyer <maxim.cournoyer@gmail.com> skribis:
>
>> Sorry I couldn't reply faster.
>
> No problem. I went ahead with this patch series, but nothing’s set in
> stone and I’m open to further changes.

No problem! I'm glad this nice UI improvement has already landed.

Toggle quote (18 lines)
>> Thanks for the detailed measurements! It does indeed seem your approach
>> is better, especially considering memory usage. Perhaps the commands
>> could have been moved to dedicated modules not using much dependency at
>> all so that their closure would have been small hence fast to load, but
>> keeping the commands definitions local to where they are useful is
>> definitely a nice property.
>
> We can’t really reduce the closure of commands. In particular, (guix
> scripts system) has to load pretty much “everything”.
>
> What we could do is use #:autoload aggressively in the (guix scripts …)
> modules, such that startup time would be as small as possible—e.g.,
> ‘--help’ would not trigger loading of a zillion modules.
>
> It’s a bit tedious though and not necessarily helpful in the general
> case where one is doing something non-trivial with the command. Well
> dunno, we could try!

Seems like too much micro-management. This further solidifies your
design choice as the right one :-).

Toggle quote (24 lines)
>>> In summary, while this approach undoubtedly looks awkward to any Lisper,
>>> I think it’s a good way to not contribute to the general impression of
>>> sluggishness and resource-hungriness of ‘guix’ commands. :-)
>>>
>>>>> + (define (display-commands commands)
>>>>> + (let* ((names (map (lambda (command)
>>>>> + (string-join (command-name command)))
>>>>> + commands))
>>>>> + (max-width (reduce max 0 (map string-length names))))
>>>>
>>>> You can drop reduce and use (max (map string-length names)) instead.
>>>
>>> I could do (apply max (map …)) but I don’t like the idea of abusing
>>> variadic argument lists in that way—I know, it’s very subjective. ;-)
>>
>> Eh, I wonder why? I may be missing something, but if max allows it,
>> doesn't it mean it's a valid use? Anyway, just curious to know what are
>> the grounds for this personal preference :-).
>
> It’s mostly aesthetic, but it comes from the idea that there could be
> limitations on the maximum number of arguments a procedure can take, or
> inefficiencies with dealing with many arguments. Now, in today’s Guile,
> there are no such issues… (And now I look really silly!) :-)

Ha! Thanks for explaining. Now I know I can shamelessly continue using
apply on procedures accepting N arguments :-).

Maxim
?