provenance.scm
| 1 | ;;; Guix Home Manager. |
| 2 | ;;; |
| 3 | ;;; Copyright © 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org> |
| 4 | ;;; Copyright © 2016 Chris Marusich <cmmarusich@gmail.com> |
| 5 | ;;; Copyright © 2020 Jan (janneke) Nieuwenhuizen <janneke@gnu.org> |
| 6 | ;;; Copyright © 2020 Jelle Licht <jlicht@fsfe.org> |
| 7 | ;;; |
| 8 | ;;; This file is based on work found in GNU Guix. |
| 9 | ;;; |
| 10 | ;;; This program is free software: you can redistribute it and/or modify |
| 11 | ;;; it under the terms of the GNU General Public License as published by |
| 12 | ;;; the Free Software Foundation, either version 3 of the License, or |
| 13 | ;;; (at your option) any later version. |
| 14 | ;;; |
| 15 | ;;; This program is distributed in the hope that it will be useful, |
| 16 | ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 17 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 18 | ;;; GNU General Public License for more details. |
| 19 | ;;; |
| 20 | ;;; You should have received a copy of the GNU General Public License |
| 21 | ;;; along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 22 | |
| 23 | (define-module (home provenance) |
| 24 | #:use-module (gnu services) |
| 25 | #:use-module (guix channels) |
| 26 | #:use-module (guix describe) |
| 27 | #:use-module (guix diagnostics) |
| 28 | #:autoload (guix openpgp) (openpgp-format-fingerprint) |
| 29 | #:use-module (guix gexp) |
| 30 | #:use-module (guix monads) |
| 31 | #:use-module (guix profiles) |
| 32 | #:use-module (guix records) |
| 33 | #:use-module (guix store) |
| 34 | #:use-module (home) |
| 35 | #:autoload (ice-9 pretty-print) (pretty-print) |
| 36 | #:export (provenance-home-type |
| 37 | home-with-provenance)) |
| 38 | |
| 39 | (define (object->pretty-string obj) |
| 40 | "Like 'object->string', but using 'pretty-print'." |
| 41 | (call-with-output-string |
| 42 | (lambda (port) |
| 43 | (pretty-print obj port)))) |
| 44 | |
| 45 | (define (channel->code channel) |
| 46 | "Return code to build CHANNEL, ready to be dropped in a 'channels.scm' |
| 47 | file." |
| 48 | ;; Since the 'introduction' field is backward-incompatible, and since it's |
| 49 | ;; optional when using the "official" 'guix channel, include it if and only |
| 50 | ;; if we're referring to a different channel. |
| 51 | (let ((intro (and (not (equal? (list channel) %default-channels)) |
| 52 | (channel-introduction channel)))) |
| 53 | `(channel (name ',(channel-name channel)) |
| 54 | (url ,(channel-url channel)) |
| 55 | (branch ,(channel-branch channel)) |
| 56 | (commit ,(channel-commit channel)) |
| 57 | ,@(if intro |
| 58 | `((introduction |
| 59 | (make-channel-introduction |
| 60 | ,(channel-introduction-first-signed-commit intro) |
| 61 | (openpgp-fingerprint |
| 62 | ,(openpgp-format-fingerprint |
| 63 | (channel-introduction-first-commit-signer |
| 64 | intro)))))) |
| 65 | '())))) |
| 66 | |
| 67 | (define (channel->sexp channel) |
| 68 | "Return an sexp describing CHANNEL. The sexp is _not_ code and is meant to |
| 69 | be parsed by tools; it's potentially more future-proof than code." |
| 70 | ;; TODO: Add CHANNEL's introduction. Currently we can't do that because |
| 71 | ;; older 'guix system describe' expect exactly name/url/branch/commit |
| 72 | ;; without any additional fields. |
| 73 | `(channel (name ,(channel-name channel)) |
| 74 | (url ,(channel-url channel)) |
| 75 | (branch ,(channel-branch channel)) |
| 76 | (commit ,(channel-commit channel)))) |
| 77 | |
| 78 | (define (provenance-file channels configuration-file) |
| 79 | "Return a 'provenance' file describing CHANNELS, a list of channels, and |
| 80 | CONFIGURATION-FILE, which can be either #f or a <local-file> containing the OS |
| 81 | configuration being used." |
| 82 | (scheme-file "provenance" |
| 83 | #~(provenance |
| 84 | (version 0) |
| 85 | (channels #+@(if channels |
| 86 | (map channel->sexp channels) |
| 87 | '())) |
| 88 | (configuration-file #+configuration-file)))) |
| 89 | |
| 90 | (define (provenance-entry config-file) |
| 91 | "Return system entries describing the operating system provenance: the |
| 92 | channels in use and CONFIG-FILE, if it is true." |
| 93 | (define profile |
| 94 | (current-profile)) |
| 95 | |
| 96 | (define channels |
| 97 | (and=> profile profile-channels)) |
| 98 | |
| 99 | (let ((config-file (cond ((string? config-file) |
| 100 | (local-file config-file "home.scm")) |
| 101 | ((not config-file) |
| 102 | #f) |
| 103 | (else |
| 104 | config-file)))) |
| 105 | `((".provenance" ,(provenance-file channels config-file)) |
| 106 | ,@(if channels |
| 107 | `((".channels.scm" |
| 108 | ,(plain-file "channels.scm" |
| 109 | (object->pretty-string |
| 110 | `(list |
| 111 | ,@(map channel->code channels)))))) |
| 112 | '()) |
| 113 | ,@(if config-file |
| 114 | `((".home.scm" ,config-file)) |
| 115 | '())))) |
| 116 | |
| 117 | (define provenance-home-type |
| 118 | (home-type |
| 119 | (name 'provenance) |
| 120 | (extensions |
| 121 | (list |
| 122 | (home-extension |
| 123 | (target root-home-type) |
| 124 | (compute provenance-entry)))) |
| 125 | (description "The provenance home type"))) |
| 126 | |
| 127 | (define (home-configuration-file h) |
| 128 | "Return the configuration file of H, based on its 'location' field, or #f |
| 129 | if it could not be determined." |
| 130 | (let ((file (and=> (home-location h) |
| 131 | location-file))) |
| 132 | (and file |
| 133 | (or (and (string-prefix? "/" file) file) |
| 134 | (search-path %load-path file))))) |
| 135 | |
| 136 | (define* (home-with-provenance h |
| 137 | #:optional |
| 138 | (configuration-file |
| 139 | (home-configuration-file h))) |
| 140 | "Return a variant of H that stores its own provenance information, |
| 141 | including CONFIGURATION-FILE, if available. This is achieved by adding an |
| 142 | instance of PROVENANCE-HOME-TYPE to its configurations." |
| 143 | (home |
| 144 | (inherit h) |
| 145 | (configurations (cons (user-home provenance-home-type configuration-file) |
| 146 | (home-configurations h))))) |
| 147 |