mirror of
https://git.savannah.gnu.org/git/guix.git
synced 2025-02-07 11:29:59 +01:00
doc: Add "Guix Profiles in Practice" to the cookbook.
* doc/guix-cookbook.texi (Advanced package management): New chapter. * doc/guix-cookbook.texi (Guix Profiles in Practice): New section.
This commit is contained in:
parent
faf2843b86
commit
4c463569b7
1 changed files with 389 additions and 0 deletions
|
@ -58,6 +58,7 @@ Translation Project}.
|
||||||
* Scheme tutorials:: Meet your new favorite language!
|
* Scheme tutorials:: Meet your new favorite language!
|
||||||
* Packaging:: Packaging tutorials
|
* Packaging:: Packaging tutorials
|
||||||
* System Configuration:: Customizing the GNU System
|
* System Configuration:: Customizing the GNU System
|
||||||
|
* Advanced package management:: Power to the users!
|
||||||
|
|
||||||
* Acknowledgments:: Thanks!
|
* Acknowledgments:: Thanks!
|
||||||
* GNU Free Documentation License:: The license of this document.
|
* GNU Free Documentation License:: The license of this document.
|
||||||
|
@ -778,6 +779,394 @@ likely that you'll need to modify the initrd on a machine using a custom
|
||||||
kernel, since certain modules which are expected to be built may not be
|
kernel, since certain modules which are expected to be built may not be
|
||||||
available for inclusion into the initrd.
|
available for inclusion into the initrd.
|
||||||
|
|
||||||
|
@c *********************************************************************
|
||||||
|
@node Advanced package management
|
||||||
|
@chapter Advanced package management
|
||||||
|
|
||||||
|
Guix is a functional package manager that offers many features beyond
|
||||||
|
what more traditional package managers can do. To the uninitiated,
|
||||||
|
those features might not have obvious use cases at first. The purpose
|
||||||
|
of this chapter is to demonstrate some advanced package management
|
||||||
|
concepts.
|
||||||
|
|
||||||
|
@pxref{Package Management,,, guix, GNU Guix Reference Manual} for a complete
|
||||||
|
reference.
|
||||||
|
|
||||||
|
@menu
|
||||||
|
* Guix Profiles in Practice:: Strategies for multiple profiles and manifests.
|
||||||
|
@end menu
|
||||||
|
|
||||||
|
@node Guix Profiles in Practice
|
||||||
|
@section Guix Profiles in Practice
|
||||||
|
|
||||||
|
Guix provides a very useful feature that may be quite foreign to newcomers:
|
||||||
|
@emph{profiles}. They are a way to group package installations together and all users
|
||||||
|
on a same system are free to use as many profiles as they want.
|
||||||
|
|
||||||
|
Whether you're a developer or not, you may find that multiple profiles bring you
|
||||||
|
great power and flexibility. While they shift the paradigm somewhat compared to
|
||||||
|
@emph{traditional package managers}, they are very convenient to use once you've
|
||||||
|
understood how to set them up.
|
||||||
|
|
||||||
|
If you are familiar with Python's @samp{virtualenv}, you can think of a profile as a
|
||||||
|
kind of universal @samp{virtualenv} that can hold any kind of software whatsoever, not
|
||||||
|
just Python software. Furthermore, profiles are self-sufficient: they capture
|
||||||
|
all the runtime dependencies which guarantees that all programs within a profile
|
||||||
|
will always work at any point in time.
|
||||||
|
|
||||||
|
Multiple profiles have many benefits:
|
||||||
|
|
||||||
|
@itemize
|
||||||
|
@item
|
||||||
|
Clean semantic separation of the various packages a user needs for different contexts.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Multiple profiles can be made available into the environment either on login
|
||||||
|
or within a dedicated shell.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Profiles can be loaded on demand. For instance, the user can use multiple
|
||||||
|
shells, each of them running different profiles.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Isolation: Programs from one profile will not use programs from the other, and
|
||||||
|
they user can even install different versions of the same programs to the two
|
||||||
|
profiles without conflict.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Deduplication: Profiles share dependencies that happens to be the exact same.
|
||||||
|
This makes multiple profiles storage-efficient.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Reproducible: when used with declarative manifests, a profile can be fully
|
||||||
|
specified by the Guix commit that was active when it was set up. This means
|
||||||
|
that the exact same profile can be @uref{https://guix.gnu.org/blog/2018/multi-dimensional-transactions-and-rollbacks-oh-my/, set up anywhere, anytime}, with just the
|
||||||
|
commit information. See the section on @ref{Reproducible profiles}.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Easier upgrades and maintenance: Multiple profiles make it easy to keep
|
||||||
|
package listings at hand and make upgrades completely friction-less.
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
Concretely, here follows some typical profiles:
|
||||||
|
|
||||||
|
@itemize
|
||||||
|
@item
|
||||||
|
The dependencies of a project you are working on.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Your favourite programming language libraries.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Laptop-specific programs (like @samp{powertop}) that you don't need on a desktop.
|
||||||
|
|
||||||
|
@item
|
||||||
|
@TeX{}live (this one can be really useful when you need to install just one
|
||||||
|
package for this one document you've just received over email).
|
||||||
|
|
||||||
|
@item
|
||||||
|
Games.
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
Let's dive in the set up!
|
||||||
|
|
||||||
|
@node Basic setup with manifests
|
||||||
|
@subsection Basic setup with manifests
|
||||||
|
|
||||||
|
A Guix profile can be set up @emph{via} a so-called @emph{manifest specification} that looks like
|
||||||
|
this:
|
||||||
|
|
||||||
|
@example
|
||||||
|
(specifications->manifest
|
||||||
|
'("package-1"
|
||||||
|
;; Version 1.3 of package-2.
|
||||||
|
"package-2@@1.3"
|
||||||
|
;; The "lib" output of package-3.
|
||||||
|
"package-3:lib"
|
||||||
|
; ...
|
||||||
|
"package-N"))
|
||||||
|
@end example
|
||||||
|
|
||||||
|
See @pxref{Invoking guix package,,, guix, GNU Guix Reference Manual} for
|
||||||
|
the syntax details.
|
||||||
|
|
||||||
|
We can create a manifest specification per profile and install them this way:
|
||||||
|
|
||||||
|
@example
|
||||||
|
GUIX_EXTRA_PROFILES=$HOME/.guix-extra-profiles
|
||||||
|
mkdir -p "$GUIX_EXTRA_PROFILES"/my-project # if it does not exist yet
|
||||||
|
guix package --manifest=/path/to/guix-my-project-manifest.scm --profile="$GUIX_EXTRA_PROFILES"/my-project/my-project
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Here we set an arbitrary variable @samp{GUIX_EXTRA_PROFILES} to point to the directory
|
||||||
|
where we will store our profiles in the rest of this article.
|
||||||
|
|
||||||
|
Placing all your profiles in a single directory, with each profile getting its
|
||||||
|
own sub-directory, is somewhat cleaner. This way, each sub-directory will
|
||||||
|
contain all the symlinks for precisely one profile. Besides, "looping over
|
||||||
|
profiles" becomes obvious from any programming language (e.g. a shell script) by
|
||||||
|
simply looping over the sub-directories of @samp{$GUIX_EXTRA_PROFILES}.
|
||||||
|
|
||||||
|
Note that it's also possible to loop over the output of
|
||||||
|
|
||||||
|
@example
|
||||||
|
guix package --list-profiles
|
||||||
|
@end example
|
||||||
|
|
||||||
|
although you'll probably have to filter out @samp{~/.config/guix/current}.
|
||||||
|
|
||||||
|
To enable all profiles on login, add this to your @samp{~/.bash_profile} (or similar):
|
||||||
|
|
||||||
|
@example
|
||||||
|
for i in $GUIX_EXTRA_PROFILES/*; do
|
||||||
|
profile=$i/$(basename "$i")
|
||||||
|
if [ -f "$profile"/etc/profile ]; then
|
||||||
|
GUIX_PROFILE="$profile"
|
||||||
|
. "$GUIX_PROFILE"/etc/profile
|
||||||
|
fi
|
||||||
|
unset profile
|
||||||
|
done
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Note to Guix System users: the above reflects how your default profile
|
||||||
|
@samp{~/.guix-profile} is activated from @samp{/etc/profile}, that latter being loaded by
|
||||||
|
@samp{~/.bashrc} by default.
|
||||||
|
|
||||||
|
You can obviously choose to only enable a subset of them:
|
||||||
|
|
||||||
|
@example
|
||||||
|
for i in "$GUIX_EXTRA_PROFILES"/my-project-1 "$GUIX_EXTRA_PROFILES"/my-project-2; do
|
||||||
|
profile=$i/$(basename "$i")
|
||||||
|
if [ -f "$profile"/etc/profile ]; then
|
||||||
|
GUIX_PROFILE="$profile"
|
||||||
|
. "$GUIX_PROFILE"/etc/profile
|
||||||
|
fi
|
||||||
|
unset profile
|
||||||
|
done
|
||||||
|
@end example
|
||||||
|
|
||||||
|
When a profile is off, it's straightforward to enable it for an individual shell
|
||||||
|
without "polluting" the rest of the user session:
|
||||||
|
|
||||||
|
@example
|
||||||
|
GUIX_PROFILE="path/to/my-project" ; . "$GUIX_PROFILE"/etc/profile
|
||||||
|
@end example
|
||||||
|
|
||||||
|
The key to enabling a profile is to @emph{source} its @samp{etc/profile} file. This file
|
||||||
|
contains shell code that exports the right environment variables necessary to
|
||||||
|
activate the software contained in the profile. It is built automatically by
|
||||||
|
Guix and meant to be sourced.
|
||||||
|
It contains the same variables you would get if you ran:
|
||||||
|
|
||||||
|
@example
|
||||||
|
guix package --search-paths=prefix --profile=$my_profile"
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Once again, see (@pxref{Invoking guix package,,, guix, GNU Guix Reference Manual})
|
||||||
|
for the command line options.
|
||||||
|
|
||||||
|
To upgrade a profile, simply install the manifest again:
|
||||||
|
|
||||||
|
@example
|
||||||
|
guix package -m /path/to/guix-my-project-manifest.scm -p "$GUIX_EXTRA_PROFILES"/my-project/my-project
|
||||||
|
@end example
|
||||||
|
|
||||||
|
To upgrade all profiles, it's easy enough to loop over them. For instance,
|
||||||
|
assuming your manifest specifications are stored in
|
||||||
|
@samp{~/.guix-manifests/guix-$profile-manifest.scm}, with @samp{$profile} being the name
|
||||||
|
of the profile (e.g. "project1"), you could do the following in Bourne shell:
|
||||||
|
|
||||||
|
@example
|
||||||
|
for profile in "$GUIX_EXTRA_PROFILES"/*; do
|
||||||
|
guix package --profile="$profile" --manifest="$HOME/.guix-manifests/guix-$profile-manifest.scm"
|
||||||
|
done
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Each profile has its own generations:
|
||||||
|
|
||||||
|
@example
|
||||||
|
guix package -p "$GUIX_EXTRA_PROFILES"/my-project/my-project --list-generations
|
||||||
|
@end example
|
||||||
|
|
||||||
|
You can roll-back to any generation of a given profile:
|
||||||
|
|
||||||
|
@example
|
||||||
|
guix package -p "$GUIX_EXTRA_PROFILES"/my-project/my-project --switch-generations=17
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@node Required packages
|
||||||
|
@subsection Required packages
|
||||||
|
|
||||||
|
Activating a profile essentially boils down to exporting a bunch of
|
||||||
|
environmental variables. This is the role of the @samp{etc/profile} within the
|
||||||
|
profile.
|
||||||
|
|
||||||
|
@emph{Note: Only the environmental variables of the packages that consume them will
|
||||||
|
be set.}
|
||||||
|
|
||||||
|
For instance, @samp{MANPATH} won't be set if there is no consumer application for man
|
||||||
|
pages within the profile. So if you need to transparently access man pages once
|
||||||
|
the profile is loaded, you've got two options:
|
||||||
|
|
||||||
|
@itemize
|
||||||
|
@item
|
||||||
|
Either export the variable manually, e.g.
|
||||||
|
@example
|
||||||
|
export MANPATH=/path/to/profile$@{MANPATH:+:@}$MANPATH"
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@item
|
||||||
|
Or include @samp{man-db} to the profile manifest.
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
The same is true for @samp{INFOPATH} (you can install @samp{info-reader}),
|
||||||
|
@samp{PKG_CONFIG_PATH} (install @samp{pkg-config}), etc.
|
||||||
|
|
||||||
|
@node Default profile
|
||||||
|
@subsection Default profile
|
||||||
|
|
||||||
|
What about the default profile that Guix keeps in @samp{~/.guix-profile}?
|
||||||
|
|
||||||
|
You can assign it the role you want. Typically you would install the manifest
|
||||||
|
of the packages you want to use all the time.
|
||||||
|
|
||||||
|
Alternatively, you could keep it "manifest-less" for throw-away packages
|
||||||
|
that you would just use for a couple of days.
|
||||||
|
This way makes it convenient to run
|
||||||
|
|
||||||
|
@example
|
||||||
|
guix install package-foo
|
||||||
|
guix upgrade package-bar
|
||||||
|
@end example
|
||||||
|
|
||||||
|
without having to specify the path to a profile.
|
||||||
|
|
||||||
|
@node The benefits of manifests
|
||||||
|
@subsection The benefits of manifests
|
||||||
|
|
||||||
|
Manifests are a convenient way to keep your package lists around and, say,
|
||||||
|
to synchronize them across multiple machines using a version control system.
|
||||||
|
|
||||||
|
A common complaint about manifests is that they can be slow to install when they
|
||||||
|
contain large number of packages. This is especially cumbersome when you just
|
||||||
|
want get an upgrade for one package within a big manifest.
|
||||||
|
|
||||||
|
This is one more reason to use multiple profiles, which happen to be just
|
||||||
|
perfect to break down manifests into multiple sets of semantically connected
|
||||||
|
packages. Using multiple, small profiles provides more flexibility and
|
||||||
|
usability.
|
||||||
|
|
||||||
|
Manifests come with multiple benefits. In particular, they ease maintenance:
|
||||||
|
|
||||||
|
@itemize
|
||||||
|
@item
|
||||||
|
When a profile is set up from a manifest, the manifest itself is
|
||||||
|
self-sufficient to keep a "package listing" around and reinstall the profile
|
||||||
|
later or on a different system. For ad-hoc profiles, we would need to
|
||||||
|
generate a manifest specification manually and maintain the package versions
|
||||||
|
for the packages that don't use the default version.
|
||||||
|
|
||||||
|
@item
|
||||||
|
@code{guix package --upgrade} always tries to update the packages that have
|
||||||
|
propagated inputs, even if there is nothing to do. Guix manifests remove this
|
||||||
|
problem.
|
||||||
|
|
||||||
|
@item
|
||||||
|
When partially upgrading a profile, conflicts may arise (due to diverging
|
||||||
|
dependencies between the updated and the non-updated packages) and they can be
|
||||||
|
annoying to resolve manually. Manifests remove this problem altogether since
|
||||||
|
all packages are always upgraded at once.
|
||||||
|
|
||||||
|
@item
|
||||||
|
As mentioned above, manifests allow for reproducible profiles, while the
|
||||||
|
imperative @code{guix install}, @code{guix upgrade}, etc. do not, since they produce
|
||||||
|
different profiles every time even when they hold the same packages. See
|
||||||
|
@uref{https://issues.guix.gnu.org/issue/33285, the related discussion on the matter}.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Manifest specifications are usable by other @samp{guix} commands. For example, you
|
||||||
|
can run @code{guix weather -m manifest.scm} to see how many substitutes are
|
||||||
|
available, which can help you decide whether you want to try upgrading today
|
||||||
|
or wait a while. Another example: you can run @code{guix pack -m manifest.scm} to
|
||||||
|
create a pack containing all the packages in the manifest (and their
|
||||||
|
transitive references).
|
||||||
|
|
||||||
|
@item
|
||||||
|
Finally, manifests have a Scheme representation, the @samp{<manifest>} record type.
|
||||||
|
They can be manipulated in Scheme and passed to the various Guix @uref{https://en.wikipedia.org/wiki/Api, APIs}.
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
It's important to understand that while manifests can be used to declare
|
||||||
|
profiles, they are not strictly equivalent: profiles have the side effect that
|
||||||
|
they "pin" packages in the store, which prevents them from being
|
||||||
|
garbage-collected (@pxref{Invoking guix gc,,, guix, GNU Guix Reference Manual})
|
||||||
|
and ensures that they will still be available at any point in
|
||||||
|
the future.
|
||||||
|
|
||||||
|
Let's take an example:
|
||||||
|
|
||||||
|
@enumerate
|
||||||
|
@item
|
||||||
|
We have an environment for hacking on a project for which there isn't a Guix
|
||||||
|
package yet. We build the environment using a manifest, and then run @code{guix
|
||||||
|
environment -m manifest.scm}. So far so good.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Many weeks pass and we have run a couple of @code{guix pull} in the mean time.
|
||||||
|
Maybe a dependency from our manifest has been updated; or we may have run
|
||||||
|
@code{guix gc} and some packages needed by our manifest have been
|
||||||
|
garbage-collected.
|
||||||
|
|
||||||
|
@item
|
||||||
|
Eventually, we set to work on that project again, so we run @code{guix environment
|
||||||
|
-m manifest.scm}. But now we have to wait for Guix to build and install
|
||||||
|
stuff!
|
||||||
|
@end enumerate
|
||||||
|
|
||||||
|
Ideally, we could spare the rebuild time. And indeed we can, all we need is to
|
||||||
|
install the manifest to a profile and use @code{GUIX_PROFILE=/the/profile;
|
||||||
|
. "$GUIX_PROFILE"/etc/profile} as explained above: this guarantees that our
|
||||||
|
hacking environment will be available at all times.
|
||||||
|
|
||||||
|
@emph{Security warning:} While keeping old profiles around can be convenient, keep in
|
||||||
|
mind that outdated packages may not have received the latest security fixes.
|
||||||
|
|
||||||
|
@node Reproducible profiles
|
||||||
|
@subsection Reproducible profiles
|
||||||
|
|
||||||
|
To reproduce a profile bit-for-bit, we need two pieces of information:
|
||||||
|
|
||||||
|
@itemize
|
||||||
|
@item
|
||||||
|
a manifest,
|
||||||
|
@item
|
||||||
|
a Guix channel specification.
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
Indeed, manifests alone might not be enough: different Guix versions (or
|
||||||
|
different channels) can produce different outputs for a given manifest.
|
||||||
|
|
||||||
|
You can output the Guix channel specification with @samp{guix describe
|
||||||
|
--format=channels}.
|
||||||
|
Save this to a file, say @samp{channel-specs.scm}.
|
||||||
|
|
||||||
|
On another computer, you can use the channel specification file and the manifest
|
||||||
|
to reproduce the exact same profile:
|
||||||
|
|
||||||
|
@example
|
||||||
|
GUIX_EXTRA_PROFILES=$HOME/.guix-extra-profiles
|
||||||
|
GUIX_EXTRA=$HOME/.guix-extra
|
||||||
|
|
||||||
|
mkdir "$GUIX_EXTRA"/my-project
|
||||||
|
guix pull --channels=channel-specs.scm --profile "$GUIX_EXTRA/my-project/guix"
|
||||||
|
|
||||||
|
mkdir -p "$GUIX_EXTRA_PROFILES/my-project"
|
||||||
|
"$GUIX_EXTRA"/my-project/guix/bin/guix package --manifest=/path/to/guix-my-project-manifest.scm --profile="$GUIX_EXTRA_PROFILES"/my-project/my-project
|
||||||
|
@end example
|
||||||
|
|
||||||
|
It's safe to delete the Guix channel profile you've just installed with the
|
||||||
|
channel specification, the project profile does not depend on it.
|
||||||
|
|
||||||
@c *********************************************************************
|
@c *********************************************************************
|
||||||
@node Acknowledgments
|
@node Acknowledgments
|
||||||
@chapter Acknowledgments
|
@chapter Acknowledgments
|
||||||
|
|
Loading…
Add table
Reference in a new issue