summary refs log tree commit diff
path: root/guix/scripts/package.scm
diff options
context:
space:
mode:
Diffstat (limited to 'guix/scripts/package.scm')
-rw-r--r--guix/scripts/package.scm139
1 files changed, 85 insertions, 54 deletions
diff --git a/guix/scripts/package.scm b/guix/scripts/package.scm
index fd42cdb36e..b87aee0be9 100644
--- a/guix/scripts/package.scm
+++ b/guix/scripts/package.scm
@@ -261,19 +261,46 @@ synopsis or description matches all of REGEXPS."
        ((<)  #t)
        (else #f)))))
 
-(define (upgradeable? name current-version current-path)
-  "Return #t if there's a version of package NAME newer than CURRENT-VERSION,
-or if the newest available version is equal to CURRENT-VERSION but would have
-an output path different than CURRENT-PATH."
-  (match (vhash-assoc name (find-newest-available-packages))
-    ((_ candidate-version pkg . rest)
-     (case (version-compare candidate-version current-version)
-       ((>) #t)
-       ((<) #f)
-       ((=) (let ((candidate-path (derivation->output-path
-                                   (package-derivation (%store) pkg))))
-              (not (string=? current-path candidate-path))))))
-    (#f #f)))
+(define (transaction-upgrade-entry entry transaction)
+  "Return a variant of TRANSACTION that accounts for the upgrade of ENTRY, a
+<manifest-entry>."
+  (define (supersede old new)
+    (info (_ "package '~a' has been superseded by '~a'~%")
+          (manifest-entry-name old) (package-name new))
+    (manifest-transaction-install-entry
+     (package->manifest-entry new (manifest-entry-output old))
+     (manifest-transaction-remove-pattern
+      (manifest-pattern
+        (name (manifest-entry-name old))
+        (version (manifest-entry-version old))
+        (output (manifest-entry-output old)))
+      transaction)))
+
+  (match entry
+    (($ <manifest-entry> name version output (? string? path))
+     (match (vhash-assoc name (find-newest-available-packages))
+       ((_ candidate-version pkg . rest)
+        (match (package-superseded pkg)
+          ((? package? new)
+           (supersede entry new))
+          (#f
+           (case (version-compare candidate-version version)
+             ((>)
+              (manifest-transaction-install-entry
+               (package->manifest-entry pkg output)
+               transaction))
+             ((<)
+              transaction)
+             ((=)
+              (let ((candidate-path (derivation->output-path
+                                     (package-derivation (%store) pkg))))
+                (if (string=? path candidate-path)
+                    transaction
+                    (manifest-transaction-install-entry
+                     (package->manifest-entry pkg output)
+                     transaction))))))))
+       (#f
+        transaction)))))
 
 
 ;;;
@@ -553,24 +580,20 @@ upgrading, #f otherwise."
       (output #f)
       (item item))))
 
-(define (options->installable opts manifest)
+(define (options->installable opts manifest transaction)
   "Given MANIFEST, the current manifest, and OPTS, the result of 'args-fold',
-return the new list of manifest entries."
+return an variant of TRANSACTION that accounts for the specified installations
+and upgrades."
   (define upgrade?
     (options->upgrade-predicate opts))
 
-  (define to-upgrade
-    (filter-map (match-lambda
-                  (($ <manifest-entry> name version output path _)
-                   (and (upgrade? name)
-                        (upgradeable? name version path)
-                        (let ((output (or output "out")))
-                          (call-with-values
-                              (lambda ()
-                                (specification->package+output name output))
-                            package->manifest-entry))))
-                  (_ #f))
-                (manifest-entries manifest)))
+  (define upgraded
+    (fold (lambda (entry transaction)
+            (if (upgrade? (manifest-entry-name entry))
+                (transaction-upgrade-entry entry transaction)
+                transaction))
+          transaction
+          (manifest-entries manifest)))
 
   (define to-install
     (filter-map (match-lambda
@@ -587,23 +610,29 @@ return the new list of manifest entries."
                   (_ #f))
                 opts))
 
-  (append to-upgrade to-install))
-
-(define (options->removable options manifest)
-  "Given options, return the list of manifest patterns of packages to be
-removed from MANIFEST."
-  (filter-map (match-lambda
-               (('remove . spec)
-                (call-with-values
-                    (lambda ()
-                      (package-specification->name+version+output spec))
-                  (lambda (name version output)
-                    (manifest-pattern
-                      (name name)
-                      (version version)
-                      (output output)))))
-               (_ #f))
-              options))
+  (fold manifest-transaction-install-entry
+        upgraded
+        to-install))
+
+(define (options->removable options manifest transaction)
+  "Given options, return a variant of TRANSACTION augmented with the list of
+patterns of packages to remove."
+  (fold (lambda (opt transaction)
+          (match opt
+            (('remove . spec)
+             (call-with-values
+                 (lambda ()
+                   (package-specification->name+version+output spec))
+               (lambda (name version output)
+                 (manifest-transaction-remove-pattern
+                  (manifest-pattern
+                    (name name)
+                    (version version)
+                    (output output))
+                  transaction))))
+            (_ transaction)))
+        transaction
+        options))
 
 (define (register-gc-root store profile)
   "Register PROFILE, a profile generation symlink, as a GC root, unless it
@@ -814,16 +843,18 @@ processed, #f otherwise."
             opts)
 
   ;; Then, process normal package installation/removal/upgrade.
-  (let* ((manifest    (profile-manifest profile))
-         (install     (options->installable opts manifest))
-         (remove      (options->removable opts manifest))
-         (transaction (manifest-transaction
-                       (install (map transform-entry install))
-                       (remove remove)))
-         (new         (manifest-perform-transaction manifest transaction)))
-
-    (unless (and (null? install) (null? remove))
-      (show-manifest-transaction store manifest transaction
+  (let* ((manifest (profile-manifest profile))
+         (step1    (options->installable opts manifest
+                                         (manifest-transaction)))
+         (step2    (options->removable opts manifest step1))
+         (step3    (manifest-transaction
+                    (inherit step2)
+                    (install (map transform-entry
+                                  (manifest-transaction-install step2)))))
+         (new      (manifest-perform-transaction manifest step3)))
+
+    (unless (manifest-transaction-null? step3)
+      (show-manifest-transaction store manifest step3
                                  #:dry-run? dry-run?)
       (build-and-use-profile store profile new
                              #:bootstrap? bootstrap?