code:
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2017 Jan Nieuwenhuizen <janneke@gnu.org>
;;; Copyright © 2018 Clément Lassieur <clement@lassieur.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/>.

;;;
;;; This file defines build jobs for the Hydra continuation integration
;;; tool.
;;;

(use-modules (system base compile))

(eval-when (expand load eval)

  ;; Pre-load the compiler so we don't end up auto-compiling it.
  (compile #t)

  ;; Use our very own Guix modules.
  (set! %fresh-auto-compile #t)

  ;; Ignore .go files except for Guile's.  This is because our checkout in the
  ;; store has mtime set to the epoch, and thus .go files look newer, even
  ;; though they may not correspond.  Use 'reverse' so that /gnu/store/…-guile
  ;; comes before /run/current-system/profile.
  (set! %load-compiled-path
    (list
     (dirname (dirname (search-path (reverse %load-compiled-path)
                                    "ice-9/boot-9.go")))))

  (and=> (assoc-ref (current-source-location) 'filename)
         (lambda (file)
           (let ((dir (canonicalize-path
                       (string-append (dirname file) "/../.."))))
             (format (current-error-port) "prepending ~s to the load path~%"
                     dir)
             (set! %load-path (cons dir %load-path))))))

(use-modules (guix config)
             (guix store)
             (guix grafts)
             (guix profiles)
             (guix packages)
             (guix derivations)
             (guix monads)
             (guix ui)
             ((guix licenses) #:select (gpl3+))
             ((guix utils) #:select (%current-system))
             ((guix scripts system) #:select (read-operating-system))
             ((guix scripts pack)
              #:select (lookup-compressor self-contained-tarball))
             (gnu bootloader)
             (gnu bootloader u-boot)
             (gnu packages)
             (gnu packages gcc)
             (gnu packages base)
             (gnu packages gawk)
             (gnu packages guile)
             (gnu packages gettext)
             (gnu packages compression)
             (gnu packages multiprecision)
             (gnu packages make-bootstrap)
             (gnu packages package-management)
             (gnu system)
             (gnu system vm)
             (gnu system install)
             (gnu tests)
             (srfi srfi-1)
             (srfi srfi-26)
             (ice-9 match))

;; XXX: Debugging hack: since `hydra-eval-guile-jobs' redirects the output
;; port to the bit bucket, let us write to the error port instead.
(setvbuf (current-error-port) _IOLBF)
(set-current-output-port (current-error-port))

(define* (package->alist store package system
                         #:optional (package-derivation package-derivation))
  "Convert PACKAGE to an alist suitable for Hydra."
  (parameterize ((%graft? #f))
    `((derivation . ,(derivation-file-name
                      (package-derivation store package system
                                          #:graft? #f)))
      (description . ,(package-synopsis package))
      (long-description . ,(package-description package))
      (license . ,(package-license package))
      (home-page . ,(package-home-page package))
      (maintainers . ("bug-guix@gnu.org"))
      (max-silent-time . ,(or (assoc-ref (package-properties package)
                                         'max-silent-time)
                              3600))              ;1 hour by default
      (timeout . ,(or (assoc-ref (package-properties package) 'timeout)
                      72000)))))                  ;20 hours by default

(define (package-job store job-name package system)
  "Return a job called JOB-NAME that builds PACKAGE on SYSTEM."
  (let ((job-name (symbol-append job-name (string->symbol ".")
                                 (string->symbol system))))
    `(,job-name . ,(cut package->alist store package system))))

(define (package-cross-job store job-name package target system)
  "Return a job called TARGET.JOB-NAME that cross-builds PACKAGE for TARGET on
SYSTEM."
  `(,(symbol-append (string->symbol target) (string->symbol ".") job-name
                    (string->symbol ".") (string->symbol system)) .
    ,(cute package->alist store package system
           (lambda* (store package system #:key graft?)
             (package-cross-derivation store package target system
                                       #:graft? graft?)))))

(define %core-packages
  ;; Note: Don't put the '-final' package variants because (1) that's
  ;; implicit, and (2) they cannot be cross-built (due to the explicit input
  ;; chain.)
  (list gcc-4.8 gcc-4.9 gcc-5 glibc binutils
        gmp mpfr mpc coreutils findutils diffutils patch sed grep
        gawk gnu-gettext hello guile-2.0 guile-2.2 zlib gzip xz
        %bootstrap-binaries-tarball
        %binutils-bootstrap-tarball
        (%glibc-bootstrap-tarball)
        %gcc-bootstrap-tarball
        %guile-bootstrap-tarball
        %bootstrap-tarballs))

(define %packages-to-cross-build
  %core-packages)

(define %cross-targets
  '("mips64el-linux-gnu"
    "mips64el-linux-gnuabi64"
    "arm-linux-gnueabihf"
    "aarch64-linux-gnu"
    "powerpc-linux-gnu"
    "i586-pc-gnu"                                 ;aka. GNU/Hurd
    "i686-w64-mingw32"))

(define %guixsd-supported-systems
  '("x86_64-linux" "i686-linux" "armhf-linux"))

(define %u-boot-systems
  '("armhf-linux"))

(define (qemu-jobs store system)
  "Return a list of jobs that build QEMU images for SYSTEM."
  (define (->alist drv)
    `((derivation . ,(derivation-file-name drv))
      (description . "Stand-alone QEMU image of the GNU system")
      (long-description . "This is a demo stand-alone QEMU image of the GNU
system.")
      (license . ,gpl3+)
      (home-page . ,%guix-home-page-url)
      (maintainers . ("bug-guix@gnu.org"))))

  (define (->job name drv)
    (let ((name (symbol-append name (string->symbol ".")
                               (string->symbol system))))
      `(,name . ,(lambda ()
                   (parameterize ((%graft? #f))
                     (->alist drv))))))

  (define MiB
    (expt 2 20))

  (if (member system %guixsd-supported-systems)
      (if (member system %u-boot-systems)
          (list (->job 'flash-image
                       (run-with-store store
                         (mbegin %store-monad
                           (set-guile-for-build (default-guile))
                           (system-disk-image
                            (operating-system (inherit installation-os)
                             (bootloader (bootloader-configuration
                                          (bootloader u-boot-bootloader)
                                          (target #f))))
                            #:disk-image-size
                            (* 1024 MiB))))))
          (list (->job 'usb-image
                       (run-with-store store
                         (mbegin %store-monad
                           (set-guile-for-build (default-guile))
                           (system-disk-image installation-os
                                              #:disk-image-size
                                              (* 1024 MiB)))))
                (->job 'iso9660-image
                       (run-with-store store
                         (mbegin %store-monad
                           (set-guile-for-build (default-guile))
                           (system-disk-image installation-os
                                              #:file-system-type
                                              "iso9660"))))))
      '()))

(define (system-test-jobs store system)
  "Return a list of jobs for the system tests."
  (define (test->thunk test)
    (lambda ()
      (define drv
        (run-with-store store
          (mbegin %store-monad
            (set-current-system system)
            (set-grafting #f)
            (set-guile-for-build (default-guile))
            (system-test-value test))))

      `((derivation . ,(derivation-file-name drv))
        (description . ,(format #f "GuixSD '~a' system test"
                                (system-test-name test)))
        (long-description . ,(system-test-description test))
        (license . ,gpl3+)
        (home-page . ,%guix-home-page-url)
        (maintainers . ("bug-guix@gnu.org")))))

  (define (->job test)
    (let ((name (string->symbol
                 (string-append "test." (system-test-name test)
                                "." system))))
      (cons name (test->thunk test))))

  (if (member system %guixsd-supported-systems)
      (map ->job (all-system-tests))
      '()))

(define (tarball-jobs store system)
  "Return Hydra jobs to build the self-contained Guix binary tarball."
  (define (->alist drv)
    `((derivation . ,(derivation-file-name drv))
      (description . "Stand-alone binary Guix tarball")
      (long-description . "This is a tarball containing binaries of Guix and
all its dependencies, and ready to be installed on non-GuixSD distributions.")
      (license . ,gpl3+)
      (home-page . ,%guix-home-page-url)
      (maintainers . ("bug-guix@gnu.org"))))

  (define (->job name drv)
    (let ((name (symbol-append name (string->symbol ".")
                               (string->symbol system))))
      `(,name . ,(lambda ()
                   (parameterize ((%graft? #f))
                     (->alist drv))))))

  ;; XXX: Add a job for the stable Guix?
  (list (->job 'binary-tarball
               (run-with-store store
                 (mbegin %store-monad
                   (set-guile-for-build (default-guile))
                   (>>= (profile-derivation (packages->manifest (list guix)))
                        (lambda (profile)
                          (self-contained-tarball "guix-binary" profile
                                                  #:localstatedir? #t
                                                  #:compressor
                                                  (lookup-compressor "xz")))))
                 #:system system))))

(define job-name
  ;; Return the name of a package's job.
  (compose string->symbol
           (cut package-full-name <> "-")))

(define package->job
  (let ((base-packages
         (delete-duplicates
          (append-map (match-lambda
                       ((_ package _ ...)
                        (match (package-transitive-inputs package)
                          (((_ inputs _ ...) ...)
                           inputs))))
                      (%final-inputs)))))
    (lambda (store package system)
      "Return a job for PACKAGE on SYSTEM, or #f if this combination is not
valid."
      (cond ((member package base-packages)
             (package-job store (symbol-append 'base. (job-name package))
                          package system))
            ((supported-package? package system)
             (let ((drv (package-derivation store package system
                                            #:graft? #f)))
               (and (substitutable-derivation? drv)
                    (package-job store (job-name package)
                                 package system))))
            (else
             #f)))))

(define (all-packages)
  "Return the list of packages to build."
  (define (adjust package result)
    (cond ((package-replacement package)
           (cons* package                         ;build both
                  (package-replacement package)
                  result))
          ((package-superseded package)
           result)                                ;don't build it
          (else
           (cons package result))))

  (fold-packages adjust
                 (fold adjust '()                 ;include base packages
                       (match (%final-inputs)
                         (((labels packages _ ...) ...)
                          packages)))
                 #:select? (const #t)))           ;include hidden packages

(define (arguments->manifests arguments)
  "Return the list of manifests extracted from ARGUMENTS."
  (map (match-lambda
         ((input-name . relative-path)
          (let* ((checkout (assq-ref arguments (string->symbol input-name)))
                 (base (assq-ref checkout 'file-name)))
            (in-vicinity base relative-path))))
       (assq-ref arguments 'manifests)))

(define (manifests->packages store manifests)
  "Return the list of packages found in MANIFESTS."
  (define (load-manifest manifest)
    (save-module-excursion
     (lambda ()
       (set-current-module (make-user-module '((guix profiles) (gnu))))
       (primitive-load manifest))))

  (delete-duplicates!
   (map manifest-entry-item
        (append-map (compose manifest-entries
                             load-manifest)
                    manifests))))

;;;
;;; Hydra entry point.
;;;

(define (hydra-jobs store arguments)
  "Return Hydra jobs."
  (define subset
    (match (assoc-ref arguments 'subset)
      ("core" 'core)                              ; only build core packages
      ("hello" 'hello)                            ; only build hello
      (((? string?) (? string?) ...) 'list)       ; only build selected list of packages
      ("manifests" 'manifests)                    ; only build packages in the list of manifests
      (_ 'all)))                                  ; build everything

  (define systems
    (match (assoc-ref arguments 'systems)
      (#f              %hydra-supported-systems)
      ((lst ...)       lst)
      ((? string? str) (call-with-input-string str read))))

  (define (cross-jobs system)
    (define (from-32-to-64? target)
      ;; Return true if SYSTEM is 32-bit and TARGET is 64-bit.  This hack
      ;; prevents known-to-fail cross-builds from i686-linux or armhf-linux to
      ;; mips64el-linux-gnuabi64.
      (and (or (string-prefix? "i686-" system)
               (string-prefix? "i586-" system)
               (string-prefix? "armhf-" system))
           (string-contains target "64")))    ;x86_64, mips64el, aarch64, etc.

    (define (same? target)
      ;; Return true if SYSTEM and TARGET are the same thing.  This is so we
      ;; don't try to cross-compile to 'mips64el-linux-gnu' from
      ;; 'mips64el-linux'.
      (or (string-contains target system)
          (and (string-prefix? "armhf" system)    ;armhf-linux
               (string-prefix? "arm" target))))   ;arm-linux-gnueabihf

    (define (pointless? target)
      ;; Return #t if it makes no sense to cross-build to TARGET from SYSTEM.
      (match system
        ((or "x86_64-linux" "i686-linux")
         (if (string-contains target "mingw")
             (not (string=? "x86_64-linux" system))
             #f))
        (_
         ;; Don't try to cross-compile from non-Intel platforms: this isn't
         ;; very useful and these are often brittle configurations.
         #t)))

    (define (either proc1 proc2 proc3)
      (lambda (x)
        (or (proc1 x) (proc2 x) (proc3 x))))

    (append-map (lambda (target)
                  (map (lambda (package)
                         (package-cross-job store (job-name package)
                                            package target system))
                       %packages-to-cross-build))
                (remove (either from-32-to-64? same? pointless?)
                        %cross-targets)))

  ;; Turn off grafts.  Grafting is meant to happen on the user's machines.
  (parameterize ((%graft? #f))
    ;; Return one job for each package, except bootstrap packages.
    (append-map (lambda (system)
                  (format (current-error-port)
                          "evaluating for '~a' (heap size: ~a MiB)...~%"
                          system
                          (round
                           (/ (assoc-ref (gc-stats) 'heap-size)
                              (expt 2. 20))))
                  (invalidate-derivation-caches!)
                  (case subset
                    ((all)
                     ;; Build everything, including replacements.
                     (let ((all (all-packages))
                           (job (lambda (package)
                                  (package->job store package
                                                system))))
                       (append (filter-map job all)
                               (qemu-jobs store system)
                               (system-test-jobs store system)
                               (tarball-jobs store system)
                               (cross-jobs system))))
                    ((core)
                     ;; Build core packages only.
                     (append (map (lambda (package)
                                    (package-job store (job-name package)
                                                 package system))
                                  %core-packages)
                             (cross-jobs system)))
                    ((hello)
                     ;; Build hello package only.
                     (if (string=? system (%current-system))
                         (let ((hello (specification->package "hello")))
                           (list (package-job store (job-name hello) hello system)))
                         '()))
                    ((list)
                     ;; Build selected list of packages only.
                     (if (string=? system (%current-system))
                         (let* ((names (assoc-ref arguments 'subset))
                                (packages (map specification->package names)))
                           (map (lambda (package)
                                    (package-job store (job-name package)
                                                 package system))
                                  packages))
                         '()))
                    ((manifests)
                     ;; Build packages in the list of manifests.
                     (let* ((manifests (arguments->manifests arguments))
                            (packages (manifests->packages store manifests)))
                       (map (lambda (package)
                              (package-job store (job-name package)
                                           package system))
                            packages)))
                    (else
                     (error "unknown subset" subset))))
                systems)))


code:
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2017, 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/>.

;;;
;;; This file defines a continuous integration job to build the same modular
;;; Guix as 'guix pull', which is defined in (guix self).
;;;

(use-modules (guix store)
             (guix config)
             (guix utils)
             ((guix packages) #:select (%hydra-supported-systems))
             (guix derivations)
             (guix monads)
             ((guix licenses) #:prefix license:)
             (srfi srfi-1)
             (ice-9 match))

;; XXX: Debugging hack: since `hydra-eval-guile-jobs' redirects the output
;; port to the bit bucket, let us write to the error port instead.
(setvbuf (current-error-port) _IOLBF)
(set-current-output-port (current-error-port))

(define* (build-job store source version system)
  "Return a Hydra job a list building the modular Guix derivation from SOURCE
for SYSTEM.  Use VERSION as the version identifier."
  (lambda ()
    (define build
      (primitive-load (string-append source "/build-aux/build-self.scm")))

    `((derivation . ,(derivation-file-name
                      (run-with-store store
                        (build source #:version version #:system system
                               #:pull-version 1
                               #:guile-version "2.2")))) ;the latest 2.2.x
      (description . "Modular Guix")
      (long-description
       . "This is the modular Guix package as produced by 'guix pull'.")
      (license . ,license:gpl3+)
      (home-page . ,%guix-home-page-url)
      (maintainers . (,%guix-bug-report-address)))))

(define (hydra-jobs store arguments)
  "Return Hydra jobs."
  (define systems
    (match (assoc-ref arguments 'systems)
      (#f              %hydra-supported-systems)
      ((lst ...)       lst)
      ((? string? str) (call-with-input-string str read))))

  (define guix-checkout
    (or (assq-ref arguments 'guix)                ;Hydra on hydra
        (assq-ref arguments 'guix-modular)))      ;Cuirass on berlin

  (define version
    (or (assq-ref guix-checkout 'revision)
        "0.unknown"))

  (let ((file (assq-ref guix-checkout 'file-name)))
    (format (current-error-port) "using checkout ~s (~s; arguments: ~s)~%"
            guix-checkout file arguments)

    (map (lambda (system)
           (let ((name (string->symbol
                        (string-append "guix." system))))
             `(,name
               . ,(build-job store file version system))))
         systems)))

license: mit


code:
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2013, 2014, 2015, 2016, 2017, 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/>.

;;;
;;; This file defines build jobs of Guix itself for the Hydra continuation
;;; integration tool.
;;;

;; Attempt to use our very own Guix modules.
(eval-when (expand load eval)

  ;; Ignore any available .go, and force recompilation.  This is because our
  ;; checkout in the store has mtime set to the epoch, and thus .go files look
  ;; newer, even though they may not correspond.
  (set! %fresh-auto-compile #t)

  ;; Display which files are loaded.
  (set! %load-verbosely #t)

  (and=> (assoc-ref (current-source-location) 'filename)
         (lambda (file)
           (let ((dir (string-append (dirname file) "/../..")))
             (format (current-error-port) "prepending ~s to the load path~%"
                     dir)
             (set! %load-path (cons dir %load-path))))))

(use-modules (guix store)
             (guix packages)
             (guix utils)
             (guix grafts)
             (guix derivations)
             (guix build-system gnu)
             (gnu packages package-management)
             (srfi srfi-1)
             (srfi srfi-26)
             (ice-9 match))

;; XXX: Debugging hack: since `hydra-eval-guile-jobs' redirects the output
;; port to the bit bucket, let us write to the error port instead.
(setvbuf (current-error-port) _IOLBF)
(set-current-output-port (current-error-port))

(define* (package->alist store package system
                         #:optional (package-derivation package-derivation))
  "Convert PACKAGE to an alist suitable for Hydra."
  `((derivation . ,(derivation-file-name
                    (parameterize ((%graft? #f))
                      (package-derivation store package system
                                          #:graft? #f))))
    (description . ,(package-synopsis package))
    (long-description . ,(package-description package))
    (license . ,(package-license package))
    (home-page . ,(package-home-page package))
    (maintainers . ("bug-guix@gnu.org"))))

(define (hydra-jobs store arguments)
  "Return Hydra jobs."
  (define systems
    (match (filter-map (match-lambda
                        (('system . value)
                         value)
                        (_ #f))
                       arguments)
      ((lst ..1)
       lst)
      (_
       (list (%current-system)))))

  (define guix-checkout
    (assq-ref arguments 'guix))

  (let ((file (assq-ref guix-checkout 'file-name)))
    (format (current-error-port) "using checkout ~s (~s)~%"
            guix-checkout file)

    `((tarball . ,(cute package->alist store
                        (dist-package guix file)
                        (%current-system)))

      ,@(map (lambda (system)
               (let ((name (string->symbol
                            (string-append "guix." system))))
                 `(,name
                   . ,(cute package->alist store
                            (package
                              (inherit guix)
                              (version "latest")
                              (source file))
                            system))))
             %hydra-supported-systems))))


code:
#!/bin/sh

# GNU Guix --- Functional package management for GNU
# Copyright © 2012, 2013, 2014, 2015, 2017, 2018 Ludovic Courtès <ludo@gnu.org>
# Copyright © 2017 Eric Bavier <bavier@cray.com>
#
# 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/>.

# Usage: ./pre-inst-env COMMAND ARG...
#
# Run COMMAND in a pre-installation environment.  Typical use is
# "./pre-inst-env guix build hello".

# By default we may end up with absolute directory names that contain '..',
# which get into $GUILE_LOAD_PATH, leading to '..' in the module file names
# recorded by Guile.  To avoid that, make sure we get a real absolute
# directory name.  Additionally, use '-P' to get the canonical directory name
# so that Guile's 'relative' %file-port-name-canonicalization can actually
# work (see <http://bugs.gnu.org/17935>.)
abs_top_srcdir="`cd "@abs_top_srcdir@" > /dev/null; pwd -P`"
abs_top_builddir="`cd "@abs_top_builddir@" > /dev/null; pwd -P`"

GUILE_LOAD_COMPILED_PATH="$abs_top_builddir${GUILE_LOAD_COMPILED_PATH:+:}$GUILE_LOAD_COMPILED_PATH"
GUILE_LOAD_PATH="$abs_top_builddir:$abs_top_srcdir${GUILE_LOAD_PATH:+:}$GUILE_LOAD_PATH"
export GUILE_LOAD_COMPILED_PATH GUILE_LOAD_PATH

# Define $PATH so that `guix' and friends are easily found.

PATH="$abs_top_builddir/scripts:$abs_top_builddir:$PATH"
export PATH

# Daemon helpers.

NIX_ROOT_FINDER="$abs_top_builddir/nix/scripts/list-runtime-roots"
NIX_SUBSTITUTERS="$abs_top_builddir/nix/scripts/substitute"
NIX_LIBEXEC_DIR="@abs_top_builddir@/nix/scripts" # for 'guix-authenticate'

export NIX_ROOT_FINDER NIX_SUBSTITUTERS NIX_LIBEXEC_DIR

NIX_BUILD_HOOK="$abs_top_builddir/nix/scripts/offload"
@BUILD_DAEMON_OFFLOAD_TRUE@export NIX_BUILD_HOOK
@BUILD_DAEMON_OFFLOAD_FALSE@# No offloading support.
@BUILD_DAEMON_OFFLOAD_FALSE@unset NIX_BUILD_HOOK

# The following variables need only be defined when compiling Guix
# modules, but we define them to be on the safe side in case of
# auto-compilation.

NIX_HASH="@NIX_HASH@"
export NIX_HASH

# Define $GUIX_UNINSTALLED to prevent `guix' from
# prepending @guilemoduledir@ to the Guile load paths.

GUIX_UNINSTALLED=1
export GUIX_UNINSTALLED

exec "$@"


code:
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2016, 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 (run-system-tests)
  #:use-module (gnu tests)
  #:use-module (guix store)
  #:use-module (guix status)
  #:use-module (guix monads)
  #:use-module (guix derivations)
  #:use-module (guix ui)
  #:use-module (srfi srfi-1)
  #:use-module (srfi srfi-34)
  #:use-module (ice-9 match)
  #:export (run-system-tests))

(define (built-derivations* drv)
  (lambda (store)
    (guard (c ((nix-protocol-error? c)
               (values #f store)))
      (values (build-derivations store drv) store))))

(define (filterm mproc lst)                       ;XXX: move to (guix monads)
  (with-monad %store-monad
    (>>= (foldm %store-monad
                (lambda (item result)
                  (mlet %store-monad ((keep? (mproc item)))
                    (return (if keep?
                                (cons item result)
                                result))))
                '()
                lst)
         (lift1 reverse %store-monad))))

(define (run-system-tests . args)
  (define tests
    ;; Honor the 'TESTS' environment variable so that one can select a subset
    ;; of tests to run in the usual way:
    ;;
    ;;   make check-system TESTS=installed-os
    (match (getenv "TESTS")
      (#f
       (all-system-tests))
      ((= string-tokenize (tests ...))
       (filter (lambda (test)
                 (member (system-test-name test) tests))
               (all-system-tests)))))

  (format (current-error-port) "Running ~a system tests...~%"
          (length tests))

  (with-store store
    (with-status-report print-build-event
      (run-with-store store
        (mlet* %store-monad ((drv (mapm %store-monad system-test-value tests))
                             (out -> (map derivation->output-path drv)))
          (mbegin %store-monad
            (show-what-to-build* drv)
            (set-build-options* #:keep-going? #t #:keep-failed? #t
                                #:print-build-trace #t
                                #:print-extended-build-trace? #t
                                #:fallback? #t)
            (built-derivations* drv)
            (mlet %store-monad ((valid  (filterm (store-lift valid-path?)
                                                 out))
                                (failed (filterm (store-lift
                                                  (negate valid-path?))
                                                 out)))
              (format #t "TOTAL: ~a\n" (length drv))
              (for-each (lambda (item)
                          (format #t "PASS: ~a~%" item))
                        valid)
              (for-each (lambda (item)
                          (format #t "FAIL: ~a~%" item))
                        failed)
              (exit (null? failed)))))))))


code:
;;;; test-driver.scm - Guile test driver for Automake testsuite harness

(define script-version "2017-03-22.13") ;UTC

;;; Copyright © 2015, 2016 Mathieu Lirzin <mthl@gnu.org>
;;;
;;; This program 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.
;;;
;;; This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.

;;;; Commentary:
;;;
;;; This script provides a Guile test driver using the SRFI-64 Scheme API for
;;; test suites.  SRFI-64 is distributed with Guile since version 2.0.9.
;;;
;;;; Code:

(use-modules (ice-9 getopt-long)
             (ice-9 pretty-print)
             (srfi srfi-26)
             (srfi srfi-64))

(define (show-help)
  (display "Usage:
   test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
               [--expect-failure={yes|no}] [--color-tests={yes|no}]
               [--enable-hard-errors={yes|no}] [--brief={yes|no}}] [--]
               TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS]
The '--test-name', '--log-file' and '--trs-file' options are mandatory.\n"))

(define %options
  '((test-name                 (value #t))
    (log-file                  (value #t))
    (trs-file                  (value #t))
    (color-tests               (value #t))
    (expect-failure            (value #t)) ;XXX: not implemented yet
    (enable-hard-errors        (value #t)) ;not implemented in SRFI-64
    (brief                     (value #t))
    (help    (single-char #\h) (value #f))
    (version (single-char #\V) (value #f))))

(define (option->boolean options key)
  "Return #t if the value associated with KEY in OPTIONS is \"yes\"."
  (and=> (option-ref options key #f) (cut string=? <> "yes")))

(define* (test-display field value  #:optional (port (current-output-port))
                       #:key pretty?)
  "Display \"FIELD: VALUE\\n\" on PORT."
  (if pretty?
      (begin
        (format port "~A:~%" field)
        (pretty-print value port #:per-line-prefix "+ "))
      (format port "~A: ~S~%" field value)))

(define* (result->string symbol #:key colorize?)
  "Return SYMBOL as an upper case string.  Use colors when COLORIZE is #t."
  (let ((result (string-upcase (symbol->string symbol))))
    (if colorize?
        (string-append (case symbol
                         ((pass)       "")  ;green
                         ((xfail)      "")  ;light green
                         ((skip)       "")  ;blue
                         ((fail xpass) "")  ;red
                         ((error)      "")) ;magenta
                       result
                       "")          ;no color
        result)))

(define* (test-runner-gnu test-name #:key color? brief? out-port trs-port)
  "Return an custom SRFI-64 test runner.  TEST-NAME is a string specifying the
file name of the current the test.  COLOR? specifies whether to use colors,
and BRIEF?, well, you know.  OUT-PORT and TRS-PORT must be output ports.  The
current output port is supposed to be redirected to a '.log' file."

  (define (test-on-test-begin-gnu runner)
    ;; Procedure called at the start of an individual test case, before the
    ;; test expression (and expected value) are evaluated.
    (let ((result (cute assq-ref (test-result-alist runner) <>)))
      (format #t "test-name: ~A~%" (result 'test-name))
      (format #t "location: ~A~%"
              (string-append (result 'source-file) ":"
                             (number->string (result 'source-line))))
      (test-display "source" (result 'source-form) #:pretty? #t)))

  (define (test-on-test-end-gnu runner)
    ;; Procedure called at the end of an individual test case, when the result
    ;; of the test is available.
    (let* ((results (test-result-alist runner))
           (result? (cut assq <> results))
           (result  (cut assq-ref results <>)))
      (unless brief?
        ;; Display the result of each test case on the console.
        (format out-port "~A: ~A - ~A~%"
                (result->string (test-result-kind runner) #:colorize? color?)
                test-name (test-runner-test-name runner)))
      (when (result? 'expected-value)
        (test-display "expected-value" (result 'expected-value)))
      (when (result? 'expected-error)
        (test-display "expected-error" (result 'expected-error) #:pretty? #t))
      (when (result? 'actual-value)
        (test-display "actual-value" (result 'actual-value)))
      (when (result? 'actual-error)
        (test-display "actual-error" (result 'actual-error) #:pretty? #t))
      (format #t "result: ~a~%" (result->string (result 'result-kind)))
      (newline)
      (format trs-port ":test-result: ~A ~A~%"
              (result->string (test-result-kind runner))
              (test-runner-test-name runner))))

  (define (test-on-group-end-gnu runner)
    ;; Procedure called by a 'test-end', including at the end of a test-group.
    (let ((fail (or (positive? (test-runner-fail-count runner))
                    (positive? (test-runner-xpass-count runner))))
          (skip (or (positive? (test-runner-skip-count runner))
                    (positive? (test-runner-xfail-count runner)))))
      ;; XXX: The global results need some refinements for XPASS.
      (format trs-port ":global-test-result: ~A~%"
              (if fail "FAIL" (if skip "SKIP" "PASS")))
      (format trs-port ":recheck: ~A~%"
              (if fail "yes" "no"))
      (format trs-port ":copy-in-global-log: ~A~%"
              (if (or fail skip) "yes" "no"))
      (when brief?
        ;; Display the global test group result on the console.
        (format out-port "~A: ~A~%"
                (result->string (if fail 'fail (if skip 'skip 'pass))
                                #:colorize? color?)
                test-name))
      #f))

  (let ((runner (test-runner-null)))
    (test-runner-on-test-begin! runner test-on-test-begin-gnu)
    (test-runner-on-test-end! runner test-on-test-end-gnu)
    (test-runner-on-group-end! runner test-on-group-end-gnu)
    (test-runner-on-bad-end-name! runner test-on-bad-end-name-simple)
    runner))

;;;
;;; Entry point.
;;;

(define (main . args)
  (let* ((opts   (getopt-long (command-line) %options))
         (option (cut option-ref opts <> <>)))
    (cond
     ((option 'help #f)    (show-help))
     ((option 'version #f) (format #t "test-driver.scm ~A" script-version))
     (else
      (let ((log (open-file (option 'log-file "") "w0"))
            (trs (open-file (option 'trs-file "") "wl"))
            (out (duplicate-port (current-output-port) "wl")))
        (redirect-port log (current-output-port))
        (redirect-port log (current-warning-port))
        (redirect-port log (current-error-port))
        (test-with-runner
            (test-runner-gnu (option 'test-name #f)
                             #:color? (option->boolean opts 'color-tests)
                             #:brief? (option->boolean opts 'brief)
                             #:out-port out #:trs-port trs)
          (load-from-path (option 'test-name #f)))
        (close-port log)
        (close-port trs)
        (close-port out))))
    (exit 0)))

;;; Local Variables:
;;; eval: (add-hook 'write-file-functions 'time-stamp)
;;; time-stamp-start: "(define script-version \""
;;; time-stamp-format: "%:y-%02m-%02d.%02H"
;;; time-stamp-time-zone: "UTC"
;;; time-stamp-end: "\") ;UTC"
;;; End:

;;;; test-driver.scm ends here.


code:
#!/bin/sh

# GNU Guix --- Functional package management for GNU
# Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 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/>.

# Usage: ./test-env COMMAND ARG...
#
# Run the daemon in the build directory, and run COMMAND within
# `pre-inst-env'.  This is used to run unit tests with the just-built
# daemon, unless `--disable-daemon' was passed at configure time.

# Make sure 'cd' behaves deterministically and doesn't write anything to
# stdout.
unset CDPATH

case "$1" in
    --quiet-stderr)
	# Silence the daemon's output, which is often useless, as well as that
	# of Bash (such as "Terminated" messages when 'guix-daemon' is
	# killed.)
	exec 2> /dev/null
	shift
	;;
esac

if [ -x "@abs_top_builddir@/guix-daemon" ]
then
    NIX_STORE_DIR="@GUIX_TEST_ROOT@/store"

    # Do that because store.scm calls `canonicalize-path' on it.
    mkdir -p "$NIX_STORE_DIR"

    # Canonicalize the store directory name in an attempt to avoid symlinks in
    # it or its parent directories.  See <http://bugs.gnu.org/17935>.
    NIX_STORE_DIR="`cd "@GUIX_TEST_ROOT@/store"; pwd -P`"

    NIX_LOCALSTATE_DIR="@GUIX_TEST_ROOT@/var"
    NIX_LOG_DIR="@GUIX_TEST_ROOT@/var/log/guix"
    NIX_DB_DIR="@GUIX_TEST_ROOT@/db"
    NIX_ROOT_FINDER="@abs_top_builddir@/nix/scripts/list-runtime-roots"

    # Choose a PID-dependent name to allow for parallel builds.  Note
    # that the directory name must be chosen so that the socket's file
    # name is less than 108-char long (the size of `sun_path' in glibc).
    # Currently, in Nix builds, we're at ~106 chars...
    NIX_STATE_DIR="@GUIX_TEST_ROOT@/var/$$"

    # We can't exit when we reach the limit, because perhaps the test doesn't
    # actually rely on the daemon, but at least warn.
    if test "`echo -n "$NIX_STATE_DIR/daemon-socket/socket" | wc -c`" -ge 108
    then
	echo "warning: exceeding socket file name limit; test may fail!" >&2
    fi

    # The configuration directory, for import/export signing keys.
    GUIX_CONFIGURATION_DIRECTORY="@GUIX_TEST_ROOT@/etc"
    if [ ! -d "$GUIX_CONFIGURATION_DIRECTORY" ]
    then
	# Copy the keys so that the secret key has the right permissions (the
	# daemon errors out when this is not the case.)
	mkdir -p "$GUIX_CONFIGURATION_DIRECTORY"
	cp "@abs_top_srcdir@/tests/signing-key.sec"	\
	    "@abs_top_srcdir@/tests/signing-key.pub"	\
	    "$GUIX_CONFIGURATION_DIRECTORY"
	chmod 400 "$GUIX_CONFIGURATION_DIRECTORY/signing-key.sec"
    fi

    # A place to store data of the substituter.
    GUIX_BINARY_SUBSTITUTE_URL="file://$NIX_STATE_DIR/substituter-data"
    rm -rf "$NIX_STATE_DIR/substituter-data"
    mkdir -p "$NIX_STATE_DIR/substituter-data"

    # For a number of tests, we want to allow unsigned narinfos, for
    # simplicity.
    GUIX_ALLOW_UNAUTHENTICATED_SUBSTITUTES=yes

    # Place for the substituter's cache.
    XDG_CACHE_HOME="$NIX_STATE_DIR/cache-$$"

    # For the (guix import snix) tests.
    NIXPKGS="@NIXPKGS@"

    export NIX_IGNORE_SYMLINK_STORE NIX_STORE_DIR		\
	NIX_LOCALSTATE_DIR NIX_LOG_DIR NIX_STATE_DIR NIX_DB_DIR	\
	NIX_ROOT_FINDER GUIX_BINARY_SUBSTITUTE_URL		\
        GUIX_ALLOW_UNAUTHENTICATED_SUBSTITUTES			\
        GUIX_CONFIGURATION_DIRECTORY XDG_CACHE_HOME NIXPKGS

    # Launch the daemon without chroot support because is may be
    # unavailable, for instance if we're not running as root.
    "@abs_top_builddir@/pre-inst-env"				\
	"@abs_top_builddir@/guix-daemon" --disable-chroot	\
	--substitute-urls="$GUIX_BINARY_SUBSTITUTE_URL" &

    daemon_pid=$!
    trap "kill $daemon_pid ; rm -rf $NIX_STATE_DIR" EXIT

    # The test suite expects the 'guile-bootstrap' package to be available.
    # Normally the Guile bootstrap tarball is downloaded by a fixed-output
    # derivation but when network access is missing we allow users to drop
    # the tarball in 'gnu/packages/bootstrap/SYSTEM' and "intern" it here.
    bootstrap_directory="@abs_top_builddir@/gnu/packages/bootstrap/@guix_system@"
    if [ -d "$bootstrap_directory" ]
    then
	# Make sure 'guix-daemon' is listening before invoking 'guix
	# download'.
	"@abs_top_builddir@/pre-inst-env" "@GUILE@" -c \
	     '(use-modules (guix))
(let loop ((i 10))
  (catch #t
    (lambda () (open-connection))
    (lambda (key . args)
      (if (zero? i)
          (apply throw key args)
          (begin (usleep 500000) (loop (- i 1)))))))'

	for file in "$bootstrap_directory"/guile-*
	do
	    [ -f "$file" ] &&					\
	    "@abs_top_builddir@/pre-inst-env"			\
		guix download "file://$file" > /dev/null
	done
    fi
fi

# Avoid issues that could stem from l10n, such as language/encoding
# mismatches.
unset LANGUAGE
LC_MESSAGES=C
export LC_MESSAGES

# Disable grafts by default because they can cause things to be built
# regardless of '--dry-run'.
GUIX_BUILD_OPTIONS="--no-grafts"
export GUIX_BUILD_OPTIONS

# Ignore user settings.
unset GUIX_PACKAGE_PATH

storedir="@storedir@"
prefix="@prefix@"
datarootdir="@datarootdir@"
datadir="@datadir@"
localstatedir="@localstatedir@"
export storedir prefix datarootdir datadir localstatedir

"@abs_top_builddir@/pre-inst-env" "$@"
exit $?


code:
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2017, 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/>.

;;; Commentary:
;;;
;;; This script updates the list of new and updated packages in 'NEWS'.
;;;
;;; Code:

(use-modules (gnu) (guix)
             (guix build utils)
             ((guix ui) #:select (fill-paragraph))
             (srfi srfi-1)
             (srfi srfi-11)
             (ice-9 match)
             (ice-9 rdelim)
             (ice-9 regex)
             (ice-9 pretty-print))

(define %header-rx
  (make-regexp "^\\* Changes in (version )?([0-9.]+) \\(since ([0-9.]+)\\)"))

(define (NEWS->versions port)
  "Return two values: the previous version and the current version as read
from PORT, which is an input port on the 'NEWS' file."
  (let loop ()
    (let ((line (read-line port)))
      (cond ((eof-object? line)
             (error "failed to determine previous and current version"
                    port))
            ((regexp-exec %header-rx line)
             =>
             (lambda (match)
               (values (match:substring match 3)
                       (match:substring match 2))))
            (else
             (loop))))))

(define (skip-to-org-heading port)
  "Read from PORT until an Org heading is found."
  (let loop ()
    (let ((next (peek-char port)))
      (cond ((eqv? next #\*)
             #t)
            ((eof-object? next)
             (error "next heading could not be found"))
            (else
             (read-line port)
             (loop))))))

(define (rewrite-org-section input output heading-rx proc)
  "Write to OUTPUT the text read from INPUT, but with the first Org section
matching HEADING-RX replaced by NEW-HEADING and CONTENTS."
  (let loop ()
    (let ((line (read-line input)))
      (cond ((eof-object? line)
             (error "failed to match heading regexp" heading-rx))
            ((regexp-exec heading-rx line)
             =>
             (lambda (match)
               (proc match output)
               (skip-to-org-heading input)
               (dump-port input output)
               #t))
            (else
             (display line output)
             (newline output)
             (loop))))))

(define (enumeration->paragraph lst)
  "Turn LST, a list of strings, into a single string that is a ready-to-print
paragraph."
  (fill-paragraph (string-join (sort lst string<?) ", ")
                  75))

(define (write-packages-added news-file old new)
  "Write to NEWS-FILE the list of packages added between OLD and NEW."
  (let ((added (lset-difference string=? (map car new) (map car old))))
    (with-atomic-file-replacement news-file
      (lambda (input output)
        (rewrite-org-section input output
                             (make-regexp "^(\\*+) (.*) new packages")
                             (lambda (match port)
                               (let ((stars (match:substring match 1)))
                                 (format port
                                         "~a ~a new packages~%~%~a~%~%"
                                         stars (length added)
                                         (enumeration->paragraph added)))))))))

(define (write-packages-updates news-file old new)
  "Write to NEWS-FILE the list of packages upgraded between OLD and NEW."
  (let ((upgraded (filter-map (match-lambda
                                ((package . new-version)
                                 (match (assoc package old)
                                   ((_ . old-version)
                                    (and (version>? new-version old-version)
                                         (string-append package "@"
                                                        new-version)))
                                   (_ #f))))
                              new)))
    (with-atomic-file-replacement news-file
      (lambda (input output)
        (rewrite-org-section input output
                             (make-regexp "^(\\*+) (.*) package updates")
                             (lambda (match port)
                               (let ((stars (match:substring match 1)))
                                 (format port
                                         "~a ~a package updates~%~%~a~%~%"
                                         stars (length upgraded)
                                         (enumeration->paragraph upgraded)))))))))

(define (main . args)
  (match args
    ((news-file data-directory)
     ;; Don't browse things listed in the user's $GUIX_PACKAGE_PATH and
     ;; in external channels.
     (parameterize ((%package-module-path
                     %default-package-module-path))
       (define (package-file version)
         (string-append data-directory "/packages-"
                        version ".txt"))

       (let-values (((previous-version new-version)
                     (call-with-input-file news-file NEWS->versions)))
         (let* ((old (call-with-input-file (package-file previous-version)
                       read))
                (new (fold-packages (lambda (p r)
                                      (alist-cons (package-name p) (package-version p)
                                                  r))
                                    '())))
           (call-with-output-file (package-file new-version)
             (lambda (port)
               (pretty-print new port)))

           (write-packages-added news-file old new)
           (write-packages-updates news-file old new)))))
    (x
     (format (current-error-port) "Usage: update-NEWS NEWS-FILE DATA-DIRECTORY

Update the list of new and updated packages in NEWS-FILE using the
previous-version package list from DATA-DIRECTORY.\n")
     (exit 1))))

(apply main (cdr (command-line)))


code:
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2017 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/>.

;;; Commentary:
;;;
;;; This scripts updates the definition of the 'guix' package in Guix for the
;;; current commit.  It requires Git to be installed.
;;;
;;; Code:

(use-modules (guix)
             (guix git-download)
             (guix upstream)
             (guix utils)
             (guix base32)
             (guix build utils)
             (gnu packages package-management)
             (ice-9 match))

(define %top-srcdir
  (string-append (current-source-directory) "/.."))

(define version-controlled?
  (git-predicate %top-srcdir))

(define (package-definition-location)
  "Return the source properties of the definition of the 'guix' package."
  (call-with-input-file (location-file (package-location guix))
    (lambda (port)
      (let loop ()
        (match (read port)
          ((? eof-object?)
           (error "definition of 'guix' package could not be found"
                  (port-filename port)))
          (('define-public 'guix value)
           (source-properties value))
          (_
           (loop)))))))

(define* (update-definition commit hash
                            #:key version old-hash)
  "Return a one-argument procedure that takes a string, the definition of the
'guix' package, and returns a string, the update definition for VERSION,
COMMIT."
  (define (linear-offset str line column)
    ;; Return the offset in characters to reach LINE and COLUMN (both
    ;; zero-indexed) in STR.
    (call-with-input-string str
      (lambda (port)
        (let loop ((offset 0))
          (cond ((and (= (port-column port) column)
                      (= (port-line port) line))
                 offset)
                ((eof-object? (read-char port))
                 (error "line and column not reached!"
                        str))
                (else
                 (loop (+ 1 offset))))))))

  (define (update-hash str)
    ;; Replace OLD-HASH with HASH in STR.
    (string-replace-substring str
                              (bytevector->nix-base32-string old-hash)
                              (bytevector->nix-base32-string hash)))

  (lambda (str)
    (match (call-with-input-string str read)
      (('let (('version old-version)
              ('commit old-commit)
              ('revision old-revision))
         defn)
       (let* ((location (source-properties defn))
              (line     (assq-ref location 'line))
              (column   0)
              (offset   (linear-offset str line column)))
         (string-append (format #f "(let ((version \"~a\")
        (commit \"~a\")
        (revision ~a))\n"
                                (or version old-version)
                                commit
                                (if (and version
                                         (not (string=? version old-version)))
                                    0
                                    (+ 1 old-revision)))
                        (string-drop (update-hash str) offset))))
      (exp
       (error "'guix' package definition is not as expected" exp)))))

(define (main . args)
  (match args
    ((commit version)
     (with-store store
       (let* ((source   (add-to-store store
                                      "guix-checkout" ;dummy name
                                      #t "sha256" %top-srcdir
                                      #:select? version-controlled?))
              (hash     (query-path-hash store source))
              (location (package-definition-location))
              (old-hash (origin-sha256 (package-source guix))))
         (edit-expression location
                          (update-definition commit hash
                                             #:old-hash old-hash
                                             #:version version))

         ;; Re-add SOURCE to the store, but this time under the real name used
         ;; in the 'origin'.  This allows us to build the package without
         ;; having to make a real checkout; thus, it also works when working
         ;; on a private branch.
         (reload-module
          (resolve-module '(gnu packages package-management)))

         (let* ((source (add-to-store store
                                      (origin-file-name (package-source guix))
                                      #t "sha256" source))
                (root   (store-path-package-name source)))

           ;; Add an indirect GC root for SOURCE in the current directory.
           (false-if-exception (delete-file root))
           (symlink source root)
           (add-indirect-root store root)

           (format #t "source code for commit ~a: ~a (GC root: ~a)~%"
                   commit source root)))))
    ((commit)
     ;; Automatically deduce the version and revision numbers.
     (main commit #f))))

(apply main (cdr (command-line)))


code:
dnl -*- Autoconf -*- fragment for the C++ daemon.

AC_MSG_CHECKING([whether to build daemon])
AC_MSG_RESULT([$guix_build_daemon])

dnl C++ environment.  This macro must be used unconditionnaly.
AC_PROG_CXX
AM_PROG_AR
AC_LANG([C++])

if test "x$guix_build_daemon" = "xyes"; then

  GUIX_ASSERT_CXX11

  AC_PROG_RANLIB
  AC_CONFIG_HEADER([nix/config.h])

  dnl Use 64-bit file system calls so that we can support files > 2 GiB.
  AC_SYS_LARGEFILE

  dnl Look for zlib, a required dependency.
  AC_CHECK_LIB([z], [gzdopen], [true],
    [AC_MSG_ERROR([Guix requires zlib.  See http://www.zlib.net/.])])
  AC_CHECK_HEADERS([zlib.h], [true],
    [AC_MSG_ERROR([Guix requires zlib.  See http://www.zlib.net/.])])

  dnl Look for libbz2, an optional dependency.
  AC_CHECK_LIB([bz2], [BZ2_bzWriteOpen], [HAVE_LIBBZ2=yes], [HAVE_LIBBZ2=no])
  if test "x$HAVE_LIBBZ2" = xyes; then
    AC_CHECK_HEADERS([bzlib.h])
    HAVE_LIBBZ2="$ac_cv_header_bzlib_h"
  fi

  dnl Look for SQLite, a required dependency.
  PKG_CHECK_MODULES([SQLITE3], [sqlite3 >= 3.6.19])

  AC_DEFINE([NIX_VERSION], ["0.0.0"], [Fake Nix version number.])
  AC_DEFINE_UNQUOTED([SYSTEM], ["$guix_system"],
    [Guix host system type--i.e., platform and OS kernel tuple.])

  case "$LIBGCRYPT_PREFIX" in
    no)
      LIBGCRYPT_CFLAGS=""
      ;;
    *)
      LIBGCRYPT_CFLAGS="-I$LIBGCRYPT_PREFIX/include"
      ;;
  esac

  case "$LIBGCRYPT_LIBDIR" in
    no | "")
      LIBGCRYPT_LIBS="-lgcrypt"
      ;;
    *)
      LIBGCRYPT_LIBS="-L$LIBGCRYPT_LIBDIR -lgcrypt"
      ;;
  esac

  AC_SUBST([LIBGCRYPT_CFLAGS])
  AC_SUBST([LIBGCRYPT_LIBS])

  save_CFLAGS="$CFLAGS"
  save_LDFLAGS="$LDFLAGS"
  CFLAGS="$CFLAGS $LIBGCRYPT_CFLAGS"
  LDFLAGS="$LDFLAGS $LIBGCRYPT_LDFLAGS"

  have_gcrypt=yes
  AC_CHECK_LIB([gcrypt], [gcry_md_open], [:], [have_gcrypt=no])
  AC_CHECK_HEADER([gcrypt.h], [:], [have_gcrypt=no])
  if test "x$have_gcrypt" != "xyes"; then
    AC_MSG_ERROR([GNU libgcrypt not found; please install it.])
  fi

  CFLAGS="$save_CFLAGS"
  LDFLAGS="$save_LDFLAGS"

  dnl Chroot support.
  AC_CHECK_FUNCS([chroot unshare])
  AC_CHECK_HEADERS([sched.h sys/param.h sys/mount.h sys/syscall.h])

  if test "x$ac_cv_func_chroot" != "xyes"; then
    AC_MSG_ERROR(['chroot' function missing, bailing out])
  fi

  dnl lutimes and lchown: used when canonicalizing store items.
  dnl posix_fallocate: used when extracting archives.
  dnl vfork: to speed up spawning of helper programs.
  dnl   `--> now disabled because of unpredictable behavior:
  dnl        see <http://lists.gnu.org/archive/html/guix-devel/2014-05/msg00036.html>
  dnl        and Nix commit f794465c (Nov. 2012).
  dnl sched_setaffinity: to improve RPC locality.
  dnl statvfs: to detect disk-full conditions.
  dnl strsignal: for error reporting.
  AC_CHECK_FUNCS([lutimes lchown posix_fallocate sched_setaffinity \
     statvfs nanosleep strsignal])

  dnl Check whether the store optimiser can optimise symlinks.
  AC_MSG_CHECKING([whether it is possible to create a link to a symlink])
  ln -s bla tmp_link
  if ln tmp_link tmp_link2 2> /dev/null; then
      AC_MSG_RESULT(yes)
      AC_DEFINE(CAN_LINK_SYMLINK, 1, [Whether link() works on symlinks.])
  else
      AC_MSG_RESULT(no)
  fi
  rm -f tmp_link tmp_link2

  dnl Check for <locale>.
  AC_LANG_PUSH(C++)
  AC_CHECK_HEADERS([locale])
  AC_LANG_POP(C++)

  dnl Check whether we have the `personality' syscall, which allows us
  dnl to do i686-linux builds on x86_64-linux machines.
  AC_CHECK_HEADERS([sys/personality.h])

  dnl Check for <linux/fs.h> (for immutable file support).
  AC_CHECK_HEADERS([linux/fs.h])

  dnl Determine the appropriate default list of substitute URLs (GnuTLS
  dnl is required so we can default to 'https'.)
  case "x$host_cpu" in
    xaarch64)
      # Currently only berlin.guixsd.org provides aarch64 binaries.
      guix_substitute_urls="https://berlin.guixsd.org"
      ;;
    *)
      guix_substitute_urls="https://mirror.hydra.gnu.org"
      ;;
  esac

  AC_MSG_CHECKING([for default substitute URLs])
  AC_MSG_RESULT([$guix_substitute_urls])

  AC_DEFINE_UNQUOTED([GUIX_SUBSTITUTE_URLS], ["$guix_substitute_urls"],
    [Default list of substitute URLs used by 'guix-daemon'.])

  dnl Check for Guile-SSH, which is required by 'guix offload'.
  GUIX_CHECK_GUILE_SSH

  case "x$guix_cv_have_recent_guile_ssh" in
    xyes)
      guix_build_daemon_offload="yes"
      AC_DEFINE([HAVE_DAEMON_OFFLOAD_HOOK], [1],
	[Define if the daemon's 'offload' build hook is being built (requires Guile-SSH).])
      ;;
    *)
      guix_build_daemon_offload="no"
      ;;
  esac

  dnl Temporary directory used to store the daemon's data.
  GUIX_TEST_ROOT_DIRECTORY
  GUIX_TEST_ROOT="$ac_cv_guix_test_root"
  AC_SUBST([GUIX_TEST_ROOT])

  GUIX_CHECK_LOCALSTATEDIR

  AC_CONFIG_FILES([nix/scripts/list-runtime-roots],
    [chmod +x nix/scripts/list-runtime-roots])
  AC_CONFIG_FILES([nix/scripts/download],
    [chmod +x nix/scripts/download])
  AC_CONFIG_FILES([nix/scripts/substitute],
    [chmod +x nix/scripts/substitute])
  AC_CONFIG_FILES([nix/scripts/guix-authenticate],
    [chmod +x nix/scripts/guix-authenticate])
  AC_CONFIG_FILES([nix/scripts/offload],
    [chmod +x nix/scripts/offload])
fi

AM_CONDITIONAL([HAVE_LIBBZ2], [test "x$HAVE_LIBBZ2" = "xyes"])
AM_CONDITIONAL([BUILD_DAEMON], [test "x$guix_build_daemon" = "xyes"])
AM_CONDITIONAL([BUILD_DAEMON_OFFLOAD],			\
  [test "x$guix_build_daemon" = "xyes"			\
   && test "x$guix_build_daemon_offload" = "xyes"])


code:
#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ(2.68)
AC_INIT([GNU Guix],
  [m4_esyscmd([build-aux/git-version-gen .tarball-version])],
  [bug-guix@gnu.org], [guix],
  [https://www.gnu.org/software/guix/])
AC_CONFIG_AUX_DIR([build-aux])

AM_INIT_AUTOMAKE([1.14 gnu silent-rules subdir-objects \
 color-tests parallel-tests -Woverride -Wno-portability])

# Enable silent rules by default.
AM_SILENT_RULES([yes])

AC_CONFIG_SRCDIR([guix.scm])
AC_CONFIG_MACRO_DIR([m4])

dnl For the C++ code.  This must be used early.
AC_USE_SYSTEM_EXTENSIONS

AM_GNU_GETTEXT([external])
AM_GNU_GETTEXT_VERSION([0.18.1])

GUIX_SYSTEM_TYPE
GUIX_ASSERT_SUPPORTED_SYSTEM

AC_ARG_WITH(store-dir,
  AC_HELP_STRING([--with-store-dir=PATH],
    [file name of the store (defaults to /gnu/store)]),
  [storedir="$withval"],
  [storedir="/gnu/store"])
AC_SUBST(storedir)

AC_ARG_WITH([bash-completion-dir],
  AC_HELP_STRING([--with-bash-completion-dir=DIR],
    [name of the Bash completion directory]),
  [bashcompletiondir="$withval"],
  [bashcompletiondir='${sysconfdir}/bash_completion.d'])
AC_SUBST([bashcompletiondir])

AC_ARG_WITH([zsh-completion-dir],
  AC_HELP_STRING([--with-zsh-completion-dir=DIR],
    [name of the Zsh completion directory]),
  [zshcompletiondir="$withval"],
  [zshcompletiondir='${datadir}/zsh/site-functions'])
AC_SUBST([zshcompletiondir])

AC_ARG_WITH([fish-completion-dir],
  AC_HELP_STRING([--with-fish-completion-dir=DIR],
    [name of the Fish completion directory]),
  [fishcompletiondir="$withval"],
  [fishcompletiondir='${datadir}/fish/vendor_completions.d'])
AC_SUBST([fishcompletiondir])

AC_ARG_WITH([selinux-policy-dir],
  AC_HELP_STRING([--with-selinux-policy-dir=DIR],
    [name of the SELinux policy directory]),
  [selinux_policydir="$withval"],
  [selinux_policydir='${datadir}/selinux/'])
AC_SUBST([selinux_policydir])

dnl Better be verbose.
AC_MSG_CHECKING([for the store directory])
AC_MSG_RESULT([$storedir])

AC_ARG_ENABLE([daemon],
  [AS_HELP_STRING([--disable-daemon], [do not build the Nix daemon (C++)])],
  [guix_build_daemon="$enableval"],
  [guix_build_daemon="yes"])

# Prepare a version of $localstatedir & co. that does not contain references
# to shell variables.
guix_prefix="`eval echo $prefix | sed -e"s|NONE|/usr/local|g"`"
guix_localstatedir="`eval echo $localstatedir | sed -e "s|NONE|$guix_prefix|g"`"
guix_sysconfdir="`eval echo $sysconfdir | sed -e "s|NONE|$guix_prefix|g"`"
guix_sbindir="`eval echo $sbindir | sed -e "s|NONE|$guix_prefix|g"`"
AC_SUBST([guix_localstatedir])
AC_SUBST([guix_sysconfdir])
AC_SUBST([guix_sbindir])

GUIX_CHECK_FILE_NAME_LIMITS([can_run_tests])
AM_CONDITIONAL([CAN_RUN_TESTS], [test "x$can_run_tests" = "xyes"])

dnl We require pkg.m4 (from pkg-config) and guile.m4 (from Guile.)
dnl Make sure they are available.
m4_pattern_forbid([PKG_CHECK_MODULES])
m4_pattern_forbid([GUILE_MODULE_AVAILABLE])
m4_pattern_forbid([^GUILE_P])
m4_pattern_allow([^GUILE_PKG_ERRORS])
m4_pattern_forbid([^GUIX_])

dnl Search for 'guile' and 'guild'.  This macro defines
dnl 'GUILE_EFFECTIVE_VERSION'.
GUILE_PKG([2.2 2.0])
GUILE_PROGS
if test "x$GUILD" = "x"; then
   AC_MSG_ERROR(['guild' binary not found; please check your guile-2.x installation.])
fi

if test "x$GUILE_EFFECTIVE_VERSION" = "x2.0"; then
  PKG_CHECK_MODULES([GUILE], [guile-2.0 >= 2.0.13])
fi

dnl Installation directories for .scm and .go files.
guilemoduledir="${datarootdir}/guile/site/$GUILE_EFFECTIVE_VERSION"
guileobjectdir="${libdir}/guile/$GUILE_EFFECTIVE_VERSION/site-ccache"
AC_SUBST([guilemoduledir])
AC_SUBST([guileobjectdir])

dnl The GnuTLS bindings are necessary for substitutes over HTTPS and for 'guix
dnl pull', among other things.
GUILE_MODULE_AVAILABLE([have_gnutls], [(gnutls)])
if test "x$have_gnutls" != "xyes"; then
  AC_MSG_ERROR([The Guile bindings of GnuTLS are missing; please install them.])
fi

dnl Check for Guile-Git.
GUILE_MODULE_AVAILABLE([have_guile_git], [(git)])
if test "x$have_guile_git" != "xyes"; then
  AC_MSG_ERROR([Guile-Git is missing; please install it.])
fi

dnl Guile-JSON is used in various places.
GUILE_MODULE_AVAILABLE([have_guile_json], [(json)])
AM_CONDITIONAL([HAVE_GUILE_JSON], [test "x$have_guile_json" = "xyes"])

dnl Guile-Sqlite3 is used by the (guix store ...) modules.
GUIX_CHECK_GUILE_SQLITE3
if test "x$guix_cv_have_recent_guile_sqlite3" != "xyes"; then
  AC_MSG_ERROR([A recent Guile-SQLite3 could not be found; please install it.])
fi

GUILE_MODULE_AVAILABLE([have_guile_gcrypt], [(gcrypt hash)])
if test "x$have_guile_gcrypt" != "xyes"; then
  AC_MSG_ERROR([Guile-Gcrypt could not be found; please install it.])
fi

dnl Make sure we have a full-fledged Guile.
GUIX_ASSERT_GUILE_FEATURES([regex posix socket net-db threads])

dnl Make sure we don't suffer from the bug in 'equal?' wrt. syntax objects
dnl found in 2.2.1.  See <https://bugs.gnu.org/29903>.
GUIX_ASSERT_SYNTAX_OBJECT_EQUAL

AC_PROG_SED

dnl Decompressors, for use by the substituter and other modules.
AC_PATH_PROG([GZIP], [gzip])
AC_PATH_PROG([BZIP2], [bzip2])
AC_PATH_PROG([XZ], [xz])
AC_SUBST([GZIP])
AC_SUBST([BZIP2])
AC_SUBST([XZ])

AC_ARG_WITH([nix-prefix],
  [AS_HELP_STRING([--with-nix-prefix=DIR],
    [search for Nix in DIR (for testing purposes and '--disable-daemon' builds)])],
  [case "$withval" in
    yes|no) ;;
    *)
      NIX_PREFIX="$withval"
      PATH="$NIX_PREFIX/bin:$PATH"; export PATH
      AC_SUBST([NIX_PREFIX])
      ;;
   esac],
  [])

AC_PATH_PROG([NIX_HASH], [nix-hash])
if test "x$guix_build_daemon$NIX_HASH" = "xno"; then
   AC_MSG_ERROR([Nix programs not found; please install Nix or use `--with-nix-prefix'.])
fi

AC_ARG_WITH([nixpkgs],
  [AS_HELP_STRING([--with-nixpkgs=DIR],
    [search for Nixpkgs in DIR (for testing purposes only)])],
  [case "$withval" in
    yes|no) AC_MSG_ERROR([Please use `--with-nixpkgs=DIR'.]);;
    *)      NIXPKGS="$withval";;
   esac],
  [])

AC_MSG_CHECKING([for Nixpkgs source tree])
if test -f "$NIXPKGS/default.nix"; then
   AC_MSG_RESULT([$NIXPKGS])
   AC_SUBST([NIXPKGS])
else
   AC_MSG_RESULT([not found])
fi

LIBGCRYPT="libgcrypt"
LIBGCRYPT_LIBDIR="no"
LIBGCRYPT_PREFIX="no"

AC_ARG_WITH([libgcrypt-prefix],
  [AS_HELP_STRING([--with-libgcrypt-prefix=DIR], [search for GNU libgcrypt in DIR])],
  [case "$withval" in
    yes|no)
      ;;
    *)
      LIBGCRYPT="$withval/lib/libgcrypt"
      LIBGCRYPT_PREFIX="$withval"
      LIBGCRYPT_LIBDIR="$withval/lib"
      ;;
   esac])

AC_ARG_WITH([libgcrypt-libdir],
  [AS_HELP_STRING([--with-libgcrypt-libdir=DIR],
     [search for GNU libgcrypt's shared library in DIR])],
  [case "$withval" in
    yes|no)
      LIBGCRYPT="libgcrypt"
      LIBGCRYPT_LIBDIR="no"
      ;;
    *)
      LIBGCRYPT="$withval/libgcrypt"
      LIBGCRYPT_LIBDIR="$withval"
      ;;
   esac])

dnl If none of the --with-libgcrypt-* options was used, try to determine the
dnl the library directory.
case "x$LIBGCRYPT_PREFIX$LIBGCRYPT_LIBDIR" in
  xnono)
    GUIX_LIBGCRYPT_LIBDIR([LIBGCRYPT_LIBDIR])
    ;;
esac

dnl Library name suitable for `dynamic-link'.
AC_MSG_CHECKING([for libgcrypt shared library name])
AC_MSG_RESULT([$LIBGCRYPT])
AC_SUBST([LIBGCRYPT])
AC_SUBST([LIBGCRYPT_PREFIX])
AC_SUBST([LIBGCRYPT_LIBDIR])

dnl Library name of zlib suitable for 'dynamic-link'.
GUIX_LIBZ_LIBDIR([libz_libdir])
if test "x$libz_libdir" = "x"; then
  LIBZ="libz"
else
  LIBZ="$libz_libdir/libz"
fi
AC_MSG_CHECKING([for zlib's shared library name])
AC_MSG_RESULT([$LIBZ])
AC_SUBST([LIBZ])

dnl Check for Guile-SSH, for the (guix ssh) module.
GUIX_CHECK_GUILE_SSH
AM_CONDITIONAL([HAVE_GUILE_SSH],
  [test "x$guix_cv_have_recent_guile_ssh" = "xyes"])

AC_CACHE_SAVE

m4_include([config-daemon.ac])

dnl `dot' (from the Graphviz package) is only needed for maintainers.
dnl See `Building from Git' in the manual for more info.
AM_MISSING_PROG([DOT], [dot])

dnl Manual pages.
AM_MISSING_PROG([HELP2MAN], [help2man])

dnl Documentation translation.
AM_MISSING_PROG([PO4A_TRANSLATE], [po4a-translate])
AM_MISSING_PROG([PO4A_UPDATEPO], [po4a-updatepo])

dnl Emacs (optional), for 'etc/indent-package.el'.
AC_PATH_PROG([EMACS], [emacs], [/usr/bin/emacs])
AC_SUBST([EMACS])

case "$storedir" in
  /gnu/store)
    ;;
  *)
    AC_MSG_WARN([Using a store directory other than '/gnu/store' will prevent you])
    AC_MSG_WARN([from downloading substitutes from gnu.org.])
    ;;
esac

AC_CONFIG_FILES([Makefile
                 po/guix/Makefile.in
                 po/packages/Makefile.in
                 etc/guix-daemon.cil
                 guix/config.scm])

AC_CONFIG_FILES([test-env:build-aux/test-env.in], [chmod +x test-env])
AC_CONFIG_FILES([pre-inst-env:build-aux/pre-inst-env.in],
  [chmod +x pre-inst-env])
AC_CONFIG_FILES([etc/indent-code.el], [chmod +x etc/indent-code.el])

AC_OUTPUT