self: Remove leftover export.
[jackhill/guix/guix.git] / guix / self.scm
index 28faeaa..fea5db5 100644 (file)
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2017, 2018 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2017, 2018, 2019 Ludovic Courtès <ludo@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
   #:use-module (guix discovery)
   #:use-module (guix packages)
   #:use-module (guix sets)
-  #:use-module (guix utils)
   #:use-module (guix modules)
-  #:use-module (guix build utils)
+  #:use-module ((guix build utils) #:select (find-files))
   #:use-module ((guix build compile) #:select (%lightweight-optimizations))
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-9)
+  #:use-module (srfi srfi-35)
   #:use-module (ice-9 match)
   #:export (make-config.scm
             whole-package                     ;for internal use in 'guix pull'
             compiled-guix
-            guix-derivation
-            reload-guix))
+            guix-derivation))
 
 \f
 ;;;
 ;;; Dependency handling.
 ;;;
 
-(define* (false-if-wrong-guile package
-                               #:optional (guile-version (effective-version)))
-  "Return #f if PACKAGE depends on the \"wrong\" major version of Guile (e.g.,
-2.0 instead of 2.2), otherwise return PACKAGE."
-  (let ((guile (any (match-lambda
-                      ((label (? package? dep) _ ...)
-                       (and (string=? (package-name dep) "guile")
-                            dep)))
-                    (package-direct-inputs package))))
-    (and (or (not guile)
-             (string-prefix? guile-version
-                             (package-version guile)))
-         package)))
-
-(define (package-for-guile guile-version . names)
-  "Return the package with one of the given NAMES that depends on
-GUILE-VERSION (\"2.0\" or \"2.2\"), or #f if none of the packages matches."
-  (let loop ((names names))
-    (match names
-      (()
-       #f)
-      ((name rest ...)
-       (match (specification->package name)
-         (#f
-          (loop rest))
-         ((? package? package)
-          (or (false-if-wrong-guile package guile-version)
-              (loop rest))))))))
-
 (define specification->package
   ;; Use our own variant of that procedure because that of (gnu packages)
   ;; would traverse all the .scm files, which is wasteful.
@@ -84,18 +54,13 @@ GUILE-VERSION (\"2.0\" or \"2.2\"), or #f if none of the packages matches."
       ("guile-ssh"  (ref '(gnu packages ssh)   'guile-ssh))
       ("guile-git"  (ref '(gnu packages guile) 'guile-git))
       ("guile-sqlite3" (ref '(gnu packages guile) 'guile-sqlite3))
-      ("libgcrypt"  (ref '(gnu packages gnupg) 'libgcrypt))
+      ("guile-gcrypt"  (ref '(gnu packages gnupg) 'guile-gcrypt))
+      ("gnutls"     (ref '(gnu packages tls) 'gnutls))
       ("zlib"       (ref '(gnu packages compression) 'zlib))
       ("gzip"       (ref '(gnu packages compression) 'gzip))
       ("bzip2"      (ref '(gnu packages compression) 'bzip2))
       ("xz"         (ref '(gnu packages compression) 'xz))
-      ("guix"       (ref '(gnu packages package-management)
-                         'guix-register))
-      ("guile2.0-json" (ref '(gnu packages guile) 'guile2.0-json))
-      ("guile2.0-ssh"  (ref '(gnu packages ssh) 'guile2.0-ssh))
-      ("guile2.0-git"  (ref '(gnu packages guile) 'guile2.0-git))
-      ;; XXX: No "guile2.0-sqlite3".
-      (_               #f))))                     ;no such package
+      (_            #f))))                        ;no such package
 
 \f
 ;;;
@@ -113,6 +78,51 @@ GUILE-VERSION (\"2.0\" or \"2.2\"), or #f if none of the packages matches."
   (dependencies  node-dependencies)               ;list of nodes
   (compiled      node-compiled))                  ;node -> lowerable object
 
+;; File mappings are essentially an alist as passed to 'imported-files'.
+(define-record-type <file-mapping>
+  (file-mapping name alist)
+  file-mapping?
+  (name  file-mapping-name)
+  (alist file-mapping-alist))
+
+(define-gexp-compiler (file-mapping-compiler (mapping <file-mapping>)
+                                             system target)
+  ;; Here we use 'imported-files', which can arrange to directly import all
+  ;; the files instead of creating a derivation, when possible.
+  (imported-files (map (match-lambda
+                         ((destination (? local-file? file))
+                          (cons destination
+                                (local-file-absolute-file-name file)))
+                         ((destination source)
+                          (cons destination source))) ;silliness
+                       (file-mapping-alist mapping))
+                  #:name (file-mapping-name mapping)
+                  #:system system))
+
+(define (node-source+compiled node)
+  "Return a \"bundle\" containing both the source code and object files for
+NODE's modules, under their FHS directories: share/guile/site and lib/guile."
+  (define build
+    (with-imported-modules '((guix build utils))
+      #~(begin
+          (use-modules (guix build utils))
+
+          (define source
+            (string-append #$output "/share/guile/site/"
+                           (effective-version)))
+
+          (define object
+            (string-append #$output "/lib/guile/" (effective-version)
+                           "/site-ccache"))
+
+          (mkdir-p (dirname source))
+          (symlink #$(node-source node) source)
+          (mkdir-p (dirname object))
+          (symlink #$(node-compiled node) object))))
+
+  (computed-file (string-append (node-name node) "-modules")
+                 build))
+
 (define (node-fold proc init nodes)
   (let loop ((nodes nodes)
              (visited (setq))
@@ -167,8 +177,8 @@ must be present in the search path."
                           (closure modules
                                    (node-modules/recursive dependencies))))
          (module-files (map module->import modules))
-         (source (imported-files (string-append name "-source")
-                                 (append module-files extra-files))))
+         (source (file-mapping (string-append name "-source")
+                               (append module-files extra-files))))
     (node name modules source dependencies
           (compiled-modules name source
                             (map car module-files)
@@ -186,77 +196,305 @@ list of file-name/file-like objects suitable as inputs to 'imported-files'."
                (local-file file #:recursive? #t)))
        (find-files (string-append directory "/" sub-directory) pred)))
 
-(define (scheme-modules* directory sub-directory)
-  "Return the list of module names found under SUB-DIRECTORY in DIRECTORY."
-  (let ((prefix (string-length directory)))
-    (map (lambda (file)
-           (file-name->module-name (string-drop file prefix)))
-         (scheme-files (string-append directory "/" sub-directory)))))
+(define* (file-append* item file #:key (recursive? #t))
+  "Return FILE within ITEM, which may be a file name or a file-like object.
+When ITEM is a plain file name (a string), simply return a 'local-file'
+record with the new file name."
+  (match item
+    ((? string?)
+     ;; This is the optimal case: we return a new "source".  Thus, a
+     ;; derivation that depends on this sub-directory does not depend on ITEM
+     ;; itself.
+     (local-file (string-append item "/" file)
+                 #:recursive? recursive?))
+    ;; TODO: Add 'local-file?' case.
+    (_
+     ;; In this case, anything that refers to the result also depends on ITEM,
+     ;; which isn't great.
+     (file-append item "/" file))))
+
+(define* (locale-data source domain
+                      #:optional (directory domain))
+  "Return the locale data from 'po/DIRECTORY' in SOURCE, corresponding to
+DOMAIN, a gettext domain."
+  (define gettext
+    (module-ref (resolve-interface '(gnu packages gettext))
+                'gettext-minimal))
+
+  (define build
+    (with-imported-modules '((guix build utils))
+      #~(begin
+          (use-modules (guix build utils)
+                       (srfi srfi-26)
+                       (ice-9 match) (ice-9 ftw))
+
+          (define po-directory
+            #+(file-append* source (string-append "po/" directory)))
+
+          (define (compile language)
+            (let ((gmo (string-append #$output "/" language "/LC_MESSAGES/"
+                                      #$domain ".mo")))
+              (mkdir-p (dirname gmo))
+              (invoke #+(file-append gettext "/bin/msgfmt")
+                      "-c" "--statistics" "--verbose"
+                      "-o" gmo
+                      (string-append po-directory "/" language ".po"))))
+
+          (define (linguas)
+            ;; Return the list of languages.  Note: don't read 'LINGUAS'
+            ;; because it contains things like 'en@boldquot' that do not have
+            ;; a corresponding .po file.
+            (map (cut basename <> ".po")
+                 (scandir po-directory
+                          (cut string-suffix? ".po" <>))))
+
+          (for-each compile (linguas)))))
+
+  (computed-file (string-append "guix-locale-" domain)
+                 build))
+
+(define (info-manual source)
+  "Return the Info manual built from SOURCE."
+  (define texinfo
+    (module-ref (resolve-interface '(gnu packages texinfo))
+                'texinfo))
+
+  (define graphviz
+    (module-ref (resolve-interface '(gnu packages graphviz))
+                'graphviz))
+
+  (define glibc-utf8-locales
+    (module-ref (resolve-interface '(gnu packages base))
+                'glibc-utf8-locales))
+
+  (define documentation
+    (file-append* source "doc"))
+
+  (define examples
+    (file-append* source "gnu/system/examples"))
+
+  (define build
+    (with-imported-modules '((guix build utils))
+      #~(begin
+          (use-modules (guix build utils))
+
+          (mkdir #$output)
+
+          ;; Create 'version.texi'.
+          ;; XXX: Can we use a more meaningful version string yet one that
+          ;; doesn't change at each commit?
+          (call-with-output-file "version.texi"
+            (lambda (port)
+              (let ((version "0.0-git"))
+                (format port "
+@set UPDATED 1 January 1970
+@set UPDATED-MONTH January 1970
+@set EDITION ~a
+@set VERSION ~a\n" version version))))
+
+          ;; Copy configuration templates that the manual includes.
+          (for-each (lambda (template)
+                      (copy-file template
+                                 (string-append
+                                  "os-config-"
+                                  (basename template ".tmpl")
+                                  ".texi")))
+                    (find-files #$examples "\\.tmpl$"))
+
+          ;; Build graphs.
+          (mkdir-p (string-append #$output "/images"))
+          (for-each (lambda (dot-file)
+                      (invoke #+(file-append graphviz "/bin/dot")
+                              "-Tpng" "-Gratio=.9" "-Gnodesep=.005"
+                              "-Granksep=.00005" "-Nfontsize=9"
+                              "-Nheight=.1" "-Nwidth=.1"
+                              "-o" (string-append #$output "/images/"
+                                                  (basename dot-file ".dot")
+                                                  ".png")
+                              dot-file))
+                    (find-files (string-append #$documentation "/images")
+                                "\\.dot$"))
+
+          ;; Copy other PNGs.
+          (for-each (lambda (png-file)
+                      (install-file png-file
+                                    (string-append #$output "/images")))
+                    (find-files (string-append #$documentation "/images")
+                                "\\.png$"))
+
+          ;; Finally build the manual.  Copy it the Texinfo files to $PWD and
+          ;; add a symlink to the 'images' directory so that 'makeinfo' can
+          ;; see those images and produce image references in the Info output.
+          (copy-recursively #$documentation "."
+                            #:log (%make-void-port "w"))
+          (delete-file-recursively "images")
+          (symlink (string-append #$output "/images") "images")
+
+          ;; Provide UTF-8 locales needed by the 'xspara.c' code in makeinfo.
+          (setenv "GUIX_LOCPATH"
+                  #+(file-append glibc-utf8-locales "/lib/locale"))
+
+          (for-each (lambda (texi)
+                      (unless (string=? "guix.texi" texi)
+                        ;; Create 'version-LL.texi'.
+                        (let* ((base (basename texi ".texi"))
+                               (dot  (string-index base #\.))
+                               (tag  (string-drop base (+ 1 dot))))
+                          (symlink "version.texi"
+                                   (string-append "version-" tag ".texi"))))
+
+                      (invoke #+(file-append texinfo "/bin/makeinfo")
+                              texi "-I" #$documentation
+                              "-I" "."
+                              "-o" (string-append #$output "/"
+                                                  (basename texi ".texi")
+                                                  ".info")))
+                    (cons "guix.texi"
+                          (find-files "." "^guix\\.[a-z]{2}\\.texi$")))
+
+          ;; Compress Info files.
+          (setenv "PATH"
+                  #+(file-append (specification->package "gzip") "/bin"))
+          (for-each (lambda (file)
+                      (invoke "gzip" "-9n" file))
+                    (find-files #$output "\\.info(-[0-9]+)?$")))))
+
+  (computed-file "guix-manual" build))
+
+(define* (guile-module-union things #:key (name "guix-module-union"))
+  "Return the union of the subset of THINGS (packages, computed files, etc.)
+that provide Guile modules."
+  (define build
+    (with-imported-modules '((guix build union))
+      #~(begin
+          (use-modules (guix build union))
+
+          (define (modules directory)
+            (string-append directory "/share/guile/site"))
 
-(define* (guix-command modules #:key (dependencies '())
-                       (guile-version (effective-version)))
+          (define (objects directory)
+            (string-append directory "/lib/guile"))
+
+          (union-build #$output
+                       (filter (lambda (directory)
+                                 (or (file-exists? (modules directory))
+                                     (file-exists? (objects directory))))
+                               '#$things)
+
+                       #:log-port (%make-void-port "w")))))
+
+  (computed-file name build))
+
+(define* (guix-command modules
+                       #:key source (dependencies '())
+                       guile (guile-version (effective-version)))
   "Return the 'guix' command such that it adds MODULES and DEPENDENCIES in its
 load path."
+  (define module-directory
+    ;; To minimize the number of 'stat' calls needed to locate a module,
+    ;; create the union of all the module directories.
+    (guile-module-union (cons modules dependencies)))
+
   (program-file "guix-command"
                 #~(begin
                     (set! %load-path
-                      (append '#$(map (lambda (package)
-                                        (file-append package
-                                                     "/share/guile/site/"
-                                                     guile-version))
-                                      dependencies)
-                              %load-path))
+                      (cons (string-append #$module-directory
+                                           "/share/guile/site/"
+                                           (effective-version))
+                            %load-path))
 
                     (set! %load-compiled-path
-                      (append '#$(map (lambda (package)
-                                        (file-append package "/lib/guile/"
-                                                     guile-version
-                                                     "/site-ccache"))
-                                      dependencies)
-                              %load-compiled-path))
-
-                    (set! %load-path (cons #$modules %load-path))
-                    (set! %load-compiled-path
-                      (cons #$modules %load-compiled-path))
+                      (cons (string-append #$module-directory
+                                           "/lib/guile/"
+                                           (effective-version)
+                                           "/site-ccache")
+                            %load-compiled-path))
 
                     (let ((guix-main (module-ref (resolve-interface '(guix ui))
                                                  'guix-main)))
-                      ;; TODO: Compute locale data.
-                      ;; (bindtextdomain "guix" "@localedir@")
-                      ;; (bindtextdomain "guix-packages" "@localedir@")
+                      #$(if source
+                            #~(begin
+                                (bindtextdomain "guix"
+                                                #$(locale-data source "guix"))
+                                (bindtextdomain "guix-packages"
+                                                #$(locale-data source
+                                                               "guix-packages"
+                                                               "packages")))
+                            #t)
 
                       ;; XXX: It would be more convenient to change it to:
                       ;;   (exit (apply guix-main (command-line)))
-                      (apply guix-main (command-line))))))
+                      (apply guix-main (command-line))))
+                #:guile guile))
+
+(define (miscellaneous-files source)
+  "Return data files taken from SOURCE."
+  (file-mapping "guix-misc"
+                `(("etc/bash_completion.d/guix"
+                   ,(file-append* source "/etc/completion/bash/guix"))
+                  ("etc/bash_completion.d/guix-daemon"
+                   ,(file-append* source "/etc/completion/bash/guix-daemon"))
+                  ("share/zsh/site-functions/_guix"
+                   ,(file-append* source "/etc/completion/zsh/_guix"))
+                  ("share/fish/vendor_completions.d/guix.fish"
+                   ,(file-append* source "/etc/completion/fish/guix.fish"))
+                  ("share/guix/hydra.gnu.org.pub"
+                   ,(file-append* source
+                                  "/etc/substitutes/hydra.gnu.org.pub"))
+                  ("share/guix/berlin.guixsd.org.pub"
+                   ,(file-append* source
+                                  "/etc/substitutes/berlin.guixsd.org.pub"))
+                  ("share/guix/ci.guix.info.pub"  ;alias
+                   ,(file-append* source "/etc/substitutes/berlin.guixsd.org.pub")))))
 
 (define* (whole-package name modules dependencies
-                        #:key (guile-version (effective-version)))
+                        #:key
+                        (guile-version (effective-version))
+                        info daemon miscellany
+                        guile
+                        (command (guix-command modules
+                                               #:dependencies dependencies
+                                               #:guile guile
+                                               #:guile-version guile-version)))
   "Return the whole Guix package NAME that uses MODULES, a derivation of all
-the modules, and DEPENDENCIES, a list of packages depended on."
-  (let ((command (guix-command modules
-                               #:dependencies dependencies
-                               #:guile-version guile-version)))
-    ;; TODO: Move compiled modules to 'lib/guile' instead of 'share/guile'.
-    (computed-file name
-                   (with-imported-modules '((guix build utils))
-                     #~(begin
-                         (use-modules (guix build utils))
-                         (mkdir-p (string-append #$output "/bin"))
-                         (symlink #$command
-                                  (string-append #$output "/bin/guix"))
-
-                         (let ((modules (string-append #$output
-                                                       "/share/guile/site/"
-                                                       (effective-version))))
-                           (mkdir-p (dirname modules))
-                           (symlink #$modules modules)))))))
+the modules (under share/guile/site and lib/guile), and DEPENDENCIES, a list
+of packages depended on.  COMMAND is the 'guix' program to use; INFO is the
+Info manual."
+  (computed-file name
+                 (with-imported-modules '((guix build utils))
+                   #~(begin
+                       (use-modules (guix build utils))
+
+                       (mkdir-p (string-append #$output "/bin"))
+                       (symlink #$command
+                                (string-append #$output "/bin/guix"))
+
+                       (when #$daemon
+                         (symlink (string-append #$daemon "/bin/guix-daemon")
+                                  (string-append #$output "/bin/guix-daemon")))
+
+                       (let ((share (string-append #$output "/share"))
+                             (lib   (string-append #$output "/lib"))
+                             (info  #$info))
+                         (mkdir-p share)
+                         (symlink #$(file-append modules "/share/guile")
+                                  (string-append share "/guile"))
+                         (when info
+                           (symlink #$info (string-append share "/info")))
+
+                         (mkdir-p lib)
+                         (symlink #$(file-append modules "/lib/guile")
+                                  (string-append lib "/guile")))
+
+                       (when #$miscellany
+                         (copy-recursively #$miscellany #$output
+                                           #:log (%make-void-port "w")))))))
 
 (define* (compiled-guix source #:key (version %guix-version)
                         (pull-version 1)
                         (name (string-append "guix-" version))
                         (guile-version (effective-version))
-                        (guile-for-build (guile-for-build guile-version))
-                        (libgcrypt (specification->package "libgcrypt"))
+                        (guile-for-build (default-guile))
                         (zlib (specification->package "zlib"))
                         (gzip (specification->package "gzip"))
                         (bzip2 (specification->package "bzip2"))
@@ -264,30 +502,29 @@ the modules, and DEPENDENCIES, a list of packages depended on."
                         (guix (specification->package "guix")))
   "Return a file-like object that contains a compiled Guix."
   (define guile-json
-    (package-for-guile guile-version
-                       "guile-json"
-                       "guile2.0-json"))
+    (specification->package "guile-json"))
 
   (define guile-ssh
-    (package-for-guile guile-version
-                       "guile-ssh"
-                       "guile2.0-ssh"))
+    (specification->package "guile-ssh"))
 
   (define guile-git
-    (package-for-guile guile-version
-                       "guile-git"
-                       "guile2.0-git"))
+    (specification->package "guile-git"))
 
   (define guile-sqlite3
-    (package-for-guile guile-version
-                       "guile-sqlite3"
-                       "guile2.0-sqlite3"))
+    (specification->package "guile-sqlite3"))
+
+  (define guile-gcrypt
+    (specification->package "guile-gcrypt"))
+
+  (define gnutls
+    (specification->package "gnutls"))
 
   (define dependencies
     (match (append-map (lambda (package)
                          (cons (list "x" package)
                                (package-transitive-propagated-inputs package)))
-                       (list guile-git guile-json guile-ssh guile-sqlite3))
+                       (list guile-gcrypt gnutls guile-git guile-json
+                             guile-ssh guile-sqlite3))
       (((labels packages _ ...) ...)
        packages)))
 
@@ -310,17 +547,17 @@ the modules, and DEPENDENCIES, a list of packages depended on."
                  ;; rebuilt when the version changes, which in turn means we
                  ;; can have substitutes for it.
                  #:extra-modules
-                 `(((guix config)
-                    => ,(make-config.scm #:libgcrypt
-                                         (specification->package
-                                          "libgcrypt"))))
+                 `(((guix config) => ,(make-config.scm)))
 
                  ;; (guix man-db) is needed at build-time by (guix profiles)
                  ;; but we don't need to compile it; not compiling it allows
                  ;; us to avoid an extra dependency on guile-gdbm-ffi.
                  #:extra-files
-                 `(("guix/man-db.scm" ,(local-file "../guix/man-db.scm")))
+                 `(("guix/man-db.scm" ,(local-file "../guix/man-db.scm"))
+                   ("guix/store/schema.sql"
+                    ,(local-file "../guix/store/schema.sql")))
 
+                 #:extensions (list guile-gcrypt)
                  #:guile-for-build guile-for-build))
 
   (define *extra-modules*
@@ -375,15 +612,29 @@ the modules, and DEPENDENCIES, a list of packages depended on."
                  (append (file-imports source "gnu/system/examples"
                                        (const #t))
 
+                         ;; All the installer code is on the build-side.
+                         (file-imports source "gnu/installer/"
+                                       (const #t))
                          ;; Build-side code that we don't build.  Some of
                          ;; these depend on guile-rsvg, the Shepherd, etc.
                          (file-imports source "gnu/build" (const #t)))
                  #:guile-for-build
                  guile-for-build))
 
+  (define *system-test-modules*
+    ;; Ship these modules mostly so (gnu ci) can refer to them.
+    (scheme-node "guix-system-tests"
+                 `((gnu tests)
+                   ,@(scheme-modules* source "gnu/tests"))
+                 (list *core-package-modules* *package-modules*
+                       *extra-modules* *system-modules* *core-modules*)
+                 #:extensions dependencies
+                 #:guile-for-build guile-for-build))
+
   (define *cli-modules*
     (scheme-node "guix-cli"
-                 (scheme-modules* source "/guix/scripts")
+                 (append (scheme-modules* source "/guix/scripts")
+                         `((gnu ci)))
                  (list *core-modules* *extra-modules*
                        *core-package-modules* *package-modules*
                        *system-modules*)
@@ -395,12 +646,10 @@ the modules, and DEPENDENCIES, a list of packages depended on."
                  '()
                  #:extra-modules
                  `(((guix config)
-                    => ,(make-config.scm #:libgcrypt libgcrypt
-                                         #:zlib zlib
+                    => ,(make-config.scm #:zlib zlib
                                          #:gzip gzip
                                          #:bzip2 bzip2
                                          #:xz xz
-                                         #:guix guix
                                          #:package-name
                                          %guix-package-name
                                          #:package-version
@@ -411,17 +660,16 @@ the modules, and DEPENDENCIES, a list of packages depended on."
                                          %guix-home-page-url)))
                  #:guile-for-build guile-for-build))
 
-  (define built-modules
+  (define (built-modules node-subset)
     (directory-union (string-append name "-modules")
-                     (append-map (lambda (node)
-                                   (list (node-source node)
-                                         (node-compiled node)))
+                     (append-map node-subset
 
                                  ;; Note: *CONFIG* comes first so that it
                                  ;; overrides the (guix config) module that
                                  ;; comes with *CORE-MODULES*.
                                  (list *config*
                                        *cli-modules*
+                                       *system-test-modules*
                                        *system-modules*
                                        *package-modules*
                                        *core-package-modules*
@@ -443,11 +691,33 @@ the modules, and DEPENDENCIES, a list of packages depended on."
   ;; Version 1 is when we return the full package.
   (cond ((= 1 pull-version)
          ;; The whole package, with a standard file hierarchy.
-         (whole-package name built-modules dependencies
-                        #:guile-version guile-version))
+         (let* ((modules  (built-modules (compose list node-source+compiled)))
+                (command  (guix-command modules
+                                        #:source source
+                                        #:dependencies dependencies
+                                        #:guile guile-for-build
+                                        #:guile-version guile-version)))
+           (whole-package name modules dependencies
+                          #:command command
+                          #:guile guile-for-build
+
+                          ;; Include 'guix-daemon'.  XXX: Here we inject an
+                          ;; older snapshot of guix-daemon, but that's a good
+                          ;; enough approximation for now.
+                          #:daemon (module-ref (resolve-interface
+                                                '(gnu packages
+                                                      package-management))
+                                               'guix-daemon)
+
+                          #:info (info-manual source)
+                          #:miscellany (miscellaneous-files source)
+                          #:guile-version guile-version)))
         ((= 0 pull-version)
-         ;; Legacy 'guix pull': just return the compiled modules.
-         built-modules)
+         ;; Legacy 'guix pull': return the .scm and .go files as one
+         ;; directory.
+         (built-modules (lambda (node)
+                          (list (node-source node)
+                                (node-compiled node)))))
         (else
          ;; Unsupported 'guix pull' version.
          #f)))
@@ -459,8 +729,7 @@ the modules, and DEPENDENCIES, a list of packages depended on."
 
 (define %dependency-variables
   ;; (guix config) variables corresponding to dependencies.
-  '(%libgcrypt %libz %xz %gzip %bzip2 %nix-instantiate
-    %sbindir %guix-register-program))
+  '(%libz %xz %gzip %bzip2))
 
 (define %persona-variables
   ;; (guix config) variables that define Guix's persona.
@@ -470,19 +739,16 @@ the modules, and DEPENDENCIES, a list of packages depended on."
     %guix-home-page-url))
 
 (define %config-variables
-  ;; (guix config) variables corresponding to Guix configuration (storedir,
-  ;; localstatedir, etc.)
-  (sort (filter pair?
-                (module-map (lambda (name var)
-                              (and (not (memq name %dependency-variables))
-                                   (not (memq name %persona-variables))
-                                   (cons name (variable-ref var))))
-                            (resolve-interface '(guix config))))
-        (lambda (name+value1 name+value2)
-          (string<? (symbol->string (car name+value1))
-                    (symbol->string (car name+value2))))))
-
-(define* (make-config.scm #:key libgcrypt zlib gzip xz bzip2 guix
+  ;; (guix config) variables corresponding to Guix configuration.
+  (letrec-syntax ((variables (syntax-rules ()
+                               ((_)
+                                '())
+                               ((_ variable rest ...)
+                                (cons `(variable . ,variable)
+                                      (variables rest ...))))))
+    (variables %localstatedir %storedir %sysconfdir %system)))
+
+(define* (make-config.scm #:key zlib gzip xz bzip2
                           (package-name "GNU Guix")
                           (package-version "0")
                           (bug-report-address "bug-guix@gnu.org")
@@ -498,36 +764,45 @@ the modules, and DEPENDENCIES, a list of packages depended on."
                                %guix-version
                                %guix-bug-report-address
                                %guix-home-page-url
-                               %sbindir
-                               %guix-register-program
-                               %libgcrypt
+                               %store-directory
+                               %state-directory
+                               %store-database-directory
+                               %config-directory
                                %libz
                                %gzip
                                %bzip2
-                               %xz
-                               %nix-instantiate))
+                               %xz))
 
                    #$@(map (match-lambda
                              ((name . value)
                               #~(define-public #$name #$value)))
                            %config-variables)
 
+                   (define %store-directory
+                     (or (and=> (getenv "NIX_STORE_DIR") canonicalize-path)
+                         %storedir))
+
+                   (define %state-directory
+                     ;; This must match `NIX_STATE_DIR' as defined in
+                     ;; `nix/local.mk'.
+                     (or (getenv "NIX_STATE_DIR")
+                         (string-append %localstatedir "/guix")))
+
+                   (define %store-database-directory
+                     (or (getenv "NIX_DB_DIR")
+                         (string-append %state-directory "/db")))
+
+                   (define %config-directory
+                     ;; This must match `GUIX_CONFIGURATION_DIRECTORY' as
+                     ;; defined in `nix/local.mk'.
+                     (or (getenv "GUIX_CONFIGURATION_DIRECTORY")
+                         (string-append %sysconfdir "/guix")))
+
                    (define %guix-package-name #$package-name)
                    (define %guix-version #$package-version)
                    (define %guix-bug-report-address #$bug-report-address)
                    (define %guix-home-page-url #$home-page-url)
 
-                   (define %sbindir
-                     ;; This is used to define '%guix-register-program'.
-                     ;; TODO: Use a derivation that builds nothing but the
-                     ;; C++ part.
-                     #+(and guix (file-append guix "/sbin")))
-
-                   (define %guix-register-program
-                     (or (getenv "GUIX_REGISTER")
-                         (and %sbindir
-                              (string-append %sbindir "/guix-register"))))
-
                    (define %gzip
                      #+(and gzip (file-append gzip "/bin/gzip")))
                    (define %bzip2
@@ -535,59 +810,20 @@ the modules, and DEPENDENCIES, a list of packages depended on."
                    (define %xz
                      #+(and xz (file-append xz "/bin/xz")))
 
-                   (define %libgcrypt
-                     #+(and libgcrypt
-                            (file-append libgcrypt "/lib/libgcrypt")))
                    (define %libz
                      #+(and zlib
-                            (file-append zlib "/lib/libz")))
-
-                   (define %nix-instantiate       ;for (guix import snix)
-                     "nix-instantiate"))
+                            (file-append zlib "/lib/libz"))))
 
                ;; Guile 2.0 *requires* the 'define-module' to be at the
-               ;; top-level or it 'toplevel-ref' in the resulting .go file are
+               ;; top-level or the 'toplevel-ref' in the resulting .go file are
                ;; made relative to a nonexistent anonymous module.
                #:splice? #t))
 
-
 \f
 ;;;
 ;;; Building.
 ;;;
 
-(define (imported-files name files)
-  ;; This is a non-monadic, simplified version of 'imported-files' from (guix
-  ;; gexp).
-  (define same-target?
-    (match-lambda*
-      (((file1 . _) (file2 . _))
-       (string=? file1 file2))))
-
-  (define build
-    (with-imported-modules (source-module-closure
-                            '((guix build utils)))
-      #~(begin
-          (use-modules (ice-9 match)
-                       (guix build utils))
-
-          (mkdir (ungexp output)) (chdir (ungexp output))
-          (for-each (match-lambda
-                      ((final-path store-path)
-                       (mkdir-p (dirname final-path))
-
-                       ;; Note: We need regular files to be regular files, not
-                       ;; symlinks, as this makes a difference for
-                       ;; 'add-to-store'.
-                       (copy-file store-path final-path)))
-                    '#$(delete-duplicates files same-target?)))))
-
-  ;; We're just copying files around, no need to substitute or offload it.
-  (computed-file name build
-                 #:options '(#:local-build? #t
-                             #:substitutable? #f
-                             #:env-vars (("COLUMNS" . "200")))))
-
 (define* (compiled-modules name module-tree module-files
                            #:optional
                            (dependencies '())
@@ -637,8 +873,8 @@ containing MODULE-FILES and possibly other files as well."
                              #:report-load report-load
                              #:report-compilation report-compilation)))
 
-          (setvbuf (current-output-port) _IONBF)
-          (setvbuf (current-error-port) _IONBF)
+          (setvbuf (current-output-port) 'none)
+          (setvbuf (current-error-port) 'none)
 
           (set! %load-path (cons #+module-tree %load-path))
           (set! %load-path
@@ -683,26 +919,6 @@ containing MODULE-FILES and possibly other files as well."
 ;;; Building.
 ;;;
 
-(define (guile-for-build version)
-  "Return a derivation for Guile 2.0 or 2.2, whichever matches the currently
-running Guile."
-  (define canonical-package                       ;soft reference
-    (module-ref (resolve-interface '(gnu packages base))
-                'canonical-package))
-
-  (match version
-    ("2.2.2"
-     ;; Gross hack to avoid ABI incompatibilities (see
-     ;; <https://bugs.gnu.org/29570>.)
-     (module-ref (resolve-interface '(gnu packages guile))
-                 'guile-2.2.2))
-    ("2.2"
-     (canonical-package (module-ref (resolve-interface '(gnu packages guile))
-                                    'guile-2.2/fixed)))
-    ("2.0"
-     (module-ref (resolve-interface '(gnu packages guile))
-                 'guile-2.0))))
-
 (define* (guix-derivation source version
                           #:optional (guile-version (effective-version))
                           #:key (pull-version 0))
@@ -717,7 +933,18 @@ is not supported."
         version))
 
   (define guile
-    (guile-for-build guile-version))
+    ;; When PULL-VERSION >= 1, produce a self-contained Guix and use Guile 2.2
+    ;; unconditionally.
+    (default-guile))
+
+  (when (and (< pull-version 1)
+             (not (string=? (package-version guile) guile-version)))
+    ;; Guix < 0.15.0 has PULL-VERSION = 0, where the host Guile is reused and
+    ;; can be any version.  When that happens and Guile is not current (e.g.,
+    ;; it's Guile 2.0), just bail out.
+    (raise (condition
+            (&message
+             (message "Guix is too old and cannot be upgraded")))))
 
   (mbegin %store-monad
     (set-guile-for-build guile)
@@ -726,9 +953,8 @@ is not supported."
                                #:name (string-append "guix-"
                                                      (shorten version))
                                #:pull-version pull-version
-                               #:guile-version (match guile-version
-                                                 ("2.2.2" "2.2")
-                                                 (version version))
+                               #:guile-version (if (>= pull-version 1)
+                                                   "2.2" guile-version)
                                #:guile-for-build guile)))
       (if guix
           (lower-object guix)