summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am1
-rw-r--r--guix/build/pull.scm148
-rw-r--r--guix/scripts/pull.scm132
3 files changed, 158 insertions, 123 deletions
diff --git a/Makefile.am b/Makefile.am
index 13088ff525..eb278a76e9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -60,6 +60,7 @@ MODULES =					\
   guix/build/python-build-system.scm		\
   guix/build/utils.scm				\
   guix/build/union.scm				\
+  guix/build/pull.scm				\
   guix/build/rpath.scm				\
   guix/packages.scm				\
   guix/snix.scm					\
diff --git a/guix/build/pull.scm b/guix/build/pull.scm
new file mode 100644
index 0000000000..4bad88fe42
--- /dev/null
+++ b/guix/build/pull.scm
@@ -0,0 +1,148 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2013 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 (guix build pull)
+  #:use-module (guix build utils)
+  #:use-module (system base compile)
+  #:use-module (ice-9 ftw)
+  #:use-module (ice-9 match)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-26)
+  #:export (build-guix))
+
+;;; Commentary:
+;;;
+;;; Helpers for the 'guix pull' command to unpack and build Guix.
+;;;
+;;; Code:
+
+(define (call-with-process thunk)
+  "Run THUNK in a separate process that will return 0 if THUNK terminates
+normally, and 1 if an exception is raised."
+  (match (primitive-fork)
+    (0
+     (catch #t
+       (lambda ()
+         (thunk)
+         (primitive-exit 0))
+       (lambda (key . args)
+         (print-exception (current-error-port) #f key args)
+         (primitive-exit 1))))
+    (pid
+     #t)))
+
+(define* (p-for-each proc lst
+                     #:optional (max-processes (current-processor-count)))
+  "Invoke PROC for each element of LST in a separate process, using up to
+MAX-PROCESSES processes in parallel.  Raise an error if one of the processes
+exit with non-zero."
+  (define (wait-for-one-process)
+    (match (waitpid WAIT_ANY)
+      ((_ . status)
+       (unless (zero? (status:exit-val status))
+         (error "process failed" proc status)))))
+
+  (let loop ((lst   lst)
+             (running 0))
+    (match lst
+      (()
+       (or (zero? running)
+           (begin
+             (wait-for-one-process)
+             (loop lst (- running 1)))))
+      ((head . tail)
+       (if (< running max-processes)
+           (begin
+             (call-with-process (cut proc head))
+             (loop tail (+ running 1)))
+           (begin
+             (wait-for-one-process)
+             (loop lst (- running 1))))))))
+
+(define* (build-guix out tarball
+                     #:key tar gzip gcrypt)
+  "Build and install Guix in directory OUT using source from TARBALL."
+  (setvbuf (current-output-port) _IOLBF)
+  (setvbuf (current-error-port) _IOLBF)
+
+  (setenv "PATH" (string-append tar "/bin:" gzip "/bin"))
+
+  (system* "tar" "xvf" tarball)
+  (match (scandir "." (lambda (name)
+                        (and (not (member name '("." "..")))
+                             (file-is-directory? name))))
+    ((dir)
+     (chdir dir))
+    (x
+     (error "tarball did not produce a single source directory" x)))
+
+  (format #t "copying and compiling Guix to `~a'...~%" out)
+
+  ;; Copy everything under guix/ and gnu/ plus guix.scm.
+  (copy-recursively "guix" (string-append out "/guix"))
+  (copy-recursively "gnu" (string-append out "/gnu"))
+  (copy-file "guix.scm" (string-append out "/guix.scm"))
+
+  ;; Add a fake (guix config) module to allow the other modules to be
+  ;; compiled.  The user's (guix config) is the one that will be used.
+  (copy-file "guix/config.scm.in"
+             (string-append out "/guix/config.scm"))
+  (substitute* (string-append out "/guix/config.scm")
+    (("@LIBGCRYPT@")
+     (string-append gcrypt "/lib/libgcrypt")))
+
+  ;; Augment the search path so Scheme code can be compiled.
+  (set! %load-path (cons out %load-path))
+  (set! %load-compiled-path (cons out %load-compiled-path))
+
+  ;; Compile the .scm files.  Do that in independent processes, à la
+  ;; 'make -j', to work around <http://bugs.gnu.org/15602> (FIXME).
+  ;; This ensures correctness, but is overly conservative and slow.
+  ;; The solution initially implemented (and described in the bug
+  ;; above) was slightly faster but consumed memory proportional to the
+  ;; number of modules, which quickly became unacceptable.
+  (p-for-each (lambda (file)
+                (let ((go (string-append (string-drop-right file 4)
+                                         ".go")))
+                  (format (current-error-port)
+                          "compiling '~a'...~%" file)
+                  (compile-file file
+                                #:output-file go
+                                #:opts
+                                %auto-compilation-options)))
+
+              (filter (cut string-suffix? ".scm" <>)
+
+                      ;; Build guix/*.scm before gnu/*.scm to speed
+                      ;; things up.
+                      (sort (find-files out "\\.scm")
+                            (let ((guix (string-append out "/guix"))
+                                  (gnu  (string-append out "/gnu")))
+                              (lambda (a b)
+                                (or (and (string-prefix? guix a)
+                                         (string-prefix? gnu b))
+                                    (string<? a b)))))))
+
+  ;; Remove the "fake" (guix config).
+  (delete-file (string-append out "/guix/config.scm"))
+  (delete-file (string-append out "/guix/config.go"))
+
+  #t)
+
+;;; pull.scm ends here
diff --git a/guix/scripts/pull.scm b/guix/scripts/pull.scm
index 11f5cc1493..00bea1707d 100644
--- a/guix/scripts/pull.scm
+++ b/guix/scripts/pull.scm
@@ -41,129 +41,14 @@
   "Return a derivation that unpacks TARBALL into STORE and compiles Scheme
 files."
   (define builder
-    `(begin
-       (use-modules (guix build utils)
-                    (system base compile)
-                    (ice-9 ftw)
-                    (ice-9 match)
-                    (srfi srfi-1)
-                    (srfi srfi-11)
-                    (srfi srfi-26))
+    '(begin
+       (use-modules (guix build pull))
 
-       (setvbuf (current-output-port) _IOLBF)
-       (setvbuf (current-error-port) _IOLBF)
-
-       (let ((out     (assoc-ref %outputs "out"))
-             (tar     (assoc-ref %build-inputs "tar"))
-             (gzip    (assoc-ref %build-inputs "gzip"))
-             (gcrypt  (assoc-ref %build-inputs "gcrypt"))
-             (tarball (assoc-ref %build-inputs "tarball")))
-
-         (define (call-with-process thunk)
-           ;; Run THUNK in a separate process that will return 0 if THUNK
-           ;; terminates normally, and 1 if an exception is raised.
-           (match (primitive-fork)
-             (0
-              (catch #t
-                (lambda ()
-                  (thunk)
-                  (primitive-exit 0))
-                (lambda (key . args)
-                  (print-exception (current-error-port) #f key args)
-                  (primitive-exit 1))))
-             (pid
-              #t)))
-
-         (define (p-for-each proc lst)
-           ;; Invoke PROC for each element of LST in a separate process.
-           ;; Raise an error if one of the processes exit with non-zero.
-           (define (wait-for-one-process)
-             (match (waitpid WAIT_ANY)
-               ((_ . status)
-                (unless (zero? (status:exit-val status))
-                  (error "process failed" proc status)))))
-
-           (define max-processes
-             (current-processor-count))
-
-           (let loop ((lst   lst)
-                      (running 0))
-             (match lst
-               (()
-                (or (zero? running)
-                    (begin
-                      (wait-for-one-process)
-                      (loop lst (- running 1)))))
-               ((head . tail)
-                (if (< running max-processes)
-                    (begin
-                      (call-with-process (cut proc head))
-                      (loop tail (+ running 1)))
-                    (begin
-                      (wait-for-one-process)
-                      (loop lst (- running 1))))))))
-
-         (setenv "PATH" (string-append tar "/bin:" gzip "/bin"))
-
-         (system* "tar" "xvf" tarball)
-         (match (scandir "." (lambda (name)
-                               (and (not (member name '("." "..")))
-                                    (file-is-directory? name))))
-           ((dir)
-            (chdir dir))
-           (x
-            (error "tarball did not produce a single source directory" x)))
-
-         (format #t "copying and compiling Guix to `~a'...~%" out)
-
-         ;; Copy everything under guix/ and gnu/ plus guix.scm.
-         (copy-recursively "guix" (string-append out "/guix"))
-         (copy-recursively "gnu" (string-append out "/gnu"))
-         (copy-file "guix.scm" (string-append out "/guix.scm"))
-
-         ;; Add a fake (guix config) module to allow the other modules to be
-         ;; compiled.  The user's (guix config) is the one that will be used.
-         (copy-file "guix/config.scm.in"
-                    (string-append out "/guix/config.scm"))
-         (substitute* (string-append out "/guix/config.scm")
-           (("@LIBGCRYPT@")
-            (string-append gcrypt "/lib/libgcrypt")))
-
-         ;; Augment the search path so Scheme code can be compiled.
-         (set! %load-path (cons out %load-path))
-         (set! %load-compiled-path (cons out %load-compiled-path))
-
-         ;; Compile the .scm files.  Do that in independent processes, à la
-         ;; 'make -j', to work around <http://bugs.gnu.org/15602> (FIXME).
-         ;; This ensures correctness, but is overly conservative and slow.
-         ;; The solution initially implemented (and described in the bug
-         ;; above) was slightly faster but consumed memory proportional to the
-         ;; number of modules, which quickly became unacceptable.
-         (p-for-each (lambda (file)
-                       (let ((go (string-append (string-drop-right file 4)
-                                                ".go")))
-                         (format (current-error-port)
-                                 "compiling '~a'...~%" file)
-                         (compile-file file
-                                       #:output-file go
-                                       #:opts
-                                       %auto-compilation-options)))
-
-                     (filter (cut string-suffix? ".scm" <>)
-
-                             ;; Build guix/*.scm before gnu/*.scm to speed
-                             ;; things up.
-                             (sort (find-files out "\\.scm")
-                                   (let ((guix (string-append out "/guix"))
-                                         (gnu  (string-append out "/gnu")))
-                                     (lambda (a b)
-                                       (or (and (string-prefix? guix a)
-                                                (string-prefix? gnu b))
-                                           (string<? a b)))))))
-
-         ;; Remove the "fake" (guix config).
-         (delete-file (string-append out "/guix/config.scm"))
-         (delete-file (string-append out "/guix/config.go")))))
+       (build-guix (assoc-ref %outputs "out")
+                   (assoc-ref %build-inputs "tarball")
+                   #:tar (assoc-ref %build-inputs "tar")
+                   #:gzip (assoc-ref %build-inputs "gzip")
+                   #:gcrypt (assoc-ref %build-inputs "gcrypt"))))
 
   (build-expression->derivation store "guix-latest" builder
                                 #:inputs
@@ -172,7 +57,8 @@ files."
                                   ("gcrypt" ,(package-derivation store
                                                                  libgcrypt))
                                   ("tarball" ,tarball))
-                                #:modules '((guix build utils))))
+                                #:modules '((guix build pull)
+                                            (guix build utils))))
 
 
 ;;;