summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--doc/guix.texi15
-rw-r--r--guix/scripts/system.scm87
2 files changed, 93 insertions, 9 deletions
diff --git a/doc/guix.texi b/doc/guix.texi
index 4881ec6e1b..4c32df3c9f 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -3209,6 +3209,21 @@ Build the operating system's derivation, which includes all the
 configuration files and programs needed to boot and run the system.
 This action does not actually install anything.
 
+@item init
+Populate the given directory with all the files necessary to run the
+operating system specified in @var{file}.  This is useful for first-time
+installations of the GNU system.  For instance:
+
+@example
+guix system init my-os-config.scm /mnt
+@end example
+
+copies to @file{/mnt} all the store items required by the configuration
+specified in @file{my-os-config.scm}.  This includes configuration
+files, packages, and so on.  It also creates other essential files
+needed for the system to operate correctly---e.g., the @file{/etc},
+@file{/var}, and @file{/run} directories, and the @file{/bin/sh} file.
+
 @item vm
 @cindex virtual machine
 Build a virtual machine that contain the operating system declared in
diff --git a/guix/scripts/system.scm b/guix/scripts/system.scm
index 0739534b57..ee5df6e951 100644
--- a/guix/scripts/system.scm
+++ b/guix/scripts/system.scm
@@ -19,14 +19,18 @@
 (define-module (guix scripts system)
   #:use-module (guix ui)
   #:use-module (guix store)
+  #:use-module (guix gexp)
   #:use-module (guix derivations)
   #:use-module (guix packages)
   #:use-module (guix utils)
   #:use-module (guix monads)
   #:use-module (guix scripts build)
+  #:use-module (guix build utils)
+  #:use-module (guix build install)
   #:use-module (gnu system)
   #:use-module (gnu system vm)
   #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-26)
   #:use-module (srfi srfi-37)
   #:use-module (ice-9 match)
   #:export (guix-system
@@ -64,6 +68,38 @@
          (leave (_ "failed to load machine file '~a': ~s~%")
                 file args))))))
 
+(define* (install store os-dir target
+                  #:key (log-port (current-output-port)))
+  "Copy OS-DIR and its dependencies to directory TARGET.  TARGET must be an
+absolute directory name since that's what 'guix-register' expects."
+  (define to-copy
+    (let ((lst (delete-duplicates (cons os-dir (references store os-dir))
+                                  string=?)))
+      (topologically-sorted store lst)))
+
+  ;; Copy items to the new store.
+  (for-each (lambda (item)
+              (let ((dest (string-append target item))
+                    (refs (references store item)))
+                (format log-port "copying '~a'...~%" item)
+                (copy-recursively item dest
+                                  #:log (%make-void-port "w"))
+
+                ;; Register ITEM; as a side-effect, it resets timestamps, etc.
+                (unless (register-path item
+                                       #:prefix target
+                                       #:references refs)
+                  (leave (_ "failed to register '~a' under '~a'~%")
+                         item target))))
+            to-copy)
+
+  ;; Create a bunch of additional files.
+  (format log-port "populating '~a'...~%" target)
+  (populate-root-file-system target)
+
+  ;; TODO: Install GRUB.
+  )
+
 
 ;;;
 ;;; Options.
@@ -79,7 +115,9 @@ Build the operating system declared in FILE according to ACTION.\n"))
   (display (_ "\
   - 'vm', build a virtual machine image that shares the host's store\n"))
   (display (_ "\
-  - 'vm-image', build a freestanding virtual machine image.\n"))
+  - 'vm-image', build a freestanding virtual machine image\n"))
+  (display (_ "\
+  - 'init', initialize a root file system to run GNU.\n"))
 
   (show-build-options-help)
   (display (_ "
@@ -132,27 +170,50 @@ Build the operating system declared in FILE according to ACTION.\n"))
                   (leave (_ "~A: unrecognized option~%") name))
                 (lambda (arg result)
                   (if (assoc-ref result 'action)
-                      (let ((previous (assoc-ref result 'argument)))
-                        (if previous
-                            (leave (_ "~a: extraneous argument~%") previous)
-                            (alist-cons 'argument arg result)))
+                      (alist-cons 'argument arg result)
                       (let ((action (string->symbol arg)))
                         (case action
-                          ((build vm vm-image)
+                          ((build vm vm-image init)
                            (alist-cons 'action action result))
                           (else (leave (_ "~a: unknown action~%")
                                        action))))))
                 %default-options))
 
+  (define (match-pair car)
+    ;; Return a procedure that matches a pair with CAR.
+    (match-lambda
+     ((head . tail)
+      (and (eq? car head) tail))
+     (_ #f)))
+
+  (define (option-arguments opts)
+    ;; Extract the plain arguments from OPTS.
+    (let* ((args   (reverse (filter-map (match-pair 'argument) opts)))
+           (count  (length args))
+           (action (assoc-ref opts 'action)))
+      (define (fail)
+        (leave (_ "wrong number of arguments for action '~a'~%")
+               action))
+
+      (case action
+        ((build vm vm-image)
+         (unless (= count 1)
+           (fail)))
+        ((init)
+         (unless (= count 2)
+           (fail))))
+      args))
+
   (with-error-handling
     (let* ((opts   (parse-options))
-           (file   (assoc-ref opts 'argument))
+           (args   (option-arguments opts))
+           (file   (first args))
            (action (assoc-ref opts 'action))
            (os     (if file
                        (read-operating-system file)
                        (leave (_ "no configuration file specified~%"))))
            (mdrv   (case action
-                     ((build)
+                     ((build init)
                       (operating-system-derivation os))
                      ((vm-image)
                       (let ((size (assoc-ref opts 'image-size)))
@@ -171,4 +232,12 @@ Build the operating system declared in FILE according to ACTION.\n"))
       (unless dry?
         (build-derivations store (list drv))
         (display (derivation->output-path drv))
-        (newline)))))
+        (newline)
+
+        (when (eq? action 'init)
+          (let ((target (second args)))
+            (format #t (_ "initializing operating system under '~a'...~%")
+                    target)
+
+            (install store (derivation->output-path drv)
+                     (canonicalize-path target))))))))