summaryrefslogtreecommitdiff
path: root/guix
diff options
context:
space:
mode:
Diffstat (limited to 'guix')
-rw-r--r--guix/scripts/package.scm357
1 files changed, 189 insertions, 168 deletions
diff --git a/guix/scripts/package.scm b/guix/scripts/package.scm
index 84a33782da..c71cf8e76c 100644
--- a/guix/scripts/package.scm
+++ b/guix/scripts/package.scm
@@ -421,41 +421,43 @@ VERSION."
((_ version pkgs ...) pkgs)
(#f '()))))
-(define* (find-package name #:optional (output "out"))
- "Find the package NAME; NAME may contain a version number and a
-sub-derivation name. If the version number is not present, return the
-preferred newest version. If the sub-derivation name is not present, use
-OUTPUT."
- (define request name)
+(define* (specification->package+output spec #:optional (output "out"))
+ "Find the package and output specified by SPEC, or #f and #f; SPEC may
+optionally contain a version number and an output name, as in these examples:
+ guile
+ guile-2.0.9
+ guile:debug
+ guile-2.0.9:debug
+
+If SPEC does not specify a version number, return the preferred newest
+version; if SPEC does not specify an output, return OUTPUT."
(define (ensure-output p sub-drv)
(if (member sub-drv (package-outputs p))
- p
+ sub-drv
(leave (_ "package `~a' lacks output `~a'~%")
(package-full-name p)
sub-drv)))
(let*-values (((name sub-drv)
- (match (string-rindex name #\:)
- (#f (values name output))
- (colon (values (substring name 0 colon)
- (substring name (+ 1 colon))))))
+ (match (string-rindex spec #\:)
+ (#f (values spec output))
+ (colon (values (substring spec 0 colon)
+ (substring spec (+ 1 colon))))))
((name version)
(package-name->name+version name)))
(match (find-best-packages-by-name name version)
((p)
- (list name (package-version p) sub-drv (ensure-output p sub-drv)
- (package-transitive-propagated-inputs p)))
+ (values p (ensure-output p sub-drv)))
((p p* ...)
(warning (_ "ambiguous package specification `~a'~%")
- request)
+ spec)
(warning (_ "choosing ~a from ~a~%")
(package-full-name p)
(location->string (package-location p)))
- (list name (package-version p) sub-drv (ensure-output p sub-drv)
- (package-transitive-propagated-inputs p)))
+ (values p (ensure-output p sub-drv)))
(()
- (leave (_ "~a: package not found~%") request)))))
+ (leave (_ "~a: package not found~%") spec)))))
(define (upgradeable? name current-version current-path)
"Return #t if there's a version of package NAME newer than CURRENT-VERSION,
@@ -707,6 +709,112 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n"))
(cons `(query list-available ,(or arg ""))
result)))))
+(define (options->installable opts installed)
+ "Given INSTALLED, the set of currently installed packages, and OPTS, the
+result of 'args-fold', return two values: the new list of manifest entries,
+and the list of derivations that need to be built."
+ (define (canonicalize-deps deps)
+ ;; Remove duplicate entries from DEPS, a list of propagated inputs,
+ ;; where each input is a name/path tuple.
+ (define (same? d1 d2)
+ (match d1
+ ((_ p1)
+ (match d2
+ ((_ p2) (eq? p1 p2))
+ (_ #f)))
+ ((_ p1 out1)
+ (match d2
+ ((_ p2 out2)
+ (and (string=? out1 out2)
+ (eq? p1 p2)))
+ (_ #f)))))
+
+ (delete-duplicates deps same?))
+
+ (define* (package->tuple p #:optional output)
+ ;; Convert package P to a manifest tuple.
+ ;; When given a package via `-e', install the first of its
+ ;; outputs (XXX).
+ (check-package-freshness p)
+ (let* ((output (or output (car (package-outputs p))))
+ (path (package-output (%store) p output))
+ (deps (package-transitive-propagated-inputs p)))
+ `(,(package-name p)
+ ,(package-version p)
+ ,output
+ ,path
+ ,(canonicalize-deps deps))))
+
+ (define upgrade-regexps
+ (filter-map (match-lambda
+ (('upgrade . regexp)
+ (make-regexp (or regexp "")))
+ (_ #f))
+ opts))
+
+ (define packages-to-upgrade
+ (match upgrade-regexps
+ (()
+ '())
+ ((_ ...)
+ (let ((newest (find-newest-available-packages)))
+ (filter-map (match-lambda
+ ((name version output path _)
+ (and (any (cut regexp-exec <> name)
+ upgrade-regexps)
+ (upgradeable? name version path)
+ (let ((output (or output "out")))
+ (call-with-values
+ (lambda ()
+ (specification->package+output name output))
+ list))))
+ (_ #f))
+ installed)))))
+
+ (define to-upgrade
+ (map (match-lambda
+ ((package output)
+ (package->tuple package output)))
+ packages-to-upgrade))
+
+ (define packages-to-install
+ (filter-map (match-lambda
+ (('install . (? package? p))
+ (list p "out"))
+ (('install . (? string? spec))
+ (and (not (store-path? spec))
+ (let-values (((package output)
+ (specification->package+output spec)))
+ (and package (list package output)))))
+ (_ #f))
+ opts))
+
+ (define to-install
+ (append (map (match-lambda
+ ((package output)
+ (package->tuple package output)))
+ packages-to-install)
+ (filter-map (match-lambda
+ (('install . (? package?))
+ #f)
+ (('install . (? store-path? path))
+ (let-values (((name version)
+ (package-name->name+version
+ (store-path-package-name path))))
+ `(,name ,version #f ,path ())))
+ (_ #f))
+ opts)))
+
+ (define derivations
+ (map (match-lambda
+ ((package output)
+ ;; FIXME: We should really depend on just OUTPUT rather than on all
+ ;; the outputs of PACKAGE.
+ (package-derivation (%store) package)))
+ (append packages-to-install packages-to-upgrade)))
+
+ (values (append to-upgrade to-install) derivations))
+
;;;
;;; Entry point.
@@ -780,43 +888,12 @@ more information.~%"))
(define verbose? (assoc-ref opts 'verbose?))
(define profile (assoc-ref opts 'profile))
- (define (canonicalize-deps deps)
- ;; Remove duplicate entries from DEPS, a list of propagated inputs,
- ;; where each input is a name/path tuple.
- (define (same? d1 d2)
- (match d1
- ((_ p1)
- (match d2
- ((_ p2) (eq? p1 p2))
- (_ #f)))
- ((_ p1 out1)
- (match d2
- ((_ p2 out2)
- (and (string=? out1 out2)
- (eq? p1 p2)))
- (_ #f)))))
-
- (delete-duplicates deps same?))
-
(define (same-package? tuple name out)
(match tuple
((tuple-name _ tuple-output _ ...)
(and (equal? name tuple-name)
(equal? out tuple-output)))))
- (define (package->tuple p)
- ;; Convert package P to a tuple.
- ;; When given a package via `-e', install the first of its
- ;; outputs (XXX).
- (let* ((out (car (package-outputs p)))
- (path (package-output (%store) p out))
- (deps (package-transitive-propagated-inputs p)))
- `(,(package-name p)
- ,(package-version p)
- ,out
- ,p
- ,(canonicalize-deps deps))))
-
(define (show-what-to-remove/install remove install dry-run?)
;; Tell the user what's going to happen in high-level terms.
;; TODO: Report upgrades more clearly.
@@ -922,127 +999,71 @@ more information.~%"))
(_ #f))
opts))
(else
- (let* ((installed (manifest-packages (profile-manifest profile)))
- (upgrade-regexps (filter-map (match-lambda
- (('upgrade . regexp)
- (make-regexp (or regexp "")))
- (_ #f))
- opts))
- (upgrade (if (null? upgrade-regexps)
- '()
- (let ((newest (find-newest-available-packages)))
- (filter-map
- (match-lambda
- ((name version output path _)
- (and (any (cut regexp-exec <> name)
- upgrade-regexps)
- (upgradeable? name version path)
- (find-package name
- (or output "out"))))
- (_ #f))
- installed))))
- (install (append
- upgrade
- (filter-map (match-lambda
- (('install . (? package? p))
- (package->tuple p))
- (('install . (? store-path?))
- #f)
- (('install . package)
- (find-package package))
+ (let*-values (((installed)
+ (manifest-packages (profile-manifest profile)))
+ ((install* drv)
+ (options->installable opts installed)))
+ (let* ((remove (filter-map (match-lambda
+ (('remove . package)
+ package)
(_ #f))
- opts)))
- (drv (filter-map (match-lambda
- ((name version sub-drv
- (? package? package)
- (deps ...))
- (check-package-freshness package)
- (package-derivation (%store) package))
- (_ #f))
- install))
- (install*
- (append
- (filter-map (match-lambda
- (('install . (? package? p))
- #f)
- (('install . (? store-path? path))
- (let-values (((name version)
- (package-name->name+version
- (store-path-package-name
- path))))
- `(,name ,version #f ,path ())))
- (_ #f))
- opts)
- (map (lambda (tuple drv)
- (match tuple
- ((name version sub-drv _ (deps ...))
- (let ((output-path
- (derivation->output-path
- drv sub-drv)))
- `(,name ,version ,sub-drv ,output-path
- ,(canonicalize-deps deps))))))
- install drv)))
- (remove (filter-map (match-lambda
- (('remove . package)
- package)
- (_ #f))
- opts))
- (remove* (filter-map (cut assoc <> installed) remove))
- (packages
- (append install*
- (fold (lambda (package result)
- (match package
- ((name _ out _ ...)
- (filter (negate
- (cut same-package? <>
- name out))
- result))))
- (fold alist-delete installed remove)
- install*))))
-
- (when (equal? profile %current-profile)
- (ensure-default-profile))
-
- (show-what-to-remove/install remove* install* dry-run?)
- (show-what-to-build (%store) drv
- #:use-substitutes? (assoc-ref opts 'substitutes?)
- #:dry-run? dry-run?)
-
- (or dry-run?
- (and (build-derivations (%store) drv)
- (let* ((prof-drv (profile-derivation (%store) packages))
- (prof (derivation->output-path prof-drv))
- (old-drv (profile-derivation
- (%store) (manifest-packages
- (profile-manifest profile))))
- (old-prof (derivation->output-path old-drv))
- (number (generation-number profile))
-
- ;; Always use NUMBER + 1 for the new profile,
- ;; possibly overwriting a "previous future
- ;; generation".
- (name (format #f "~a-~a-link"
- profile (+ 1 number))))
- (if (string=? old-prof prof)
- (when (or (pair? install) (pair? remove))
- (format (current-error-port)
- (_ "nothing to be done~%")))
- (and (parameterize ((current-build-output-port
- ;; Output something when Guile
- ;; needs to be built.
- (if (or verbose? (guile-missing?))
- (current-error-port)
- (%make-void-port "w"))))
- (build-derivations (%store) (list prof-drv)))
- (let ((count (length packages)))
- (switch-symlinks name prof)
- (switch-symlinks profile name)
- (format #t (N_ "~a package in profile~%"
- "~a packages in profile~%"
- count)
- count)
- (display-search-paths packages
- profile)))))))))))
+ opts))
+ (remove* (filter-map (cut assoc <> installed) remove))
+ (packages
+ (append install*
+ (fold (lambda (package result)
+ (match package
+ ((name _ out _ ...)
+ (filter (negate
+ (cut same-package? <>
+ name out))
+ result))))
+ (fold alist-delete installed remove)
+ install*))))
+
+ (when (equal? profile %current-profile)
+ (ensure-default-profile))
+
+ (show-what-to-remove/install remove* install* dry-run?)
+ (show-what-to-build (%store) drv
+ #:use-substitutes? (assoc-ref opts 'substitutes?)
+ #:dry-run? dry-run?)
+
+ (or dry-run?
+ (and (build-derivations (%store) drv)
+ (let* ((prof-drv (profile-derivation (%store) packages))
+ (prof (derivation->output-path prof-drv))
+ (old-drv (profile-derivation
+ (%store) (manifest-packages
+ (profile-manifest profile))))
+ (old-prof (derivation->output-path old-drv))
+ (number (generation-number profile))
+
+ ;; Always use NUMBER + 1 for the new profile,
+ ;; possibly overwriting a "previous future
+ ;; generation".
+ (name (format #f "~a-~a-link"
+ profile (+ 1 number))))
+ (if (string=? old-prof prof)
+ (when (or (pair? install*) (pair? remove))
+ (format (current-error-port)
+ (_ "nothing to be done~%")))
+ (and (parameterize ((current-build-output-port
+ ;; Output something when Guile
+ ;; needs to be built.
+ (if (or verbose? (guile-missing?))
+ (current-error-port)
+ (%make-void-port "w"))))
+ (build-derivations (%store) (list prof-drv)))
+ (let ((count (length packages)))
+ (switch-symlinks name prof)
+ (switch-symlinks profile name)
+ (format #t (N_ "~a package in profile~%"
+ "~a packages in profile~%"
+ count)
+ count)
+ (display-search-paths packages
+ profile))))))))))))
(define (process-query opts)
;; Process any query specified by OPTS. Return #t when a query was