guix: Add home subcommand.

Julien LepillerMon Sep 16 21:27:33+0200 2019

3b193fc

guix: Add home subcommand. * guix/scripts/home.scm: New file.

README.md

4949
5050
### Making some room in your home directory
5151
52-
It is recommended to use this in a new install, when your home directory is
53-
still pretty empty. Since your home directory will be made into a Guix profile,
54-
you first want to create a new directory for your user data, for instance as
55-
root:
52+
Your home directory will be completely taken over by Guix.  In particular, when
53+
using the home manager, your home directory is entirely read-only.  A read-only
54+
home directory is not very useful though, so users of the home manager will have
55+
to use a separate directory for their documents, caches and states.  This is
56+
typically `/data/alice` for user alice.
57+
58+
It is not required to set up that directory beforehand, but if you do, you will
59+
not be able to use the home manager until you have completely wiped-out your
60+
home directory (i.e. transfered it to the new directory).  If the directory
61+
does not yet exist, your current home directory is automatically renamed to
62+
that directory, and the home manager starts working.
63+
64+
Basically, you will run (as root):
5665
5766
```bash
58-
mkdir -p /data/alice
59-
chown alice: /data/alice
67+
mkdir /data
68+
mv /home/alice /data/alice
6069
```
6170
62-
if your user is named alice. Then, move all your data over to that directory.
63-
Do not transfer your configuration, it will be useless. That transfering of data
64-
is the reason why it's simpler to start with an empty home: there is no data to
65-
transfer ;)
66-
6771
Once that is done, some parts of your home directory will still have to be
6872
read-write. This is mostly `~/.cache`, `~/.local` but also `~/.guix-profile` and
6973
`~/.config/guix`. Inside your new data directory, create them like this, as your

7478
mkdir-p .local/share .cache .config
7579
```
7680
81+
Since you have moved your entire home directory, make sure you can still access
82+
your own copy of guix and your user profile by (temporarily) setting your
83+
`$PATH` (make sure it starts with `/data/alice/.config/guix/current/bin`) and
84+
by sourcing the profile with `export GUIX_PROFILE=/data/alice/.guix-profile;
85+
source $GUIX_PROFILE/etc/profile`.  You might also need to run `hash -r`
86+
(no output) for bash to clear all its memorized binary locations.
87+
7788
### Creating the first home generation
7889
7990
To create your first home configuration, you must create a configuration file.

8293
```scheme
8394
(use-modules (home))
8495
85-
(home "/data/alice"
86-
  '())
96+
(home
97+
  (data-directory "/data/alice"))
8798
```
8899
89100
This will generate a completely empty home, except for essential configurations,

95106
user:
96107
97108
```bash
98-
guix package -p /var/guix/profiles/per-user/alice/home \
99-
  -f /data/alice/.config/guix/home.scm
100-
```
101-
102-
Still as your regular user, copy your `~/.config/guix` to your data directory.
103-
This will ensure you can still use Guix after you switch to the managed home
104-
profile:
105-
106-
```bash
107-
cp -ar ~/.config/guix /data/alice/.config/
108-
```
109-
110-
Finaly, switch to the managed home profile as root:
111-
112-
```bash
113-
mv /home/alice{,.bak} # keep a backup in case something goes wrong
114-
ln -sv /var/guix/profiles/per-user/alice/home /home/alice
109+
guix home reconfigure /data/alice/.config/guix/home.scm
115110
```
116111
117112
That's it!

129124
130125
If you are less into code, we welcome contributions in the form of documentation,
131126
translation, issues, reviews, tips and tricks. Do not hesitate to get in touch if
132-
you have an idea or want to help in any way!
132>
1330>
\ No newline at end of file
127+
you have an idea or want to help in any way!

doc/README.md

3636
this:
3737
3838
```scheme
39-
(home "/data/alice"
40-
  (list (something-home ...)
41-
        (something-else-home ...)
42-
        (other-stuff-home ...)
43-
        (yet-another-config-home ...)
44-
        ...))
39+
(home
40+
  (data-directory "/data/alice")
41+
  (configurations
42+
    (list (something-home ...)
43+
          (something-else-home ...)
44+
          (other-stuff-home ...)
45+
          (yet-another-config-home ...)
46+
          ...)))
4547
```
4648
4749
#### Desktop and Window Managers

7476
also add a similar line to your desktop or window manager's configuration to
7577
instruct it to start pulseaudio. However, pulseaudio sometimes crashes for non
7678
obvious reasons, and no graphical program will be able to restart it automatically
77-
with a proper configuration.
77>
780>
\ No newline at end of file
79+
with a proper configuration.

doc/general.md

6666
The `(home build utils)` extends the utilities provided by `(guix build utils)`
6767
with the following procedure:
6868
69-
**Scheme Procedure**: (home-file outputs path ...)
69+
**Scheme Procedure**: (home-file output path ...)
7070
71-
Return the complete path to the output of a package being defined by adding
72-
"/" between each component of _path_. _outputs_ is the content of `%build-output`
73-
in the package definition. This is not very useful for end users.
71+
Return the complete path to the output of a gexp being defined by adding
72+
"/" between each component of _path_. _output_ is the content of `#$output`
73+
in the package definition.

doc/install.md

3636
3737
### Making some room in your home directory
3838
39-
It is recommended to use this in a new install, when your home directory is
40-
still pretty empty. Since your home directory will be made into a Guix profile,
41-
you first want to create a new directory for your user data, for instance as
42-
root:
39+
Your home directory will be completely taken over by Guix.  In particular, when
40+
using the home manager, your home directory is entirely read-only.  A read-only
41+
home directory is not very useful though, so users of the home manager will have
42+
to use a separate directory for their documents, caches and states.  This is
43+
typically `/data/alice` for user alice.
44+
45+
It is not required to set up that directory beforehand, but if you do, you will
46+
not be able to use the home manager until you have completely wiped-out your
47+
home directory (i.e. transfered it to the new directory).  If the directory
48+
does not yet exist, your current home directory is automatically renamed to
49+
that directory, and the home manager starts working.
50+
51+
Basically, you will run (as root):
4352
4453
```bash
45-
mkdir -p /data/alice
46-
chown alice: /data/alice
54+
mkdir /data
55+
mv /home/alice /data/alice
4756
```
4857
49-
if your user is named alice. Then, move all your data over to that directory.
50-
Do not transfer your configuration, it will be useless. That transfering of data
51-
is the reason why it's simpler to start with an empty home: there is no data to
52-
transfer ;)
53-
5458
Once that is done, some parts of your home directory will still have to be
5559
read-write. This is mostly `~/.cache`, `~/.local` but also `~/.guix-profile` and
5660
`~/.config/guix`. Inside your new data directory, create them like this, as your

6165
mkdir-p .local/share .cache .config
6266
```
6367
68+
Since you have moved your entire home directory, make sure you can still access
69+
your own copy of guix and your user profile by (temporarily) setting your
70+
`$PATH` (make sure it starts with `/data/alice/.config/guix/current/bin`) and
71+
by sourcing the profile with `export GUIX_PROFILE=/data/alice/.guix-profile;
72+
source $GUIX_PROFILE/etc/profile`.  You might also need to run `hash -r`
73+
(no output) for bash to clear all its memorized binary locations.
74+
6475
### Creating the first home generation
6576
6677
To create your first home configuration, you must create a configuration file.

6980
```scheme
7081
(use-modules (home))
7182
72-
(home "/data/alice"
73-
  '())
83+
(home
84+
  (data-directory "/data/alice"))
7485
```
7586
7687
This will generate a completely empty home, except for essential configurations,

8293
user:
8394
8495
```bash
85-
guix package -p /var/guix/profiles/per-user/alice/home \
86-
  -f /data/alice/.config/guix/home.scm
87-
```
88-
89-
Still as your regular user, copy your `~/.config/guix` to your data directory.
90-
This will ensure you can still use Guix after you switch to the managed home
91-
profile:
92-
93-
```bash
94-
cp -ar ~/.config/guix /data/alice/.config/
95-
```
96-
97-
Finaly, switch to the managed home profile as root:
98-
99-
```bash
100-
mv /home/alice{,.bak} # keep a backup in case something goes wrong
101-
ln -sv /var/guix/profiles/per-user/alice/home /home/alice
96+
guix home reconfigure /data/alice/.config/guix/home.scm
10297
```
10398
104-
That's it!
104>
1050>
\ No newline at end of file
99+
That's it!

guix/scripts/home.scm unknown status 1

1+
;;; GNU Guix --- Functional package management for GNU
2+
;;; Copyright ?? 2019 Julien Lepiller <julien@lepiller.eu>
3+
;;;
4+
;;; This file is part of GNU Guix.
5+
;;;
6+
;;; GNU Guix is free software; you can redistribute it and/or modify it
7+
;;; under the terms of the GNU General Public License as published by
8+
;;; the Free Software Foundation; either version 3 of the License, or (at
9+
;;; your option) any later version.
10+
;;;
11+
;;; GNU Guix is distributed in the hope that it will be useful, but
12+
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
13+
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14+
;;; GNU General Public License for more details.
15+
;;;
16+
;;; You should have received a copy of the GNU General Public License
17+
;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
18+
19+
(define-module (guix scripts home)
20+
  #:use-module (guix derivations)
21+
  #:use-module (guix grafts)
22+
  #:use-module (guix monads)
23+
  #:use-module (guix packages)
24+
  #:use-module (guix profiles)
25+
  #:use-module (guix scripts)
26+
  #:use-module (guix scripts build)
27+
  #:use-module (guix status)
28+
  #:use-module (guix store)
29+
  #:use-module (guix ui)
30+
  #:use-module (guix utils)
31+
  #:use-module (home)
32+
  #:use-module (ice-9 match)
33+
  #:use-module (srfi srfi-1)
34+
  #:use-module (srfi srfi-26)
35+
  #:use-module (srfi srfi-37)
36+
  #:export (guix-home))
37+
38+
;;;
39+
;;; Command-line options.
40+
;;;
41+
42+
(define %options
43+
  (list (option '(#\h "help") #f #f
44+
                (lambda args
45+
                  (show-help)
46+
                  (exit 0)))
47+
        (option '(#\V "version") #f #f
48+
                (lambda args
49+
                  (show-version-and-exit "guix edit")))))
50+
51+
(define (show-help)
52+
  (display (G_ "Usage: guix home [OPTION ...] ACTION [ARG ...] [FILE]
53+
Manage a user home environment according to FILE and ACTION.  Some actions
54+
support additional ARGs.\n"))
55+
  (display (G_ "The valid values for ACTION are:\n"))
56+
  (newline)
57+
  (display (G_ "\
58+
   reconfigure      switch to or create a new home configuration\n"))
59+
  (display (G_ "\
60+
   build            build the home configuration without installing anything\n"))
61+
  (show-build-options-help)
62+
  (display (G_ "
63+
  -h, --help             display this help and exit"))
64+
  (display (G_ "
65+
  -V, --version          display version information and exit"))
66+
  (newline)
67+
  (show-bug-report-information))
68+
69+
(define %options
70+
  ;; Specifications of the command-line options.
71+
  (cons* (option '(#\h "help") #f #f
72+
                 (lambda args
73+
                   (show-help)
74+
                   (exit 0)))
75+
         (option '(#\V "version") #f #f
76+
                 (lambda args
77+
                   (show-version-and-exit "guix system")))
78+
         (option '(#\e "expression") #t #f
79+
                 (lambda (opt name arg result)
80+
                   (alist-cons 'expression arg result)))
81+
         (option '(#\d "derivation") #f #f
82+
                 (lambda (opt name arg result)
83+
                   (alist-cons 'derivations-only? #t result)))
84+
         (option '("on-error") #t #f
85+
                 (lambda (opt name arg result)
86+
                   (alist-cons 'on-error (string->symbol arg)
87+
                               result)))
88+
         (option '(#\t "file-system-type") #t #f
89+
                 (lambda (opt name arg result)
90+
                   (alist-cons 'file-system-type arg
91+
                               result)))
92+
         (option '("image-size") #t #f
93+
                 (lambda (opt name arg result)
94+
                   (alist-cons 'image-size (size->number arg)
95+
                               result)))
96+
         (option '(#\N "network") #f #f
97+
                 (lambda (opt name arg result)
98+
                   (alist-cons 'container-shared-network? #t result)))
99+
         (option '("no-bootloader" "no-grub") #f #f
100+
                 (lambda (opt name arg result)
101+
                   (alist-cons 'install-bootloader? #f result)))
102+
         (option '("full-boot") #f #f
103+
                 (lambda (opt name arg result)
104+
                   (alist-cons 'full-boot? #t result)))
105+
         (option '("skip-checks") #f #f
106+
                 (lambda (opt name arg result)
107+
                   (alist-cons 'skip-safety-checks? #t result)))
108+
109+
         (option '("share") #t #f
110+
                 (lambda (opt name arg result)
111+
                   (alist-cons 'file-system-mapping
112+
                               (specification->file-system-mapping arg #t)
113+
                               result)))
114+
         (option '("expose") #t #f
115+
                 (lambda (opt name arg result)
116+
                   (alist-cons 'file-system-mapping
117+
                               (specification->file-system-mapping arg #f)
118+
                               result)))
119+
120+
         (option '(#\n "dry-run") #f #f
121+
                 (lambda (opt name arg result)
122+
                   (alist-cons 'dry-run? #t (alist-cons 'graft? #f result))))
123+
         (option '(#\v "verbosity") #t #f
124+
                 (lambda (opt name arg result)
125+
                   (let ((level (string->number* arg)))
126+
                     (alist-cons 'verbosity level
127+
                                 (alist-delete 'verbosity result)))))
128+
         (option '(#\s "system") #t #f
129+
                 (lambda (opt name arg result)
130+
                   (alist-cons 'system arg
131+
                               (alist-delete 'system result eq?))))
132+
         (option '(#\r "root") #t #f
133+
                 (lambda (opt name arg result)
134+
                   (alist-cons 'gc-root arg result)))
135+
         %standard-build-options))
136+
137+
(define %default-options
138+
  ;; Alist of default option values.
139+
  `((system . ,(%current-system))
140+
    (substitutes? . #t)
141+
    (build-hook? . #t)
142+
    (print-build-trace? . #t)
143+
    (print-extended-build-trace? . #t)
144+
    (multiplexed-build-output? . #t)
145+
    (graft? . #t)
146+
    (debug . 0)
147+
    (verbosity . #f)                              ;default
148+
    (file-system-type . "ext4")
149+
    (image-size . guess)
150+
    (install-bootloader? . #t)))
151+
152+
;;;
153+
;;; Profiles
154+
;;;
155+
156+
(define %user-module
157+
  ;; Module in which the machine description file is loaded.
158+
  (make-user-module '()))
159+
160+
(define %home (getenv "HOME"))
161+
162+
(define %current-home
163+
  (string-append %profile-directory "/home"))
164+
165+
(define (ensure-home-profile data-directory)
166+
  "Ensures $HOME is a symlink to the profile.  If it is not yet the case, move
167+
it to the @var{data-directory} directory, unless it already exists, in which case
168+
report an error."
169+
  (ensure-profile-directory)
170+
171+
  (when %home %current-home
172+
    (let ((home (false-if-exception (lstat %home))))
173+
      (if home
174+
	  (unless (equal? (readlink %home) %current-home)
175+
            (if (false-if-exception (lstat data-directory))
176+
              (leave (G_ "Your $HOME directory (~a) is not a symlink to the home profile,
177+
and it cannot be moved as ~a already exists on the filesystem.~%")
178+
                    %home data-directory)
179+
              (rename-file %home data-directory)))
180+
          (symlink %current-home %home)))))
181+
182+
;;;
183+
;;; Entry point.
184+
;;;
185+
186+
(define* (perform-action action home
187+
                         #:key
188+
                         dry-run? derivations-only?
189+
                         use-substitutes?)
190+
  "Perform ACTION for HOME.  When DERIVATIONS-ONLY? is true, print the
191+
derivation file name(s) without building anything."
192+
  (define println
193+
    (cut format #t "~a~%" <>))
194+
195+
  (when (eq? action 'reconfigure)
196+
    (ensure-home-profile (home-data-directory home)))
197+
198+
  (with-store store
199+
    (let* ((drv      (run-with-store store (home->derivation home)))
200+
           (profile  (derivation->output-path drv)))
201+
      (show-what-to-build store (list drv)
202+
                          #:use-substitutes? use-substitutes?
203+
                          #:dry-run? dry-run?)
204+
205+
      (unless (or dry-run? derivations-only?)
206+
          (begin
207+
            (build-derivations store (list drv))
208+
            (case action
209+
              ((reconfigure)
210+
               (newline)
211+
               (format #t (G_ "Activating home...~%"))
212+
               (let* ((number (generation-number %current-home))
213+
                      (generation (generation-file-name %current-home (+ 1 number))))
214+
                 (switch-symlinks generation profile)
215+
                 (switch-symlinks %current-home generation))
216+
                 (format #t (G_ "Your home directory has been reconfigured.~%")))
217+
              (else
218+
                (display profile)
219+
                (newline))))))))
220+
221+
(define (process-action action args opts)
222+
  "Process ACTION, a sub-command, with the arguments are listed in ARGS.
223+
ACTION must be one of the sub-commands that takes an operating system
224+
declaration as an argument (a file name.)  OPTS is the raw alist of options
225+
resulting from command-line parsing."
226+
  (define (ensure-home-configuration file-or-exp obj)
227+
    (unless (home? obj)
228+
      (leave (G_ "'~a' does not return a home configuration~%")
229+
             file-or-exp))
230+
    obj)
231+
232+
  (let* ((file        (match args
233+
                        (() #f)
234+
                        ((x . _) x)))
235+
         (expr        (assoc-ref opts 'expression))
236+
         (system      (assoc-ref opts 'system))
237+
         (home        (ensure-home-configuration
238+
                       (or file expr)
239+
                       (cond
240+
                        ((and expr file)
241+
                         (leave
242+
                          (G_ "both file and expression cannot be specified~%")))
243+
                        (expr
244+
                         (read/eval expr))
245+
                        (file
246+
                         (load* file %user-module
247+
                                #:on-error (assoc-ref opts 'on-error)))
248+
                        (else
249+
                         (leave (G_ "no configuration specified~%"))))))
250+
251+
         (dry?        (assoc-ref opts 'dry-run?)))
252+
253+
    (with-store store
254+
      (set-build-options-from-command-line store opts)
255+
256+
      (set-guile-for-build (default-guile))
257+
258+
      (case action
259+
        (else
260+
         (unless (eq? action 'build)
261+
           (warn-about-old-distro #:suggested-command
262+
                                  "guix home reconfigure"))
263+
264+
         (perform-action action home
265+
                         #:dry-run? dry?
266+
                         #:derivations-only? (assoc-ref opts
267+
                                                        'derivations-only?)
268+
                         #:use-substitutes? (assoc-ref opts 'substitutes?)))))
269+
    (warn-about-disk-space)))
270+
271+
(define (resolve-subcommand name)
272+
  (let ((module (resolve-interface
273+
                 `(guix scripts home ,(string->symbol name))))
274+
        (proc (string->symbol (string-append "guix-home-" name))))
275+
    (module-ref module proc)))
276+
277+
(define (process-command command args opts)
278+
  "Process COMMAND, one of the 'guix system' sub-commands.  ARGS is its
279+
argument list and OPTS is the option alist."
280+
  (case command
281+
    ;; The following commands do not need to use the store, and they do not need
282+
    ;; an operating system configuration file.
283+
    ;; The following commands need to use the store, but they do not need an
284+
    ;; operating system configuration file.
285+
    ;; The following commands need to use the store, and they also
286+
    ;; need an operating system configuration file.
287+
    (else (process-action command args opts))))
288+
289+
(define (guix-home . args)
290+
  (define (parse-sub-command arg result)
291+
    ;; Parse sub-command ARG and augment RESULT accordingly.
292+
    (if (assoc-ref result 'action)
293+
        (alist-cons 'argument arg result)
294+
        (let ((action (string->symbol arg)))
295+
          (case action
296+
            ((build reconfigure)
297+
             (alist-cons 'action action result))
298+
            (else (leave (G_ "~a: unknown action~%") action))))))
299+
300+
  (define (match-pair car)
301+
    ;; Return a procedure that matches a pair with CAR.
302+
    (match-lambda
303+
      ((head . tail)
304+
       (and (eq? car head) tail))
305+
      (_ #f)))
306+
307+
  (define (option-arguments opts)
308+
    ;; Extract the plain arguments from OPTS.
309+
    (let* ((args   (reverse (filter-map (match-pair 'argument) opts)))
310+
           (count  (length args))
311+
           (action (assoc-ref opts 'action))
312+
           (expr   (assoc-ref opts 'expression)))
313+
      (define (fail)
314+
        (leave (G_ "wrong number of arguments for action '~a'~%")
315+
               action))
316+
317+
      (unless action
318+
        (format (current-error-port)
319+
                (G_ "guix home: missing command name~%"))
320+
        (format (current-error-port)
321+
                (G_ "Try 'guix home --help' for more information.~%"))
322+
        (exit 1))
323+
324+
      (case action
325+
        ((build reconfigure)
326+
         (unless (= count 1)
327+
           (fail))))
328+
      args))
329+
330+
  (with-error-handling
331+
    (let* ((opts     (parse-command-line args %options
332+
                                         (list %default-options)
333+
                                         #:argument-handler
334+
                                         parse-sub-command))
335+
           (args     (option-arguments opts))
336+
           (command  (assoc-ref opts 'action)))
337+
      (parameterize ((%graft? (assoc-ref opts 'graft?)))
338+
        (with-status-verbosity (or (assoc-ref opts 'verbosity)
339+
                                   (if (eq? command 'build) 2 1))
340+
          (process-command command args opts))))))
341+
342+
;;; home.scm ends here

home.diff unknown status 1

1+
diff --git a/README.md b/README.md
2+
index 6bd9d93..0a0e610 100644
3+
--- a/README.md
4+
+++ b/README.md
5+
@@ -41,21 +41,25 @@ section of this project:
6+
 
7+
 ### Making some room in your home directory
8+
 
9+
-It is recommended to use this in a new install, when your home directory is
10+
-still pretty empty. Since your home directory will be made into a Guix profile,
11+
-you first want to create a new directory for your user data, for instance as
12+
-root:
13+
+Your home directory will be completely taken over by Guix.  In particular, when
14+
+using the home manager, your home directory is entirely read-only.  A read-only
15+
+home directory is not very useful though, so users of the home manager will have
16+
+to use a separate directory for their documents, caches and states.  This is
17+
+typically `/data/alice` for user alice.
18+
+
19+
+It is not required to set up that directory beforehand, but if you do, you will
20+
+not be able to use the home manager until you have completely wiped-out your
21+
+home directory (i.e. transfered it to the new directory).  If the directory
22+
+does not yet exist, your current home directory is automatically renamed to
23+
+that directory, and the home manager starts working.
24+
+
25+
+Basically, you will run (as root):
26+
 
27+
 ```bash
28+
-mkdir -p /data/alice
29+
-chown alice: /data/alice
30+
+mkdir /data
31+
+mv /home/alice /data/alice
32+
 ```
33+
 
34+
-if your user is named alice. Then, move all your data over to that directory.
35+
-Do not transfer your configuration, it will be useless. That transfering of data
36+
-is the reason why it's simpler to start with an empty home: there is no data to
37+
-transfer ;)
38+
-
39+
 Once that is done, some parts of your home directory will still have to be
40+
 read-write. This is mostly `~/.cache`, `~/.local` but also `~/.guix-profile` and
41+
 `~/.config/guix`. Inside your new data directory, create them like this, as your
42+
@@ -66,6 +70,13 @@ cd /data/alice
43+
 mkdir-p .local/share .cache .config
44+
 ```
45+
 
46+
+Since you have moved your entire home directory, make sure you can still access
47+
+your own copy of guix and your user profile by (temporarily) setting your
48+
+`$PATH` (make sure it starts with `/data/alice/.config/guix/current/bin`) and
49+
+by sourcing the profile with `export GUIX_PROFILE=/data/alice/.guix-profile;
50+
+source $GUIX_PROFILE/etc/profile`.  You might also need to run `hash -r`
51+
+(no output) for bash to clear all its memorized binary locations.
52+
+
53+
 ### Creating the first home generation
54+
 
55+
 To create your first home configuration, you must create a configuration file.
56+
@@ -74,8 +85,8 @@ For instance, create `/data/alice/.config/guix/home.scm`:
57+
 ```scheme
58+
 (use-modules (home))
59+
 
60+
-(home "/data/alice"
61+
-  '())
62+
+(home
63+
+  (data-directory "/data/alice"))
64+
 ```
65+
 
66+
 This will generate a completely empty home, except for essential configurations,
67+
@@ -87,23 +98,7 @@ To build your first generation of your home environment, run as your regular
68+
 user:
69+
 
70+
 ```bash
71+
-guix package -p /var/guix/profiles/per-user/alice/home \
72+
-  -f /data/alice/.config/guix/home.scm
73+
-```
74+
-
75+
-Still as your regular user, copy your `~/.config/guix` to your data directory.
76+
-This will ensure you can still use Guix after you switch to the managed home
77+
-profile:
78+
-
79+
-```bash
80+
-cp -ar ~/.config/guix /data/alice/.config/
81+
-```
82+
-
83+
-Finaly, switch to the managed home profile as root:
84+
-
85+
-```bash
86+
-mv /home/alice{,.bak} # keep a backup in case something goes wrong
87+
-ln -sv /var/guix/profiles/per-user/alice/home /home/alice
88+
+guix home reconfigure /data/alice/.config/guix/home.scm
89+
 ```
90+
 
91+
 That's it!
92+
@@ -121,4 +116,4 @@ over the world!
93+
 
94+
 If you are less into code, we welcome contributions in the form of documentation,
95+
 translation, issues, reviews, tips and tricks. Do not hesitate to get in touch if
96+
-you have an idea or want to help in any way!
97+
\ No newline at end of file
98+
+you have an idea or want to help in any way!
99+
diff --git a/doc/README.md b/doc/README.md
100+
index 1ade3a5..384294a 100644
101+
--- a/doc/README.md
102+
+++ b/doc/README.md
103+
@@ -36,12 +36,14 @@ with "-home", you know that you can use it in the list of configurations, like
104+
 this:
105+
 
106+
 ```scheme
107+
-(home "/data/alice"
108+
-  (list (something-home ...)
109+
-        (something-else-home ...)
110+
-        (other-stuff-home ...)
111+
-        (yet-another-config-home ...)
112+
-        ...))
113+
+(home
114+
+  (data-directory "/data/alice")
115+
+  (configurations
116+
+    (list (something-home ...)
117+
+          (something-else-home ...)
118+
+          (other-stuff-home ...)
119+
+          (yet-another-config-home ...)
120+
+          ...)))
121+
 ```
122+
 
123+
 #### Desktop and Window Managers
124+
@@ -69,4 +71,4 @@ Unfortunately, that means you cannot configure pulseaudio through Guix. You can
125+
 also add a similar line to your desktop or window manager's configuration to
126+
 instruct it to start pulseaudio. However, pulseaudio sometimes crashes for non
127+
 obvious reasons, and no graphical program will be able to restart it automatically
128+
-with a proper configuration.
129+
\ No newline at end of file
130+
+with a proper configuration.
131+
diff --git a/doc/general.md b/doc/general.md
132+
index f6abd1b..23fd91f 100644
133+
--- a/doc/general.md
134+
+++ b/doc/general.md
135+
@@ -66,8 +66,8 @@ Build-side Utilities
136+
 The `(home build utils)` extends the utilities provided by `(guix build utils)`
137+
 with the following procedure:
138+
 
139+
-**Scheme Procedure**: (home-file outputs path ...)
140+
+**Scheme Procedure**: (home-file output path ...)
141+
 
142+
-Return the complete path to the output of a package being defined by adding
143+
-"/" between each component of _path_. _outputs_ is the content of `%build-output`
144+
-in the package definition. This is not very useful for end users.
145+
+Return the complete path to the output of a gexp being defined by adding
146+
+"/" between each component of _path_. _output_ is the content of `#$output`
147+
+in the package definition.
148+
diff --git a/doc/install.md b/doc/install.md
149+
index 16b8149..bda7456 100644
150+
--- a/doc/install.md
151+
+++ b/doc/install.md
152+
@@ -28,21 +28,25 @@ Usage
153+
 
154+
 ### Making some room in your home directory
155+
 
156+
-It is recommended to use this in a new install, when your home directory is
157+
-still pretty empty. Since your home directory will be made into a Guix profile,
158+
-you first want to create a new directory for your user data, for instance as
159+
-root:
160+
+Your home directory will be completely taken over by Guix.  In particular, when
161+
+using the home manager, your home directory is entirely read-only.  A read-only
162+
+home directory is not very useful though, so users of the home manager will have
163+
+to use a separate directory for their documents, caches and states.  This is
164+
+typically `/data/alice` for user alice.
165+
+
166+
+It is not required to set up that directory beforehand, but if you do, you will
167+
+not be able to use the home manager until you have completely wiped-out your
168+
+home directory (i.e. transfered it to the new directory).  If the directory
169+
+does not yet exist, your current home directory is automatically renamed to
170+
+that directory, and the home manager starts working.
171+
+
172+
+Basically, you will run (as root):
173+
 
174+
 ```bash
175+
-mkdir -p /data/alice
176+
-chown alice: /data/alice
177+
+mkdir /data
178+
+mv /home/alice /data/alice
179+
 ```
180+
 
181+
-if your user is named alice. Then, move all your data over to that directory.
182+
-Do not transfer your configuration, it will be useless. That transfering of data
183+
-is the reason why it's simpler to start with an empty home: there is no data to
184+
-transfer ;)
185+
-
186+
 Once that is done, some parts of your home directory will still have to be
187+
 read-write. This is mostly `~/.cache`, `~/.local` but also `~/.guix-profile` and
188+
 `~/.config/guix`. Inside your new data directory, create them like this, as your
189+
@@ -53,6 +57,13 @@ cd /data/alice
190+
 mkdir-p .local/share .cache .config
191+
 ```
192+
 
193+
+Since you have moved your entire home directory, make sure you can still access
194+
+your own copy of guix and your user profile by (temporarily) setting your
195+
+`$PATH` (make sure it starts with `/data/alice/.config/guix/current/bin`) and
196+
+by sourcing the profile with `export GUIX_PROFILE=/data/alice/.guix-profile;
197+
+source $GUIX_PROFILE/etc/profile`.  You might also need to run `hash -r`
198+
+(no output) for bash to clear all its memorized binary locations.
199+
+
200+
 ### Creating the first home generation
201+
 
202+
 To create your first home configuration, you must create a configuration file.
203+
@@ -61,8 +72,8 @@ For instance, create `/data/alice/.config/guix/home.scm`:
204+
 ```scheme
205+
 (use-modules (home))
206+
 
207+
-(home "/data/alice"
208+
-  '())
209+
+(home
210+
+  (data-directory "/data/alice"))
211+
 ```
212+
 
213+
 This will generate a completely empty home, except for essential configurations,
214+
@@ -74,23 +85,7 @@ To build your first generation of your home environment, run as your regular
215+
 user:
216+
 
217+
 ```bash
218+
-guix package -p /var/guix/profiles/per-user/alice/home \
219+
-  -f /data/alice/.config/guix/home.scm
220+
+guix home reconfigure /data/alice/.config/guix/home.scm
221+
 ```
222+
 
223+
-Still as your regular user, copy your `~/.config/guix` to your data directory.
224+
-This will ensure you can still use Guix after you switch to the managed home
225+
-profile:
226+
-
227+
-```bash
228+
-cp -ar ~/.config/guix /data/alice/.config/
229+
-```
230+
-
231+
-Finaly, switch to the managed home profile as root:
232+
-
233+
-```bash
234+
-mv /home/alice{,.bak} # keep a backup in case something goes wrong
235+
-ln -sv /var/guix/profiles/per-user/alice/home /home/alice
236+
-```
237+
-
238+
-That's it!
239+
\ No newline at end of file
240+
+That's it!
241+
diff --git a/guix/scripts/home.scm b/guix/scripts/home.scm
242+
index d4b54ea..76a7fe5 100644
243+
--- a/guix/scripts/home.scm
244+
+++ b/guix/scripts/home.scm
245+
@@ -17,9 +17,21 @@
246+
 ;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
247+
 
248+
 (define-module (guix scripts home)
249+
+  #:use-module (guix derivations)
250+
+  #:use-module (guix grafts)
251+
+  #:use-module (guix monads)
252+
+  #:use-module (guix packages)
253+
+  #:use-module (guix profiles)
254+
   #:use-module (guix scripts)
255+
+  #:use-module (guix scripts build)
256+
+  #:use-module (guix status)
257+
+  #:use-module (guix store)
258+
   #:use-module (guix ui)
259+
   #:use-module (guix utils)
260+
+  #:use-module (home)
261+
+  #:use-module (ice-9 match)
262+
+  #:use-module (srfi srfi-1)
263+
+  #:use-module (srfi srfi-26)
264+
   #:use-module (srfi srfi-37)
265+
   #:export (guix-home))
266+
 
267+
@@ -37,8 +49,16 @@
268+
                   (show-version-and-exit "guix edit")))))
269+
 
270+
 (define (show-help)
271+
-  (display (G_ "Usage: guix home CONFIG
272+
-Manage a user home environment according to CONFIG\n"))
273+
+  (display (G_ "Usage: guix home [OPTION ...] ACTION [ARG ...] [FILE]
274+
+Manage a user home environment according to FILE and ACTION.  Some actions
275+
+support additional ARGs.\n"))
276+
+  (display (G_ "The valid values for ACTION are:\n"))
277+
+  (newline)
278+
+  (display (G_ "\
279+
+   reconfigure      switch to or create a new home configuration\n"))
280+
+  (display (G_ "\
281+
+   build            build the home configuration without installing anything\n"))
282+
+  (show-build-options-help)
283+
   (display (G_ "
284+
   -h, --help             display this help and exit"))
285+
   (display (G_ "
286+
@@ -46,19 +66,276 @@ Manage a user home environment according to CONFIG\n"))
287+
   (newline)
288+
   (show-bug-report-information))
289+
 
290+
+(define %options
291+
+  ;; Specifications of the command-line options.
292+
+  (cons* (option '(#\h "help") #f #f
293+
+                 (lambda args
294+
+                   (show-help)
295+
+                   (exit 0)))
296+
+         (option '(#\V "version") #f #f
297+
+                 (lambda args
298+
+                   (show-version-and-exit "guix system")))
299+
+         (option '(#\e "expression") #t #f
300+
+                 (lambda (opt name arg result)
301+
+                   (alist-cons 'expression arg result)))
302+
+         (option '(#\d "derivation") #f #f
303+
+                 (lambda (opt name arg result)
304+
+                   (alist-cons 'derivations-only? #t result)))
305+
+         (option '("on-error") #t #f
306+
+                 (lambda (opt name arg result)
307+
+                   (alist-cons 'on-error (string->symbol arg)
308+
+                               result)))
309+
+         (option '(#\t "file-system-type") #t #f
310+
+                 (lambda (opt name arg result)
311+
+                   (alist-cons 'file-system-type arg
312+
+                               result)))
313+
+         (option '("image-size") #t #f
314+
+                 (lambda (opt name arg result)
315+
+                   (alist-cons 'image-size (size->number arg)
316+
+                               result)))
317+
+         (option '(#\N "network") #f #f
318+
+                 (lambda (opt name arg result)
319+
+                   (alist-cons 'container-shared-network? #t result)))
320+
+         (option '("no-bootloader" "no-grub") #f #f
321+
+                 (lambda (opt name arg result)
322+
+                   (alist-cons 'install-bootloader? #f result)))
323+
+         (option '("full-boot") #f #f
324+
+                 (lambda (opt name arg result)
325+
+                   (alist-cons 'full-boot? #t result)))
326+
+         (option '("skip-checks") #f #f
327+
+                 (lambda (opt name arg result)
328+
+                   (alist-cons 'skip-safety-checks? #t result)))
329+
+
330+
+         (option '("share") #t #f
331+
+                 (lambda (opt name arg result)
332+
+                   (alist-cons 'file-system-mapping
333+
+                               (specification->file-system-mapping arg #t)
334+
+                               result)))
335+
+         (option '("expose") #t #f
336+
+                 (lambda (opt name arg result)
337+
+                   (alist-cons 'file-system-mapping
338+
+                               (specification->file-system-mapping arg #f)
339+
+                               result)))
340+
+
341+
+         (option '(#\n "dry-run") #f #f
342+
+                 (lambda (opt name arg result)
343+
+                   (alist-cons 'dry-run? #t (alist-cons 'graft? #f result))))
344+
+         (option '(#\v "verbosity") #t #f
345+
+                 (lambda (opt name arg result)
346+
+                   (let ((level (string->number* arg)))
347+
+                     (alist-cons 'verbosity level
348+
+                                 (alist-delete 'verbosity result)))))
349+
+         (option '(#\s "system") #t #f
350+
+                 (lambda (opt name arg result)
351+
+                   (alist-cons 'system arg
352+
+                               (alist-delete 'system result eq?))))
353+
+         (option '(#\r "root") #t #f
354+
+                 (lambda (opt name arg result)
355+
+                   (alist-cons 'gc-root arg result)))
356+
+         %standard-build-options))
357+
+
358+
 (define %default-options
359+
-  `((system    . ,(%current-system))))
360+
+  ;; Alist of default option values.
361+
+  `((system . ,(%current-system))
362+
+    (substitutes? . #t)
363+
+    (build-hook? . #t)
364+
+    (print-build-trace? . #t)
365+
+    (print-extended-build-trace? . #t)
366+
+    (multiplexed-build-output? . #t)
367+
+    (graft? . #t)
368+
+    (debug . 0)
369+
+    (verbosity . #f)                              ;default
370+
+    (file-system-type . "ext4")
371+
+    (image-size . guess)
372+
+    (install-bootloader? . #t)))
373+
+
374+
+;;;
375+
+;;; Profiles
376+
+;;;
377+
+
378+
+(define %user-module
379+
+  ;; Module in which the machine description file is loaded.
380+
+  (make-user-module '()))
381+
+
382+
+(define %home (getenv "HOME"))
383+
+
384+
+(define %current-home
385+
+  (string-append %profile-directory "/home"))
386+
+
387+
+(define (ensure-home-profile data-directory)
388+
+  "Ensures $HOME is a symlink to the profile.  If it is not yet the case, move
389+
+it to the @var{data-directory} directory, unless it already exists, in which case
390+
+report an error."
391+
+  (ensure-profile-directory)
392+
+
393+
+  (when %home %current-home
394+
+    (let ((home (false-if-exception (lstat %home))))
395+
+      (if home
396+
+          (if (false-if-exception (lstat data-directory))
397+
+            (rename-file %home data-directory)
398+
+            (leav (G_ "Your $HOME directory (~a) is not a symlink to a profile,
399+
+and it cannot be moved as ~a already exists on the filesystem.~%")
400+
+                  %home data-directory))
401+
+          (symlink %current-home %home)))))
402+
 
403+
 ;;;
404+
 ;;; Entry point.
405+
 ;;;
406+
 
407+
+(define* (perform-action action home
408+
+                         #:key
409+
+                         dry-run? derivations-only?
410+
+                         use-substitutes?)
411+
+  "Perform ACTION for HOME.  When DERIVATIONS-ONLY? is true, print the
412+
+derivation file name(s) without building anything."
413+
+  (define println
414+
+    (cut format #t "~a~%" <>))
415+
+
416+
+  (when (eq? action 'reconfigure)
417+
+    (ensure-home-profile (home-data-directory home))
418+
+    (maybe-suggest-running-guix-pull))
419+
+
420+
+  (with-store store
421+
+    (let* ((drv      (run-with-store store (home->derivation home)))
422+
+           (profile  (derivation->output-path drv)))
423+
+      (show-what-to-build store (list drv)
424+
+                          #:use-substitutes? use-substitutes?
425+
+                          #:dry-run? dry-run?)
426+
+
427+
+      (unless (or dry-run? derivations-only?)
428+
+          (begin
429+
+            (build-derivations store (list drv))
430+
+            (case action
431+
+              ((reconfigure)
432+
+               (newline)
433+
+               (format #t (G_ "activating home...~%"))
434+
+               (let ((number (generation-number %current-home))
435+
+                     (generation (generation-file-name %current-home number)))
436+
+                 (switch-symlinks generation profile)
437+
+                 (switch-symlinks %current-home generation)))
438+
+              (else
439+
+                (display profile)
440+
+                (newline))))))))
441+
+
442+
+(define (process-action action args opts)
443+
+  "Process ACTION, a sub-command, with the arguments are listed in ARGS.
444+
+ACTION must be one of the sub-commands that takes an operating system
445+
+declaration as an argument (a file name.)  OPTS is the raw alist of options
446+
+resulting from command-line parsing."
447+
+  (define (ensure-home-configuration file-or-exp obj)
448+
+    (unless (home? obj)
449+
+      (leave (G_ "'~a' does not return a home configuration~%")
450+
+             file-or-exp))
451+
+    obj)
452+
+
453+
+  (let* ((file        (match args
454+
+                        (() #f)
455+
+                        ((x . _) x)))
456+
+         (expr        (assoc-ref opts 'expression))
457+
+         (system      (assoc-ref opts 'system))
458+
+         (home        (ensure-home-configuration
459+
+                       (or file expr)
460+
+                       (cond
461+
+                        ((and expr file)
462+
+                         (leave
463+
+                          (G_ "both file and expression cannot be specified~%")))
464+
+                        (expr
465+
+                         (read/eval expr))
466+
+                        (file
467+
+                         (load* file %user-module
468+
+                                #:on-error (assoc-ref opts 'on-error)))
469+
+                        (else
470+
+                         (leave (G_ "no configuration specified~%"))))))
471+
+
472+
+         (dry?        (assoc-ref opts 'dry-run?)))
473+
+
474+
+    (with-store store
475+
+      (set-build-options-from-command-line store opts)
476+
+
477+
+      (set-guile-for-build (default-guile))
478+
+
479+
+      (case action
480+
+        (else
481+
+         (unless (eq? action 'build)
482+
+           (warn-about-old-distro #:suggested-command
483+
+                                  "guix home reconfigure"))
484+
+
485+
+         (perform-action action home
486+
+                         #:dry-run? dry?
487+
+                         #:derivations-only? (assoc-ref opts
488+
+                                                        'derivations-only?)
489+
+                         #:use-substitutes? (assoc-ref opts 'substitutes?)))))
490+
+    (warn-about-disk-space)))
491+
+
492+
+(define (resolve-subcommand name)
493+
+  (let ((module (resolve-interface
494+
+                 `(guix scripts home ,(string->symbol name))))
495+
+        (proc (string->symbol (string-append "guix-home-" name))))
496+
+    (module-ref module proc)))
497+
+
498+
+(define (process-command command args opts)
499+
+  "Process COMMAND, one of the 'guix system' sub-commands.  ARGS is its
500+
+argument list and OPTS is the option alist."
501+
+  (case command
502+
+    ;; The following commands do not need to use the store, and they do not need
503+
+    ;; an operating system configuration file.
504+
+    ;; The following commands need to use the store, but they do not need an
505+
+    ;; operating system configuration file.
506+
+    ;; The following commands need to use the store, and they also
507+
+    ;; need an operating system configuration file.
508+
+    (else (process-action command args opts))))
509+
+
510+
 (define (guix-home . args)
511+
+  (define (parse-sub-command arg result)
512+
+    ;; Parse sub-command ARG and augment RESULT accordingly.
513+
+    (if (assoc-ref result 'action)
514+
+        (alist-cons 'argument arg result)
515+
+        (let ((action (string->symbol arg)))
516+
+          (case action
517+
+            ((build reconfigure)
518+
+             (alist-cons 'action action result))
519+
+            (else (leave (G_ "~a: unknown action~%") action))))))
520+
+
521+
+  (define (match-pair car)
522+
+    ;; Return a procedure that matches a pair with CAR.
523+
+    (match-lambda
524+
+      ((head . tail)
525+
+       (and (eq? car head) tail))
526+
+      (_ #f)))
527+
+
528+
+  (define (option-arguments opts)
529+
+    ;; Extract the plain arguments from OPTS.
530+
+    (let* ((args   (reverse (filter-map (match-pair 'argument) opts)))
531+
+           (count  (length args))
532+
+           (action (assoc-ref opts 'action))
533+
+           (expr   (assoc-ref opts 'expression)))
534+
+      (define (fail)
535+
+        (leave (G_ "wrong number of arguments for action '~a'~%")
536+
+               action))
537+
+
538+
+      (unless action
539+
+        (format (current-error-port)
540+
+                (G_ "guix home: missing command name~%"))
541+
+        (format (current-error-port)
542+
+                (G_ "Try 'guix home --help' for more information.~%"))
543+
+        (exit 1))
544+
+
545+
+      (case action
546+
+        ((build reconfigure)
547+
+         (unless (= count 1)
548+
+           (fail))))
549+
+      args))
550+
+
551+
   (with-error-handling
552+
     (let* ((opts     (parse-command-line args %options
553+
                                          (list %default-options)
554+
-                                         #:build-options? #f)))
555+
-      (format #t "Guix Home Test~%")))
556+
-  #t)
557+
+                                         #:argument-handler
558+
+                                         parse-sub-command))
559+
+           (args     (option-arguments opts))
560+
+           (command  (assoc-ref opts 'action)))
561+
+      (parameterize ((%graft? (assoc-ref opts 'graft?)))
562+
+        (with-status-verbosity (or (assoc-ref opts 'verbosity)
563+
+                                   (if (eq? command 'build) 2 1))
564+
+          (process-command command args opts))))))
565+
 
566+
 ;;; home.scm ends here
567+
diff --git a/home.scm b/home.scm
568+
index 0a3c03a..99ff98f 100644
569+
--- a/home.scm
570+
+++ b/home.scm
571+
@@ -22,56 +22,71 @@
572+
   #:use-module (guix gexp)
573+
   #:use-module (guix licenses)
574+
   #:use-module (guix packages)
575+
+  #:use-module (guix records)
576+
+  #:use-module (ice-9 match)
577+
   #:use-module (home build utils)
578+
-  #:export (home
579+
-            use-home-modules))
580+
+  #:export (use-home-modules
581+
+            home
582+
+            home?
583+
+            home-data-directory
584+
+            home-guix-symlink
585+
+            home-guix-config-symlink
586+
+            home-local-symlink
587+
+            home-cache-symlink
588+
+            home->derivation))
589+
 
590+
 (define-syntax use-home-modules
591+
   (syntax-rules ()
592+
     ((_ modules ...)
593+
      (use-modules (home modules) ...))))
594+
 
595+
-(define* (home basedir inputs #:key
596+
-               (guix-symlink (string-append basedir "/.guix-profile"))
597+
-               (guix-config-symlink (string-append basedir "/.config/guix"))
598+
-               (local-symlink (string-append basedir "/.local"))
599+
-               (cache-symlink (string-append basedir "/.cache")))
600+
-  (define union
601+
-    (computed-file "home"
602+
+(define-record-type* <home> home
603+
+  make-home
604+
+  home?
605+
+  (data-directory home-data-directory)
606+
+  (guix-symlink   home-guix-symlink (thunked)
607+
+                  (default (string-append
608+
+                             (home-data-directory this-record)
609+
+                             "/.guix-profile")))
610+
+  (guix-config-symlink home-guix-config-symlink (thunked)
611+
+                       (default (string-append
612+
+                                  (home-data-directory this-record)
613+
+                                  "/.config/guix")))
614+
+  (local-symlink  home-local-symlink (thunked)
615+
+                  (default (string-append
616+
+                             (home-data-directory this-record)
617+
+                             "/.local")))
618+
+  (cache-symlink  home-cache-symlink (thunked)
619+
+                  (default (string-append
620+
+                             (home-data-directory this-record)
621+
+                             "/.cache")))
622+
+  (configurations home-configurations
623+
+                  (default '())))
624+
+
625+
+(define (home->derivation home)
626+
+  (define builder
627+
+    (with-imported-modules
628+
+      '((guix build utils) (home build utils))
629+
       #~(begin
630+
-          (use-modules (guix build union))
631+
-          (union-build #$output '#$inputs))
632+
-      #:options
633+
-      '(#:local-build? #t
634+
-        #:modules ((guix build union)))))
635+
-  (package
636+
-    (name "guix-home")
637+
-    (version "0")
638+
-    (source #f)
639+
-    (build-system trivial-build-system)
640+
-    (arguments
641+
-     `(#:modules ((guix build utils) (home build utils))
642+
-       #:builder
643+
-       (begin
644+
-         (use-modules (guix build utils) (home build utils))
645+
-         (mkdir-p (home-file %outputs ".config"))
646+
-         ;; For guix
647+
-         (symlink ,guix-config-symlink (home-file %outputs ".config/guix"))
648+
-         (symlink ,guix-symlink (home-file %outputs ".guix-profile"))
649+
-         ;; symlink writeable directories
650+
-         (symlink ,local-symlink (home-file %outputs ".local"))
651+
-         (symlink ,cache-symlink (home-file %outputs ".cache"))
652+
-         ;; rest of the files
653+
-         (with-directory-excursion (assoc-ref %build-inputs "union")
654+
-         (for-each
655+
-           (lambda (f)
656+
-             (mkdir-p (home-file %outputs (dirname f)))
657+
-             (symlink (string-append (assoc-ref %build-inputs "union") "/" f)
658+
-                      (home-file %outputs f)))
659+
-           (find-files "." ".*"))))))
660+
-    (inputs
661+
-     `(("union" ,union)))
662+
-    (home-page "")
663+
-    (synopsis "")
664+
-    (description "")
665+
-    (license gpl3+)))
666+
\ No newline at end of file
667+
+          (use-modules (guix build utils) (home build utils))
668+
+          (mkdir-p (home-file #$output ".config"))
669+
+          ;; For guix
670+
+          (symlink #$(home-guix-config-symlink home) (home-file #$output ".config/guix"))
671+
+          (symlink #$(home-guix-symlink home) (home-file #$output ".guix-profile"))
672+
+          ;; symlink writeable directories
673+
+          (symlink #$(home-local-symlink home) (home-file #$output ".local"))
674+
+          (symlink #$(home-cache-symlink home) (home-file #$output ".cache"))
675+
+          ;; rest of the files
676+
+          (for-each
677+
+            (lambda (config)
678+
+              (with-directory-excursion config
679+
+                (for-each
680+
+                  (lambda (f)
681+
+                    (mkdir-p (home-file #$output (dirname f)))
682+
+                    (symlink (home-file config f)
683+
+                             (home-file #$output f)))
684+
+                  (find-files "." "."))))
685+
+            (list #$@(home-configurations home))))))
686+
+  (gexp->derivation "home" builder
687+
+                    #:substitutable? #f
688+
+                    #:local-build? #t))
689+
diff --git a/home/build/utils.scm b/home/build/utils.scm
690+
index 19b66a9..832af28 100644
691+
--- a/home/build/utils.scm
692+
+++ b/home/build/utils.scm
693+
@@ -18,5 +18,5 @@
694+
 (define-module (home build utils)
695+
   #:export (home-file))
696+
 
697+
-(define (home-file outputs . path)
698+
-  (apply string-append (assoc-ref outputs "out") "/" path))
699+
\ No newline at end of file
700+
+(define (home-file output . path)
701+
+  (apply string-append output "/" path))

home.scm

2222
  #:use-module (guix gexp)
2323
  #:use-module (guix licenses)
2424
  #:use-module (guix packages)
25+
  #:use-module (guix records)
26+
  #:use-module (ice-9 match)
2527
  #:use-module (home build utils)
26-
  #:export (home
27-
            use-home-modules))
28+
  #:export (use-home-modules
29+
            home
30+
            home?
31+
            home-data-directory
32+
            home-guix-symlink
33+
            home-guix-config-symlink
34+
            home-local-symlink
35+
            home-cache-symlink
36+
            home->derivation))
2837
2938
(define-syntax use-home-modules
3039
  (syntax-rules ()
3140
    ((_ modules ...)
3241
     (use-modules (home modules) ...))))
3342
34-
(define* (home basedir inputs #:key
35-
               (guix-symlink (string-append basedir "/.guix-profile"))
36-
               (guix-config-symlink (string-append basedir "/.config/guix"))
37-
               (local-symlink (string-append basedir "/.local"))
38-
               (cache-symlink (string-append basedir "/.cache")))
39-
  (define union
40-
    (computed-file "home"
43+
(define-record-type* <home> home
44+
  make-home
45+
  home?
46+
  (data-directory home-data-directory)
47+
  (guix-symlink   home-guix-symlink (thunked)
48+
                  (default (string-append
49+
                             (home-data-directory this-record)
50+
                             "/.guix-profile")))
51+
  (guix-config-symlink home-guix-config-symlink (thunked)
52+
                       (default (string-append
53+
                                  (home-data-directory this-record)
54+
                                  "/.config/guix")))
55+
  (local-symlink  home-local-symlink (thunked)
56+
                  (default (string-append
57+
                             (home-data-directory this-record)
58+
                             "/.local")))
59+
  (cache-symlink  home-cache-symlink (thunked)
60+
                  (default (string-append
61+
                             (home-data-directory this-record)
62+
                             "/.cache")))
63+
  (configurations home-configurations
64+
                  (default '())))
65+
66+
(define (home->derivation home)
67+
  (define builder
68+
    (with-imported-modules
69+
      '((guix build utils) (home build utils))
4170
      #~(begin
42-
          (use-modules (guix build union))
43-
          (union-build #$output '#$inputs))
44-
      #:options
45-
      '(#:local-build? #t
46-
        #:modules ((guix build union)))))
47-
  (package
48-
    (name "guix-home")
49-
    (version "0")
50-
    (source #f)
51-
    (build-system trivial-build-system)
52-
    (arguments
53-
     `(#:modules ((guix build utils) (home build utils))
54-
       #:builder
55-
       (begin
56-
         (use-modules (guix build utils) (home build utils))
57-
         (mkdir-p (home-file %outputs ".config"))
58-
         ;; For guix
59-
         (symlink ,guix-config-symlink (home-file %outputs ".config/guix"))
60-
         (symlink ,guix-symlink (home-file %outputs ".guix-profile"))
61-
         ;; symlink writeable directories
62-
         (symlink ,local-symlink (home-file %outputs ".local"))
63-
         (symlink ,cache-symlink (home-file %outputs ".cache"))
64-
         ;; rest of the files
65-
         (with-directory-excursion (assoc-ref %build-inputs "union")
66-
         (for-each
67-
           (lambda (f)
68-
             (mkdir-p (home-file %outputs (dirname f)))
69-
             (symlink (string-append (assoc-ref %build-inputs "union") "/" f)
70-
                      (home-file %outputs f)))
71-
           (find-files "." ".*"))))))
72-
    (inputs
73-
     `(("union" ,union)))
74-
    (home-page "")
75-
    (synopsis "")
76-
    (description "")
77-
    (license gpl3+)))
77>
780>
\ No newline at end of file
71+
          (use-modules (guix build utils) (home build utils))
72+
          (mkdir-p (home-file #$output ".config"))
73+
          ;; For guix
74+
          (symlink #$(home-guix-config-symlink home) (home-file #$output ".config/guix"))
75+
          (symlink #$(home-guix-symlink home) (home-file #$output ".guix-profile"))
76+
          ;; symlink writeable directories
77+
          (symlink #$(home-local-symlink home) (home-file #$output ".local"))
78+
          (symlink #$(home-cache-symlink home) (home-file #$output ".cache"))
79+
          ;; rest of the files
80+
          (for-each
81+
            (lambda (config)
82+
              (with-directory-excursion config
83+
                (for-each
84+
                  (lambda (f)
85+
                    (mkdir-p (home-file #$output (dirname f)))
86+
                    (symlink (home-file config f)
87+
                             (home-file #$output f)))
88+
                  (find-files "." "."))))
89+
            (list #$@(home-configurations home))))))
90+
  (gexp->derivation "home" builder
91+
                    #:substitutable? #f
92+
                    #:local-build? #t))

home/build/utils.scm

1818
(define-module (home build utils)
1919
  #:export (home-file))
2020
21-
(define (home-file outputs . path)
22-
  (apply string-append (assoc-ref outputs "out") "/" path))
22>
230>
\ No newline at end of file
21+
(define (home-file output . path)
22+
  (apply string-append output "/" path))