aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLudovic Courtès <ludo@gnu.org>2018-09-03 15:03:33 +0200
committerLudovic Courtès <ludo@gnu.org>2018-09-07 11:40:22 +0200
commitbd7470185bae15e686c2b2a83d3f61807e6fa527 (patch)
treee0e42c0a5c9be1993dea5622d5e6bb7464d1f757
parentee94cfeb99a7e3879c92ca21318960077ce4100e (diff)
downloadgnu-guix-bd7470185bae15e686c2b2a83d3f61807e6fa527.tar
gnu-guix-bd7470185bae15e686c2b2a83d3f61807e6fa527.tar.gz
Add 'guix describe'.
* guix/scripts/describe.scm: New file. * Makefile.am (MODULES): Add it. (SH_TESTS): Add tests/guix-describe.sh. * po/guix/POTFILES.in: Add it. * guix/scripts/pull.scm (display-profile-content): Export. * guix/describe.scm (current-profile, current-profile-entries): Export. * tests/guix-describe.sh: New file. * doc/guix.texi (Features): Mention 'guix pull' and provenance tracking. (Invoking guix pull): Link to 'guix describe'. (Channels): Likewise. (Invoking guix describe): New node.
-rw-r--r--Makefile.am2
-rw-r--r--doc/guix.texi94
-rw-r--r--guix/describe.scm4
-rw-r--r--guix/scripts/describe.scm160
-rw-r--r--guix/scripts/pull.scm3
-rw-r--r--po/guix/POTFILES.in1
-rw-r--r--tests/guix-describe.sh47
7 files changed, 308 insertions, 3 deletions
diff --git a/Makefile.am b/Makefile.am
index a3498460e0..5c8639d665 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -204,6 +204,7 @@ MODULES = \
guix/scripts/authenticate.scm \
guix/scripts/refresh.scm \
guix/scripts/repl.scm \
+ guix/scripts/describe.scm \
guix/scripts/system.scm \
guix/scripts/system/search.scm \
guix/scripts/lint.scm \
@@ -409,6 +410,7 @@ SH_TESTS = \
tests/guix-environment.sh \
tests/guix-environment-container.sh \
tests/guix-graph.sh \
+ tests/guix-describe.sh \
tests/guix-lint.sh
TESTS = $(SCM_TESTS) $(SH_TESTS)
diff --git a/doc/guix.texi b/doc/guix.texi
index 30f1be2ab8..19a497c746 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -147,6 +147,7 @@ Package Management
* Invoking guix gc:: Running the garbage collector.
* Invoking guix pull:: Fetching the latest Guix and distribution.
* Channels:: Customizing the package collection.
+* Invoking guix describe:: Display information about your Guix revision.
* Invoking guix pack:: Creating software bundles.
* Invoking guix archive:: Exporting and importing store files.
@@ -1698,6 +1699,7 @@ guix package -i emacs-guix
* Invoking guix gc:: Running the garbage collector.
* Invoking guix pull:: Fetching the latest Guix and distribution.
* Channels:: Customizing the package collection.
+* Invoking guix describe:: Display information about your Guix revision.
* Invoking guix pack:: Creating software bundles.
* Invoking guix archive:: Exporting and importing store files.
@end menu
@@ -1751,7 +1753,7 @@ collected.
@cindex reproducibility
@cindex reproducible builds
-Finally, Guix takes a @dfn{purely functional} approach to package
+Guix takes a @dfn{purely functional} approach to package
management, as described in the introduction (@pxref{Introduction}).
Each @file{/gnu/store} package directory name contains a hash of all the
inputs that were used to build that package---compiler, libraries, build
@@ -1779,6 +1781,15 @@ a package to quickly set up the right development environment for their
package, without having to manually install the dependencies of the
package into their profile (@pxref{Invoking guix environment}).
+@cindex replication, of software environments
+@cindex provenance tracking, of software artifacts
+All of Guix and its package definitions is version-controlled, and
+@command{guix pull} allows you to ``travel in time'' on the history of Guix
+itself (@pxref{Invoking guix pull}). This makes it possible to replicate a
+Guix instance on a different machine or at a later point in time, which in
+turn allows you to @emph{replicate complete software environments}, while
+retaining precise @dfn{provenance tracking} of the software.
+
@node Invoking guix package
@section Invoking @command{guix package}
@@ -2806,6 +2817,9 @@ Generation 3 Jun 13 2018 23:31:07 (current)
69 packages upgraded: borg@@1.1.6, cheese@@3.28.0, @dots{}
@end example
+@ref{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
is, you can list generations, roll back to the previous
@@ -2851,6 +2865,9 @@ 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}).
+@ref{Invoking guix describe}, for a way to display information about the
+current generation only.
+
@item --profile=@var{profile}
@itemx -p @var{profile}
Use @var{profile} instead of @file{~/.config/guix/current}.
@@ -3023,6 +3040,9 @@ say, on another machine, by providing a channel specification in
(branch "dd3df5e2c8818760a8fc0bd699e55d3b69fef2bb")))
@end lisp
+The @command{guix describe --format=channels} command can even generate this
+list of channels directly (@pxref{Invoking guix describe}).
+
At this point the two machines run the @emph{exact same Guix}, with access to
the @emph{exact same packages}. The output of @command{guix build gimp} on
one machine will be exactly the same, bit for bit, as the output of the same
@@ -3034,6 +3054,78 @@ This gives you super powers, allowing you to track the provenance of binary
artifacts with very fine grain, and to reproduce software environments at
will---some sort of ``meta reproducibility'' capabilities, if you will.
+@node Invoking guix describe
+@section Invoking @command{guix describe}
+
+@cindex reproducibility
+@cindex replicating Guix
+Often you may want to answer questions like: ``Which revision of Guix am I
+using?'' or ``Which channels am I using?'' This is useful information in many
+situations: if you want to @emph{replicate} an environment on a different
+machine or user account, if you want to report a bug or to determine what
+change in the channels you are using caused it, or if you want to record your
+system state for reproducibility purposes. The @command{guix describe}
+command answers these questions.
+
+When run from a @command{guix pull}ed @command{guix}, @command{guix describe}
+displays the channel(s) that it was built from, including their repository URL
+and commit IDs (@pxref{Channels}):
+
+@example
+$ guix describe
+Generation 10 Sep 03 2018 17:32:44 (current)
+ guix e0fa68c
+ repository URL: https://git.savannah.gnu.org/git/guix.git
+ branch: master
+ commit: e0fa68c7718fffd33d81af415279d6ddb518f727
+@end example
+
+If you're familiar with the Git version control system, this is similar in
+spirit to @command{git describe}; the output is also similar to that of
+@command{guix pull --list-generations}, but limited to the current generation
+(@pxref{Invoking guix pull, the @option{--list-generations} option}). Because
+the Git commit ID shown above unambiguously refers to a snapshot of Guix, this
+information is all it takes to describe the revision of Guix you're using, and
+also to replicate it.
+
+To make it easier to replicate Guix, @command{guix describe} can also be asked
+to return a list of channels instead of the human-readable description above:
+
+@example
+$ guix describe -f channels
+(list (channel
+ (name 'guix)
+ (url "https://git.savannah.gnu.org/git/guix.git")
+ (commit
+ "e0fa68c7718fffd33d81af415279d6ddb518f727")))
+@end example
+
+@noindent
+You can save this to a file and feed it to @command{guix pull -C} on some
+other machine or at a later point in time, which will instantiate @emph{this
+exact Guix revision} (@pxref{Invoking guix pull, the @option{-C} option}).
+From there on, since you're able to deploy the same revision of Guix, you can
+just as well @emph{replicate a complete software environment}. We humbly
+think that this is @emph{awesome}, and we hope you'll like it too!
+
+The details of the options supported by @command{guix describe} are as
+follows:
+
+@table @code
+@item --format=@var{format}
+@itemx -f @var{format}
+Produce output in the specified @var{format}, one of:
+
+@table @code
+@item human
+produce human-readable output;
+@item channels
+produce a list of channel specifications that can be passed to @command{guix
+pull -C} or installed as @file{~/.config/guix/channels.scm} (@pxref{Invoking
+guix pull}).
+@end table
+@end table
+
@node Invoking guix pack
@section Invoking @command{guix pack}
diff --git a/guix/describe.scm b/guix/describe.scm
index 3122a762fe..670db63ce7 100644
--- a/guix/describe.scm
+++ b/guix/describe.scm
@@ -21,7 +21,9 @@
#:use-module (guix profiles)
#:use-module (srfi srfi-1)
#:use-module (ice-9 match)
- #:export (package-path-entries))
+ #:export (current-profile
+ current-profile-entries
+ package-path-entries))
;;; Commentary:
;;;
diff --git a/guix/scripts/describe.scm b/guix/scripts/describe.scm
new file mode 100644
index 0000000000..46feea2940
--- /dev/null
+++ b/guix/scripts/describe.scm
@@ -0,0 +1,160 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2018 Ludovic Courtès <ludo@gnu.org>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix scripts describe)
+ #:use-module ((guix ui) #:hide (display-profile-content))
+ #:use-module (guix scripts)
+ #:use-module (guix describe)
+ #:use-module (guix profiles)
+ #:use-module ((guix scripts pull) #:select (display-profile-content))
+ #:use-module (git)
+ #:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-37)
+ #:use-module (ice-9 match)
+ #:autoload (ice-9 pretty-print) (pretty-print)
+ #:export (guix-describe))
+
+
+;;;
+;;; Command-line options.
+;;;
+
+(define %options
+ ;; Specifications of the command-line options.
+ (list (option '(#\f "format") #t #f
+ (lambda (opt name arg result)
+ (unless (member arg '("human" "channels"))
+ (leave (G_ "~a: unsupported output format~%") arg))
+ (alist-cons 'format 'channels result)))
+ (option '(#\h "help") #f #f
+ (lambda args
+ (show-help)
+ (exit 0)))
+ (option '(#\V "version") #f #f
+ (lambda args
+ (show-version-and-exit "guix describe")))))
+
+(define %default-options
+ ;; Alist of default option values.
+ '((format . human)))
+
+(define (show-help)
+ (display (G_ "Usage: guix describe [OPTION]...
+Display information about the channels currently in use.\n"))
+ (display (G_ "
+ -f, --format=FORMAT display information in the given FORMAT"))
+ (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 (display-package-search-path fmt)
+ "Display GUIX_PACKAGE_PATH, if it is set, according to FMT."
+ (match (getenv "GUIX_PACKAGE_PATH")
+ (#f #t)
+ (string
+ (match fmt
+ ('human
+ (format #t "~%GUIX_PACKAGE_PATH=\"~a\"~%" string))
+ ('channels
+ (format #t (G_ "~%;; warning: GUIX_PACKAGE_PATH=\"~a\"~%")
+ string))))))
+
+(define (display-checkout-info fmt)
+ "Display information about the current checkout according to FMT, a symbol
+denoting the requested format. Exit if the current directory does not lie
+within a Git checkout."
+ (let* ((program (car (command-line)))
+ (directory (catch 'git-error
+ (lambda ()
+ (repository-discover (dirname program)))
+ (lambda (key err)
+ (leave (G_ "failed to determine origin~%")))))
+ (repository (repository-open directory))
+ (head (repository-head repository))
+ (commit (oid->string (reference-target head))))
+ (match fmt
+ ('human
+ (format #t (G_ "Git checkout:~%"))
+ (format #t (G_ " repository: ~a~%") (dirname directory))
+ (format #t (G_ " branch: ~a~%") (reference-shorthand head))
+ (format #t (G_ " commit: ~a~%") commit))
+ ('channels
+ (pretty-print `(list (channel
+ (name 'guix)
+ (url ,(dirname directory))
+ (commit ,commit))))))
+ (display-package-search-path fmt)))
+
+(define (display-profile-info profile fmt)
+ "Display information about PROFILE, a profile as created by (guix channels),
+in the format specified by FMT."
+ (define number
+ (match (profile-generations profile)
+ ((_ ... last) last)))
+
+ (match fmt
+ ('human
+ (display-profile-content profile number))
+ ('channels
+ (pretty-print
+ `(list ,@(map (lambda (entry)
+ (match (assq 'source (manifest-entry-properties entry))
+ (('source ('repository ('version 0)
+ ('url url)
+ ('branch branch)
+ ('commit commit)
+ _ ...))
+ `(channel (name ',(string->symbol
+ (manifest-entry-name entry)))
+ (url ,url)
+ (commit ,commit)))
+
+ ;; Pre-0.15.0 Guix does not provide that information,
+ ;; so there's not much we can do in that case.
+ (_ '???)))
+
+ ;; Show most recently installed packages last.
+ (reverse
+ (manifest-entries
+ (profile-manifest (generation-file-name profile
+ number)))))))))
+ (display-package-search-path fmt))
+
+
+;;;
+;;; Entry point.
+;;;
+
+(define (guix-describe . args)
+ (let* ((opts (args-fold* args %options
+ (lambda (opt name arg result)
+ (leave (G_ "~A: unrecognized option~%")
+ name))
+ cons
+ %default-options))
+ (format (assq-ref opts 'format)))
+ (with-error-handling
+ (match (current-profile)
+ (#f
+ (display-checkout-info format))
+ (profile
+ (display-profile-info profile format))))))
diff --git a/guix/scripts/pull.scm b/guix/scripts/pull.scm
index ebc5dc9b13..976e054a84 100644
--- a/guix/scripts/pull.scm
+++ b/guix/scripts/pull.scm
@@ -48,7 +48,8 @@
#:use-module (srfi srfi-37)
#:use-module (ice-9 match)
#:use-module (ice-9 vlist)
- #:export (guix-pull))
+ #:export (display-profile-content
+ guix-pull))
;;;
diff --git a/po/guix/POTFILES.in b/po/guix/POTFILES.in
index 7f881355e7..2762ea078a 100644
--- a/po/guix/POTFILES.in
+++ b/po/guix/POTFILES.in
@@ -31,6 +31,7 @@ guix/scripts/challenge.scm
guix/scripts/copy.scm
guix/scripts/pack.scm
guix/scripts/weather.scm
+guix/scripts/describe.scm
guix/gnu-maintenance.scm
guix/scripts/container.scm
guix/scripts/container/exec.scm
diff --git a/tests/guix-describe.sh b/tests/guix-describe.sh
new file mode 100644
index 0000000000..af523f0a0b
--- /dev/null
+++ b/tests/guix-describe.sh
@@ -0,0 +1,47 @@
+# GNU Guix --- Functional package management for GNU
+# Copyright © 2018 Ludovic Courtès <ludo@gnu.org>
+#
+# This file is part of GNU Guix.
+#
+# GNU Guix is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or (at
+# your option) any later version.
+#
+# GNU Guix is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+
+#
+# Test 'guix describe'.
+#
+
+guix describe --version
+
+tmpfile="t-guix-describe-$$"
+trap "rm -f $tmpfile" EXIT
+rm -f "$tmpfile"
+
+if [ -d "$abs_top_srcdir/.git" ]
+then
+ # Since we're in a Git checkout, we can at least check that these things
+ # work.
+ guix describe | grep -i "checkout"
+ if git --version > /dev/null 2>&1
+ then
+ result="`guix describe | grep commit: | cut -d : -f 2-`"
+ commit="`git log | head -1 | cut -c 7-`"
+ test "x$result" = "x$commit"
+ fi
+ guix describe -f channels
+ case "`guix describe -f channels | grep url`" in
+ *"(url \"$abs_top_srcdir\")") true;;
+ *) false;;
+ esac
+else
+ exit 77
+fi