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.
master
Ludovic Courtès 2018-09-03 15:03:33 +02:00
parent ee94cfeb99
commit bd7470185b
No known key found for this signature in database
GPG Key ID: 090B11993D9AEBB5
7 changed files with 308 additions and 3 deletions

View File

@ -204,6 +204,7 @@ MODULES = \
guix/scripts/authenticate.scm \ guix/scripts/authenticate.scm \
guix/scripts/refresh.scm \ guix/scripts/refresh.scm \
guix/scripts/repl.scm \ guix/scripts/repl.scm \
guix/scripts/describe.scm \
guix/scripts/system.scm \ guix/scripts/system.scm \
guix/scripts/system/search.scm \ guix/scripts/system/search.scm \
guix/scripts/lint.scm \ guix/scripts/lint.scm \
@ -409,6 +410,7 @@ SH_TESTS = \
tests/guix-environment.sh \ tests/guix-environment.sh \
tests/guix-environment-container.sh \ tests/guix-environment-container.sh \
tests/guix-graph.sh \ tests/guix-graph.sh \
tests/guix-describe.sh \
tests/guix-lint.sh tests/guix-lint.sh
TESTS = $(SCM_TESTS) $(SH_TESTS) TESTS = $(SCM_TESTS) $(SH_TESTS)

View File

@ -147,6 +147,7 @@ Package Management
* Invoking guix gc:: Running the garbage collector. * Invoking guix gc:: Running the garbage collector.
* Invoking guix pull:: Fetching the latest Guix and distribution. * Invoking guix pull:: Fetching the latest Guix and distribution.
* Channels:: Customizing the package collection. * Channels:: Customizing the package collection.
* Invoking guix describe:: Display information about your Guix revision.
* Invoking guix pack:: Creating software bundles. * Invoking guix pack:: Creating software bundles.
* Invoking guix archive:: Exporting and importing store files. * 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 gc:: Running the garbage collector.
* Invoking guix pull:: Fetching the latest Guix and distribution. * Invoking guix pull:: Fetching the latest Guix and distribution.
* Channels:: Customizing the package collection. * Channels:: Customizing the package collection.
* Invoking guix describe:: Display information about your Guix revision.
* Invoking guix pack:: Creating software bundles. * Invoking guix pack:: Creating software bundles.
* Invoking guix archive:: Exporting and importing store files. * Invoking guix archive:: Exporting and importing store files.
@end menu @end menu
@ -1751,7 +1753,7 @@ collected.
@cindex reproducibility @cindex reproducibility
@cindex reproducible builds @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}). management, as described in the introduction (@pxref{Introduction}).
Each @file{/gnu/store} package directory name contains a hash of all the Each @file{/gnu/store} package directory name contains a hash of all the
inputs that were used to build that package---compiler, libraries, build 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, without having to manually install the dependencies of the
package into their profile (@pxref{Invoking guix environment}). 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 @node Invoking guix package
@section Invoking @command{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{} 69 packages upgraded: borg@@1.1.6, cheese@@3.28.0, @dots{}
@end example @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 This @code{~/.config/guix/current} profile works like any other profile
created by @command{guix package} (@pxref{Invoking guix package}). That created by @command{guix package} (@pxref{Invoking guix package}). That
is, you can list generations, roll back to the previous 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 The syntax of @var{pattern} is the same as with @code{guix package
--list-generations} (@pxref{Invoking 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} @item --profile=@var{profile}
@itemx -p @var{profile} @itemx -p @var{profile}
Use @var{profile} instead of @file{~/.config/guix/current}. 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"))) (branch "dd3df5e2c8818760a8fc0bd699e55d3b69fef2bb")))
@end lisp @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 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 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 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 artifacts with very fine grain, and to reproduce software environments at
will---some sort of ``meta reproducibility'' capabilities, if you will. 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 @node Invoking guix pack
@section Invoking @command{guix pack} @section Invoking @command{guix pack}

View File

@ -21,7 +21,9 @@
#:use-module (guix profiles) #:use-module (guix profiles)
#:use-module (srfi srfi-1) #:use-module (srfi srfi-1)
#:use-module (ice-9 match) #:use-module (ice-9 match)
#:export (package-path-entries)) #:export (current-profile
current-profile-entries
package-path-entries))
;;; Commentary: ;;; Commentary:
;;; ;;;

160
guix/scripts/describe.scm Normal file
View File

@ -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))))))

View File

@ -48,7 +48,8 @@
#:use-module (srfi srfi-37) #:use-module (srfi srfi-37)
#:use-module (ice-9 match) #:use-module (ice-9 match)
#:use-module (ice-9 vlist) #:use-module (ice-9 vlist)
#:export (guix-pull)) #:export (display-profile-content
guix-pull))
;;; ;;;

View File

@ -31,6 +31,7 @@ guix/scripts/challenge.scm
guix/scripts/copy.scm guix/scripts/copy.scm
guix/scripts/pack.scm guix/scripts/pack.scm
guix/scripts/weather.scm guix/scripts/weather.scm
guix/scripts/describe.scm
guix/gnu-maintenance.scm guix/gnu-maintenance.scm
guix/scripts/container.scm guix/scripts/container.scm
guix/scripts/container/exec.scm guix/scripts/container/exec.scm

47
tests/guix-describe.sh Normal file
View File

@ -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