shell: Add '--export-manifest'.
* guix/scripts/shell.scm (show-help, %options): Add '--export-manifest'. (manifest-entry-version-prefix, manifest->code*) (export-manifest): New procedures. (guix-shell): Honor '--export-manifest'. * tests/guix-shell-export-manifest.sh: New file. * Makefile.am (SH_TESTS): Add it. * doc/guix.texi (Invoking guix shell): Document '--export-manifest'. (Invoking guix environment): Link to it. (Invoking guix pack): Likewise.
This commit is contained in:
parent
6fed836a6f
commit
c42b7baf13
4 changed files with 248 additions and 3 deletions
|
@ -572,6 +572,7 @@ SH_TESTS = \
|
||||||
tests/guix-environment.sh \
|
tests/guix-environment.sh \
|
||||||
tests/guix-environment-container.sh \
|
tests/guix-environment-container.sh \
|
||||||
tests/guix-shell.sh \
|
tests/guix-shell.sh \
|
||||||
|
tests/guix-shell-export-manifest.sh \
|
||||||
tests/guix-graph.sh \
|
tests/guix-graph.sh \
|
||||||
tests/guix-describe.sh \
|
tests/guix-describe.sh \
|
||||||
tests/guix-repl.sh \
|
tests/guix-repl.sh \
|
||||||
|
|
|
@ -5848,6 +5848,55 @@ This is similar to the same-named option in @command{guix package}
|
||||||
(@pxref{profile-manifest, @option{--manifest}}) and uses the same
|
(@pxref{profile-manifest, @option{--manifest}}) and uses the same
|
||||||
manifest files.
|
manifest files.
|
||||||
|
|
||||||
|
See @option{--export-manifest} below on how to obtain a first manifest.
|
||||||
|
|
||||||
|
@cindex manifest, exporting
|
||||||
|
@anchor{shell-export-manifest}
|
||||||
|
@item --export-manifest
|
||||||
|
Write to standard output a manifest suitable for @option{--manifest}
|
||||||
|
corresponding to given command-line options.
|
||||||
|
|
||||||
|
This is a way to ``convert'' command-line arguments into a manifest.
|
||||||
|
For example, imagine you are tired of typing long lines and would like
|
||||||
|
to get a manifest equivalent to this command line:
|
||||||
|
|
||||||
|
@example
|
||||||
|
guix shell -D guile git emacs emacs-geiser emacs-geiser-guile
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Just add @option{--export-manifest} to the command line above:
|
||||||
|
|
||||||
|
@example
|
||||||
|
guix shell --export-manifest \
|
||||||
|
-D guile git emacs emacs-geiser emacs-geiser-guile
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@noindent
|
||||||
|
... and you get a manifest along these lines:
|
||||||
|
|
||||||
|
@lisp
|
||||||
|
(concatenate-manifests
|
||||||
|
(list (specifications->manifest
|
||||||
|
(list "git"
|
||||||
|
"emacs"
|
||||||
|
"emacs-geiser"
|
||||||
|
"emacs-geiser-guile"))
|
||||||
|
(package->development-manifest
|
||||||
|
(specification->package "guile"))))
|
||||||
|
@end lisp
|
||||||
|
|
||||||
|
You can store it into a file, say @file{manifest.scm}, and from there
|
||||||
|
pass it to @command{guix shell} or indeed pretty much any @command{guix}
|
||||||
|
command:
|
||||||
|
|
||||||
|
@example
|
||||||
|
guix shell -m manifest.scm
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Voilà, you've converted a long command line into a manifest! That
|
||||||
|
conversion process honors package transformation options (@pxref{Package
|
||||||
|
Transformation Options}) so it should be lossless.
|
||||||
|
|
||||||
@item --profile=@var{profile}
|
@item --profile=@var{profile}
|
||||||
@itemx -p @var{profile}
|
@itemx -p @var{profile}
|
||||||
Create an environment containing the packages installed in @var{profile}.
|
Create an environment containing the packages installed in @var{profile}.
|
||||||
|
@ -6235,6 +6284,10 @@ This is similar to the same-named option in @command{guix package}
|
||||||
(@pxref{profile-manifest, @option{--manifest}}) and uses the same
|
(@pxref{profile-manifest, @option{--manifest}}) and uses the same
|
||||||
manifest files.
|
manifest files.
|
||||||
|
|
||||||
|
@xref{shell-export-manifest, @command{guix shell --export-manifest}},
|
||||||
|
for information on how to ``convert'' command-line options into a
|
||||||
|
manifest.
|
||||||
|
|
||||||
@item --ad-hoc
|
@item --ad-hoc
|
||||||
Include all specified packages in the resulting environment, as if an
|
Include all specified packages in the resulting environment, as if an
|
||||||
@i{ad hoc} package were defined with them as inputs. This option is
|
@i{ad hoc} package were defined with them as inputs. This option is
|
||||||
|
@ -6693,6 +6746,10 @@ for use on machines that do not have Guix installed. Note that you can
|
||||||
specify @emph{either} a manifest file @emph{or} a list of packages,
|
specify @emph{either} a manifest file @emph{or} a list of packages,
|
||||||
but not both.
|
but not both.
|
||||||
|
|
||||||
|
@xref{shell-export-manifest, @command{guix shell --export-manifest}},
|
||||||
|
for information on how to ``convert'' command-line options into a
|
||||||
|
manifest.
|
||||||
|
|
||||||
@item --system=@var{system}
|
@item --system=@var{system}
|
||||||
@itemx -s @var{system}
|
@itemx -s @var{system}
|
||||||
Attempt to build for @var{system}---e.g., @code{i686-linux}---instead of
|
Attempt to build for @var{system}---e.g., @code{i686-linux}---instead of
|
||||||
|
|
|
@ -21,7 +21,8 @@
|
||||||
#:use-module ((guix diagnostics) #:select (location))
|
#:use-module ((guix diagnostics) #:select (location))
|
||||||
#:use-module (guix scripts environment)
|
#:use-module (guix scripts environment)
|
||||||
#:autoload (guix scripts build) (show-build-options-help)
|
#:autoload (guix scripts build) (show-build-options-help)
|
||||||
#:autoload (guix transformations) (transformation-option-key?
|
#:autoload (guix transformations) (options->transformation
|
||||||
|
transformation-option-key?
|
||||||
show-transformation-options-help)
|
show-transformation-options-help)
|
||||||
#:use-module (guix scripts)
|
#:use-module (guix scripts)
|
||||||
#:use-module (guix packages)
|
#:use-module (guix packages)
|
||||||
|
@ -41,7 +42,12 @@
|
||||||
#:use-module ((guix build utils) #:select (mkdir-p))
|
#:use-module ((guix build utils) #:select (mkdir-p))
|
||||||
#:use-module (guix cache)
|
#:use-module (guix cache)
|
||||||
#:use-module ((ice-9 ftw) #:select (scandir))
|
#:use-module ((ice-9 ftw) #:select (scandir))
|
||||||
#:autoload (gnu packages) (cache-is-authoritative?)
|
#:autoload (ice-9 pretty-print) (pretty-print)
|
||||||
|
#:autoload (gnu packages) (cache-is-authoritative?
|
||||||
|
package-unique-version-prefix
|
||||||
|
specification->package
|
||||||
|
specification->package+output
|
||||||
|
specifications->manifest)
|
||||||
#:export (guix-shell))
|
#:export (guix-shell))
|
||||||
|
|
||||||
(define (show-help)
|
(define (show-help)
|
||||||
|
@ -55,10 +61,13 @@ interactive shell in that environment.\n"))
|
||||||
-D, --development include the development inputs of the next package"))
|
-D, --development include the development inputs of the next package"))
|
||||||
(display (G_ "
|
(display (G_ "
|
||||||
-f, --file=FILE add to the environment the package FILE evaluates to"))
|
-f, --file=FILE add to the environment the package FILE evaluates to"))
|
||||||
|
|
||||||
(display (G_ "
|
(display (G_ "
|
||||||
-q inhibit loading of 'guix.scm' and 'manifest.scm'"))
|
-q inhibit loading of 'guix.scm' and 'manifest.scm'"))
|
||||||
(display (G_ "
|
(display (G_ "
|
||||||
--rebuild-cache rebuild cached environment, if any"))
|
--rebuild-cache rebuild cached environment, if any"))
|
||||||
|
(display (G_ "
|
||||||
|
--export-manifest print a manifest for the given options"))
|
||||||
|
|
||||||
(show-environment-options-help)
|
(show-environment-options-help)
|
||||||
(newline)
|
(newline)
|
||||||
|
@ -112,6 +121,10 @@ interactive shell in that environment.\n"))
|
||||||
;; 'wrapped-option'.
|
;; 'wrapped-option'.
|
||||||
(alist-delete 'ad-hoc? result)))
|
(alist-delete 'ad-hoc? result)))
|
||||||
|
|
||||||
|
(option '("export-manifest") #f #f
|
||||||
|
(lambda (opt name arg result)
|
||||||
|
(alist-cons 'export-manifest? #t result)))
|
||||||
|
|
||||||
;; For consistency with 'guix package', support '-f' rather than
|
;; For consistency with 'guix package', support '-f' rather than
|
||||||
;; '-l' like 'guix environment' does.
|
;; '-l' like 'guix environment' does.
|
||||||
(option '(#\f "file") #t #f
|
(option '(#\f "file") #t #f
|
||||||
|
@ -380,6 +393,94 @@ return #f and #f."
|
||||||
(loop rest system file specs))
|
(loop rest system file specs))
|
||||||
((_ . rest) (loop rest system file specs)))))
|
((_ . rest) (loop rest system file specs)))))
|
||||||
|
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; Exporting a manifest.
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(define (manifest-entry-version-prefix entry)
|
||||||
|
"Search among all the versions of ENTRY's package that are available, and
|
||||||
|
return the shortest unambiguous version prefix for this package."
|
||||||
|
(package-unique-version-prefix (manifest-entry-name entry)
|
||||||
|
(manifest-entry-version entry)))
|
||||||
|
|
||||||
|
(define (manifest->code* manifest extra-manifests)
|
||||||
|
"Like 'manifest->code', but insert a 'concatenate-manifests' call that
|
||||||
|
concatenates MANIFESTS, a list of expressions."
|
||||||
|
(if (null? (manifest-entries manifest))
|
||||||
|
(match extra-manifests
|
||||||
|
((one) one)
|
||||||
|
(lst `(concatenate-manifests ,@extra-manifests)))
|
||||||
|
(match (manifest->code manifest
|
||||||
|
#:entry-package-version
|
||||||
|
manifest-entry-version-prefix)
|
||||||
|
(('begin exp ... last)
|
||||||
|
`(begin
|
||||||
|
,@exp
|
||||||
|
,(match extra-manifests
|
||||||
|
(() last)
|
||||||
|
(_ `(concatenate-manifests
|
||||||
|
(list ,last ,@extra-manifests)))))))))
|
||||||
|
|
||||||
|
(define (export-manifest opts port)
|
||||||
|
"Write to PORT a manifest corresponding to OPTS."
|
||||||
|
(define (manifest-lift proc)
|
||||||
|
(lambda (entry)
|
||||||
|
(match (manifest-entry-item entry)
|
||||||
|
((? package? p)
|
||||||
|
(manifest-entry
|
||||||
|
(inherit (package->manifest-entry (proc p)))
|
||||||
|
(output (manifest-entry-output entry))))
|
||||||
|
(_
|
||||||
|
entry))))
|
||||||
|
|
||||||
|
(define (validated-spec spec)
|
||||||
|
;; Return SPEC if it's a valid package spec.
|
||||||
|
(specification->package+output spec)
|
||||||
|
spec)
|
||||||
|
|
||||||
|
(let* ((transform (options->transformation opts))
|
||||||
|
(specs (reverse
|
||||||
|
(filter-map (match-lambda
|
||||||
|
(('package 'ad-hoc-package spec)
|
||||||
|
(validated-spec spec))
|
||||||
|
(_ #f))
|
||||||
|
opts)))
|
||||||
|
(extras (reverse
|
||||||
|
(filter-map (match-lambda
|
||||||
|
(('package 'package spec)
|
||||||
|
;; Make sure SPEC is valid.
|
||||||
|
(specification->package spec)
|
||||||
|
|
||||||
|
;; XXX: This is an approximation:
|
||||||
|
;; transformation options are not applied.
|
||||||
|
`(package->development-manifest
|
||||||
|
(specification->package ,spec)))
|
||||||
|
(_ #f))
|
||||||
|
opts)))
|
||||||
|
(manifest (concatenate-manifests
|
||||||
|
(cons (map-manifest-entries
|
||||||
|
(manifest-lift transform)
|
||||||
|
(specifications->manifest specs))
|
||||||
|
(filter-map (match-lambda
|
||||||
|
(('manifest . file)
|
||||||
|
(load-manifest file))
|
||||||
|
(_ #f))
|
||||||
|
opts)))))
|
||||||
|
(display (G_ "\
|
||||||
|
;; What follows is a \"manifest\" equivalent to the command line you gave.
|
||||||
|
;; You can store it in a file that you may then pass to any 'guix' command
|
||||||
|
;; that accepts a '--manifest' (or '-m') option.\n")
|
||||||
|
port)
|
||||||
|
(match (manifest->code* manifest extras)
|
||||||
|
(('begin exp ...)
|
||||||
|
(for-each (lambda (exp)
|
||||||
|
(newline port)
|
||||||
|
(pretty-print exp port))
|
||||||
|
exp))
|
||||||
|
(exp
|
||||||
|
(pretty-print exp port)))))
|
||||||
|
|
||||||
|
|
||||||
;;;
|
;;;
|
||||||
;;; One-time hints.
|
;;; One-time hints.
|
||||||
|
@ -445,4 +546,6 @@ to make sure your shell does not clobber environment variables."))) )
|
||||||
cache-entries
|
cache-entries
|
||||||
#:entry-expiration entry-expiration)))
|
#:entry-expiration entry-expiration)))
|
||||||
|
|
||||||
(guix-environment* opts))
|
(if (assoc-ref opts 'export-manifest?)
|
||||||
|
(export-manifest opts (current-output-port))
|
||||||
|
(guix-environment* opts)))
|
||||||
|
|
84
tests/guix-shell-export-manifest.sh
Normal file
84
tests/guix-shell-export-manifest.sh
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
# GNU Guix --- Functional package management for GNU
|
||||||
|
# Copyright © 2022 Ludovic Courtès <ludo@gnu.org>
|
||||||
|
#
|
||||||
|
# This file is part of GNU Guix.
|
||||||
|
#
|
||||||
|
# GNU Guix is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 3 of the License, or (at
|
||||||
|
# your option) any later version.
|
||||||
|
#
|
||||||
|
# GNU Guix is distributed in the hope that it will be useful, but
|
||||||
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#
|
||||||
|
# Test 'guix shell --export-manifest'.
|
||||||
|
#
|
||||||
|
|
||||||
|
guix shell --version
|
||||||
|
|
||||||
|
tmpdir="t-guix-manifest-$$"
|
||||||
|
trap 'rm -r "$tmpdir"' EXIT
|
||||||
|
mkdir "$tmpdir"
|
||||||
|
|
||||||
|
manifest="$tmpdir/manifest.scm"
|
||||||
|
|
||||||
|
# Basics.
|
||||||
|
guix shell --export-manifest guile-bootstrap > "$manifest"
|
||||||
|
test "$(guix build -m "$manifest")" = "$(guix build guile-bootstrap)"
|
||||||
|
|
||||||
|
guix shell -m "$manifest" --bootstrap -- \
|
||||||
|
"$SHELL" -c 'guix package --export-manifest -p "$GUIX_ENVIRONMENT"' > \
|
||||||
|
"$manifest.second"
|
||||||
|
for m in "$manifest" "$manifest.second"
|
||||||
|
do
|
||||||
|
grep -v '^;' < "$m" > "$m.new" # filter out comments
|
||||||
|
mv "$m.new" "$m"
|
||||||
|
done
|
||||||
|
|
||||||
|
cat "$manifest"
|
||||||
|
cat "$manifest.second"
|
||||||
|
|
||||||
|
cmp "$manifest" "$manifest.second"
|
||||||
|
|
||||||
|
# Combining manifests.
|
||||||
|
guix shell --export-manifest -m "$manifest" gash gash-utils \
|
||||||
|
> "$manifest.second"
|
||||||
|
guix build -m "$manifest.second" -d | \
|
||||||
|
grep "$(guix build guile-bootstrap -d)"
|
||||||
|
guix build -m "$manifest.second" -d | \
|
||||||
|
grep "$(guix build gash -d)"
|
||||||
|
|
||||||
|
# Package transformation option.
|
||||||
|
guix shell --export-manifest guile guix --with-latest=guile-json > "$manifest"
|
||||||
|
grep 'options->transformation' "$manifest"
|
||||||
|
grep '(with-latest . "guile-json")' "$manifest"
|
||||||
|
|
||||||
|
# Development manifest.
|
||||||
|
guix shell --export-manifest -D guile git > "$manifest"
|
||||||
|
grep 'package->development-manifest' "$manifest"
|
||||||
|
grep '"guile"' "$manifest"
|
||||||
|
guix build -m "$manifest" -d | \
|
||||||
|
grep "$(guix build -e '(@@ (gnu packages commencement) gcc-final)' -d)"
|
||||||
|
guix build -m "$manifest" -d | \
|
||||||
|
grep "$(guix build git -d)"
|
||||||
|
|
||||||
|
# Test various combinations to make sure generated code uses interfaces
|
||||||
|
# correctly.
|
||||||
|
for options in \
|
||||||
|
"coreutils grep sed" \
|
||||||
|
"gsl openblas gcc-toolchain --tune" \
|
||||||
|
"guile -m $manifest.previous" \
|
||||||
|
"git:send-email gdb guile:debug" \
|
||||||
|
"git -D coreutils"
|
||||||
|
do
|
||||||
|
guix shell --export-manifest $options > "$manifest"
|
||||||
|
cat "$manifest"
|
||||||
|
guix shell -m "$manifest" -n
|
||||||
|
mv "$manifest" "$manifest.previous"
|
||||||
|
done
|
Reference in a new issue