1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2014, 2015, 2016 Alex Kost <alezost@gmail.com>
4 ;;; This file is part of GNU Guix.
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.
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.
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/>.
21 ;; Information about packages and generations is passed to the elisp
22 ;; side in the form of alists of parameters (such as ‘name’ or
23 ;; ‘version’) and their values.
25 ;; ‘entries’ procedure is the “entry point” for the elisp side to get
26 ;; information about packages and generations.
28 ;; Since name/version pair is not necessarily unique, we use
29 ;; `object-address' to identify a package (for ‘id’ parameter), if
30 ;; possible. However for the obsolete packages (that can be found in
31 ;; installed manifest but not in a package directory), ‘id’ parameter is
32 ;; still "name-version" string. So ‘id’ package parameter in the code
33 ;; below is either an object-address number or a full-name string.
35 ;; To speed-up the process of getting information, the following
36 ;; auxiliary variables are used:
38 ;; - `%packages' - VHash of "package address"/"package" pairs.
40 ;; - `%package-table' - Hash table of
41 ;; "name+version key"/"list of packages" pairs.
62 (guix scripts package)
67 (define-syntax-rule (first-or-false lst)
68 (and (not (null? lst))
71 (define (list-maybe obj)
72 (if (list? obj) obj (list obj)))
74 (define (output+error thunk)
75 "Call THUNK and return 2 values: output and error output as strings."
76 (let ((output-port (open-output-string))
77 (error-port (open-output-string)))
78 (with-output-to-port output-port
79 (lambda () (with-error-to-port error-port thunk)))
80 (let ((strings (list (get-output-string output-port)
81 (get-output-string error-port))))
82 (close-output-port output-port)
83 (close-output-port error-port)
84 (apply values strings))))
86 (define (full-name->name+version spec)
87 "Given package specification SPEC with or without output,
88 return two values: name and version. For example, for SPEC
89 \"foo-0.9.1b:lib\", return \"foo\" and \"0.9.1b\"."
90 (let-values (((name version output)
91 (package-specification->name+version+output spec)))
92 (values name version)))
94 (define (name+version->full-name name version)
95 (string-append name "-" version))
97 (define* (make-package-specification name #:optional version output)
98 (let ((full-name (if version
99 (name+version->full-name name version)
102 (string-append full-name ":" output)
105 (define name+version->key cons)
106 (define key->name+version car+cdr)
109 (fold-packages (lambda (pkg res)
110 (vhash-consq (object-address pkg) pkg res))
113 (define %package-table
114 (let ((table (make-hash-table (vlist-length %packages))))
119 (let* ((key (name+version->key (package-name pkg)
120 (package-version pkg)))
121 (ref (hash-ref table key)))
123 (if ref (cons pkg ref) (list pkg)))))))
127 (define (manifest-entry->name+version+output entry)
129 (manifest-entry-name entry)
130 (manifest-entry-version entry)
131 (manifest-entry-output entry)))
133 (define (manifest-entry->package-specification entry)
135 (lambda () (manifest-entry->name+version+output entry))
136 make-package-specification))
138 (define (manifest-entries->package-specifications entries)
139 (map manifest-entry->package-specification entries))
141 (define (profile-package-specifications profile)
142 "Return a list of package specifications for PROFILE."
143 (let ((manifest (profile-manifest profile)))
144 (manifest-entries->package-specifications
145 (manifest-entries manifest))))
147 (define (profile->specifications+paths profile)
148 "Return a list of package specifications and paths for PROFILE.
149 Each element of the list is a list of the package specification and its path."
150 (let ((manifest (profile-manifest profile)))
152 (list (manifest-entry->package-specification entry)
153 (manifest-entry-item entry)))
154 (manifest-entries manifest))))
156 (define (profile-difference profile1 profile2)
157 "Return a list of package specifications for outputs installed in PROFILE1
158 and not installed in PROFILE2."
159 (let ((specs1 (profile-package-specifications profile1))
160 (specs2 (profile-package-specifications profile2)))
161 (lset-difference string=? specs1 specs2)))
163 (define (manifest-entries->hash-table entries)
164 "Return a hash table of name keys and lists of matching manifest ENTRIES."
165 (let ((table (make-hash-table (length entries))))
166 (for-each (lambda (entry)
167 (let* ((key (manifest-entry-name entry))
168 (ref (hash-ref table key)))
170 (if ref (cons entry ref) (list entry)))))
174 (define (manifest=? m1 m2)
178 (define manifest->hash-table
179 (let ((current-manifest #f)
182 "Return a hash table of name keys and matching MANIFEST entries."
183 (unless (manifest=? manifest current-manifest)
184 (set! current-manifest manifest)
185 (set! current-table (manifest-entries->hash-table
186 (manifest-entries manifest))))
189 (define* (manifest-entries-by-name manifest name #:optional version output)
190 "Return a list of MANIFEST entries matching NAME, VERSION and OUTPUT."
191 (let ((entries (or (hash-ref (manifest->hash-table manifest) name)
193 (if (or version output)
194 (filter (lambda (entry)
195 (and (or (not version)
196 (equal? version (manifest-entry-version entry)))
198 (equal? output (manifest-entry-output entry)))))
202 (define (manifest-entry-by-output entries output)
203 "Return a manifest entry from ENTRIES matching OUTPUT."
204 (find (lambda (entry)
205 (string= output (manifest-entry-output entry)))
208 (define (fold-manifest-by-name manifest proc init)
209 "Fold over MANIFEST entries.
210 Call (PROC NAME VERSION ENTRIES RESULT), using INIT as the initial value
211 of RESULT. ENTRIES is a list of manifest entries with NAME/VERSION."
212 (hash-fold (lambda (name entries res)
213 (proc name (manifest-entry-version (car entries))
216 (manifest->hash-table manifest)))
218 (define* (object-transformer param-alist #:optional (params '()))
219 "Return procedure transforming objects into alist of parameter/value pairs.
221 PARAM-ALIST is alist of available parameters (symbols) and procedures
222 returning values of these parameters. Each procedure is applied to
225 PARAMS is list of parameters from PARAM-ALIST that should be returned by
226 a resulting procedure. If PARAMS is not specified or is an empty list,
227 use all available parameters.
231 (let* ((alist `((plus1 . ,1+) (minus1 . ,1-) (mul2 . ,(cut * 2 <>))))
232 (number->alist (object-transformer alist '(plus1 mul2))))
235 ((plus1 . 9) (mul2 . 16))
237 (let* ((use-all-params (null? params))
238 (alist (filter-map (match-lambda
240 (and (or use-all-params
248 (cons param (apply proc objects))))
251 (define %manifest-entry-param-alist
252 `((output . ,manifest-entry-output)
253 (path . ,manifest-entry-item)
254 (dependencies . ,manifest-entry-dependencies)))
256 (define manifest-entry->sexp
257 (object-transformer %manifest-entry-param-alist))
259 (define (manifest-entries->sexps entries)
260 (map manifest-entry->sexp entries))
262 (define (package-inputs-names inputs)
263 "Return a list of full names of the packages from package INPUTS."
264 (filter-map (match-lambda
265 ((_ (? package? package))
266 (package-full-name package))
267 ((_ (? package? package) output)
268 (make-package-specification (package-name package)
269 (package-version package)
274 (define (package-license-names package)
275 "Return a list of license names of the PACKAGE."
276 (filter-map (lambda (license)
277 (and (license? license)
278 (license-name license)))
279 (list-maybe (package-license package))))
281 (define (package-source-names package)
282 "Return a list of source names (URLs) of the PACKAGE."
283 (let ((source (package-source package)))
284 (and (origin? source)
285 (filter-map (lambda (uri)
288 ((git-reference? uri)
289 (git-reference-url uri))
290 (else "Unknown source type")))
291 (list-maybe (origin-uri source))))))
293 (define (package-unique? package)
294 "Return #t if PACKAGE is a single package with such name/version."
295 (null? (cdr (packages-by-name (package-name package)
296 (package-version package)))))
298 (define %package-param-alist
299 `((id . ,object-address)
300 (package-id . ,object-address)
301 (name . ,package-name)
302 (version . ,package-version)
303 (license . ,package-license-names)
304 (source . ,package-source-names)
305 (synopsis . ,package-synopsis)
306 (description . ,package-description-string)
307 (home-url . ,package-home-page)
308 (outputs . ,package-outputs)
309 (systems . ,package-supported-systems)
310 (non-unique . ,(negate package-unique?))
311 (inputs . ,(lambda (pkg)
312 (package-inputs-names
313 (package-inputs pkg))))
314 (native-inputs . ,(lambda (pkg)
315 (package-inputs-names
316 (package-native-inputs pkg))))
317 (propagated-inputs . ,(lambda (pkg)
318 (package-inputs-names
319 (package-propagated-inputs pkg))))
320 (location . ,(lambda (pkg)
321 (location->string (package-location pkg))))))
323 (define (package-param package param)
324 "Return a value of a PACKAGE PARAM."
325 (and=> (assq-ref %package-param-alist param)
329 ;;; Finding packages.
331 (define (package-by-address address)
332 (and=> (vhash-assq address %packages)
335 (define (packages-by-name+version name version)
336 (or (hash-ref %package-table
337 (name+version->key name version))
340 (define (packages-by-full-name full-name)
342 (lambda () (full-name->name+version full-name))
343 packages-by-name+version))
345 (define (packages-by-id id)
347 (let ((pkg (package-by-address id)))
348 (if pkg (list pkg) '()))
349 (packages-by-full-name id)))
351 (define (id->name+version id)
353 (and=> (package-by-address id)
355 (values (package-name pkg)
356 (package-version pkg))))
357 (full-name->name+version id)))
359 (define (package-by-id id)
360 (first-or-false (packages-by-id id)))
362 (define (newest-package-by-id id)
363 (and=> (id->name+version id)
365 (first-or-false (find-best-packages-by-name name #f)))))
367 (define (matching-packages predicate)
368 (fold-packages (lambda (pkg res)
374 (define (filter-packages-by-output packages output)
375 (filter (lambda (package)
376 (member output (package-outputs package)))
379 (define* (packages-by-name name #:optional version output)
380 "Return a list of packages matching NAME, VERSION and OUTPUT."
381 (let ((packages (if version
382 (packages-by-name+version name version)
384 (lambda (pkg) (string=? name (package-name pkg)))))))
386 (filter-packages-by-output packages output)
389 (define (manifest-entry->packages entry)
391 (lambda () (manifest-entry->name+version+output entry))
394 (define (packages-by-regexp regexp match-params)
395 "Return a list of packages matching REGEXP string.
396 MATCH-PARAMS is a list of parameters that REGEXP can match."
397 (define (package-match? package regexp)
399 (let ((val (package-param package param)))
400 (and (string? val) (regexp-exec regexp val))))
403 (let ((re (make-regexp regexp regexp/icase)))
404 (matching-packages (cut package-match? <> re))))
406 (define (all-available-packages)
407 "Return a list of all available packages."
408 (matching-packages (const #t)))
410 (define (newest-available-packages)
411 "Return a list of the newest available packages."
412 (vhash-fold (lambda (name elem res)
417 (find-newest-available-packages)))
420 ;;; Making package/output patterns.
422 (define (specification->package-pattern specification)
425 (full-name->name+version specification))
428 (define (specification->output-pattern specification)
431 (package-specification->name+version+output specification #f))
434 (define (id->package-pattern id)
436 (package-by-address id)
437 (specification->package-pattern id)))
439 (define (id->output-pattern id)
440 "Return an output pattern by output ID.
441 ID should be '<package-address>:<output>' or '<name>-<version>:<output>'."
442 (let-values (((name version output)
443 (package-specification->name+version+output id)))
445 (list name version output)
446 (list (package-by-address (string->number name))
449 (define (specifications->package-patterns . specifications)
450 (map specification->package-pattern specifications))
452 (define (specifications->output-patterns . specifications)
453 (map specification->output-pattern specifications))
455 (define (ids->package-patterns . ids)
456 (map id->package-pattern ids))
458 (define (ids->output-patterns . ids)
459 (map id->output-pattern ids))
461 (define* (manifest-patterns-result packages res obsolete-pattern
462 #:optional installed-pattern)
463 "Auxiliary procedure for 'manifest-package-patterns' and
464 'manifest-output-patterns'."
466 (cons (obsolete-pattern) res)
467 (if installed-pattern
468 ;; We don't need duplicates for a list of installed packages,
469 ;; so just take any (car) package.
470 (cons (installed-pattern (car packages)) res)
473 (define* (manifest-package-patterns manifest #:optional obsolete-only?)
474 "Return a list of package patterns for MANIFEST entries.
475 If OBSOLETE-ONLY? is #f, use all entries, otherwise make patterns only
476 for obsolete packages."
477 (fold-manifest-by-name
479 (lambda (name version entries res)
480 (manifest-patterns-result (packages-by-name name version)
482 (lambda () (list name version entries))
483 (and (not obsolete-only?)
484 (cut list <> entries))))
487 (define* (manifest-output-patterns manifest #:optional obsolete-only?)
488 "Return a list of output patterns for MANIFEST entries.
489 If OBSOLETE-ONLY? is #f, use all entries, otherwise make patterns only
490 for obsolete packages."
491 (fold (lambda (entry res)
492 (manifest-patterns-result (manifest-entry->packages entry)
495 (and (not obsolete-only?)
496 (cut list <> entry))))
498 (manifest-entries manifest)))
500 (define (obsolete-package-patterns manifest)
501 (manifest-package-patterns manifest #t))
503 (define (obsolete-output-patterns manifest)
504 (manifest-output-patterns manifest #t))
507 ;;; Transforming package/output patterns into alists.
509 (define (obsolete-package-sexp name version entries)
510 "Return an alist with information about obsolete package.
511 ENTRIES is a list of installed manifest entries."
512 `((id . ,(name+version->full-name name version))
515 (outputs . ,(map manifest-entry-output entries))
517 (installed . ,(manifest-entries->sexps entries))))
519 (define (package-pattern-transformer manifest params)
520 "Return 'package-pattern->package-sexps' procedure."
521 (define package->sexp
522 (object-transformer %package-param-alist params))
524 (define* (sexp-by-package package #:optional
525 (entries (manifest-entries-by-name
527 (package-name package)
528 (package-version package))))
529 (cons (cons 'installed (manifest-entries->sexps entries))
530 (package->sexp package)))
532 (define (->sexps pattern)
534 ((? package? package)
535 (list (sexp-by-package package)))
536 (((? package? package) entries)
537 (list (sexp-by-package package entries)))
538 ((name version entries)
539 (list (obsolete-package-sexp
540 name version entries)))
542 (let ((packages (packages-by-name name version)))
544 (let ((entries (manifest-entries-by-name
545 manifest name version)))
548 (list (obsolete-package-sexp
549 name version entries))))
550 (map sexp-by-package packages))))
555 (define (output-pattern-transformer manifest params)
556 "Return 'output-pattern->output-sexps' procedure."
557 (define package->sexp
558 (object-transformer (alist-delete 'id %package-param-alist)
561 (define manifest-entry->sexp
562 (object-transformer (alist-delete 'output %manifest-entry-param-alist)
565 (define* (output-sexp pkg-alist pkg-address output
567 (let ((entry-alist (if entry
568 (manifest-entry->sexp entry)
570 (base `((id . ,(string-append
571 (number->string pkg-address)
574 (installed . ,(->bool entry)))))
575 (append entry-alist base pkg-alist)))
577 (define (obsolete-output-sexp entry)
578 (let-values (((name version output)
579 (manifest-entry->name+version+output entry)))
580 (let ((base `((id . ,(make-package-specification
581 name version output))
582 (package-id . ,(name+version->full-name name version))
588 (append (manifest-entry->sexp entry) base))))
590 (define* (sexps-by-package package #:optional output
591 (entries (manifest-entries-by-name
593 (package-name package)
594 (package-version package))))
595 ;; Assuming that PACKAGE has this OUTPUT.
596 (let ((pkg-alist (package->sexp package))
597 (address (object-address package))
600 (package-outputs package))))
601 (map (lambda (output)
602 (output-sexp pkg-alist address output
603 (manifest-entry-by-output entries output)))
606 (define* (sexps-by-manifest-entry entry #:optional
607 (packages (manifest-entry->packages
610 (list (obsolete-output-sexp entry))
611 (map (lambda (package)
612 (output-sexp (package->sexp package)
613 (object-address package)
614 (manifest-entry-output entry)
618 (define (->sexps pattern)
620 ((? package? package)
621 (sexps-by-package package))
622 ((package (? string? output))
623 (sexps-by-package package output))
624 ((? manifest-entry? entry)
625 (list (obsolete-output-sexp entry)))
627 (sexps-by-manifest-entry entry (list package)))
628 ((name version output)
629 (let ((packages (packages-by-name name version output)))
631 (let ((entries (manifest-entries-by-name
632 manifest name version output)))
633 (append-map (cut sexps-by-manifest-entry <>)
635 (append-map (cut sexps-by-package <> output)
641 (define (entry-type-error entry-type)
642 (error (format #f "Wrong entry-type '~a'" entry-type)))
644 (define (search-type-error entry-type search-type)
645 (error (format #f "Wrong search type '~a' for entry-type '~a'"
646 search-type entry-type)))
648 (define %pattern-transformers
649 `((package . ,package-pattern-transformer)
650 (output . ,output-pattern-transformer)))
652 (define (pattern-transformer entry-type)
653 (assq-ref %pattern-transformers entry-type))
655 ;; All procedures from inner alists are called with (MANIFEST . SEARCH-VALS)
656 ;; as arguments; see `package/output-sexps'.
657 (define %patterns-makers
658 (let* ((apply-to-rest (lambda (proc)
659 (lambda (_ . rest) (apply proc rest))))
660 (apply-to-first (lambda (proc)
661 (lambda (first . _) (proc first))))
662 (manifest-package-proc (apply-to-first manifest-package-patterns))
663 (manifest-output-proc (apply-to-first manifest-output-patterns))
664 (regexp-proc (lambda (_ regexp params . __)
665 (packages-by-regexp regexp params)))
666 (all-proc (lambda _ (all-available-packages)))
667 (newest-proc (lambda _ (newest-available-packages))))
669 (id . ,(apply-to-rest ids->package-patterns))
670 (name . ,(apply-to-rest specifications->package-patterns))
671 (installed . ,manifest-package-proc)
672 (obsolete . ,(apply-to-first obsolete-package-patterns))
673 (regexp . ,regexp-proc)
674 (all-available . ,all-proc)
675 (newest-available . ,newest-proc))
677 (id . ,(apply-to-rest ids->output-patterns))
678 (name . ,(apply-to-rest specifications->output-patterns))
679 (installed . ,manifest-output-proc)
680 (obsolete . ,(apply-to-first obsolete-output-patterns))
681 (regexp . ,regexp-proc)
682 (all-available . ,all-proc)
683 (newest-available . ,newest-proc)))))
685 (define (patterns-maker entry-type search-type)
686 (or (and=> (assq-ref %patterns-makers entry-type)
687 (cut assq-ref <> search-type))
688 (search-type-error entry-type search-type)))
690 (define (package/output-sexps profile params entry-type
691 search-type search-vals)
692 "Return information about packages or package outputs.
693 See 'entry-sexps' for details."
694 (let* ((manifest (profile-manifest profile))
695 (patterns (if (and (eq? entry-type 'output)
696 (eq? search-type 'profile-diff))
699 (map specification->output-pattern
700 (profile-difference p1 p2)))
702 (apply (patterns-maker entry-type search-type)
703 manifest search-vals)))
704 (->sexps ((pattern-transformer entry-type) manifest params)))
705 (append-map ->sexps patterns)))
708 ;;; Getting information about generations.
710 (define (generation-param-alist profile)
711 "Return an alist of generation parameters and procedures for PROFILE."
712 (let ((current (generation-number profile)))
715 (prev-number . ,(cut previous-generation-number profile <>))
716 (current . ,(cut = current <>))
717 (path . ,(cut generation-file-name profile <>))
718 (time . ,(lambda (gen)
719 (time-second (generation-time profile gen)))))))
721 (define (matching-generations profile predicate)
722 "Return a list of PROFILE generations matching PREDICATE."
723 (filter predicate (profile-generations profile)))
725 (define (last-generations profile number)
726 "Return a list of last NUMBER generations.
727 If NUMBER is 0 or less, return all generations."
728 (let ((generations (profile-generations profile))
729 (number (if (<= number 0) +inf.0 number)))
730 (if (> (length generations) number)
731 (list-head (reverse generations) number)
734 (define (find-generations profile search-type search-vals)
735 "Find PROFILE's generations matching SEARCH-TYPE and SEARCH-VALS."
738 (matching-generations profile (cut memq <> search-vals)))
740 (last-generations profile (car search-vals)))
742 (last-generations profile +inf.0))
746 (matching-generations
749 (let ((time (time-second (generation-time profile gen))))
752 (else (search-type-error "generation" search-type))))
754 (define (generation-sexps profile params search-type search-vals)
755 "Return information about generations.
756 See 'entry-sexps' for details."
757 (let ((generations (find-generations profile search-type search-vals))
758 (->sexp (object-transformer (generation-param-alist profile)
760 (map ->sexp generations)))
762 (define system-generation-boot-parameters
764 (lambda (profile generation)
765 "Return boot parameters for PROFILE's system GENERATION."
766 (let* ((gen-file (generation-file-name profile generation))
767 (param-file (string-append gen-file "/parameters")))
768 (call-with-input-file param-file read-boot-parameters)))))
770 (define (system-generation-param-alist profile)
771 "Return an alist of system generation parameters and procedures for
773 (append (generation-param-alist profile)
774 `((label . ,(lambda (gen)
775 (boot-parameters-label
776 (system-generation-boot-parameters
778 (root-device . ,(lambda (gen)
779 (boot-parameters-root-device
780 (system-generation-boot-parameters
782 (kernel . ,(lambda (gen)
783 (boot-parameters-kernel
784 (system-generation-boot-parameters
787 (define (system-generation-sexps profile params search-type search-vals)
788 "Return an alist with information about system generations."
789 (let ((generations (find-generations profile search-type search-vals))
790 (->sexp (object-transformer (system-generation-param-alist profile)
792 (map ->sexp generations)))
795 ;;; Getting package/output/generation entries (alists).
797 (define (entries profile params entry-type search-type search-vals)
798 "Return information about entries.
800 ENTRY-TYPE is a symbol defining a type of returning information. Should
801 be: 'package', 'output' or 'generation'.
803 SEARCH-TYPE and SEARCH-VALS define how to get the information.
804 SEARCH-TYPE should be one of the following symbols:
806 - If ENTRY-TYPE is 'package' or 'output':
807 'id', 'name', 'regexp', 'all-available', 'newest-available',
808 'installed', 'obsolete', 'generation'.
810 - If ENTRY-TYPE is 'generation':
811 'id', 'last', 'all', 'time'.
813 PARAMS is a list of parameters for receiving. If it is an empty list,
814 get information with all available parameters, which are:
816 - If ENTRY-TYPE is 'package':
817 'id', 'name', 'version', 'outputs', 'license', 'synopsis',
818 'description', 'home-url', 'inputs', 'native-inputs',
819 'propagated-inputs', 'location', 'installed'.
821 - If ENTRY-TYPE is 'output':
822 'id', 'package-id', 'name', 'version', 'output', 'license',
823 'synopsis', 'description', 'home-url', 'inputs', 'native-inputs',
824 'propagated-inputs', 'location', 'installed', 'path', 'dependencies'.
826 - If ENTRY-TYPE is 'generation':
827 'id', 'number', 'prev-number', 'path', 'time'.
829 Returning value is a list of alists. Each alist consists of
830 parameter/value pairs."
833 (package/output-sexps profile params entry-type
834 search-type search-vals))
836 (generation-sexps profile params
837 search-type search-vals))
839 (system-generation-sexps profile params
840 search-type search-vals))
841 (else (entry-type-error entry-type))))
846 (define* (package->manifest-entry* package #:optional output)
849 (check-package-freshness package)
850 (package->manifest-entry package output))))
852 (define* (make-install-manifest-entries id #:optional output)
853 (package->manifest-entry* (package-by-id id) output))
855 (define* (make-upgrade-manifest-entries id #:optional output)
856 (package->manifest-entry* (newest-package-by-id id) output))
858 (define* (make-manifest-pattern id #:optional output)
859 "Make manifest pattern from a package ID and OUTPUT."
860 (let-values (((name version)
861 (id->name+version id)))
868 (define (convert-action-pattern pattern proc)
869 "Convert action PATTERN into a list of objects returned by PROC.
870 PROC is called: (PROC ID) or (PROC ID OUTPUT)."
874 (let ((obj (proc id)))
875 (if obj (list obj) '()))
876 (filter-map (cut proc id <>)
880 (define (convert-action-patterns patterns proc)
881 (append-map (cut convert-action-pattern <> proc)
884 (define* (process-package-actions
885 profile #:key (install '()) (upgrade '()) (remove '())
886 (use-substitutes? #t) dry-run?)
887 "Perform package actions.
889 INSTALL, UPGRADE, REMOVE are lists of 'package action patterns'.
890 Each pattern should have the following form:
894 ID is an object address or a full-name of a package.
895 OUTPUTS is a list of package outputs (may be an empty list)."
896 (format #t "The process begins ...~%")
897 (let* ((install (append
898 (convert-action-patterns
899 install make-install-manifest-entries)
900 (convert-action-patterns
901 upgrade make-upgrade-manifest-entries)))
902 (remove (convert-action-patterns remove make-manifest-pattern))
903 (transaction (manifest-transaction (install install)
905 (manifest (profile-manifest profile))
906 (new-manifest (manifest-perform-transaction
907 manifest transaction)))
908 (unless (and (null? install) (null? remove))
910 (let* ((derivation (run-with-store store
912 (set-guile-for-build (default-guile))
913 (profile-derivation new-manifest))))
914 (derivations (list derivation))
915 (new-profile (derivation->output-path derivation)))
916 (set-build-options store
917 #:print-build-trace #f
918 #:use-substitutes? use-substitutes?)
919 (show-manifest-transaction store manifest transaction
921 (show-what-to-build store derivations
922 #:use-substitutes? use-substitutes?
925 (let ((name (generation-file-name
927 (+ 1 (generation-number profile)))))
928 (and (build-derivations store derivations)
929 (let* ((entries (manifest-entries new-manifest))
930 (count (length entries)))
931 (switch-symlinks name new-profile)
932 (switch-symlinks profile name)
933 (format #t (N_ "~a package in profile~%"
934 "~a packages in profile~%"
937 (display-search-paths entries (list profile)))))))))))
939 (define (delete-generations* profile generations)
940 "Delete GENERATIONS from PROFILE.
941 GENERATIONS is a list of generation numbers."
943 (delete-generations store profile generations)))
945 (define (package-location-string id-or-name)
946 "Return a location string of a package with ID-OR-NAME."
947 (and-let* ((package (or (package-by-id id-or-name)
948 (first (packages-by-name id-or-name))))
949 (location (package-location package)))
950 (location->string location)))
952 (define (package-source-derivation->store-path derivation)
953 "Return a store path of the package source DERIVATION."
954 (match (derivation-outputs derivation)
955 ;; Source derivation is always (("out" . derivation)).
957 (derivation-output-path output-drv))
960 (define (package-source-path package-id)
961 "Return a store file path to a source of a package PACKAGE-ID."
962 (and-let* ((package (package-by-id package-id))
963 (source (package-source package)))
965 (package-source-derivation->store-path
966 (package-source-derivation store source)))))
968 (define* (package-source-build-derivation package-id #:key dry-run?
969 (use-substitutes? #t))
970 "Build source derivation of a package PACKAGE-ID."
971 (and-let* ((package (package-by-id package-id))
972 (source (package-source package)))
974 (let* ((derivation (package-source-derivation store source))
975 (derivations (list derivation)))
976 (set-build-options store
977 #:print-build-trace #f
978 #:use-substitutes? use-substitutes?)
979 (show-what-to-build store derivations
980 #:use-substitutes? use-substitutes?
983 (build-derivations store derivations))
984 (format #t "The source store path: ~a~%"
985 (package-source-derivation->store-path derivation))))))
988 ;;; Executing guix commands
990 (define (guix-command . args)
991 "Run 'guix ARGS ...' command."
993 (lambda () (apply run-guix args))
996 (define (guix-command-output . args)
997 "Return 2 strings with 'guix ARGS ...' output and error output."
1000 (parameterize ((guix-warning-port (current-error-port)))
1001 (apply guix-command args)))))
1003 (define (help-string . commands)
1004 "Return string with 'guix COMMANDS ... --help' output."
1005 (apply guix-command-output `(,@commands "--help")))
1007 (define (pipe-guix-output guix-args command-args)
1008 "Run 'guix GUIX-ARGS ...' command and pipe its output to a shell command
1009 defined by COMMAND-ARGS.
1010 Return #t if the shell command was executed successfully."
1011 (let ((pipe (apply open-pipe* OPEN_WRITE command-args)))
1012 (with-output-to-port pipe
1013 (lambda () (apply guix-command guix-args)))
1014 (zero? (status:exit-val (close-pipe pipe)))))
1017 ;;; Lists of packages, lint checkers, etc.
1019 (define (graph-type-names)
1020 "Return a list of names of available graph node types."
1021 (map (@ (guix graph) node-type-name)
1022 (@ (guix scripts graph) %node-types)))
1024 (define (refresh-updater-names)
1025 "Return a list of names of available refresh updater types."
1026 (map (@ (guix upstream) upstream-updater-name)
1027 (@ (guix scripts refresh) %updaters)))
1029 (define (lint-checker-names)
1030 "Return a list of names of available lint checkers."
1031 (map (lambda (checker)
1032 (symbol->string (lint-checker-name checker)))
1035 (define (package-names)
1036 "Return a list of names of available packages."
1038 (fold-packages (lambda (pkg res)
1039 (cons (package-name pkg) res))
1042 ;; See the comment to 'guix-package-names' function in "guix-popup.el".
1043 (define (package-names-lists)
1044 (map list (package-names)))