Subject: [bug#58463] [PATCH] * doc: guix-cookbook: Add a "Guix API usage examples"

From: Fulbert <[email-masked]>
Date: Wed, 12 Oct 2022 08:39:15 +0200

Sorry, I forgot to attach the patch, so here it is.

>From c1af5a6ea0e56d0764969e118f0c55942db90e7b Mon Sep 17 00:00:00 2001
From: Fulbert <[email-masked]>
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 = #<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
+@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 <derivation> 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<TAB>
+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{}]/<module-name>.scm'' tree
+structure with the corresponding module declaration
+@code{(define-module (guix extensions [@dots{}] <module-name>) @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