From 7bc46ecc34ceb042ff890e5d306d0a2a736e891d Mon Sep 17 00:00:00 2001 From: Ricardo Wurmus Date: Sun, 8 Sep 2019 14:35:44 +0200 Subject: doc: Add Guix Cookbook. * .gitignore: Update ignore list. * Makefile.am (assert-no-store-file-names): Exclude the cookbook. * bootstrap: Generate po files for cookbook translations. * doc/guix-cookbook.texi: New file. * doc/local.mk (info_TEXINFOS): Add it; add a rule to build cookbook translations. * po/doc/local.mk (DOC_COOKBOOK_PO_FILES): New variable. (EXTRA_DIST): Add cookbook pot file and po files. (doc-po-update-cookbook-%): New target. (doc-pot-update): Also update cookbook pot file. (doc-po-update): Also update cookbook po files. --- doc/guix-cookbook.texi | 821 +++++++++++++++++++++++++++++++++++++++++++++++++ doc/local.mk | 9 +- 2 files changed, 829 insertions(+), 1 deletion(-) create mode 100644 doc/guix-cookbook.texi (limited to 'doc') diff --git a/doc/guix-cookbook.texi b/doc/guix-cookbook.texi new file mode 100644 index 0000000000..66f94a0fe7 --- /dev/null +++ b/doc/guix-cookbook.texi @@ -0,0 +1,821 @@ +\input texinfo +@c -*-texinfo-*- + +@c %**start of header +@setfilename guix-cookbook.info +@documentencoding UTF-8 +@settitle GNU Guix Cookbook +@c %**end of header + +@copying +Copyright @copyright{} 2019 Ricardo Wurmus@* +Copyright @copyright{} 2019 Efraim Flashner@* +Copyright @copyright{} 2019 Pierre Neidhardt@* + +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.3 or +any later version published by the Free Software Foundation; with no +Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A +copy of the license is included in the section entitled ``GNU Free +Documentation License''. +@end copying + +@dircategory System administration +@direntry +* Guix cookbook: (guix-cookbook). Tutorials and examples for GNU Guix. +@end direntry + +@titlepage +@title GNU Guix Cookbook +@subtitle Tutorials and examples for using the GNU Guix Functional Package Manager +@author The GNU Guix Developers + +@page +@vskip 0pt plus 1filll + +@insertcopying +@end titlepage + +@contents + +@c ********************************************************************* +@node Top +@top GNU Guix Cookbook + +This document presents tutorials and detailed examples for GNU@tie{}Guix, a +functional package management tool written for the GNU system. Please +@pxref{Top,,, guix, GNU Guix reference manual} for details about the system, +its API, and related concepts. + +@c TRANSLATORS: You can replace the following paragraph with information on +@c how to join your own translation team and how to report issues with the +@c translation. +If you would like to translate this document in your native language, consider +joining the @uref{https://translationproject.org/domain/guix-cookbook.html, +Translation Project}. + +@menu +* Scheme tutorials:: Meet your new favorite language! +* Packaging:: Packaging tutorials +* System Configuration:: Customizing the GNU System + +* Acknowledgments:: Thanks! +* GNU Free Documentation License:: The license of this document. +* Concept Index:: Concepts. + +@detailmenu + --- The Detailed Node Listing --- + +Scheme tutorials + +* A Scheme Crash Course:: Learn the basics of Scheme + +Packaging + +* Packaging Tutorial:: Let's add a package to Guix! + +System Configuration + +* Customizing the Kernel:: Creating and using a custom Linux kernel + + +@end detailmenu +@end menu + +@c ********************************************************************* +@node Scheme tutorials +@chapter Scheme tutorials + +GNU@tie{}Guix is written in the general purpose programming language Scheme, +and many of its features can be accessed and manipulated programmatically. +You can use Scheme to generate package definitions, to modify them, to build +them, to deploy whole operating systems, etc. + +Knowing the basics of how to program in Scheme will unlock many of the +advanced features Guix provides --- and you don't even need to be an +experienced programmer to use them! + +Let's get started! + +@node A Scheme Crash Course +@section A Scheme Crash Course + +@cindex Scheme, crash course + +Guix uses the Guile implementation of Scheme. To start playing with the +language, install it with @code{guix install guile} and start a +@uref{https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop, +REPL} by running @code{guile} from the command line. + +Alternatively you can also run @code{guix environment --ad-hoc guile -- guile} +if you'd rather not have Guile installed in your user profile. + +In the following examples we use the @code{>} symbol to denote the REPL +prompt, that is, the line reserved for user input. @xref{Using Guile +Interactively,,, guile, GNU Guile Reference Manual}) for more details on the +REPL. + +@itemize +@item +Scheme syntax boils down to a tree of expressions (or @emph{s-expression} in +Lisp lingo). An expression can be a literal such as numbers and strings, or a +compound which is a parenthesized list of compounds and literals. @code{#t} +and @code{#f} stand for the booleans "true" and "false", respectively. + +Examples of valid expressions: + +@example scheme +> "Hello World!" +"Hello World!" +> 17 +17 +> (display (string-append "Hello " "Guix" "\n")) +"Hello Guix!" +@end example + +@item +This last example is a function call nested in another function call. When a +parenthesized expression is evaluated, the first term is the function and the +rest are the arguments passed to the function. Every function returns the +last evaluated expression as its return value. + +@item +Anonymous functions are declared with the @code{lambda} term: + +@example scheme +> (lambda (x) (* x x)) +#:24:0 (x)> +@end example + +The above procedure returns the square of its argument. Since everything is +an expression, the @code{lambda} expression returns an anonymous procedure, +which can in turn be applied to an argument: + +@example scheme +> ((lambda (x) (* x x)) 3) +9 +@end example + +@item +Anything can be assigned a global name with @code{define}: + +@example scheme +> (define a 3) +> (define square (lambda (x) (* x x))) +> (square a) +9 +@end example + +@item +Procedures can be defined more concisely with the following syntax: + +@example scheme +(define (square x) (* x x)) +@end example + +@item +A list structure can be created with the @code{list} procedure: + +@example scheme +> (list 2 a 5 7) +(2 3 5 7) +@end example + +@item +The @emph{quote} disables evaluation of a parenthesized expression: the first +term is not called over the other terms. Thus it effectively returns a list +of terms. + +@example scheme +> '(display (string-append "Hello " "Guix" "\n")) +(display (string-append "Hello " "Guix" "\n")) +> '(2 a 5 7) +(2 a 5 7) +@end example + +@item +The @emph{quasiquote} disables evaluation of a parenthesized expression until +a comma re-enables it. Thus it provides us with fine-grained control over +what is evaluated and what is not. + +@example scheme +> `(2 a 5 7 (2 ,a 5 ,(+ a 4))) +(2 a 5 7 (2 3 5 7)) +@end example + +Note that the above result is a list of mixed elements: numbers, symbols (here +@code{a}) and the last element is a list itself. + +@item +Multiple variables can be named locally with @code{let}: + +@example scheme +> (define x 10) +> (let ((x 2) + (y 3)) + (list x y)) +(2 3) +> x +10 +> y +ERROR: In procedure module-lookup: Unbound variable: y +@end example + +Use @code{let*} to allow later variable declarations to refer to earlier +definitions. + +@example scheme +> (let* ((x 2) + (y (* x 3))) + (list x y)) +(2 6) +@end example + +@item +The keyword syntax is @code{#:}; it is used to create unique identifiers. +@pxref{Keywords,,, guile, GNU Guile Reference Manual}. + +@item +The percentage @code{%} is typically used for read-only global variables in +the build stage. Note that it is merely a convention, like @code{_} in C. +Scheme treats @code{%} exactly the same as any other letter. + +@item +Modules are created with @code{define-module}. For instance + +@example scheme +(define-module (guix build-system ruby) + #:use-module (guix store) + #:export (ruby-build + ruby-build-system)) +@end example + +defines the module @code{guix build-system ruby} which must be located in +@file{guix/build-system/ruby.scm} somewhere in the Guile load path. It +depends on the @code{(guix store)} module and it exports two variables, +@code{ruby-build} and @code{ruby-build-system}. +@end itemize + +For a more detailed introduction, check out +@uref{http://www.troubleshooters.com/codecorn/scheme_guile/hello.htm, Scheme +at a Glance}, by Steve Litt. + +One of the reference Scheme books is the seminal ``Structure and +Interpretation of Computer Programs'', by Harold Abelson and Gerald Jay +Sussman, with Julie Sussman. You'll find a +@uref{https://mitpress.mit.edu/sites/default/files/sicp/index.html, free copy +online}, together with +@uref{https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-001-structure-and-interpretation-of-computer-programs-spring-2005/video-lectures/, +videos of the lectures by the authors}. The book is available in Texinfo +format as the @code{sicp} Guix package. Go ahead, run @code{guix install +sicp} and start reading with @code{info sicp} (or with the Emacs Info reader). +An @uref{https://sarabander.github.io/sicp/, unofficial ebook is also +available}. + +You'll find more books, tutorials and other resources at +@url{https://schemers.org/}. + + +@c ********************************************************************* +@node Packaging +@chapter Packaging + +@cindex packaging + +This chapter is dedicated to teaching you how to add packages to the +collection of packages that come with GNU Guix. This involves writing package +definitions in Guile Scheme, organizing them in package modules, and building +them. + +@menu +* Packaging Tutorial:: A tutorial on how to add packages to Guix. +@end menu + +@node Packaging Tutorial +@section Packaging Tutorial + +GNU Guix stands out as the @emph{hackable} package manager, mostly because it +uses @uref{https://www.gnu.org/software/guile/, GNU Guile}, a powerful +high-level programming language, one of the +@uref{https://en.wikipedia.org/wiki/Scheme_%28programming_language%29, Scheme} +dialects from the +@uref{https://en.wikipedia.org/wiki/Lisp_%28programming_language%29, Lisp family}. + +Package definitions are also written in Scheme, which empowers Guix in some +very unique ways, unlike most other package managers that use shell scripts or +simple languages. + +@itemize +@item +Use functions, structures, macros and all of Scheme expressiveness for your +package definitions. + +@item +Inheritance makes it easy to customize a package by inheriting from it and +modifying only what is needed. + +@item +Batch processing: the whole package collection can be parsed, filtered and +processed. Building a headless server with all graphical interfaces stripped +out? It's possible. Want to rebuild everything from source using specific +compiler optimization flags? Pass the @code{#:make-flags "..."} argument to +the list of packages. It wouldn't be a stretch to think +@uref{https://wiki.gentoo.org/wiki/USE_flag, Gentoo USE flags} here, but this +goes even further: the changes don't have to be thought out beforehand by the +packager, they can be @emph{programmed} by the user! +@end itemize + +The following tutorial covers all the basics around package creation with Guix. +It does not assume much knowledge of the Guix system nor of the Lisp language. +The reader is only expected to be familiar with the command line and to have some +basic programming knowledge. + +@subsection A "Hello World" package + +The “Defining Packages” section of the manual introduces the basics of Guix +packaging (@pxref{Defining Packages,,, guix, GNU Guix Reference Manual}). In +the following section, we will partly go over those basics again. + +``GNU hello'' is a dummy project that serves as an idiomatic example for +packaging. It uses the GNU build system (@code{./configure && make && make +install}). Guix already provides a package definition which is a perfect +example to start with. You can look up its declaration with @code{guix edit +hello} from the command line. Let's see how it looks: + +@example scheme +(define-public hello + (package + (name "hello") + (version "2.10") + (source (origin + (method url-fetch) + (uri (string-append "mirror://gnu/hello/hello-" version + ".tar.gz")) + (sha256 + (base32 + "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i")))) + (build-system gnu-build-system) + (synopsis "Hello, GNU world: An example GNU package") + (description + "GNU Hello prints the message \"Hello, world!\" and then exits. It +serves as an example of standard GNU coding practices. As such, it supports +command-line arguments, multiple languages, and so on.") + (home-page "https://www.gnu.org/software/hello/") + (license gpl3+))) +@end example + +As you can see, most of it is rather straightforward. But let's review the +fields together: + +@table @samp +@item name +The project name. Using Scheme conventions, we prefer to keep it +lower case, without underscore and using dash-separated words. + +@item source +This field contains a description of the source code origin. The +@code{origin} record contains these fields: + +@enumerate +@item The method, here @code{url-fetch} to download via HTTP/FTP, but other methods + exist, such as @code{git-fetch} for Git repositories. +@item The URI, which is typically some @code{https://} location for @code{url-fetch}. Here + the special `mirror://gnu` refers to a set of well known locations, all of + which can be used by Guix to fetch the source, should some of them fail. +@item The @code{sha256} checksum of the requested file. This is essential to ensure + the source is not corrupted. Note that Guix works with base32 strings, + hence the call to the @code{base32} function. +@end enumerate + +@item build-system + +This is where the power of abstraction provided by the Scheme language really +shines: in this case, the @code{gnu-build-system} abstracts away the famous +@code{./configure && make && make install} shell invocations. Other build +systems include the @code{trivial-build-system} which does not do anything and +requires from the packager to program all the build steps, the +@code{python-build-system}, the @code{emacs-build-system}, and many more +(@pxref{Build Systems,,, guix, GNU Guix Reference Manual}). + +@item synopsis +It should be a concise summary of what the package does. For many packages a +tagline from the project's home page can be used as the synopsis. + +@item description +Same as for the synopsis, it's fine to re-use the project description from the +homepage. Note that Guix uses Texinfo syntax. + +@item home-page +Use HTTPS if available. + +@item license +See @code{guix/licenses.scm} in the project source for a full list of +available licenses. +@end table + +Time to build our first package! Nothing fancy here for now: we will stick to a +dummy "my-hello", a copy of the above declaration. + +As with the ritualistic "Hello World" taught with most programming languages, +this will possibly be the most "manual" approach. We will work out an ideal +setup later; for now we will go the simplest route. + +Save the following to a file @file{my-hello.scm}. + +@example scheme +(use-modules (guix packages) + (guix download) + (guix build-system gnu) + (guix licenses)) + +(package + (name "my-hello") + (version "2.10") + (source (origin + (method url-fetch) + (uri (string-append "mirror://gnu/hello/hello-" version + ".tar.gz")) + (sha256 + (base32 + "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i")))) + (build-system gnu-build-system) + (synopsis "Hello, Guix world: An example custom Guix package") + (description + "GNU Hello prints the message \"Hello, world!\" and then exits. It +serves as an example of standard GNU coding practices. As such, it supports +command-line arguments, multiple languages, and so on.") + (home-page "https://www.gnu.org/software/hello/") + (license gpl3+)) +@end example + +We will explain the extra code in a moment. + +Feel free to play with the different values of the various fields. If you +change the source, you'll need to update the checksum. Indeed, Guix refuses to +build anything if the given checksum does not match the computed checksum of the +source code. To obtain the correct checksum of the package declaration, we +need to download the source, compute the sha256 checksum and convert it to +base32. + +Thankfully, Guix can automate this task for us; all we need is to provide the +URI: + +@c TRANSLATORS: This is example shell output. +@example sh +$ guix download mirror://gnu/hello/hello-2.10.tar.gz + +Starting download of /tmp/guix-file.JLYgL7 +From https://ftpmirror.gnu.org/gnu/hello/hello-2.10.tar.gz... +following redirection to `https://mirror.ibcp.fr/pub/gnu/hello/hello-2.10.tar.gz'... + …10.tar.gz 709KiB 2.5MiB/s 00:00 [##################] 100.0% +/gnu/store/hbdalsf5lpf01x4dcknwx6xbn6n5km6k-hello-2.10.tar.gz +0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i +@end example + +In this specific case the output tells us which mirror was chosen. +If the result of the above command is not the same as in the above snippet, +update your @code{my-hello} declaration accordingly. + +Note that GNU package tarballs come with an OpenPGP signature, so you +should definitely check the signature of this tarball with `gpg` to +authenticate it before going further: + +@c TRANSLATORS: This is example shell output. +@example sh +$ guix download mirror://gnu/hello/hello-2.10.tar.gz.sig + +Starting download of /tmp/guix-file.03tFfb +From https://ftpmirror.gnu.org/gnu/hello/hello-2.10.tar.gz.sig... +following redirection to `https://ftp.igh.cnrs.fr/pub/gnu/hello/hello-2.10.tar.gz.sig'... + ….tar.gz.sig 819B 1.2MiB/s 00:00 [##################] 100.0% +/gnu/store/rzs8wba9ka7grrmgcpfyxvs58mly0sx6-hello-2.10.tar.gz.sig +0q0v86n3y38z17rl146gdakw9xc4mcscpk8dscs412j22glrv9jf +$ gpg --verify /gnu/store/rzs8wba9ka7grrmgcpfyxvs58mly0sx6-hello-2.10.tar.gz.sig /gnu/store/hbdalsf5lpf01x4dcknwx6xbn6n5km6k-hello-2.10.tar.gz +gpg: Signature made Sun 16 Nov 2014 01:08:37 PM CET +gpg: using RSA key A9553245FDE9B739 +gpg: Good signature from "Sami Kerola " [unknown] +gpg: aka "Sami Kerola (http://www.iki.fi/kerolasa/) " [unknown] +gpg: WARNING: This key is not certified with a trusted signature! +gpg: There is no indication that the signature belongs to the owner. +Primary key fingerprint: 8ED3 96E3 7E38 D471 A005 30D3 A955 3245 FDE9 B739 +@end example + +You can then happily run + +@c TRANSLATORS: Do not translate this command +@example sh +$ guix package --install-from-file=my-hello.scm +@end example + +You should now have @code{my-hello} in your profile! + +@c TRANSLATORS: Do not translate this command +@example sh +$ guix package --list-installed=my-hello +my-hello 2.10 out +/gnu/store/f1db2mfm8syb8qvc357c53slbvf1g9m9-my-hello-2.10 +@end example + +We've gone as far as we could without any knowledge of Scheme. Before moving +on to more complex packages, now is the right time to brush up on your Scheme +knowledge. @pxref{A Scheme Crash Course} to get up to speed. + +@c TODO: Continue the tutorial + + +@c ********************************************************************* +@node System Configuration +@chapter System Configuration + +Guix offers a flexible language for declaratively configuring your Guix +System. This flexibility can at times be overwhelming. The purpose of this +chapter is to demonstrate some advanced configuration concepts. + +@pxref{System Configuration,,, guix, GNU Guix Reference Manual} for a complete +reference. + +@menu +* Customizing the Kernel:: Creating and using a custom Linux kernel on Guix System. +@end menu + +@node Customizing the Kernel +@section Customizing the Kernel + +Guix is, at its core, a source based distribution with substitutes +(@pxref{Substitutes,,, guix, GNU Guix Reference Manual}), and as such building +packages from their source code is an expected part of regular package +installations and upgrades. Given this starting point, it makes sense that +efforts are made to reduce the amount of time spent compiling packages, and +recent changes and upgrades to the building and distribution of substitutes +continues to be a topic of discussion within Guix. + +The kernel, while not requiring an overabundance of RAM to build, does take a +rather long time on an average machine. The official kernel configuration, as +is the case with many GNU/Linux distributions, errs on the side of +inclusiveness, and this is really what causes the build to take such a long +time when the kernel is built from source. + +The Linux kernel, however, can also just be described as a regular old +package, and as such can be customized just like any other package. The +procedure is a little bit different, although this is primarily due to the +nature of how the package definition is written. + +The @code{linux-libre} kernel package definition is actually a procedure which +creates a package. + +@example scheme +(define* (make-linux-libre version hash supported-systems + #:key + ;; A function that takes an arch and a variant. + ;; See kernel-config for an example. + (extra-version #f) + (configuration-file #f) + (defconfig "defconfig") + (extra-options %default-extra-linux-options) + (patches (list %boot-logo-patch))) + ...) +@end example + +The current @code{linux-libre} package is for the 5.1.x series, and is +declared like this: + +@example scheme +(define-public linux-libre + (make-linux-libre %linux-libre-version + %linux-libre-hash + '("x86_64-linux" "i686-linux" "armhf-linux" "aarch64-linux") + #:patches %linux-libre-5.1-patches + #:configuration-file kernel-config)) +@end example + +Any keys which are not assigned values inherit their default value from the +@code{make-linux-libre} definition. When comparing the two snippets above, +you may notice that the code comment in the first doesn't actually refer to +the @code{#:extra-version} keyword; it is actually for +@code{#:configuration-file}. Because of this, it is not actually easy to +include a custom kernel configuration from the definition, but don't worry, +there are other ways to work with what we do have. + +There are two ways to create a kernel with a custom kernel configuration. The +first is to provide a standard @file{.config} file during the build process by +including an actual @file{.config} file as a native input to our custom +kernel. The following is a snippet from the custom @code{'configure} phase of +the @code{make-linux-libre} package definition: + +@example scheme +(let ((build (assoc-ref %standard-phases 'build)) + (config (assoc-ref (or native-inputs inputs) "kconfig"))) + + ;; Use a custom kernel configuration file or a default + ;; configuration file. + (if config + (begin + (copy-file config ".config") + (chmod ".config" #o666)) + (invoke "make" ,defconfig)) +@end example + +Below is a sample kernel package. The @code{linux-libre} package is nothing +special and can be inherited from and have its fields overridden like any +other package: + +@example scheme +(define-public linux-libre/E2140 + (package + (inherit linux-libre) + (native-inputs + `(("kconfig" ,(local-file "E2140.config")) + ,@@(alist-delete "kconfig" + (package-native-inputs linux-libre)))))) +@end example + +In the same directory as the file defining @code{linux-libre-E2140} is a file +named @file{E2140.config}, which is an actual kernel configuration file. The +@code{defconfig} keyword of @code{make-linux-libre} is left blank here, so the +only kernel configuration in the package is the one which was included in the +@code{native-inputs} field. + +The second way to create a custom kernel is to pass a new value to the +@code{extra-options} keyword of the @code{make-linux-libre} procedure. The +@code{extra-options} keyword works with another function defined right below +it: + +@example scheme +(define %default-extra-linux-options + `(;; https://lists.gnu.org/archive/html/guix-devel/2014-04/msg00039.html + ("CONFIG_DEVPTS_MULTIPLE_INSTANCES" . #t) + ;; Modules required for initrd: + ("CONFIG_NET_9P" . m) + ("CONFIG_NET_9P_VIRTIO" . m) + ("CONFIG_VIRTIO_BLK" . m) + ("CONFIG_VIRTIO_NET" . m) + ("CONFIG_VIRTIO_PCI" . m) + ("CONFIG_VIRTIO_BALLOON" . m) + ("CONFIG_VIRTIO_MMIO" . m) + ("CONFIG_FUSE_FS" . m) + ("CONFIG_CIFS" . m) + ("CONFIG_9P_FS" . m))) + +(define (config->string options) + (string-join (map (match-lambda + ((option . 'm) + (string-append option "=m")) + ((option . #t) + (string-append option "=y")) + ((option . #f) + (string-append option "=n"))) + options) + "\n")) +@end example + +And in the custom configure script from the `make-linux-libre` package: + +@example scheme +;; Appending works even when the option wasn't in the +;; file. The last one prevails if duplicated. +(let ((port (open-file ".config" "a")) + (extra-configuration ,(config->string extra-options))) + (display extra-configuration port) + (close-port port)) + +(invoke "make" "oldconfig")))) +@end example + +So by not providing a configuration-file the @file{.config} starts blank, and +then we write into it the collection of flags that we want. Here's another +custom kernel: + +@example scheme +(define %macbook41-full-config + (append %macbook41-config-options + %filesystems + %efi-support + %emulation + (@@@@ (gnu packages linux) %default-extra-linux-options))) + +(define-public linux-libre-macbook41 + ;; XXX: Access the internal 'make-linux-libre' procedure, which is + ;; private and unexported, and is liable to change in the future. + ((@@@@ (gnu packages linux) make-linux-libre) (@@@@ (gnu packages linux) %linux-libre-version) + (@@@@ (gnu packages linux) %linux-libre-hash) + '("x86_64-linux") + #:extra-version "macbook41" + #:patches (@@@@ (gnu packages linux) %linux-libre-5.1-patches) + #:extra-options %macbook41-config-options)) +@end example + +In the above example @code{%filesystems} is a collection of flags enabling +different filesystem support, @code{%efi-support} enables EFI support and +@code{%emulation} enables a x86_64-linux machine to act in 32-bit mode also. +@code{%default-extra-linux-options} are the ones quoted above, which had to be +added in since they were replaced in the @code{extra-options} keyword. + +This all sounds like it should be doable, but how does one even know which +modules are required for a particular system? Two places that can be helpful +in trying to answer this question is the +@uref{https://wiki.gentoo.org/wiki/Handbook:AMD64/Installation/Kernel, Gentoo +Handbook} and the +@uref{https://www.kernel.org/doc/html/latest/admin-guide/README.html?highlight=localmodconfig, +documentation from the kernel itself}. From the kernel documentation, it +seems that @code{make localmodconfig} is the command we want. + +In order to actually run @code{make localmodconfig} we first need to get and +unpack the kernel source code: + +@example shell +tar xf $(guix build linux-libre --source) +@end example + +Once inside the directory containing the source code run @code{touch .config} +to create an initial, empty @file{.config} to start with. @code{make +localmodconfig} works by seeing what you already have in @file{.config} and +letting you know what you're missing. If the file is blank then you're +missing everything. The next step is to run: + +@example shell +guix environment linux-libre -- make localmodconfig +@end example + +and note the output. Do note that the @file{.config} file is still empty. +The output generally contains two types of warnings. The first start with +"WARNING" and can actually be ignored in our case. The second read: + +@example shell +module pcspkr did not have configs CONFIG_INPUT_PCSPKR +@end example + +For each of these lines, copy the @code{CONFIG_XXXX_XXXX} portion into the +@file{.config} in the directory, and append @code{=m}, so in the end it looks +like this: + +@example shell +CONFIG_INPUT_PCSPKR=m +CONFIG_VIRTIO=m +@end example + +After copying all the configuration options, run @code{make localmodconfig} +again to make sure that you don't have any output starting with "module". +After all of these machine specific modules there are a couple more left that +are also needed. @code{CONFIG_MODULES} is necessary so that you can build and +load modules separately and not have everything built into the kernel. +@code{CONFIG_BLK_DEV_SD} is required for reading from hard drives. It is +possible that there are other modules which you will need. + +This post does not aim to be a guide to configuring your own kernel however, +so if you do decide to build a custom kernel you'll have to seek out other +guides to create a kernel which is just right for your needs. + +The second way to setup the kernel configuration makes more use of Guix's +features and allows you to share configuration segments between different +kernels. For example, all machines using EFI to boot have a number of EFI +configuration flags that they need. It is likely that all the kernels will +share a list of filesystems to support. By using variables it is easier to +see at a glance what features are enabled and to make sure you don't have +features in one kernel but missing in another. + +Left undiscussed however, is Guix's initrd and its customization. It is +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 +available for inclusion into the initrd. + +@c ********************************************************************* +@node Acknowledgments +@chapter Acknowledgments + +Guix is based on the @uref{https://nixos.org/nix/, Nix package manager}, +which was designed and +implemented by Eelco Dolstra, with contributions from other people (see +the @file{nix/AUTHORS} file in Guix.) Nix pioneered functional package +management, and promoted unprecedented features, such as transactional +package upgrades and rollbacks, per-user profiles, and referentially +transparent build processes. Without this work, Guix would not exist. + +The Nix-based software distributions, Nixpkgs and NixOS, have also been +an inspiration for Guix. + +GNU@tie{}Guix itself is a collective work with contributions from a +number of people. See the @file{AUTHORS} file in Guix for more +information on these fine people. The @file{THANKS} file lists people +who have helped by reporting bugs, taking care of the infrastructure, +providing artwork and themes, making suggestions, and more---thank you! + +This document includes adapted sections from articles that have previously +been published on the Guix blog at @uref{https://guix.gnu.org/blog}. + + +@c ********************************************************************* +@node GNU Free Documentation License +@appendix GNU Free Documentation License +@cindex license, GNU Free Documentation License +@include fdl-1.3.texi + +@c ********************************************************************* +@node Concept Index +@unnumbered Concept Index +@printindex cp + +@bye + +@c Local Variables: +@c ispell-local-dictionary: "american"; +@c End: diff --git a/doc/local.mk b/doc/local.mk index 336e961c4f..850612605b 100644 --- a/doc/local.mk +++ b/doc/local.mk @@ -26,7 +26,8 @@ info_TEXINFOS = %D%/guix.texi \ %D%/guix.es.texi \ %D%/guix.fr.texi \ %D%/guix.ru.texi \ - %D%/guix.zh_CN.texi + %D%/guix.zh_CN.texi \ + %D%/guix-cookbook.texi %C%_guix_TEXINFOS = \ %D%/contributing.texi \ @@ -108,6 +109,12 @@ $(srcdir)/%D%/guix.%.texi: po/doc/guix-manual.%.po $(srcdir)/%D%/contributing.%. -$(AM_V_POXREF)$(xref_command) -mv "$@.tmp" "$@" +$(srcdir)/%D%/guix-cookbook.%.texi: po/doc/guix-cookbook.%.po + -$(AM_V_PO4A)$(PO4A_TRANSLATE) $(PO4A_PARAMS) -m "%D%/guix-cookbook.texi" -p "$<" -l "$@.tmp" + -sed -i "s|guix-cookbook\.info|$$(basename "$@" | sed 's|texi$$|info|')|" "$@.tmp" + -$(AM_V_POXREF)$(xref_command) + -mv "$@.tmp" "$@" + $(srcdir)/%D%/contributing.%.texi: po/doc/guix-manual.%.po -$(AM_V_PO4A)$(PO4A_TRANSLATE) $(PO4A_PARAMS) -m "%D%/contributing.texi" -p "$<" -l "$@.tmp" -$(AM_V_POXREF)$(xref_command) -- cgit v1.2.3 From 3c4f5ad7f403cc5ff0524d62a8612b0decaeaeb8 Mon Sep 17 00:00:00 2001 From: 宋文武 Date: Fri, 13 Sep 2019 17:53:59 +0800 Subject: services: Add nftables-service-type. * gnu/services/networking.scm (%default-nftables-ruleset): New variable. (): New record type. (nftables-shepherd-service): New procedure. (nftables-service-type): New service type. * doc/guix.texi (Networking Services): Document it. --- doc/guix.texi | 27 +++++++++++++++ gnu/services/networking.scm | 82 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 108 insertions(+), 1 deletion(-) (limited to 'doc') diff --git a/doc/guix.texi b/doc/guix.texi index 55935b3794..666ecb5b47 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -13041,6 +13041,33 @@ objects}). @end table @end deftp +@cindex nftables +@defvr {Scheme Variable} nftables-service-type +This is the service type to set up a nftables configuration. nftables is a +netfilter project that aims to replace the existing iptables, ip6tables, +arptables and ebtables framework. It provides a new packet filtering +framework, a new user-space utility @command{nft}, and a compatibility layer +for iptables. This service comes with a default ruleset +@code{%default-nftables-ruleset} that rejecting all incomming connections +except those to the ssh port 22. To use it, simply write: + +@lisp +(service nftables-service-type) +@end lisp +@end defvr + +@deftp {Data Type} nftables-configuration +The data type representing the configuration of nftables. + +@table @asis +@item @code{package} (default: @code{nftables}) +The nftables package that provides @command{nft}. +@item @code{ruleset} (default: @code{%default-nftables-ruleset}) +The nftables ruleset to use. This may be any ``file-like'' object +(@pxref{G-Expressions, file-like objects}). +@end table +@end deftp + @cindex NTP (Network Time Protocol), service @cindex ntpd, service for the Network Time Protocol daemon @cindex real time clock diff --git a/gnu/services/networking.scm b/gnu/services/networking.scm index c775242f99..dd63009116 100644 --- a/gnu/services/networking.scm +++ b/gnu/services/networking.scm @@ -11,6 +11,7 @@ ;;; Copyright © 2018 Arun Isaac ;;; Copyright © 2019 Florian Pelz ;;; Copyright © 2019 Maxim Cournoyer +;;; Copyright © 2019 Sou Bunnbu ;;; ;;; This file is part of GNU Guix. ;;; @@ -144,7 +145,14 @@ (define-module (gnu services networking) iptables-configuration-iptables iptables-configuration-ipv4-rules iptables-configuration-ipv6-rules - iptables-service-type)) + iptables-service-type + + nftables-service-type + nftables-configuration + nftables-configuration? + nftables-configuration-package + nftables-configuration-ruleset + %default-nftables-ruleset)) ;;; Commentary: ;;; @@ -1415,4 +1423,76 @@ (define iptables-service-type (list (service-extension shepherd-root-service-type (compose list iptables-shepherd-service)))))) +;;; +;;; nftables +;;; + +(define %default-nftables-ruleset + (plain-file "nftables.conf" + "# A simple and safe firewall +table inet filter { + chain input { + type filter hook input priority 0; policy drop; + + # early drop of invalid connections + ct state invalid drop + + # allow established/related connections + ct state { established, related } accept + + # allow from loopback + iifname lo accept + + # allow icmp + ip protocol icmp accept + ip6 nexthdr icmpv6 accept + + # allow ssh + tcp dport ssh accept + + # reject everything else + reject with icmpx type port-unreachable + } + chain forward { + type filter hook forward priority 0; policy drop; + } + chain output { + type filter hook output priority 0; policy accept; + } +} +")) + +(define-record-type* + nftables-configuration + make-nftables-configuration + nftables-configuration? + (package nftables-configuration-package + (default nftables)) + (ruleset nftables-configuration-ruleset ; file-like object + (default %default-nftables-ruleset))) + +(define nftables-shepherd-service + (match-lambda + (($ package ruleset) + (let ((nft (file-append package "/sbin/nft"))) + (shepherd-service + (documentation "Packet filtering and classification") + (provision '(nftables)) + (start #~(lambda _ + (invoke #$nft "--file" #$ruleset))) + (stop #~(lambda _ + (invoke #$nft "flush" "ruleset")))))))) + +(define nftables-service-type + (service-type + (name 'nftables) + (description + "Run @command{nft}, setting up the specified ruleset.") + (extensions + (list (service-extension shepherd-root-service-type + (compose list nftables-shepherd-service)) + (service-extension profile-service-type + (compose list nftables-configuration-package)))) + (default-value (nftables-configuration)))) + ;;; networking.scm ends here -- cgit v1.2.3 From d0980ef41859d1f0e4deb98a7f1d6f4ab2c9d4c4 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Wed, 18 Sep 2019 22:46:21 +0200 Subject: doc: Mention the "repository name" for 'guix pack -f docker'. This is a followup to 0074844366381e3056d09492b8b437836c7adb61. * doc/guix.texi (Invoking guix pack): Mention the repository name. --- doc/guix.texi | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'doc') diff --git a/doc/guix.texi b/doc/guix.texi index 666ecb5b47..da62194a16 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -4835,7 +4835,9 @@ specified binaries and symlinks. @item docker This produces a tarball that follows the @uref{https://github.com/docker/docker/blob/master/image/spec/v1.2.md, -Docker Image Specification}. +Docker Image Specification}. The ``repository name'' as it appears in +the output of the @command{docker images} command is computed from +package names passed on the command line or in the manifest file. @item squashfs This produces a SquashFS image containing all the specified binaries and -- cgit v1.2.3 From da551107129d22dfb2a4278a55b702a7340e7f51 Mon Sep 17 00:00:00 2001 From: Konrad Hinsen Date: Wed, 18 Sep 2019 09:52:18 +0200 Subject: scripts: pull: Add options for generation management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * guix/scripts/pull.scm (%options) Add --roll-back, --switch-generation, --delete-generations (process-generation-change): New function (guix-pull): Execute generation management operations * doc/guix.texi: Document the generation management operations Signed-off-by: Ludovic Courtès --- doc/guix.texi | 47 +++++++++++++++++++++++++++++++++++++++++++++-- guix/scripts/pull.scm | 41 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 85 insertions(+), 3 deletions(-) (limited to 'doc') diff --git a/doc/guix.texi b/doc/guix.texi index da62194a16..0ed59072c9 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -3673,11 +3673,20 @@ Generation 3 Jun 13 2018 23:31:07 (current) @xref{Invoking guix describe, @command{guix describe}}, for other ways to describe the current status of Guix. -This @code{~/.config/guix/current} profile works like any other profile -created by @command{guix package} (@pxref{Invoking guix package}). That +This @code{~/.config/guix/current} profile works exactly like the profiles +created by @command{guix package} (@pxref{Invoking guix package}). That is, you can list generations, roll back to the previous generation---i.e., the previous Guix---and so on: +@example +$ guix pull --roll-back +switched from generation 3 to 2 +$ guix pull --delete-generations=1 +deleting /var/guix/profiles/per-user/charlie/current-guix-1-link +@end example + +You can also use @command{guix package} (@pxref{Invoking guix package}) +to manage the profile by naming it explicitly: @example $ guix package -p ~/.config/guix/current --roll-back switched from generation 3 to 2 @@ -3724,6 +3733,40 @@ is provided, the subset of generations that match @var{pattern}. The syntax of @var{pattern} is the same as with @code{guix package --list-generations} (@pxref{Invoking guix package}). +@item --roll-back +@cindex rolling back +@cindex undoing transactions +@cindex transactions, undoing +Roll back to the previous @dfn{generation} of @file{~/.config/guix/current}---i.e., +undo the last transaction. + +@item --switch-generation=@var{pattern} +@itemx -S @var{pattern} +@cindex generations +Switch to a particular generation defined by @var{pattern}. + +@var{pattern} may be either a generation number or a number prefixed +with ``+'' or ``-''. The latter means: move forward/backward by a +specified number of generations. For example, if you want to return to +the latest generation after @code{--roll-back}, use +@code{--switch-generation=+1}. + +@item --delete-generations[=@var{pattern}] +@itemx -d [@var{pattern}] +When @var{pattern} is omitted, delete all generations except the current +one. + +This command accepts the same patterns as @option{--list-generations}. +When @var{pattern} is specified, delete the matching generations. When +@var{pattern} specifies a duration, generations @emph{older} than the +specified duration match. For instance, @code{--delete-generations=1m} +deletes generations that are more than one month old. + +If the current generation matches, it is @emph{not} deleted. + +Note that deleting generations prevents rolling back to them. +Consequently, this command must be used with care. + @xref{Invoking guix describe}, for a way to display information about the current generation only. diff --git a/guix/scripts/pull.scm b/guix/scripts/pull.scm index 4b03cea2e3..c9835cef34 100644 --- a/guix/scripts/pull.scm +++ b/guix/scripts/pull.scm @@ -38,7 +38,8 @@ (define-module (guix scripts pull) #:use-module (guix git) #:use-module (git) #:use-module (gnu packages) - #:use-module ((guix scripts package) #:select (build-and-use-profile)) + #:use-module ((guix scripts package) #:select (build-and-use-profile + delete-matching-generations)) #:use-module ((gnu packages base) #:select (canonical-package)) #:use-module (gnu packages guile) #:use-module ((gnu packages bootstrap) @@ -91,6 +92,14 @@ (define (show-help) (display (G_ " -l, --list-generations[=PATTERN] list generations matching PATTERN")) + (display (G_ " + --roll-back roll back to the previous generation")) + (display (G_ " + -d, --delete-generations[=PATTERN] + delete generations matching PATTERN")) + (display (G_ " + -S, --switch-generation=PATTERN + switch to a generation matching PATTERN")) (display (G_ " -p, --profile=PROFILE use PROFILE instead of ~/.config/guix/current")) (display (G_ " @@ -120,6 +129,18 @@ (define %options (lambda (opt name arg result) (cons `(query list-generations ,arg) result))) + (option '("roll-back") #f #f + (lambda (opt name arg result) + (cons '(generation roll-back) + result))) + (option '(#\S "switch-generation") #t #f + (lambda (opt name arg result) + (cons `(generation switch ,arg) + result))) + (option '(#\d "delete-generations") #f #t + (lambda (opt name arg result) + (cons `(generation delete ,arg) + result))) (option '(#\N "news") #f #f (lambda (opt name arg result) (cons '(query display-news) result))) @@ -505,6 +526,22 @@ (define (list-generations profile numbers) (display-profile-news profile #:current-is-newer? #t)))) +(define (process-generation-change opts profile) + "Process a request to change the current generation (roll-back, switch, delete)." + (unless (assoc-ref opts 'dry-run?) + (match (assoc-ref opts 'generation) + (('roll-back) + (with-store store + (roll-back* store profile))) + (('switch pattern) + (let ((number (relative-generation-spec->number profile pattern))) + (if number + (switch-to-generation* profile number) + (leave (G_ "cannot switch to generation '~a'~%") pattern)))) + (('delete pattern) + (with-store store + (delete-matching-generations store profile pattern)))))) + (define (channel-list opts) "Return the list of channels to use. If OPTS specify a channel file, channels are read from there; otherwise, if ~/.config/guix/channels.scm @@ -572,6 +609,8 @@ (define (guix-pull . args) (profile (or (assoc-ref opts 'profile) %current-profile))) (cond ((assoc-ref opts 'query) (process-query opts profile)) + ((assoc-ref opts 'generation) + (process-generation-change opts profile)) (else (with-store store (ensure-default-profile) -- cgit v1.2.3 From aeb51370da7c854e8167066df9b138e15d7363e6 Mon Sep 17 00:00:00 2001 From: zimoun Date: Thu, 19 Sep 2019 19:24:42 +0200 Subject: guix package: Add 'guix show' alias. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * guix/scripts/show.scm: New file. * Makefile.am (MODULES): Add it. * po/guix/POTFILES.in: Add it. * tests/guix-package-aliases.sh: Add test. * doc/guix.texi (Invoking guix package): Document it and use it in a example. Signed-off-by: Ludovic Courtès --- Makefile.am | 1 + doc/guix.texi | 8 ++++-- guix/scripts/show.scm | 67 +++++++++++++++++++++++++++++++++++++++++++ po/guix/POTFILES.in | 1 + tests/guix-package-aliases.sh | 4 +++ 5 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 guix/scripts/show.scm (limited to 'doc') diff --git a/Makefile.am b/Makefile.am index 93d18d7df6..f71ea77671 100644 --- a/Makefile.am +++ b/Makefile.am @@ -241,6 +241,7 @@ MODULES = \ guix/scripts/remove.scm \ guix/scripts/upgrade.scm \ guix/scripts/search.scm \ + guix/scripts/show.scm \ guix/scripts/gc.scm \ guix/scripts/hash.scm \ guix/scripts/pack.scm \ diff --git a/doc/guix.texi b/doc/guix.texi index 0ed59072c9..af1903f6ff 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -2657,7 +2657,9 @@ For your convenience, we also provide the following aliases: @item @command{guix remove} is an alias for @command{guix package -r}, @item -and @command{guix upgrade} is an alias for @command{guix package -u}. +@command{guix upgrade} is an alias for @command{guix package -u}, +@item +and @command{guix show} is an alias for @command{guix package --show=}. @end itemize These aliases are less expressive than @command{guix package} and provide @@ -3020,9 +3022,9 @@ version: 3.3.5 @end example You may also specify the full name of a package to only get details about a -specific version of it: +specific version of it (this time using the @command{guix show} alias): @example -$ guix package --show=python@@3.4 | recsel -p name,version +$ guix show python@@3.4 | recsel -p name,version name: python version: 3.4.3 @end example diff --git a/guix/scripts/show.scm b/guix/scripts/show.scm new file mode 100644 index 0000000000..94f0559358 --- /dev/null +++ b/guix/scripts/show.scm @@ -0,0 +1,67 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2019 Simon Tournier +;;; +;;; 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 show) + #:use-module (guix ui) + #:use-module (guix scripts package) + #:use-module (guix scripts) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26) + #:use-module (srfi srfi-37) + #:export (guix-show)) + +(define (show-help) + (display (G_ "Usage: guix show [OPTION] PACKAGE... +Show details about PACKAGE.")) + (display (G_" +This is an alias for 'guix package --show='.\n")) + (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 %options + ;; Specification of the command-line options. + (list (option '(#\h "help") #f #f + (lambda args + (show-help) + (exit 0))) + (option '(#\V "version") #f #f + (lambda args + (show-version-and-exit "guix show"))))) + +(define (guix-show . args) + (define (handle-argument arg result) + ;; Treat all non-option arguments as regexps. + (cons `(query show ,arg) + result)) + + (define opts + (args-fold* args %options + (lambda (opt name arg . rest) + (leave (G_ "~A: unrecognized option~%") name)) + handle-argument + '())) + + (unless (assoc-ref opts 'query) + (leave (G_ "missing arguments: no package to show~%"))) + + (guix-package* opts)) diff --git a/po/guix/POTFILES.in b/po/guix/POTFILES.in index 8b556ac0ec..f629034d61 100644 --- a/po/guix/POTFILES.in +++ b/po/guix/POTFILES.in @@ -47,6 +47,7 @@ guix/scripts/install.scm guix/scripts/remove.scm guix/scripts/upgrade.scm guix/scripts/search.scm +guix/scripts/show.scm guix/scripts/gc.scm guix/scripts/hash.scm guix/scripts/import.scm diff --git a/tests/guix-package-aliases.sh b/tests/guix-package-aliases.sh index 5c68664093..9c038b99a5 100644 --- a/tests/guix-package-aliases.sh +++ b/tests/guix-package-aliases.sh @@ -58,3 +58,7 @@ if guix remove -i guile-bootstrap -p "$profile" --bootstrap then false; else true; fi guix search '\' game | grep '^name: gnubg' + +guix show --version +guix show guile +guix show python@3 | grep "^name: python" -- cgit v1.2.3 From 8ba7fd3cd6962f1c1aaaa5f71eed7f9222094f25 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Sat, 14 Sep 2019 23:16:54 +0200 Subject: channels: Add support for a news file. * guix/channels.scm ()[news-file]: New field. (read-channel-metadata): Set the 'news-file' field. (read-channel-metadata-from-source): Likewise. (, ): New record types. (sexp->channel-news-entry, read-channel-news) (channel-news-for-commit): New procedures. * guix/tests/git.scm (populate-git-repository): For 'add', allow CONTENTS to be a procedure. * tests/channels.scm ("channel-news, no news") ("channel-news, one entry"): New tests. * doc/guix.texi (Channels): Document it. --- doc/guix.texi | 62 +++++++++++++++++++++++++++ guix/channels.scm | 123 +++++++++++++++++++++++++++++++++++++++++++++++++---- guix/tests/git.scm | 7 ++- tests/channels.scm | 99 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 282 insertions(+), 9 deletions(-) (limited to 'doc') diff --git a/doc/guix.texi b/doc/guix.texi index af1903f6ff..cd108faa8f 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -3991,6 +3991,68 @@ add a meta-data file @file{.guix-channel} that contains: (directory "guix")) @end lisp +@cindex news, for channels +@subsection Writing Channel News + +Channel authors may occasionally want to communicate to their users +information about important changes in the channel. You'd send them all +an email, but that's not convenient. + +Instead, channels can provide a @dfn{news file}; when the channel users +run @command{guix pull}, that news file is automatically read and +@command{guix pull --news} can display the announcements that correspond +to the new commits that have been pulled, if any. + +To do that, channel authors must first declare the name of the news file +in their @file{.guix-channel} file: + +@lisp +(channel + (version 0) + (news-file "etc/news.txt")) +@end lisp + +The news file itself, @file{etc/news.txt} in this example, must look +something like this: + +@lisp +(channel-news + (version 0) + (entry (commit "d894ab8e9bfabcefa6c49d9ba2e834dd5a73a300") + (title (en "Fixed terrible bug") + (fr "Oh la la")) + (body (en "@@emph@{Good news@}! It's fixed!") + (eo "Certe ĝi pli bone funkcias nun!"))) + (entry (commit "bdcabe815cd28144a2d2b4bc3c5057b051fa9906") + (title (en "Added a great package") + (ca "Què vol dir guix?")) + (body (en "Don't miss the @@code@{hello@} package!")))) +@end lisp + +The file consists of a list of @dfn{news entries}. Each entry is +associated with a commit: it describes changes made in this commit, +possibly in preceding commits as well. Users see entries only the first +time they obtain the commit the entry refers to. + +The @code{title} field should be a one-line summary while @code{body} +can be arbitrarily long, and both can contain Texinfo markup +(@pxref{Overview,,, texinfo, GNU Texinfo}). Both the title and body are +a list of language tag/message tuples, which allows @command{guix pull} +to display news in the language that corresponds to the user's locale. + +If you want to translate news using a gettext-based workflow, you can +extract translatable strings with @command{xgettext} (@pxref{xgettext +Invocation,,, gettext, GNU Gettext Utilities}). For example, assuming +you write news entries in English first, the command below creates a PO +file containing the strings to translate: + +@example +xgettext -o news.po -l scheme -ken etc/news.scm +@end example + +To sum up, yes, you could use your channel as a blog. But beware, this +is @emph{not quite} what your users might expect. + @subsection Replicating Guix @cindex pinning, channels diff --git a/guix/channels.scm b/guix/channels.scm index ebb2cacbc7..0dadba616f 100644 --- a/guix/channels.scm +++ b/guix/channels.scm @@ -19,6 +19,7 @@ ;;; along with GNU Guix. If not, see . (define-module (guix channels) + #:use-module (git) #:use-module (guix git) #:use-module (guix records) #:use-module (guix gexp) @@ -29,6 +30,7 @@ (define-module (guix channels) #:use-module (guix derivations) #:use-module (guix combinators) #:use-module (guix diagnostics) + #:use-module (guix sets) #:use-module (guix store) #:use-module (guix i18n) #:use-module ((guix utils) @@ -67,7 +69,14 @@ (define-module (guix channels) %channel-profile-hooks channel-instances->derivation - profile-channels)) + profile-channels + + channel-news-entry? + channel-news-entry-commit + channel-news-entry-title + channel-news-entry-body + + channel-news-for-commit)) ;;; Commentary: ;;; @@ -110,10 +119,11 @@ (define-record-type (checkout channel-instance-checkout)) (define-record-type - (channel-metadata directory dependencies) + (channel-metadata directory dependencies news-file) channel-metadata? (directory channel-metadata-directory) ;string with leading slash - (dependencies channel-metadata-dependencies)) ;list of + (dependencies channel-metadata-dependencies) ;list of + (news-file channel-metadata-news-file)) ;string | #f (define (channel-reference channel) "Return the \"reference\" for CHANNEL, an sexp suitable for @@ -129,12 +139,13 @@ (define (read-channel-metadata port) (match (read port) (('channel ('version 0) properties ...) (let ((directory (and=> (assoc-ref properties 'directory) first)) - (dependencies (or (assoc-ref properties 'dependencies) '()))) + (dependencies (or (assoc-ref properties 'dependencies) '())) + (news-file (and=> (assoc-ref properties 'news-file) first))) (channel-metadata - (cond ((not directory) "/") + (cond ((not directory) "/") ;directory ((string-prefix? "/" directory) directory) (else (string-append "/" directory))) - (map (lambda (item) + (map (lambda (item) ;dependencies (let ((get (lambda* (key #:optional default) (or (and=> (assoc-ref item key) first) default)))) (and-let* ((name (get 'name)) @@ -145,7 +156,8 @@ (define (read-channel-metadata port) (branch branch) (url url) (commit (get 'commit)))))) - dependencies)))) + dependencies) + news-file))) ;news-file ((and ('channel ('version version) _ ...) sexp) (raise (condition (&message (message "unsupported '.guix-channel' version")) @@ -169,7 +181,7 @@ (define (read-channel-metadata-from-source source) read-channel-metadata)) (lambda args (if (= ENOENT (system-error-errno args)) - (channel-metadata "/" '()) + (channel-metadata "/" '() #f) (apply throw args))))) (define (channel-instance-metadata instance) @@ -560,3 +572,98 @@ (define (profile-channels profile) ;; Show most recently installed packages last. (reverse (manifest-entries (profile-manifest profile))))) + + +;;; +;;; News. +;;; + +;; Channel news. +(define-record-type + (channel-news entries) + channel-news? + (entries channel-news-entries)) ;list of + +;; News entry, associated with a specific commit of the channel. +(define-record-type + (channel-news-entry commit title body) + channel-news-entry? + (commit channel-news-entry-commit) ;hex string + (title channel-news-entry-title) ;list of language tag/string pairs + (body channel-news-entry-body)) ;list of language tag/string pairs + +(define (sexp->channel-news-entry entry) + "Return the record corresponding to ENTRY, an sexp." + (define (pair language message) + (cons (symbol->string language) message)) + + (match entry + (('entry ('commit commit) + ('title ((? symbol? title-tags) (? string? titles)) ...) + ('body ((? symbol? body-tags) (? string? bodies)) ...) + _ ...) + (channel-news-entry commit + (map pair title-tags titles) + (map pair body-tags bodies))) + (_ + (raise (condition + (&message (message "invalid channel news entry")) + (&error-location + (location (source-properties->location + (source-properties entry))))))))) + +(define (read-channel-news port) + "Read a channel news feed from PORT and return it as a +record." + (match (false-if-exception (read port)) + (('channel-news ('version 0) entries ...) + (channel-news (map sexp->channel-news-entry entries))) + (('channel-news ('version version) _ ...) + ;; This is an unsupported version from the future. There's nothing wrong + ;; with that (the user may simply need to upgrade the 'guix' channel to + ;; be able to read it), so silently ignore it. + (channel-news '())) + (#f + (raise (condition + (&message (message "syntactically invalid channel news file"))))) + (sexp + (raise (condition + (&message (message "invalid channel news file")) + (&error-location + (location (source-properties->location + (source-properties sexp))))))))) + +(define* (channel-news-for-commit channel new #:optional old) + "Return a list of for CHANNEL between commits OLD and +NEW. When OLD is omitted or is #f, return all the news entries of CHANNEL." + (catch 'git-error + (lambda () + (let* ((checkout (update-cached-checkout (channel-url channel) + #:ref `(commit . ,new))) + (metadata (read-channel-metadata-from-source checkout)) + (news-file (channel-metadata-news-file metadata)) + (news-file (and news-file + (string-append checkout "/" news-file)))) + (if (and news-file (file-exists? news-file)) + (let ((entries (channel-news-entries (call-with-input-file news-file + read-channel-news)))) + (if old + (with-repository checkout repository + (let* ((new (commit-lookup repository (string->oid new))) + (old (commit-lookup repository (string->oid old))) + (commits (list->set + (map (compose oid->string commit-id) + (commit-difference new old))))) + (filter (lambda (entry) + (set-contains? commits + (channel-news-entry-commit entry))) + entries))) + entries)) + '()))) + (lambda (key error . rest) + ;; If commit NEW or commit OLD cannot be found, then something must be + ;; wrong (for example, the history of CHANNEL was rewritten and these + ;; commits no longer exist upstream), so quietly return the empty list. + (if (= GIT_ENOTFOUND (git-error-code error)) + '() + (apply throw key error rest))))) diff --git a/guix/tests/git.scm b/guix/tests/git.scm index 52abe77c83..9d5b1ae321 100644 --- a/guix/tests/git.scm +++ b/guix/tests/git.scm @@ -18,6 +18,7 @@ (define-module (guix tests git) #:use-module (git) + #:use-module ((guix git) #:select (with-repository)) #:use-module (guix utils) #:use-module (guix build utils) #:use-module (ice-9 match) @@ -55,7 +56,11 @@ (define (git command . args) (mkdir-p (dirname file)) (call-with-output-file file (lambda (port) - (display contents port))) + (display (if (string? contents) + contents + (with-repository directory repository + (contents repository))) + port))) (git "add" file) (loop rest))) ((('commit text) rest ...) diff --git a/tests/channels.scm b/tests/channels.scm index e83b5437d3..58101bcb72 100644 --- a/tests/channels.scm +++ b/tests/channels.scm @@ -28,6 +28,10 @@ (define-module (test-channels) #:use-module (guix gexp) #:use-module ((guix utils) #:select (error-location? error-location location-line)) + #:use-module ((guix build utils) #:select (which)) + #:use-module (git) + #:use-module (guix git) + #:use-module (guix tests git) #:use-module (srfi srfi-1) #:use-module (srfi srfi-26) #:use-module (srfi srfi-34) @@ -246,4 +250,99 @@ (define (lookup name) (depends? drv3 (list drv2 drv0) (list)))))))) +(unless (which (git-command)) (test-skip 1)) +(test-equal "channel-news, no news" + '() + (with-temporary-git-repository directory + '((add "a.txt" "A") + (commit "the commit")) + (with-repository directory repository + (let ((channel (channel (url (string-append "file://" directory)) + (name 'foo))) + (latest (reference-name->oid repository "HEAD"))) + (channel-news-for-commit channel (oid->string latest)))))) + +(unless (which (git-command)) (test-skip 1)) +(test-assert "channel-news, one entry" + (with-temporary-git-repository directory + `((add ".guix-channel" + ,(object->string + '(channel (version 0) + (news-file "news.scm")))) + (commit "first commit") + (add "src/a.txt" "A") + (commit "second commit") + (add "news.scm" + ,(lambda (repository) + (let ((previous + (reference-name->oid repository "HEAD"))) + (object->string + `(channel-news + (version 0) + (entry (commit ,(oid->string previous)) + (title (en "New file!") + (eo "Nova dosiero!")) + (body (en "Yeah, a.txt.")))))))) + (commit "third commit") + (add "src/b.txt" "B") + (commit "fourth commit") + (add "news.scm" + ,(lambda (repository) + (let ((second + (commit-id + (find-commit repository "second commit"))) + (previous + (reference-name->oid repository "HEAD"))) + (object->string + `(channel-news + (version 0) + (entry (commit ,(oid->string previous)) + (title (en "Another file!")) + (body (en "Yeah, b.txt."))) + (entry (commit ,(oid->string second)) + (title (en "Old news.") + (eo "Malnovaĵoj.")) + (body (en "For a.txt")))))))) + (commit "fifth commit")) + (with-repository directory repository + (define (find-commit* message) + (oid->string (commit-id (find-commit repository message)))) + + (let ((channel (channel (url (string-append "file://" directory)) + (name 'foo))) + (commit1 (find-commit* "first commit")) + (commit2 (find-commit* "second commit")) + (commit3 (find-commit* "third commit")) + (commit4 (find-commit* "fourth commit")) + (commit5 (find-commit* "fifth commit"))) + ;; First try fetching all the news up to a given commit. + (and (null? (channel-news-for-commit channel commit2)) + (lset= string=? + (map channel-news-entry-commit + (channel-news-for-commit channel commit5)) + (list commit2 commit4)) + (lset= equal? + (map channel-news-entry-title + (channel-news-for-commit channel commit5)) + '((("en" . "Another file!")) + (("en" . "Old news.") ("eo" . "Malnovaĵoj.")))) + (lset= string=? + (map channel-news-entry-commit + (channel-news-for-commit channel commit3)) + (list commit2)) + + ;; Now fetch news entries that apply to a commit range. + (lset= string=? + (map channel-news-entry-commit + (channel-news-for-commit channel commit3 commit1)) + (list commit2)) + (lset= string=? + (map channel-news-entry-commit + (channel-news-for-commit channel commit5 commit3)) + (list commit4)) + (lset= string=? + (map channel-news-entry-commit + (channel-news-for-commit channel commit5 commit1)) + (list commit4 commit2))))))) + (test-end "channels") -- cgit v1.2.3 From 9719e8d37aaa63e1c8f9d4ab1e28d49e2e56d85b Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Sat, 21 Sep 2019 21:29:30 +0200 Subject: channels: Allow news entries to refer to a tag. Suggested by Ricardo Wurmus . * guix/channels.scm ()[tag]: New field. (sexp->channel-news-entry): Accept either 'commit' or 'tag' in 'entry' forms. (resolve-channel-news-entry-tag): New procedure. (channel-news-for-commit): Move 'with-repository' form one level higher. Call 'resolve-channel-news-entry-tag' on all the news entries. * guix/tests/git.scm (populate-git-repository): Add clause for 'tag'. * tests/channels.scm ("channel-news, one entry"): Create a tag and add an entry with a tag. Check that the tag is resolved and also visible in the record. * doc/guix.texi (Channels): Mention tags in news entries. --- doc/guix.texi | 8 ++++---- guix/channels.scm | 42 ++++++++++++++++++++++++++++++++---------- guix/tests/git.scm | 3 +++ tests/channels.scm | 9 +++++++-- 4 files changed, 46 insertions(+), 16 deletions(-) (limited to 'doc') diff --git a/doc/guix.texi b/doc/guix.texi index cd108faa8f..33bf08e9dd 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -4018,7 +4018,7 @@ something like this: @lisp (channel-news (version 0) - (entry (commit "d894ab8e9bfabcefa6c49d9ba2e834dd5a73a300") + (entry (tag "the-bug-fix") (title (en "Fixed terrible bug") (fr "Oh la la")) (body (en "@@emph@{Good news@}! It's fixed!") @@ -4030,9 +4030,9 @@ something like this: @end lisp The file consists of a list of @dfn{news entries}. Each entry is -associated with a commit: it describes changes made in this commit, -possibly in preceding commits as well. Users see entries only the first -time they obtain the commit the entry refers to. +associated with a commit or tag: it describes changes made in this +commit, possibly in preceding commits as well. Users see entries only +the first time they obtain the commit the entry refers to. The @code{title} field should be a one-line summary while @code{body} can be arbitrarily long, and both can contain Texinfo markup diff --git a/guix/channels.scm b/guix/channels.scm index 0dadba616f..4e6e7090ac 100644 --- a/guix/channels.scm +++ b/guix/channels.scm @@ -40,6 +40,7 @@ (define-module (guix channels) #:use-module (srfi srfi-2) #:use-module (srfi srfi-9) #:use-module (srfi srfi-11) + #:use-module (srfi srfi-26) #:use-module (srfi srfi-34) #:use-module (srfi srfi-35) #:autoload (guix self) (whole-package make-config.scm) @@ -73,6 +74,7 @@ (define-module (guix channels) channel-news-entry? channel-news-entry-commit + channel-news-entry-tag channel-news-entry-title channel-news-entry-body @@ -586,9 +588,10 @@ (define-record-type ;; News entry, associated with a specific commit of the channel. (define-record-type - (channel-news-entry commit title body) + (channel-news-entry commit tag title body) channel-news-entry? - (commit channel-news-entry-commit) ;hex string + (commit channel-news-entry-commit) ;hex string | #f + (tag channel-news-entry-tag) ;#f | string (title channel-news-entry-title) ;list of language tag/string pairs (body channel-news-entry-body)) ;list of language tag/string pairs @@ -598,11 +601,12 @@ (define (pair language message) (cons (symbol->string language) message)) (match entry - (('entry ('commit commit) + (('entry ((and (or 'commit 'tag) type) commit-or-tag) ('title ((? symbol? title-tags) (? string? titles)) ...) ('body ((? symbol? body-tags) (? string? bodies)) ...) _ ...) - (channel-news-entry commit + (channel-news-entry (and (eq? type 'commit) commit-or-tag) + (and (eq? type 'tag) commit-or-tag) (map pair title-tags titles) (map pair body-tags bodies))) (_ @@ -633,6 +637,20 @@ (define (read-channel-news port) (location (source-properties->location (source-properties sexp))))))))) +(define (resolve-channel-news-entry-tag repository entry) + "If ENTRY has its 'commit' field set, return ENTRY. Otherwise, lookup +ENTRY's 'tag' in REPOSITORY and return ENTRY with its 'commit' field set to +the field its 'tag' refers to. A 'git-error' exception is raised if the tag +cannot be found." + (if (channel-news-entry-commit entry) + entry + (let* ((tag (channel-news-entry-tag entry)) + (reference (string-append "refs/tags/" tag)) + (oid (reference-name->oid repository reference))) + (channel-news-entry (oid->string oid) tag + (channel-news-entry-title entry) + (channel-news-entry-body entry))))) + (define* (channel-news-for-commit channel new #:optional old) "Return a list of for CHANNEL between commits OLD and NEW. When OLD is omitted or is #f, return all the news entries of CHANNEL." @@ -645,10 +663,14 @@ (define* (channel-news-for-commit channel new #:optional old) (news-file (and news-file (string-append checkout "/" news-file)))) (if (and news-file (file-exists? news-file)) - (let ((entries (channel-news-entries (call-with-input-file news-file - read-channel-news)))) - (if old - (with-repository checkout repository + (with-repository checkout repository + (let* ((news (call-with-input-file news-file + read-channel-news)) + (entries (map (lambda (entry) + (resolve-channel-news-entry-tag repository + entry)) + (channel-news-entries news)))) + (if old (let* ((new (commit-lookup repository (string->oid new))) (old (commit-lookup repository (string->oid old))) (commits (list->set @@ -657,8 +679,8 @@ (define* (channel-news-for-commit channel new #:optional old) (filter (lambda (entry) (set-contains? commits (channel-news-entry-commit entry))) - entries))) - entries)) + entries)) + entries))) '()))) (lambda (key error . rest) ;; If commit NEW or commit OLD cannot be found, then something must be diff --git a/guix/tests/git.scm b/guix/tests/git.scm index 9d5b1ae321..21573ac14e 100644 --- a/guix/tests/git.scm +++ b/guix/tests/git.scm @@ -66,6 +66,9 @@ (define (git command . args) ((('commit text) rest ...) (git "commit" "-m" text) (loop rest)) + ((('tag name) rest ...) + (git "tag" name) + (loop rest)) ((('branch name) rest ...) (git "branch" name) (loop rest)) diff --git a/tests/channels.scm b/tests/channels.scm index 58101bcb72..f5a7955483 100644 --- a/tests/channels.scm +++ b/tests/channels.scm @@ -272,6 +272,7 @@ (define (lookup name) (commit "first commit") (add "src/a.txt" "A") (commit "second commit") + (tag "tag-for-first-news-entry") (add "news.scm" ,(lambda (repository) (let ((previous @@ -299,7 +300,7 @@ (define (lookup name) (entry (commit ,(oid->string previous)) (title (en "Another file!")) (body (en "Yeah, b.txt."))) - (entry (commit ,(oid->string second)) + (entry (tag "tag-for-first-news-entry") (title (en "Old news.") (eo "Malnovaĵoj.")) (body (en "For a.txt")))))))) @@ -343,6 +344,10 @@ (define (find-commit* message) (lset= string=? (map channel-news-entry-commit (channel-news-for-commit channel commit5 commit1)) - (list commit4 commit2))))))) + (list commit4 commit2)) + (lset= equal? + (map channel-news-entry-tag + (channel-news-for-commit channel commit5 commit1)) + '(#f "tag-for-first-news-entry"))))))) (test-end "channels") -- cgit v1.2.3 From 7faffdc2d53b982d8443c376d6ed2f41a13b3f36 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Sun, 15 Sep 2019 17:57:10 +0200 Subject: pull: Display channel news. * guix/scripts/pull.scm (display-news-entry) (display-channel-specific-news): New procedures. (display-channel-news): Call it. (display-new/upgraded-packages): Adjust hint message. * doc/guix.texi (Invoking guix pull): Mention it. --- doc/guix.texi | 11 ++++++---- guix/scripts/pull.scm | 61 ++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 65 insertions(+), 7 deletions(-) (limited to 'doc') diff --git a/doc/guix.texi b/doc/guix.texi index 33bf08e9dd..4830f39cdb 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -3720,13 +3720,16 @@ Read the list of channels from @var{file} instead of evaluates to a list of channel objects. @xref{Channels}, for more information. +@cindex channel news @item --news @itemx -N -Display the list of packages added or upgraded since the previous generation. +Display the list of packages added or upgraded since the previous +generation, as well as, occasionally, news written by channel authors +for their users (@pxref{Channels, Writing Channel News}). -This is the same information as displayed upon @command{guix pull} completion, -but without ellipses; it is also similar to the output of @command{guix pull --l} for the last generation (see below). +The package information is the same as displayed upon @command{guix +pull} completion, but without ellipses; it is also similar to the output +of @command{guix pull -l} for the last generation (see below). @item --list-generations[=@var{pattern}] @itemx -l [@var{pattern}] diff --git a/guix/scripts/pull.scm b/guix/scripts/pull.scm index 472947bb3a..d734df5e24 100644 --- a/guix/scripts/pull.scm +++ b/guix/scripts/pull.scm @@ -19,6 +19,7 @@ (define-module (guix scripts pull) #:use-module (guix ui) + #:use-module (guix colors) #:use-module (guix utils) #:use-module ((guix status) #:select (with-status-verbosity)) #:use-module (guix scripts) @@ -229,6 +230,48 @@ (define (channel=? channel1 channel2) ;; Assume that the URL matters less than the name. (eq? (channel-name channel1) (channel-name channel2))) +(define (display-news-entry entry language port) + "Display ENTRY, a , in LANGUAGE, a language code, to +PORT." + (let ((title (channel-news-entry-title entry)) + (body (channel-news-entry-body entry))) + (format port " ~a~%" + (highlight + (string-trim-right + (texi->plain-text (or (assoc-ref title language) + (assoc-ref title (%default-message-language)) + ""))))) + (format port (G_ " commit ~a~%") + (channel-news-entry-commit entry)) + (newline port) + (format port " ~a~%" + (indented-string + (parameterize ((%text-width (- (%text-width) 4))) + (string-trim-right + (texi->plain-text (or (assoc-ref body language) + (assoc-ref body (%default-message-language)) + "")))) + 4)))) + +(define* (display-channel-specific-news new old + #:key (port (current-output-port))) + "Display channel news applicable the commits between OLD and NEW, where OLD +and NEW are records with a proper 'commit' field." + (let ((channel new) + (old (channel-commit old)) + (new (channel-commit new))) + (when (and old new) + (let ((language (current-message-language))) + (match (channel-news-for-commit channel new old) + (() ;no news is good news + #t) + ((entries ...) + (newline port) + (format port (G_ "News for channel '~a'~%") + (channel-name channel)) + (for-each (cut display-news-entry <> language port) entries) + (newline port))))))) + (define (display-channel-news profile) "Display news about the channels of PROFILE " (define previous @@ -259,7 +302,20 @@ (define previous (N_ " ~*One channel removed:~%" " ~a channels removed:~%" count) count) - (for-each display-channel removed))))))))) + (for-each display-channel removed)))) + + ;; Display channel-specific news for those channels that were + ;; here before and are still around afterwards. + (for-each (match-lambda + ((new old) + (display-channel-specific-news new old))) + (filter-map (lambda (new) + (define old + (find (cut channel=? new <>) + old-channels)) + + (and old (list new old))) + new-channels))))))) (define (display-news profile) ;; Display profile news, with the understanding that this process represents @@ -534,8 +590,7 @@ (define upgraded-count (length upgraded)) (when (and concise? (or (> new-count concise/max-item-count) (> upgraded-count concise/max-item-count))) - (display-hint (G_ "Run @command{guix pull --news} to view the complete -list of package changes."))))) + (display-hint (G_ "Run @command{guix pull --news} to read all the news."))))) (define (display-profile-content-diff profile gen1 gen2) "Display the changes in PROFILE GEN2 compared to generation GEN1." -- cgit v1.2.3 From cb3ee1c5070ad3b82491d7ba61fc120910427121 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 23 Sep 2019 12:26:59 +0200 Subject: doc: Explain that '--profile' expects a file name. * doc/guix.texi (Invoking guix package): Explain that the argument to --profile is a file name. --- doc/guix.texi | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'doc') diff --git a/doc/guix.texi b/doc/guix.texi index 4830f39cdb..d3170bb46e 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -2918,6 +2918,25 @@ variable, even though, taken individually, neither @file{foo} nor @itemx -p @var{profile} Use @var{profile} instead of the user's default profile. +@var{profile} must be the name of a file that will be created upon +completion. Concretely, @var{profile} will be a mere symbolic link +(``symlink'') pointing to the actual profile where packages are +installed: + +@example +$ guix install hello -p ~/code/my-profile +@dots{} +$ ~/code/my-profile/bin/hello +Hello, world! +@end example + +All it takes to get rid of the profile is to remove this symlink and its +siblings that point to specific generations: + +@example +$ rm ~/code/my-profile ~/code/my-profile-*-link +@end example + @cindex collisions, in a profile @cindex colliding packages in profiles @cindex profile collisions -- cgit v1.2.3 From 46a8b76ce7d861ff39211536b91dbef9ed7701b5 Mon Sep 17 00:00:00 2001 From: Tobias Geerinckx-Rice Date: Mon, 23 Sep 2019 20:49:19 +0200 Subject: doc: Fix typo. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * doc/guix.texi (Build Systems): Fix/spoil ‘libary’ typo/joke. --- doc/guix.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'doc') diff --git a/doc/guix.texi b/doc/guix.texi index d3170bb46e..093199c63b 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -6181,7 +6181,7 @@ package, correctly capitalized. For packages requiring shared library dependencies, you may need to write the @file{/deps/deps.jl} file manually. It's usually a line of @code{const -variable = /gnu/store/libary.so} for each dependency, plus a void function +variable = /gnu/store/library.so} for each dependency, plus a void function @code{check_deps() = nothing}. Some older packages that aren't using @file{Package.toml} yet, will require -- cgit v1.2.3