guix build: Add '--with-branch' transformation option.

* guix/scripts/build.scm (evaluate-git-replacement-specs)
(transform-package-source-branch): New procedures.
(%transformations, %transformation-options): Add 'with-branch'.
(show-transformation-options-help): Likewise.
* tests/guix-build-branch.sh: New file.
* Makefile.am (SH_TESTS): Add it.
* doc/guix.texi (Package Transformation Options): Document it.
This commit is contained in:
Ludovic Courtès 2018-11-27 15:34:34 +01:00 committed by Ludovic Courtès
parent 49ae3f6d89
commit 96915a448c
No known key found for this signature in database
GPG key ID: 090B11993D9AEBB5
4 changed files with 129 additions and 3 deletions

View file

@ -407,6 +407,7 @@ endif
SH_TESTS = \ SH_TESTS = \
tests/guix-build.sh \ tests/guix-build.sh \
tests/guix-build-branch.sh \
tests/guix-download.sh \ tests/guix-download.sh \
tests/guix-gc.sh \ tests/guix-gc.sh \
tests/guix-hash.sh \ tests/guix-hash.sh \

View file

@ -6451,6 +6451,33 @@ must be compatible. If @var{replacement} is somehow incompatible with
@var{package}, then the resulting package may be unusable. Use with @var{package}, then the resulting package may be unusable. Use with
care! care!
@item --with-branch=@var{package}=@var{branch}
@cindex Git, using the latest commit
@cindex latest commit, building
Build @var{package} from the latest commit of @var{branch}. The @code{source}
field of @var{package} must be an origin with the @code{git-fetch} method
(@pxref{origin Reference}) or a @code{git-checkout} object; the repository URL
is taken from that @code{source}.
For instance, the following command builds @code{guile-sqlite3} from the
latest commit of its @code{master} branch, and then builds @code{guix} (which
depends on it) and @code{cuirass} (which depends on @code{guix}) against this
specific @code{guile-sqlite3} build:
@example
guix build --with-branch=guile-sqlite3=master cuirass
@end example
@cindex continuous integration
Obviously, since it uses the latest commit of the given branch, the result of
such a command varies over time. Nevertheless it is a convenient way to
rebuild entire software stacks against the latest commit of one or more
packages. This is particularly useful in the context of continuous
integration (CI).
Checkouts are kept in a cache under @file{~/.cache/guix/checkouts} to speed up
consecutive accesses to the same repository. You may want to clean it up once
in a while to save disk space.
@end table @end table
@node Additional Build Options @node Additional Build Options

View file

@ -45,6 +45,8 @@ (define-module (guix scripts build)
#:use-module (srfi srfi-37) #:use-module (srfi srfi-37)
#:autoload (gnu packages) (specification->package %package-module-path) #:autoload (gnu packages) (specification->package %package-module-path)
#:autoload (guix download) (download-to-store) #:autoload (guix download) (download-to-store)
#:autoload (guix git-download) (git-reference?)
#:autoload (guix git) (git-checkout?)
#:use-module (guix status) #:use-module (guix status)
#:use-module ((guix progress) #:select (current-terminal-columns)) #:use-module ((guix progress) #:select (current-terminal-columns))
#:use-module ((guix build syscalls) #:select (terminal-columns)) #:use-module ((guix build syscalls) #:select (terminal-columns))
@ -270,6 +272,48 @@ (define (replacement-pair old new)
(rewrite obj) (rewrite obj)
obj)))) obj))))
(define (evaluate-git-replacement-specs specs)
"Parse SPECS, a list of strings like \"guile=stable-2.2\", and return a list
of package pairs. Raise an error if an element of SPECS uses invalid syntax,
or if a package it refers to could not be found."
(define not-equal
(char-set-complement (char-set #\=)))
(map (lambda (spec)
(match (string-tokenize spec not-equal)
((name branch)
(let* ((old (specification->package name))
(source (package-source old))
(url (cond ((and (origin? source)
(git-reference? (origin-uri source)))
(git-reference-url (origin-uri source)))
((git-checkout? source)
(git-checkout-url source))
(else
(leave (G_ "the source of ~a is not a Git \
reference~%")
(package-full-name old))))))
(cons old
(package
(inherit old)
(version (string-append "git." branch))
(source (git-checkout (url url) (branch branch)))))))
(x
(leave (G_ "invalid replacement specification: ~s~%") spec))))
specs))
(define (transform-package-source-branch replacement-specs)
"Return a procedure that, when passed a package, replaces its direct
dependencies according to REPLACEMENT-SPECS. REPLACEMENT-SPECS is a list of
strings like \"guile-next=stable-3.0\" meaning that packages are built using
'guile-next' from the latest commit on its 'stable-3.0' branch."
(let* ((replacements (evaluate-git-replacement-specs replacement-specs))
(rewrite (package-input-rewriting replacements)))
(lambda (store obj)
(if (package? obj)
(rewrite obj)
obj))))
(define %transformations (define %transformations
;; Transformations that can be applied to things to build. The car is the ;; Transformations that can be applied to things to build. The car is the
;; key used in the option alist, and the cdr is the transformation ;; key used in the option alist, and the cdr is the transformation
@ -277,7 +321,8 @@ (define %transformations
;; things to build. ;; things to build.
`((with-source . ,transform-package-source) `((with-source . ,transform-package-source)
(with-input . ,transform-package-inputs) (with-input . ,transform-package-inputs)
(with-graft . ,transform-package-inputs/graft))) (with-graft . ,transform-package-inputs/graft)
(with-branch . ,transform-package-source-branch)))
(define %transformation-options (define %transformation-options
;; The command-line interface to the above transformations. ;; The command-line interface to the above transformations.
@ -291,7 +336,9 @@ (define %transformation-options
(option '("with-input") #t #f (option '("with-input") #t #f
(parser 'with-input)) (parser 'with-input))
(option '("with-graft") #t #f (option '("with-graft") #t #f
(parser 'with-graft))))) (parser 'with-graft))
(option '("with-branch") #t #f
(parser 'with-branch)))))
(define (show-transformation-options-help) (define (show-transformation-options-help)
(display (G_ " (display (G_ "
@ -302,7 +349,10 @@ (define (show-transformation-options-help)
replace dependency PACKAGE by REPLACEMENT")) replace dependency PACKAGE by REPLACEMENT"))
(display (G_ " (display (G_ "
--with-graft=PACKAGE=REPLACEMENT --with-graft=PACKAGE=REPLACEMENT
graft REPLACEMENT on packages that refer to PACKAGE"))) graft REPLACEMENT on packages that refer to PACKAGE"))
(display (G_ "
--with-branch=PACKAGE=BRANCH
build PACKAGE from the latest commit of BRANCH")))
(define (options->transformation opts) (define (options->transformation opts)

View file

@ -0,0 +1,48 @@
# 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 build --with-branch'.
#
guix build --version
# 'guix build --with-branch' requires access to the network to clone the
# Git repository below.
if ! guile -c '(getaddrinfo "www.gnu.org" "80" AI_NUMERICSERV)' 2> /dev/null
then
# Skipping.
exit 77
fi
orig_drv="`guix build guile-gcrypt -d`"
latest_drv="`guix build guile-gcrypt --with-branch=guile-gcrypt=master -d`"
test -n "$latest_drv"
test "$orig_drv" != "$latest_drv"
# FIXME: '-S' currently doesn't work with non-derivation source.
# checkout="`guix build guile-gcrypt --with-branch=guile-gcrypt=master -S`"
checkout="`guix gc --references "$latest_drv" | grep guile-gcrypt | grep -v -E '(-builder|\.drv)'`"
test -d "$checkout"
test -f "$checkout/COPYING"
orig_drv="`guix build guix -d`"
latest_drv="`guix build guix --with-branch=guile-gcrypt=master -d`"
guix gc -R "$latest_drv" | grep guile-gcrypt-git.master
test "$orig_drv" != "$latest_drv"