From 3178b1a442c2f2eeeec1ff73bb852d2837b8aa3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= Date: Mon, 27 Nov 2023 18:09:23 +0100 Subject: [PATCH] monad-repl: Add REPL commands to inspect package arguments. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * guix/monad-repl.scm (keyword-argument-value, package-argument-command): New procedures. (phases, configure-flags, make-flags): New REPL commands. * doc/guix.texi (package Reference): Link to “Using Guix Interactively”. (Defining Package Variants): Add “Tips” quotation. (Build Phases): Add “Tip” quotation. (Using Guix Interactively): Document the new REPL commands. Change-Id: I7049c1d8aa9241e07d7c921aa396e578a1b4ef16 --- doc/guix.texi | 61 +++++++++++++++++++++++++++++++++++++ guix/monad-repl.scm | 74 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 131 insertions(+), 4 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index 1fd2e21608..7dde9b727b 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -7975,6 +7975,10 @@ The exact set of supported keywords depends on the build system @code{#:phases}. The @code{#:phases} keyword in particular lets you modify the set of build phases for your package (@pxref{Build Phases}). +The REPL has dedicated commands to interactively inspect values of some +of these arguments, as a convenient debugging aid (@pxref{Using Guix +Interactively}). + @quotation Compatibility Note Until version 1.3.0, the @code{arguments} field would typically use @code{quote} (@code{'}) or @code{quasiquote} (@code{`}) and no @@ -8774,6 +8778,23 @@ when @var{cut?} returns true for a given package. When @var{deep?} is true, @va applied to implicit inputs as well. @end deffn +@quotation Tips +Understanding what a variant really looks like can be difficult as one +starts combining the tools shown above. There are several ways to +inspect a package before attempting to build it that can prove handy: + +@itemize +@item +You can inspect the package interactively at the REPL, for instance to +view its inputs, the code of its build phases, or its configure flags +(@pxref{Using Guix Interactively}). + +@item +When rewriting dependencies, @command{guix graph} can often help +visualize the changes that are made (@pxref{Invoking guix graph}). +@end itemize +@end quotation + @node Writing Manifests @section Writing Manifests @@ -10585,6 +10606,11 @@ we have seen before. @xref{Build Utilities}, for more about the helpers used by this phase, and for more examples of @code{modify-phases}. +@quotation Tip +You can inspect the code associated with a package's @code{#:phases} +argument interactively, at the REPL (@pxref{Using Guix Interactively}). +@end quotation + @cindex code staging @cindex staging, of code Keep in mind that build phases are code evaluated at the time the @@ -12763,6 +12789,30 @@ scheme@@(guix-user)> (scandir (string-append $3 "/bin")) $5 = ("." ".." "egrep" "fgrep" "grep") @end example +As a packager, you may be willing to inspect the build phases or flags +of a given package; this is particularly useful when relying a lot on +inheritance to define package variants (@pxref{Defining Package +Variants}) or when package arguments are a result of some computation, +both of which can make it harder to foresee what ends up in the package +arguments. Additional commands let you inspect those package arguments: + +@example +scheme@@(guix-user)> ,phases grep +$1 = (modify-phases %standard-phases + (add-after 'install 'fix-egrep-and-fgrep + (lambda* (#:key outputs #:allow-other-keys) + (let* ((out (assoc-ref outputs "out")) + (bin (string-append out "/bin"))) + (substitute* (list (string-append bin "/egrep") + (string-append bin "/fgrep")) + (("^exec grep") + (string-append "exec " bin "/grep"))))))) +scheme@@(guix-user)> ,configure-flags findutils +$2 = (list "--localstatedir=/var") +scheme@@(guix-user)> ,make-flags binutils +$3 = '("MAKEINFO=true") +@end example + At a lower-level, a useful command is @code{lower}: it takes a file-like object and ``lowers'' it into a derivation (@pxref{Derivations}) or a store file: @@ -12794,6 +12844,17 @@ This is similar to the @option{--verbosity} command-line option shows build events only, and higher levels print build logs. @end deffn +@deffn {REPL command} phases @var{package} +@deffnx {REPL command} configure-flags @var{package} +@deffnx {REPL command} make-flags @var{package} +These REPL commands return the value of one element of the +@code{arguments} field of @var{package} (@pxref{package Reference}): the +first one show the staged code associated with @code{#:phases} +(@pxref{Build Phases}), the second shows the code for +@code{#:configure-flags}, and @code{,make-flags} returns the code for +@code{#:make-flags}. +@end deffn + @deffn {REPL command} run-in-store @var{exp} Run @var{exp}, a monadic expression, through the store monad. @xref{The Store Monad}, for more information. diff --git a/guix/monad-repl.scm b/guix/monad-repl.scm index 8a6053edd5..d6b39112b7 100644 --- a/guix/monad-repl.scm +++ b/guix/monad-repl.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2014, 2015, 2016, 2022 Ludovic Courtès +;;; Copyright © 2014-2016, 2022-2023 Ludovic Courtès ;;; ;;; This file is part of GNU Guix. ;;; @@ -21,13 +21,15 @@ #:use-module (guix monads) #:use-module (guix utils) #:use-module (guix packages) + #:autoload (guix build-system) (bag) #:use-module (guix status) - #:autoload (guix gexp) (lower-object) + #:autoload (guix gexp) (gexp gexp? lower-gexp lowered-gexp-sexp lower-object) #:use-module ((guix derivations) #:select (derivation? derivation->output-paths built-derivations)) + #:autoload (guix read-print) (pretty-print-with-comments) #:use-module (ice-9 match) - #:use-module (ice-9 pretty-print) + #:autoload (ice-9 pretty-print) (pretty-print) #:use-module (system repl repl) #:use-module (system repl common) #:use-module (system repl command) @@ -138,4 +140,68 @@ Enter a REPL for values in the store monad." (repl-option-set! new 'interp #t) (run-repl new)))) -;;; monad-repl.scm ends here + +;;; +;;; Viewing package arguments. +;;; + +(define (keyword-argument-value args keyword default) + "Return the value associated with KEYWORD in ARGS, a keyword/value sequence, +or DEFAULT if KEYWORD is missing from ARGS." + (let loop ((args args)) + (match args + (() + default) + ((kw value rest ...) + (if (eq? kw keyword) + value + (loop rest)))))) + +(define (package-argument-command repl form keyword default) + "Implement a command that display KEYWORD, a keyword such as #:phases, in +the arguments of the package FORM evaluates to. Return DEFAULT is KEYWORD is +missing from those arguments." + (match (repl-eval repl form) + ((? package? package) + (let* ((bag* (bag + (inherit (package->bag package)) + (build (lambda* (name inputs #:rest args) + (with-monad %store-monad + (return (keyword-argument-value args keyword + default)))))))) + (define phases + (parameterize ((%graft? #f)) + (with-store store + (set-build-options store + #:print-build-trace #t + #:print-extended-build-trace? #t + #:multiplexed-build-output? #t) + (run-with-store store + (mlet %store-monad ((exp (bag->derivation bag*))) + (if (gexp? exp) + (mlet %store-monad ((gexp (lower-gexp exp))) + (return (lowered-gexp-sexp gexp))) + (return exp))))))) + + (run-hook before-print-hook phases) + (let ((column (port-column (current-output-port)))) + (pretty-print-with-comments (current-output-port) phases + #:indent column) + (newline (current-output-port))))) + (_ + (format #t ";; ERROR: This command only accepts package records.~%")))) + +(define-meta-command ((phases guix) repl (form)) + "phases +Return the build phases of the package defined by FORM." + (package-argument-command repl form #:phases #~%standard-phases)) + +(define-meta-command ((configure-flags guix) repl (form)) + "configure-flags +Return the configure flags of the package defined by FORM." + (package-argument-command repl form #:configure-flags #~'())) + +(define-meta-command ((make-flags guix) repl (form)) + "make-flags +Return the make flags of the package defined by FORM." + (package-argument-command repl form #:make-flags #~'()))