Guix repl usage - exemples from Simon Tournier presentation

Fulbert

2022-10-08 07:55:50

Note: this file was written in pandoc.markdown and it source is available here by just replacing the URL suffix from .html to .md.txt. The pandoc configuration used in the conversion to html is also available whith the same URL replacing .html with .yaml.txt.

Guix repl usage exemplesfrom : Simon Tournier presentation, given at the 10 years of Guix event.

Interactions with Guix as a library through its API via repl, script and “(undocumented) guix extension” (API subject to changes, script/extension might break at any update… [or maybe this warning was meant specifically for the “extensions”(?) part]).

Throuthout this doc:

1 Guix repl

1.1 B. a.-ba

Note: the repl command ,use (module path name) (shortened ,u) can be used as an equivalent for (use-modules (module path name)). ,use alone will list currently imported modules.

$ guix repl
GNU Guile 3.0.8
;;  [skipped licence preamble]
> (use-modules (gnu packages base))
> findutils
$1 = #<package findutils@4.8.0 gnu/packages/base.scm:294 7fc88588ddc0>
> ,use(guix)
> (package-name findutils)
$2 = "findutils"
> (package-version findutils)
$3 = "4.8.0"
> (package? findutils)
$4 = #t

Note: the repl command ,describe (can be shortened ,d):

Usage: describe OBJ
Show description/documentation. (#f if unavailable)
> ,d package->derivation
Return the <derivation> object of PACKAGE for SYSTEM.
> ,describe package-name
#f

Note: when a module is imported, its exported objects are listed in TAB-… completions.

> package-in<TAB>
package-input-error?          package-input-rewriting/spec
package-input-rewriting       package-inputs

1.2 select count packages on criteria

(→ 4min 20s into Simon Tournier presentation)

In the following repl session

repl session:

$ guix repl
GNU Guile 3.0.8
;;  [skipped licence preamble]
> (use-modules
  (guix)
  (guix build-system haskell)
  (gnu)
  (ice-9 match))
>
> (define haskell-packages
  (fold-packages
    (lambda (package result)
      (if (eq? (package-build-system package) haskell-build-system)
         (cons package result)
         result))
    '()))
> (define (cabal-revision? package)
  (apply (lambda* (#:key cabal-revision #:allow-other-keys)
                  (match cabal-revision
                         ((revision hash) #t)
                         (_ #f)))
         (package-arguments package)))
> (define cabal-revision-packages
  (filter cabal-revision? haskell-packages))
> (length haskell-packages)
$1 = 721
> (length cabal-revision-packages)
$2 = 108

1.3 table count/group on criteria

(→ 5min 20s into Simon Tournier presentation)

The arguments-vs-import.scm file shown below demonstrate some more sophisticated selection and grouping of packages, and can be passed to guix repl like so: guix repl -- arguments-vs-import.scm. Its interpretation will output a table similar to the one show below the script-file content, giving the number of packages which “tweak” their arguments to the build and the number of packages which don’t, all grouped by build-system types.

arguments-vs-import.scm file content:

(use-modules (guix)
             (gnu)
             (ice-9 match))

(define table (make-hash-table))

(fold-packages (lambda (package result)
                 (let ((bs (build-system-name
                             (package-build-system package)))
                       (arg (package-arguments package)))
                   (match (hash-ref result bs)
                          ((tot wo wi)
                           (if (null? arg)
                             (hash-set! result bs (list
                                                    (1+ tot)
                                                    (1+ wo)
                                                    wi))
                             (hash-set! result bs (list
                                                    (1+ tot)
                                                    wo
                                                    (1+ wi)))))
                          (#f (if (null? arg)
                                (hash-set! result bs (list 1 1 0))
                                (hash-set! result bs (list 1 0 1))))
                          (_ (format #t "Error: ~s~%" (package-name package))))
                   result))
               table)

(define fmt "~13s: ~4s = ~4s = ~4s + ~4s~%")
(format #t fmt
        'key 'tot 'tot 'no-arguments 'arguments)
(hash-for-each-handle (lambda (kv)
                       (match kv
                              ((key . value)
                               (match value
                                      ((tot wo wi)
                                       (format #t fmt
                                               key
                                               (+ wo wi)
                                               tot wo wi))))))
                     table)

call from shell and output:

$ cd ~/tmp/10-years-of-guix
$ guix repl -- guix-repl-and-beyond.scm
key          : tot  = tot  = no-arguments + arguments
ocaml        : 57   = 57   = 0    + 57
haskell      : 721  = 721  = 504  + 217
clojure      : 11   = 11   = 0    + 11
[skipping some for clarity]
meson        : 442  = 442  = 89   + 353
texlive      : 143  = 143  = 0    + 143
python       : 2619 = 2619 = 797  + 1822
binary       : 14   = 14   = 0    + 14

2 Guix script

Simon Tournier does not say much about using guix through scripts… probably because there is not much to say and the following links should answer most questions.

Nevertheless, the script “explore”, from Ludovic Courtès, used in the next section to demonstrate a “script-to-extension conversion”, is probably an interesting exemple of using the guix API. See the links below for more:

3 Guix extension

(→ 7min 05s into Simon Tournier presentation)

3.1 minimal exemple

As a minimal exemple of a guix extension, the following file, ~/tmp/10-years-of-guix/guix/extensions/hello.scm, is used:

(define-module (guix extensions hello)
               #:export (guix-hello))

(define-command (guix-hello . cmd-line)
                (category plumbing)
                (synopsis "hello world")
                (display (G_ "hello folks!")))

The environment variable GUIX_EXTENSIONS_PATH has to include the path to the scrip file.

With this in place, we can see the hello extension integrated in the guix CLI, as the following capture shows, with the new command “hello” added to the “plumbing” category:

$ export GUIX_EXTENSIONS_PATH="$HOME/tmp/10-years-of-guix/guix/extensions"
$ guix help
Utilisation : guix OPTION | COMMANDE ARGS...
Lance la COMMANDE avec les arguments ARGS, le cas échéant.
# [skipping 40 lines for clarity …] 
  commandes de plomberie
    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
    hello      hello world

Signalez toute anomalie à : bug-guix@gnu.org.
# [skipping for clarity]

3.2 Ludovic Courtès’s explore.scm program

The explore.scm can then be modified as follows to have it work as a Guix extension rather than a script.

(→ 9min 13s into Simon Tournier presentation)

3.2.1 removing the shebang call to guile

-#!/bin/sh
-exec “${GUILE:-guile}” -e “(@ (explore) guix-explore)” -s “$0" "$@”
-!#

3.2.2 replacing the module declaration with appropriate path/name

-(define-module (explore)
+(define-module (guix extensions explore)

3.2.3 adding the module (guix scripts) to the use-module list


  #:use-module (guix ui)
+ #:use-module (guix scripts)
  #:use-module (guix store)

3.2.4 modifying the guix-explore definition

-(define (guix-explore args)
+(define-command (guix-explore . args)
+ (category extension)
+ (synopsis “explore your service”)
(define %user-module …

3.2.5 note on the path to the script

[It seems that] to be used as a guix extension, Guix requires a script to live under a “[/…]/guix/extensions[/…]/<module-name>.scm” tree structure with the corresponding module declaration (define-module (guix extensions […] <module-name>) ….

This will work:

$ pwd
~/tmp/10-years-of-guix/guix/extensions/test
$ head -1 hello.scm
(define-module (guix extensions test hello)

… while this won’t work:

$ pwd
~/tmp/10-years-of-guix/guix/test
$ head -1 hello.scm
(define-module (guix test hello)

… nor this:

$ pwd
~/tmp/10-years-of-guix/nono/
$ head -1 hello.scm
(define-module (nono hello)

3.2.6 lauching

Note: explore produces a visual and interactive representation of the services used in a OS declaration. The user has to provide a path to the OS configuration file to explore.

All set, explore can now be used as a Guix extension like so:

$ export GUIX_EXTENSIONS_PATH=/path/to/guix/extensions
$ guix explore -- /path/to/configure.scm