Browse Source

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/ New file.
* (SH_TESTS): Add it.
* doc/guix.texi (Package Transformation Options): Document it.
Ludovic Courtès 3 years ago
committed by Ludovic Courtès
No known key found for this signature in database GPG Key ID: 90B11993D9AEBB5
4 changed files with 129 additions and 3 deletions
  1. +1
  2. +27
  3. +53
  4. +48

+ 1
- 0 View File

@ -407,6 +407,7 @@ endif
tests/ \
tests/ \
tests/ \
tests/ \
tests/ \

+ 27
- 0
doc/guix.texi 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
@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:
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
@node Additional Build Options

+ 53
- 3
guix/scripts/build.scm View File

@ -45,6 +45,8 @@
#:use-module (srfi srfi-37)
#:autoload (gnu packages) (specification->package %package-module-path)
#:autoload (guix download) (download-to-store)
#:autoload (guix git-download) (git-reference?)
#:autoload (guix git) (git-checkout?)
#:use-module (guix status)
#:use-module ((guix progress) #:select (current-terminal-columns))
#:use-module ((guix build syscalls) #:select (terminal-columns))
@ -270,6 +272,48 @@ current 'gnutls' package, after which version 3.5.4 is grafted onto them."
(rewrite 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))
(leave (G_ "the source of ~a is not a Git \
(package-full-name old))))))
(cons old
(inherit old)
(version (string-append "git." branch))
(source (git-checkout (url url) (branch branch)))))))
(leave (G_ "invalid replacement specification: ~s~%") spec))))
(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)
(define %transformations
;; 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
@ -277,7 +321,8 @@ current 'gnutls' package, after which version 3.5.4 is grafted onto them."
;; things to build.
`((with-source . ,transform-package-source)
(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
;; The command-line interface to the above transformations.
@ -291,7 +336,9 @@ current 'gnutls' package, after which version 3.5.4 is grafted onto them."
(option '("with-input") #t #f
(parser 'with-input))
(option '("with-graft") #t #f
(parser 'with-graft)))))
(parser 'with-graft))
(option '("with-branch") #t #f
(parser 'with-branch)))))
(define (show-transformation-options-help)
(display (G_ "
@ -302,7 +349,10 @@ current 'gnutls' package, after which version 3.5.4 is grafted onto them."
replace dependency PACKAGE by REPLACEMENT"))
(display (G_ "
graft REPLACEMENT on packages that refer to PACKAGE")))
graft REPLACEMENT on packages that refer to PACKAGE"))
(display (G_ "
build PACKAGE from the latest commit of BRANCH")))
(define (options->transformation opts)

+ 48
- 0
tests/ View File

@ -0,0 +1,48 @@
# GNU Guix --- Functional package management for GNU
# Copyright © 2018 Ludovic Courtès <>
# 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
# 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 <>.
# 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 "" "80" AI_NUMERICSERV)' 2> /dev/null
# Skipping.
exit 77
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"