From c1af5a6ea0e56d0764969e118f0c55942db90e7b Mon Sep 17 00:00:00 2001 From: Fulbert Date: Wed, 12 Oct 2022 07:57:47 +0200 Subject: [PATCH] * doc: guix-cookbook: Add a "Guix API usage examples" chapter. * doc/guix-cookbook.texi ("Guix API usage examples"): New chapter. Transcript of examples given in "Guix REPL - to infinity and beyond" by Simon Tournier at the "10 years of Guix" event. --- doc/guix-cookbook.texi | 426 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 426 insertions(+) diff --git a/doc/guix-cookbook.texi b/doc/guix-cookbook.texi index b61adc06da..8c6954b049 100644 --- a/doc/guix-cookbook.texi +++ b/doc/guix-cookbook.texi @@ -73,6 +73,7 @@ Weblate} (@pxref{Translating Guix,,, guix, GNU Guix reference manual}). * System Configuration:: Customizing the GNU System * Advanced package management:: Power to the users! * Environment management:: Control environment +* API usage examples:: Using the API via REPL, scripts and extensions. * Acknowledgments:: Thanks! * GNU Free Documentation License:: The license of this document. @@ -94,6 +95,11 @@ System Configuration * Auto-Login to a Specific TTY:: Automatically Login a User to a Specific TTY * Customizing the Kernel:: Creating and using a custom Linux kernel on Guix System. +API usage examples + +* API usage examples:: Using Guix through its API via REPL, script and extensions. + Transcript of Simon Tournier presentation : Guix REPL - to infinity and beyond + @end detailmenu @end menu @@ -2977,6 +2983,426 @@ will have predefined environment variables and procedures. Run @command{direnv allow} to setup the environment for the first time. +@c ********************************************************************* +@node API usage examples +@chapter API usage examples + +This chapter is a transcript of the examples given by Simon Tournier in +his presentation +@uref{https://10years.guix.gnu.org/video/guix-repl-to-infinity-and-beyond/,Guix +REPL - to infinity and beyond} (16 minutes video) at the +@uref{https://10years.guix.gnu.org/,10 years of Guix} event. + +Interactions with Guix as a library through its API via  REPL, script +and ``guix extension'' (API subject to changes, +script/extension might break at any update@dots{}). + +Throuthout this chapter : + +@itemize +@item +shell prompt shortened to : @code{'$ '} +@item +guix REPL prompt shortened to : @code{'> '} +@end itemize + +@menu +* Guix REPL:: +* Guix script:: +* Guix extension:: +@end menu + +@node Guix REPL +@section Guix REPL +@anchor{#guix-repl} + +@menu +* 101:: +* select count packages on criteria:: +* table count/group on criteria:: +@end menu + +@node 101 +@subsection 101 +@anchor{#101} +@quotation Note +the REPL command @code{,use (module path name)} (shortened +@code{,u}) can be used as an equivalent for +@code{(use-modules (module path name))}. @code{,use} alone will list +currently imported modules. +@end quotation + +Simple Guix REPL session +@example sh +$ guix repl +GNU Guile 3.0.8 +;; [skipped licence preamble] +> (use-modules (gnu packages base)) +> findutils +$1 = # +> ,use(guix) +> (package-name findutils) +$2 = "findutils" +> (package-version findutils) +$3 = "4.8.0" +> (package? findutils) +$4 = #t +@end example + +@quotation Note +the REPL command @code{,describe} (can be shortened @code{,d}) : +Usage: describe OBJ@* +Show description/documentation. (#f if unavailable) +@example sh +> ,d package->derivation +Return the object of PACKAGE for SYSTEM. +> ,describe package-name +#f +@end example +@end quotation + +@quotation Note +when a module is imported, its exported objects are listed in +TAB-@dots{} completions. + +@example sh +> package-in +package-input-error? package-input-rewriting/spec +package-input-rewriting package-inputs +@end example +@end quotation + +@node select count packages on criteria +@subsection select count packages on criteria +@anchor{#select-count-packages-on-criteria} +(→ 4 min 20 s into Simon Tournier presentation) + +In the following REPL session + +@itemize +@item +count of haskell packages and ; + +@item +count of haskell pacakges using the @code{#:cabal-revision} argument +@emph{(present in the package ghc-crypthohash-sha1, as shown below, for +instance)} + +@lisp +(define-public ghc-cryptohash-sha1 + (package + ;; skipped for clarity + (build-system haskell-build-system) + (arguments + `(#:cabal-revision + ("6" "10rpxrmqgwihmplczglwxf5q3l13z9j3kvi065z884y4dymmnkgc") + ;; … +@end lisp + +@end itemize + +REPL session : + +@example sh +$ 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 +@end example + +@node table count/group on criteria +@subsection table count/group on criteria +@anchor{#table-countgroup-on-criteria} +(→ 5 min 20 s into Simon Tournier presentation) + +The @code{arguments-vs-import.scm} file shown below demonstrate some +more sophisticated selection and grouping of packages, and can be passed +to @code{guix repl} like so : +@example sh +$ guix repl -- arguments-vs-import.scm +@end example +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. + +@code{arguments-vs-import.scm} file content : + +@lisp +(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) +@end lisp + +call from shell and output : + +@example sh +$ 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 for clarity] +meson : 442 = 442 = 89 + 353 +texlive : 143 = 143 = 0 + 143 +python : 2619 = 2619 = 797 + 1822 +binary : 14 = 14 = 0 + 14 +@end example + +@node Guix script +@section Guix script +@anchor{#guix-script} +Simon Tournier does not say much about using guix through scripts@dots{} +probably because there is not much to say and the following links should +answer most questions. + +@itemize +@item +@uref{https://www.gnu.org/software/guile/manual/html_node/Running-Guile-Scripts.html#Running-Guile-Scripts,Running +Guile Scripts (Guile Reference Manual)} +@item +@uref{https://www.gnu.org/software/guile/manual/html_node/Guile-Scripting.html#Guile-Scripting,Guile +Scripting (Guile Reference Manual)} +@item +@uref{https://www.gnu.org/software/coreutils/manual/html_node/env-invocation.html#env-invocation,env +invocation (GNU Coreutils 9.1)} +@end itemize + +Nevertheless, the script ``@code{explore}'', from Ludovic Courtès, used +in the next section to demonstrate a ``script-to-extension conversion'', +is probably an interesting example of using the guix API. See the links +below for more : + +@itemize +@item +@uref{https://10years.guix.gnu.org/video/explore-your-system/,Ten Years +of Guix --- Explore your system --- Ludovic Courtès} +@item +@uref{https://notabug.org/civodul/guix-explorer,civodul/guix-explorer: +Exploring Guix System. - NotABug.org: Free code hosting} +@end itemize + +@node Guix extension +@section Guix extension +@anchor{#guix-extension} +(→ 7 min 05 s into Simon Tournier presentation) + +@menu +* minimal example:: +* Ludovic Courtès's explore.scm program:: +@end menu + +@node minimal example +@subsection minimal example +@anchor{#minimal-example} +As a minimal example of a guix extension, the following file, +@code{~/tmp/10-years-of-guix/guix/extensions/hello.scm}, is used : + +@lisp +(define-module (guix extensions hello) + #:export (guix-hello)) + +(define-command (guix-hello . cmd-line) + (category plumbing) + (synopsis "hello world") + (display (G_ "hello folks!"))) +@end lisp + +The environment variable @code{GUIX_EXTENSIONS_PATH} has to include the +path to the scrip file. + +With this in place, we can see the @code{hello} extension integrated in +the @code{guix} CLI, as the following capture shows, with the new +command ``hello'' added to the ``plumbing'' category : + +@example sh +$ export GUIX_EXTENSIONS_PATH="$HOME/tmp/10-years-of-guix/guix/extensions" +$ guix help +Usage: guix OPTION | COMMAND ARGS... +Run COMMAND with ARGS, if given. +# [skipping for clarity …] + 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 + hello hello world + +Report bugs to: bug-guix@@gnu.org. +# … +@end example + +@node Ludovic Courtès's explore.scm program +@subsection Ludovic Courtès's explore.scm program +@anchor{#ludovic-courtèss-explore.scm-program} +The @code{explore.scm} script can then be modified as follows to have it work +as a Guix extension rather than a script. + +(→ 9 min 13 s into Simon Tournier presentation) + +@itemize +@item +removing the shebang call to guile + +@example +@verbatim +-#!/bin/sh +-exec "${GUILE:-guile}" -e "(@ (explore) guix-explore)" -s "$0" "$@" +-!# +@end verbatim +@end example + +@item +replacing the module declaration with appropriate path/name +@example +@verbatim +-(define-module (explore) ++(define-module (guix extensions explore) +@end verbatim +@end example + +@item +adding the module guix scripts to the use-module list +@example +@dots{} +@verbatim + #:use-module (guix ui) ++ #:use-module (guix scripts) + #:use-module (guix store) +@end verbatim +@dots{} +@end example + +@item +modifying the guix-explore definition +@example +@verbatim +-(define (guix-explore args) ++(define-command (guix-explore . args) ++ (category extension) ++ (synopsis ``explore your service'') +(define %user-module @dots{} +@end verbatim +@dots{} +@end example +@end itemize + +@quotation 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 +``[/@dots{}]/guix/extensions[/@dots{}]/.scm'' tree +structure with the corresponding module declaration +@code{(define-module (guix extensions [@dots{}] ) @dots{}}. + +This will work : + +@example sh +$ pwd +~/tmp/10-years-of-guix/guix/extensions/test +$ head -1 hello.scm +(define-module (guix extensions test hello) +@end example + +@dots{} while this won't work : + +@example sh +$ pwd +~/tmp/10-years-of-guix/guix/test +$ head -1 hello.scm +(define-module (guix test hello) +@end example + +@dots{} nor this : + +@example sh +$ pwd +~/tmp/10-years-of-guix/nono/ +$ head -1 hello.scm +(define-module (nono hello) +@end example +@end quotation + +lauching + +@quotation Note +@code{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. +@end quotation + +All set, explore can now be used as a Guix extension like so : + +@example sh +$ export GUIX_EXTENSIONS_PATH=/path/to/guix/extensions +$ guix explore -- /path/to/configure.scm +@end example + @c ********************************************************************* @node Acknowledgments @chapter Acknowledgments -- 2.38.0