From patchwork Mon Oct 11 21:38:01 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Ludovic_Court=C3=A8s?= X-Patchwork-Id: 33771 Return-Path: X-Original-To: patchwork@mira.cbaines.net Delivered-To: patchwork@mira.cbaines.net Received: by mira.cbaines.net (Postfix, from userid 113) id B566C27BBE3; Mon, 11 Oct 2021 22:39:46 +0100 (BST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on mira.cbaines.net X-Spam-Level: X-Spam-Status: No, score=-2.9 required=5.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_MSPIKE_H2,SPF_HELO_PASS,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.2 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mira.cbaines.net (Postfix) with ESMTPS id 4E91327BBE1 for ; Mon, 11 Oct 2021 22:39:45 +0100 (BST) Received: from localhost ([::1]:36234 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ma31M-0007GD-EF for patchwork@mira.cbaines.net; Mon, 11 Oct 2021 17:39:44 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:47526) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ma30j-0006bl-0C for guix-patches@gnu.org; Mon, 11 Oct 2021 17:39:05 -0400 Received: from debbugs.gnu.org ([209.51.188.43]:49614) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1ma30i-0004rC-BL for guix-patches@gnu.org; Mon, 11 Oct 2021 17:39:04 -0400 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1ma30i-0001Q4-8O for guix-patches@gnu.org; Mon, 11 Oct 2021 17:39:04 -0400 X-Loop: help-debbugs@gnu.org Subject: [bug#50960] [PATCH v2 03/11] Add 'guix shell'. Resent-From: Ludovic =?utf-8?q?Court=C3=A8s?= Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Mon, 11 Oct 2021 21:39:04 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 50960 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 50960@debbugs.gnu.org Cc: Ludovic =?utf-8?q?Court=C3=A8s?= Received: via spool by 50960-submit@debbugs.gnu.org id=B50960.16339883325362 (code B ref 50960); Mon, 11 Oct 2021 21:39:04 +0000 Received: (at 50960) by debbugs.gnu.org; 11 Oct 2021 21:38:52 +0000 Received: from localhost ([127.0.0.1]:32912 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ma30R-0001OF-2V for submit@debbugs.gnu.org; Mon, 11 Oct 2021 17:38:52 -0400 Received: from eggs.gnu.org ([209.51.188.92]:45452) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ma308-0001M1-VV for 50960@debbugs.gnu.org; Mon, 11 Oct 2021 17:38:35 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]:40568) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ma303-0004Vy-Bx; Mon, 11 Oct 2021 17:38:23 -0400 Received: from 91-160-117-201.subs.proxad.net ([91.160.117.201]:53321 helo=gnu.org) by fencepost.gnu.org with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1ma302-0007Y0-S1; Mon, 11 Oct 2021 17:38:23 -0400 From: Ludovic =?utf-8?q?Court=C3=A8s?= Date: Mon, 11 Oct 2021 23:38:01 +0200 Message-Id: <20211011213809.17482-4-ludo@gnu.org> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20211011213809.17482-1-ludo@gnu.org> References: <20211002102116.27726-1-ludo@gnu.org> <20211011213809.17482-1-ludo@gnu.org> MIME-Version: 1.0 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: "Guix-patches" X-getmail-retrieved-from-mailbox: Patches From: Ludovic Courtès * guix/scripts/shell.scm, tests/guix-shell.sh: New files. * Makefile.am (MODULES): Add 'shell.scm'. (SH_TESTS): Add 'tests/guix-shell.sh'. * guix/scripts/environment.scm (show-environment-options-help): New procedure. (show-help): Use it. (guix-environment*): New procedure. (guix-environment): Use it. * po/guix/POTFILES.in: Add it. * doc/guix.texi (Features): Refer to "guix shell" (Invoking guix package): Likewise. (Development): Likewise. (Invoking guix shell): New node. (Invoking guix environment): Add deprecation warning. (Debugging Build Failures): Use 'guix shell' in examples. (Invoking guix container): Refer to 'guix shell'. (Invoking guix processes, Virtualization Services): Adjust examples to use 'guix shell'. * doc/contributing.texi (Building from Git): Refer to 'guix shell'. --- Makefile.am | 2 + doc/contributing.texi | 8 +- doc/guix.texi | 366 ++++++++++++++++++++++++++++++++--- guix/scripts/environment.scm | 52 +++-- guix/scripts/shell.scm | 135 +++++++++++++ po/guix/POTFILES.in | 1 + tests/guix-shell.sh | 54 ++++++ 7 files changed, 575 insertions(+), 43 deletions(-) create mode 100644 guix/scripts/shell.scm create mode 100644 tests/guix-shell.sh diff --git a/Makefile.am b/Makefile.am index b66789fa0b..c28c8799ec 100644 --- a/Makefile.am +++ b/Makefile.am @@ -315,6 +315,7 @@ MODULES = \ guix/scripts/import/stackage.scm \ guix/scripts/import/texlive.scm \ guix/scripts/environment.scm \ + guix/scripts/shell.scm \ guix/scripts/publish.scm \ guix/scripts/edit.scm \ guix/scripts/size.scm \ @@ -550,6 +551,7 @@ SH_TESTS = \ tests/guix-authenticate.sh \ tests/guix-environment.sh \ tests/guix-environment-container.sh \ + tests/guix-shell.sh \ tests/guix-graph.sh \ tests/guix-describe.sh \ tests/guix-repl.sh \ diff --git a/doc/contributing.texi b/doc/contributing.texi index fbb3c47c78..363bbe9278 100644 --- a/doc/contributing.texi +++ b/doc/contributing.texi @@ -73,10 +73,10 @@ all the dependencies and appropriate environment variables are set up to hack on Guix: @example -guix environment guix --pure +guix shell -D guix --pure @end example -@xref{Invoking guix environment}, for more information on that command. +@xref{Invoking guix shell}, for more information on that command. If you are unable to use Guix when building Guix from a checkout, the following are the required packages in addition to those mentioned in the @@ -92,10 +92,10 @@ installation instructions (@pxref{Requirements}). @end itemize On Guix, extra dependencies can be added by instead running @command{guix -environment} with @option{--ad-hoc}: +shell}: @example -guix environment guix --pure --ad-hoc help2man git strace +guix shell -D guix help2man git strace --pure @end example Run @command{./bootstrap} to generate the build system infrastructure diff --git a/doc/guix.texi b/doc/guix.texi index bc3f5a537b..b0d745b9e3 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -118,6 +118,7 @@ Documentation License''. @dircategory Software development @direntry +* guix shell: (guix)Invoking guix shell. Creating software environments. * guix environment: (guix)Invoking guix environment. Building development environments with Guix. * guix build: (guix)Invoking guix build. Building packages. * guix pack: (guix)Invoking guix pack. Creating binary bundles. @@ -261,6 +262,7 @@ Channels Development +* Invoking guix shell:: Spawning one-off software environments. * Invoking guix environment:: Setting up development environments. * Invoking guix pack:: Creating software bundles. * The GCC toolchain:: Working with languages supported by GCC. @@ -3066,10 +3068,10 @@ substitutes: they can force a local build and @emph{challenge} providers (@pxref{Invoking guix challenge}). Control over the build environment is a feature that is also useful for -developers. The @command{guix environment} command allows developers of +developers. The @command{guix shell} command allows developers of a package to quickly set up the right development environment for their package, without having to manually install the dependencies of the -package into their profile (@pxref{Invoking guix environment}). +package into their profile (@pxref{Invoking guix shell}). @cindex replication, of software environments @cindex provenance tracking, of software artifacts @@ -3233,7 +3235,7 @@ As an example, @var{file} might contain a definition like this Developers may find it useful to include such a @file{guix.scm} file in the root of their project source tree that can be used to test development snapshots and create reproducible development environments -(@pxref{Invoking guix environment}). +(@pxref{Invoking guix shell}). The @var{file} may also contain a JSON representation of one or more package definitions. Running @code{guix package -f} on @@ -5558,31 +5560,352 @@ If you are a software developer, Guix provides tools that you should find helpful---independently of the language you're developing in. This is what this chapter is about. -The @command{guix environment} command provides a convenient way to set up -@dfn{development environments} containing all the dependencies and tools -necessary to work on the software package of your choice. The @command{guix +The @command{guix shell} command provides a convenient way to set up +one-off software environments, be it for development purposes or to run +a command without installing it in your profile. The @command{guix pack} command allows you to create @dfn{application bundles} that can be easily distributed to users who do not run Guix. @menu +* Invoking guix shell:: Spawning one-off software environments. * Invoking guix environment:: Setting up development environments. * Invoking guix pack:: Creating software bundles. * The GCC toolchain:: Working with languages supported by GCC. * Invoking guix git authenticate:: Authenticating Git repositories. @end menu -@node Invoking guix environment -@section Invoking @command{guix environment} +@node Invoking guix shell +@section Invoking @command{guix shell} @cindex reproducible build environments @cindex development environments @cindex @command{guix environment} @cindex environment, package build environment -The purpose of @command{guix environment} is to assist hackers in -creating reproducible development environments without polluting their -package profile. The @command{guix environment} tool takes one or more -packages, builds all of their inputs, and creates a shell -environment to use them. +The purpose of @command{guix shell} is to make it easy to create one-off +software environments, without changing one's profile. It is typically +used to create development environments; it is also a convenient way to +run applications without ``polluting'' your profile. + +@quotation Note +The @command{guix shell} command was recently introduced to supersede +@command{guix environment} (@pxref{Invoking guix environment}). If you +are familiar with @command{guix environment}, you will notice that it is +similar but also---we hope!---more convenient. +@end quotation + +The general syntax is: + +@example +guix shell [@var{options}] [@var{package}@dots{}] +@end example + +The following example creates a environment containing Python and NumPy, +building and downloading any missing package, and runs the +@command{python3} command in that environment: + +@example +guix shell python python-numpy -- python3 +@end example + +Development environments can be created as in the example below, which +spawns an interactive shell containing all the dependencies and +environment variables needed to work on Inkscape: + +@example +guix shell --development inkscape +@end example + +Exiting the shell places the user back in the original environment +before @command{guix shell} was invoked. The next garbage collection +(@pxref{Invoking guix gc}) may clean up packages that were installed in +the environment and that are no longer used outside of it. + +By default, the shell session or command runs in an @emph{augmented} +environment, where the new packages are added to search path environment +variables such as @code{PATH}. You can, instead, choose to create an +@emph{isolated} environment containing nothing but the packages you +asked for. Passing the @option{--pure} option clears environment +variable definitions found in the parent environment@footnote{Users +sometimes wrongfully augment environment variables such as @env{PATH} in +their @file{~/.bashrc} file. As a consequence, when @command{guix +environment} launches it, Bash may read @file{~/.bashrc}, thereby +introducing ``impurities'' in these environment variables. It is an +error to define such environment variables in @file{.bashrc}; instead, +they should be defined in @file{.bash_profile}, which is sourced only by +log-in shells. @xref{Bash Startup Files,,, bash, The GNU Bash Reference +Manual}, for details on Bash start-up files.}; passing +@option{--container} goes one step further by spawning a @dfn{container} +isolated from the rest of the system: + +@example +guix shell --container emacs gcc-toolchain +@end example + +The command above spawns an interactive shell in a container when +nothing but @code{emacs}, @code{gcc-toolchain}, and their dependencies +is available. The container lacks network access and shares no files +other than the current working directory with the surrounding +environment. This is useful to prevent access to system-wide resources +such as @file{/usr/bin} on foreign distros. + +This @option{--container} option can also prove useful if you wish to +run a security-sensitive application, such as a web browser, in an +isolated environment. For example, the command below launches +Ungoogled-Chromium in an isolated environment, this time sharing network +access with the host and preserving its @code{DISPLAY} environment +variable, but without even sharing the current directory: + +@example +guix shell --container --network --no-cwd ungoogled-chromium \ + --preserve='^DISPLAY$' -- chromium +@end example + +@vindex GUIX_ENVIRONMENT +@command{guix shell} defines the @env{GUIX_ENVIRONMENT} +variable in the shell it spawns; its value is the file name of the +profile of this environment. This allows users to, say, define a +specific prompt for development environments in their @file{.bashrc} +(@pxref{Bash Startup Files,,, bash, The GNU Bash Reference Manual}): + +@example +if [ -n "$GUIX_ENVIRONMENT" ] +then + export PS1="\u@@\h \w [dev]\$ " +fi +@end example + +@noindent +...@: or to browse the profile: + +@example +$ ls "$GUIX_ENVIRONMENT/bin" +@end example + +The available options are summarized below. + +@table @code +@item --development +@itemx -D +Cause @command{guix shell} to include in the environment the +dependencies of the following package rather than the package itself. +This can be combined with other packages. For instance, the command +below starts an interactive shell containing the build-time dependencies +of GNU@tie{}Guile, plus Autoconf, Automake, and Libtool: + +@example +guix shell -D guile autoconf automake libtool +@end example + +@item --expression=@var{expr} +@itemx -e @var{expr} +Create an environment for the package or list of packages that +@var{expr} evaluates to. + +For example, running: + +@example +guix shell -D -e '(@@ (gnu packages maths) petsc-openmpi)' +@end example + +starts a shell with the environment for this specific variant of the +PETSc package. + +Running: + +@example +guix shell -e '(@@ (gnu) %base-packages)' +@end example + +starts a shell with all the base system packages available. + +The above commands only use the default output of the given packages. +To select other outputs, two element tuples can be specified: + +@example +guix shell -e '(list (@@ (gnu packages bash) bash) "include")' +@end example + +@item --file=@var{file} +@itemx -f @var{file} +Create an environment containing the package or list of packages that +the code within @var{file} evaluates to. + +As an example, @var{file} might contain a definition like this +(@pxref{Defining Packages}): + +@lisp +@verbatiminclude environment-gdb.scm +@end lisp + +With the file above, you can enter a development environment for GDB by +running: + +@example +guix shell -D -f gdb-devel.scm +@end example + +@item --manifest=@var{file} +@itemx -m @var{file} +Create an environment for the packages contained in the manifest object +returned by the Scheme code in @var{file}. This option can be repeated +several times, in which case the manifests are concatenated. + +This is similar to the same-named option in @command{guix package} +(@pxref{profile-manifest, @option{--manifest}}) and uses the same +manifest files. + +@item --pure +Unset existing environment variables when building the new environment, except +those specified with @option{--preserve} (see below). This has the effect of +creating an environment in which search paths only contain package inputs. + +@item --preserve=@var{regexp} +@itemx -E @var{regexp} +When used alongside @option{--pure}, preserve the environment variables +matching @var{regexp}---in other words, put them on a ``white list'' of +environment variables that must be preserved. This option can be repeated +several times. + +@example +guix shell --pure --preserve=^SLURM openmpi @dots{} \ + -- mpirun @dots{} +@end example + +This example runs @command{mpirun} in a context where the only environment +variables defined are @env{PATH}, environment variables whose name starts +with @samp{SLURM}, as well as the usual ``precious'' variables (@env{HOME}, +@env{USER}, etc.). + +@item --search-paths +Display the environment variable definitions that make up the +environment. + +@item --system=@var{system} +@itemx -s @var{system} +Attempt to build for @var{system}---e.g., @code{i686-linux}. + +@item --container +@itemx -C +@cindex container +Run @var{command} within an isolated container. The current working +directory outside the container is mapped inside the container. +Additionally, unless overridden with @option{--user}, a dummy home +directory is created that matches the current user's home directory, and +@file{/etc/passwd} is configured accordingly. + +The spawned process runs as the current user outside the container. Inside +the container, it has the same UID and GID as the current user, unless +@option{--user} is passed (see below). + +@item --network +@itemx -N +For containers, share the network namespace with the host system. +Containers created without this flag only have access to the loopback +device. + +@item --link-profile +@itemx -P +For containers, link the environment profile to @file{~/.guix-profile} +within the container and set @code{GUIX_ENVIRONMENT} to that. +This is equivalent to making @file{~/.guix-profile} a symlink to the +actual profile within the container. +Linking will fail and abort the environment if the directory already +exists, which will certainly be the case if @command{guix shell} +was invoked in the user's home directory. + +Certain packages are configured to look in @file{~/.guix-profile} for +configuration files and data;@footnote{For example, the +@code{fontconfig} package inspects @file{~/.guix-profile/share/fonts} +for additional fonts.} @option{--link-profile} allows these programs to +behave as expected within the environment. + +@item --user=@var{user} +@itemx -u @var{user} +For containers, use the username @var{user} in place of the current +user. The generated @file{/etc/passwd} entry within the container will +contain the name @var{user}, the home directory will be +@file{/home/@var{user}}, and no user GECOS data will be copied. Furthermore, +the UID and GID inside the container are 1000. @var{user} +need not exist on the system. + +Additionally, any shared or exposed path (see @option{--share} and +@option{--expose} respectively) whose target is within the current user's +home directory will be remapped relative to @file{/home/USER}; this +includes the automatic mapping of the current working directory. + +@example +# will expose paths as /home/foo/wd, /home/foo/test, and /home/foo/target +cd $HOME/wd +guix shell --container --user=foo \ + --expose=$HOME/test \ + --expose=/tmp/target=$HOME/target +@end example + +While this will limit the leaking of user identity through home paths +and each of the user fields, this is only one useful component of a +broader privacy/anonymity solution---not one in and of itself. + +@item --no-cwd +For containers, the default behavior is to share the current working +directory with the isolated container and immediately change to that +directory within the container. If this is undesirable, +@option{--no-cwd} will cause the current working directory to @emph{not} +be automatically shared and will change to the user's home directory +within the container instead. See also @option{--user}. + +@item --expose=@var{source}[=@var{target}] +@itemx --share=@var{source}[=@var{target}] +For containers, @option{--expose} (resp. @option{--share}) exposes the +file system @var{source} from the host system as the read-only +(resp. writable) file system @var{target} within the container. If +@var{target} is not specified, @var{source} is used as the target mount +point in the container. + +The example below spawns a Guile REPL in a container in which the user's +home directory is accessible read-only via the @file{/exchange} +directory: + +@example +guix shell --container --expose=$HOME=/exchange guile -- guile +@end example + +@item --root=@var{file} +@itemx -r @var{file} +@cindex persistent environment +@cindex garbage collector root, for environments +Make @var{file} a symlink to the profile for this environment, and +register it as a garbage collector root. + +This is useful if you want to protect your environment from garbage +collection, to make it ``persistent''. + +When this option is omitted, the environment is protected from garbage +collection only for the duration of the @command{guix shell} +session. This means that next time you recreate the same environment, +you could have to rebuild or re-download packages. @xref{Invoking guix +gc}, for more on GC roots. +@end table + +@command{guix shell} also supports all of the common build options that +@command{guix build} supports (@pxref{Common Build Options}) as well as +package transformation options (@pxref{Package Transformation Options}). + +@node Invoking guix environment +@section Invoking @command{guix environment} + +The purpose of @command{guix environment} is to assists in creating +development environments. + +@quotation Deprecation warning +The @command{guix environment} command is deprecated in favor of +@command{guix shell}, which performs similar functions but is more +convenient to use. @xref{Invoking guix shell}. + +Being deprecated, @command{guix environment} is slated for eventual +removal, but the Guix project is committed to keeping it until May 1st, +2023. Please get in touch with us at @email{guix-devel@@gnu.org} if you +would like to discuss it. +@end quotation The general syntax is: @@ -11098,14 +11421,14 @@ a container similar to the one the build daemon creates: $ guix build -K foo @dots{} $ cd /tmp/guix-build-foo.drv-0 -$ guix environment --no-grafts -C foo --ad-hoc strace gdb +$ guix shell --no-grafts -C foo strace gdb [env]# source ./environment-variables [env]# cd foo-1.2 @end example Here, @command{guix environment -C} creates a container and spawns a new -shell in it (@pxref{Invoking guix environment}). The @command{--ad-hoc -strace gdb} part adds the @command{strace} and @command{gdb} commands to +shell in it (@pxref{Invoking guix shell}). The @command{strace gdb} +part adds the @command{strace} and @command{gdb} commands to the container, which you may find handy while debugging. The @option{--no-grafts} option makes sure we get the exact same environment, with ungrafted packages (@pxref{Security Updates}, for more @@ -11119,7 +11442,7 @@ remove @file{/bin/sh}: @end example (Don't worry, this is harmless: this is all happening in the throw-away -container created by @command{guix environment}.) +container created by @command{guix shell}.) The @command{strace} command is probably not in the search path, but we can run: @@ -13315,8 +13638,8 @@ is subject to radical change in the future. The purpose of @command{guix container} is to manipulate processes running within an isolated environment, commonly known as a -``container'', typically created by the @command{guix environment} -(@pxref{Invoking guix environment}) and @command{guix system container} +``container'', typically created by the @command{guix shell} +(@pxref{Invoking guix shell}) and @command{guix system container} (@pxref{Invoking guix system}) commands. The general syntax is: @@ -13502,7 +13825,7 @@ listed.}. Here's an example of the information it returns: $ sudo guix processes SessionPID: 19002 ClientPID: 19090 -ClientCommand: guix environment --ad-hoc python +ClientCommand: guix shell python SessionPID: 19402 ClientPID: 19367 @@ -29697,8 +30020,7 @@ When the service is running, you can view its console by connecting to it with a VNC client, for example with: @example -guix environment --ad-hoc tigervnc-client -- \ - vncviewer localhost:5900 +guix shell tigervnc-client -- vncviewer localhost:5900 @end example The default configuration (see @code{hurd-vm-configuration} below) diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm index 54f48a7482..77956fc018 100644 --- a/guix/scripts/environment.scm +++ b/guix/scripts/environment.scm @@ -50,7 +50,11 @@ (define-module (guix scripts environment) #:use-module (srfi srfi-37) #:use-module (srfi srfi-98) #:export (assert-container-features - guix-environment)) + guix-environment + guix-environment* + show-environment-options-help + (%options . %environment-options) + (%default-options . %environment-default-options))) (define %default-shell (or (getenv "SHELL") "/bin/sh")) @@ -66,23 +70,16 @@ (define* (show-search-paths profile manifest #:key pure?) (newline))) (profile-search-paths profile manifest))) -(define (show-help) - (display (G_ "Usage: guix environment [OPTION]... PACKAGE... [-- COMMAND...] -Build an environment that includes the dependencies of PACKAGE and execute -COMMAND or an interactive shell in that environment.\n")) +(define (show-environment-options-help) + "Print help about options shared between 'guix environment' and 'guix +shell'." (display (G_ " -e, --expression=EXPR create environment for the package that EXPR evaluates to")) (display (G_ " - -l, --load=FILE create environment for the package that the code within - FILE evaluates to")) - (display (G_ " -m, --manifest=FILE create environment with the manifest from FILE")) (display (G_ " -p, --profile=PATH create environment from profile at PATH")) - (display (G_ " - --ad-hoc include all specified packages in the environment instead - of only their inputs")) (display (G_ " --pure unset existing environment variables")) (display (G_ " @@ -118,7 +115,24 @@ (define (show-help) (display (G_ " -v, --verbosity=LEVEL use the given verbosity LEVEL")) (display (G_ " - --bootstrap use bootstrap binaries to build the environment")) + --bootstrap use bootstrap binaries to build the environment"))) + +(define (show-help) + (display (G_ "Usage: guix environment [OPTION]... PACKAGE... [-- COMMAND...] +Build an environment that includes the dependencies of PACKAGE and execute +COMMAND or an interactive shell in that environment.\n")) + (warning (G_ "This command is deprecated in favor of 'guix shell'.\n")) + (newline) + + ;; These two options are left out in 'guix shell'. + (display (G_ " + -l, --load=FILE create environment for the package that the code within + FILE evaluates to")) + (display (G_ " + --ad-hoc include all specified packages in the environment instead + of only their inputs")) + + (show-environment-options-help) (newline) (show-build-options-help) (newline) @@ -649,11 +663,15 @@ (define (register-gc-root target root) (define-command (guix-environment . args) (category development) - (synopsis "spawn one-off software environments") + (synopsis "spawn one-off software environments (deprecated)") + (guix-environment* (parse-args args))) + +(define (guix-environment* opts) + "Run the 'guix environment' command on OPTS, an alist resulting for +command-line option processing with 'parse-command-line'." (with-error-handling - (let* ((opts (parse-args args)) - (pure? (assoc-ref opts 'pure)) + (let* ((pure? (assoc-ref opts 'pure)) (container? (assoc-ref opts 'container?)) (link-prof? (assoc-ref opts 'link-profile?)) (network? (assoc-ref opts 'network?)) @@ -724,8 +742,8 @@ (define manifest (prof-drv (manifest->derivation manifest system bootstrap?)) (profile -> (if profile - (readlink* profile) - (derivation->output-path prof-drv))) + (readlink* profile) + (derivation->output-path prof-drv))) (gc-root -> (assoc-ref opts 'gc-root))) ;; First build the inputs. This is necessary even for diff --git a/guix/scripts/shell.scm b/guix/scripts/shell.scm new file mode 100644 index 0000000000..190dd8837d --- /dev/null +++ b/guix/scripts/shell.scm @@ -0,0 +1,135 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2021 Ludovic Courtès +;;; +;;; 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 . + +(define-module (guix scripts shell) + #:use-module (guix ui) + #:use-module (guix scripts environment) + #:autoload (guix scripts build) (show-build-options-help) + #:autoload (guix transformations) (show-transformation-options-help) + #:use-module (guix scripts) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26) + #:use-module (srfi srfi-37) + #:use-module (srfi srfi-71) + #:use-module (ice-9 match) + #:export (guix-shell)) + +(define (show-help) + (display (G_ "Usage: guix shell [OPTION] PACKAGES... [-- COMMAND...] +Build an environment that includes PACKAGES and execute COMMAND or an +interactive shell in that environment.\n")) + (newline) + + ;; These two options differ from 'guix environment'. + (display (G_ " + -D, --development include the development inputs of the next package")) + (display (G_ " + -f, --file=FILE create environment for the package that the code within + FILE evaluates to")) + + (show-environment-options-help) + (newline) + (show-build-options-help) + (newline) + (show-transformation-options-help) + (newline) + (display (G_ " + -h, --help display this help and exit")) + (display (G_ " + -V, --version display version information and exit")) + (newline) + (show-bug-report-information)) + +(define (tag-package-arg opts arg) + "Return a two-element list with the form (TAG ARG) that tags ARG with either +'ad-hoc' in OPTS has the 'ad-hoc?' key set to #t, or 'inputs' otherwise." + (if (assoc-ref opts 'ad-hoc?) + `(ad-hoc-package ,arg) + `(package ,arg))) + +(define (ensure-ad-hoc alist) + (if (assq-ref alist 'ad-hoc?) + alist + `((ad-hoc? . #t) ,@alist))) + +(define (wrapped-option opt) + "Wrap OPT, a SRFI-37 option, such that its processor always adds the +'ad-hoc?' flag to the resulting alist." + (option (option-names opt) + (option-required-arg? opt) + (option-optional-arg? opt) + (compose ensure-ad-hoc (option-processor opt)))) + +(define %options + ;; Specification of the command-line options. + (let ((to-remove '("ad-hoc" "inherit" "load" "help" "version"))) + (append + (list (option '(#\h "help") #f #f + (lambda args + (show-help) + (exit 0))) + (option '(#\V "version") #f #f + (lambda args + (show-version-and-exit "guix shell"))) + + (option '(#\D "development") #f #f + (lambda (opt name arg result) + ;; Temporarily remove the 'ad-hoc?' flag from result. + ;; The next option will put it back thanks to + ;; 'wrapped-option'. + (alist-delete 'ad-hoc? result))) + + ;; For consistency with 'guix package', support '-f' rather than + ;; '-l' like 'guix environment' does. + (option '(#\f "file") #t #f + (lambda (opt name arg result) + (alist-cons 'load (tag-package-arg result arg) + result)))) + (filter-map (lambda (opt) + (and (not (any (lambda (name) + (member name to-remove)) + (option-names opt))) + (wrapped-option opt))) + %environment-options)))) + +(define %default-options + `((ad-hoc? . #t) ;always true + ,@%environment-default-options)) + +(define (parse-args args) + "Parse the list of command line arguments ARGS." + (define (handle-argument arg result) + (alist-cons 'package (tag-package-arg result arg) + (ensure-ad-hoc result))) + + ;; The '--' token is used to separate the command to run from the rest of + ;; the operands. + (let ((args command (break (cut string=? "--" <>) args))) + (let ((opts (parse-command-line args %options (list %default-options) + #:argument-handler handle-argument))) + (match command + (() opts) + (("--") opts) + (("--" command ...) (alist-cons 'exec command opts)))))) + + +(define-command (guix-shell . args) + (category development) + (synopsis "spawn one-off software environments") + + (guix-environment* (parse-args args))) diff --git a/po/guix/POTFILES.in b/po/guix/POTFILES.in index f5b76bf582..f8abeb2d38 100644 --- a/po/guix/POTFILES.in +++ b/po/guix/POTFILES.in @@ -99,6 +99,7 @@ guix/derivations.scm guix/scripts/archive.scm guix/scripts/build.scm guix/scripts/environment.scm +guix/scripts/shell.scm guix/scripts/time-machine.scm guix/scripts/import/cpan.scm guix/scripts/import/crate.scm diff --git a/tests/guix-shell.sh b/tests/guix-shell.sh new file mode 100644 index 0000000000..f08637f7ff --- /dev/null +++ b/tests/guix-shell.sh @@ -0,0 +1,54 @@ +# GNU Guix --- Functional package management for GNU +# Copyright © 2021 Ludovic Courtès +# +# 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 . + +# +# Test the 'guix shell' alias. +# + +guix shell --version + +tmpdir="t-guix-shell-$$" +trap 'rm -r "$tmpdir"' EXIT +mkdir "$tmpdir" + +guix shell --bootstrap --pure guile-bootstrap -- guile --version + +# '--ad-hoc' is a thing of the past. +! guix shell --ad-hoc guile-bootstrap + +if guile -c '(getaddrinfo "www.gnu.org" "80" AI_NUMERICSERV)' 2> /dev/null +then + # Compute the build environment for the initial GNU Make. + guix shell --bootstrap --no-substitutes --search-paths --pure \ + -D -e '(@ (guix tests) gnu-make-for-tests)' > "$tmpdir/a" + + # Make sure bootstrap binaries are in the profile. + profile=`grep "^export PATH" "$tmpdir/a" | sed -r 's|^.*="(.*)/bin"|\1|'` + + # Make sure the bootstrap binaries are all listed where they belong. + grep -E "^export PATH=\"$profile/bin\"" "$tmpdir/a" + grep -E "^export CPATH=\"$profile/include\"" "$tmpdir/a" + grep -E "^export LIBRARY_PATH=\"$profile/lib\"" "$tmpdir/a" + for dep in bootstrap-binaries-0 gcc-bootstrap-0 glibc-bootstrap-0 + do + guix gc --references "$profile" | grep "$dep" + done + + # 'make-boot0' itself must not be listed. + ! guix gc --references "$profile" | grep make-boot0 +fi