self: Remove leftover export.
[jackhill/guix/guix.git] / guix / self.scm
index 3e29c9a..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 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.
@@ -89,12 +60,7 @@ GUILE-VERSION (\"2.0\" or \"2.2\"), or #f if none of the packages matches."
       ("gzip"       (ref '(gnu packages compression) 'gzip))
       ("bzip2"      (ref '(gnu packages compression) 'bzip2))
       ("xz"         (ref '(gnu packages compression) 'xz))
-      ("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".
-      ("guile2.0-gnutls" (ref '(gnu packages tls) 'gnutls/guile-2.0))
-      (_               #f))))                     ;no such package
+      (_            #f))))                        ;no such package
 
 \f
 ;;;
@@ -133,6 +99,30 @@ GUILE-VERSION (\"2.0\" or \"2.2\"), or #f if none of the packages matches."
                   #: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))
@@ -206,21 +196,22 @@ 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* (sub-directory item sub-directory)
-  "Return SUB-DIRECTORY within ITEM, which may be a file name or a file-like
-object."
+(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 "/" sub-directory)
-                 #:recursive? #t))
+     (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 "/" sub-directory))))
+     (file-append item "/" file))))
 
 (define* (locale-data source domain
                       #:optional (directory domain))
@@ -238,7 +229,7 @@ DOMAIN, a gettext domain."
                        (ice-9 match) (ice-9 ftw))
 
           (define po-directory
-            #+(sub-directory source (string-append "po/" directory)))
+            #+(file-append* source (string-append "po/" directory)))
 
           (define (compile language)
             (let ((gmo (string-append #$output "/" language "/LC_MESSAGES/"
@@ -272,11 +263,15 @@ DOMAIN, a gettext domain."
     (module-ref (resolve-interface '(gnu packages graphviz))
                 'graphviz))
 
+  (define glibc-utf8-locales
+    (module-ref (resolve-interface '(gnu packages base))
+                'glibc-utf8-locales))
+
   (define documentation
-    (sub-directory source "doc"))
+    (file-append* source "doc"))
 
   (define examples
-    (sub-directory source "gnu/system/examples"))
+    (file-append* source "gnu/system/examples"))
 
   (define build
     (with-imported-modules '((guix build utils))
@@ -290,7 +285,7 @@ DOMAIN, a gettext domain."
           ;; doesn't change at each commit?
           (call-with-output-file "version.texi"
             (lambda (port)
-              (let ((version "0.0-git)"))
+              (let ((version "0.0-git"))
                 (format port "
 @set UPDATED 1 January 1970
 @set UPDATED-MONTH January 1970
@@ -335,6 +330,10 @@ DOMAIN, a gettext domain."
           (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'.
@@ -351,40 +350,64 @@ DOMAIN, a gettext domain."
                                                   (basename texi ".texi")
                                                   ".info")))
                     (cons "guix.texi"
-                          (find-files "." "^guix\\.[a-z]{2}\\.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* (guix-command modules #:optional compiled-modules
+(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 (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 source-directories
-    (map (lambda (package)
-           (file-append package "/share/guile/site/"
-                        guile-version))
-         dependencies))
-
-  (define object-directories
-    (map (lambda (package)
-           (file-append package "/lib/guile/"
-                        guile-version "/site-ccache"))
-         dependencies))
+  (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 (filter file-exists? '#$source-directories)
-                              %load-path))
-
-                    (set! %load-compiled-path
-                      (append (filter file-exists? '#$object-directories)
-                              %load-compiled-path))
+                      (cons (string-append #$module-directory
+                                           "/share/guile/site/"
+                                           (effective-version))
+                            %load-path))
 
-                    (set! %load-path (cons #$modules %load-path))
                     (set! %load-compiled-path
-                      (cons (or #$compiled-modules #$modules)
+                      (cons (string-append #$module-directory
+                                           "/lib/guile/"
+                                           (effective-version)
+                                           "/site-ccache")
                             %load-compiled-path))
 
                     (let ((guix-main (module-ref (resolve-interface '(guix ui))
@@ -404,24 +427,44 @@ load path."
                       (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))
-                        compiled-modules
-                        info daemon guile
+                        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.  COMMAND is the
-'guix' program to use; INFO is the Info manual.  When COMPILED-MODULES is
-true, it is linked as 'lib/guile/X.Y/site-ccache'; otherwise, .go files are
-assumed to be part of 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"))
@@ -430,30 +473,28 @@ assumed to be part of MODULES."
                          (symlink (string-append #$daemon "/bin/guix-daemon")
                                   (string-append #$output "/bin/guix-daemon")))
 
-                       (let ((modules (string-append #$output
-                                                     "/share/guile/site/"
-                                                     (effective-version)))
-                             (info    #$info))
-                         (mkdir-p (dirname modules))
-                         (symlink #$modules modules)
+                       (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 #$output
-                                                   "/share/info"))))
-
-                       ;; Object files.
-                       (when #$compiled-modules
-                         (let ((modules (string-append #$output "/lib/guile/"
-                                                       (effective-version)
-                                                       "/site-ccache")))
-                           (mkdir-p (dirname modules))
-                           (symlink #$compiled-modules modules)))))))
+                           (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))
+                        (guile-for-build (default-guile))
                         (zlib (specification->package "zlib"))
                         (gzip (specification->package "gzip"))
                         (bzip2 (specification->package "bzip2"))
@@ -461,32 +502,22 @@ assumed to be part of MODULES."
                         (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
-    (package-for-guile guile-version
-                       "guile-gcrypt"))
+    (specification->package "guile-gcrypt"))
 
   (define gnutls
-    (package-for-guile guile-version
-                       "gnutls" "guile2.0-gnutls"))
+    (specification->package "gnutls"))
 
   (define dependencies
     (match (append-map (lambda (package)
@@ -581,15 +612,29 @@ assumed to be part of MODULES."
                  (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*)
@@ -624,6 +669,7 @@ assumed to be part of MODULES."
                                  ;; comes with *CORE-MODULES*.
                                  (list *config*
                                        *cli-modules*
+                                       *system-test-modules*
                                        *system-modules*
                                        *package-modules*
                                        *core-package-modules*
@@ -645,15 +691,13 @@ assumed to be part of MODULES."
   ;; Version 1 is when we return the full package.
   (cond ((= 1 pull-version)
          ;; The whole package, with a standard file hierarchy.
-         (let* ((modules  (built-modules (compose list node-source)))
-                (compiled (built-modules (compose list node-compiled)))
-                (command  (guix-command modules compiled
+         (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
-                          #:compiled-modules compiled
                           #:command command
                           #:guile guile-for-build
 
@@ -666,6 +710,7 @@ assumed to be part of MODULES."
                                                'guix-daemon)
 
                           #:info (info-manual source)
+                          #:miscellany (miscellaneous-files source)
                           #:guile-version guile-version)))
         ((= 0 pull-version)
          ;; Legacy 'guix pull': return the .scm and .go files as one
@@ -774,7 +819,6 @@ assumed to be part of MODULES."
                ;; made relative to a nonexistent anonymous module.
                #:splice? #t))
 
-
 \f
 ;;;
 ;;; Building.
@@ -829,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
@@ -875,21 +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"
-     (canonical-package (module-ref (resolve-interface '(gnu packages guile))
-                                    'guile-2.2)))
-    ("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))
@@ -906,9 +935,16 @@ is not supported."
   (define guile
     ;; When PULL-VERSION >= 1, produce a self-contained Guix and use Guile 2.2
     ;; unconditionally.
-    (guile-for-build (if (>= pull-version 1)
-                         "2.2"
-                         guile-version)))
+    (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)