summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--gnu/packages.scm15
-rw-r--r--guix/gnu-maintenance.scm95
2 files changed, 84 insertions, 26 deletions
diff --git a/gnu/packages.scm b/gnu/packages.scm
index 281d0d297d..c9efd0d691 100644
--- a/gnu/packages.scm
+++ b/gnu/packages.scm
@@ -348,13 +348,16 @@ it."
                                           #:ftp-open ftp-open*
                                           #:ftp-close (const #f))
                           (_ "looking for the latest release of GNU ~a...") name)
-            ((latest-version . _)
-             (when (version>? latest-version full-name)
-               (format (current-error-port)
-                       (_ "~a: note: using ~a \
+            ((? gnu-release? release)
+             (let ((latest-version
+                    (string-append (gnu-release-package release) "-"
+                                   (gnu-release-version release))))
+              (when (version>? latest-version full-name)
+                (format (current-error-port)
+                        (_ "~a: note: using ~a \
 but ~a is available upstream~%")
-                       (location->string (package-location package))
-                       full-name latest-version)))
+                        (location->string (package-location package))
+                        full-name latest-version))))
             (_ #t)))))
     (lambda (key . args)
       ;; Silently ignore networking errors rather than preventing
diff --git a/guix/gnu-maintenance.scm b/guix/gnu-maintenance.scm
index 7b608daea2..bfc03359ac 100644
--- a/guix/gnu-maintenance.scm
+++ b/guix/gnu-maintenance.scm
@@ -56,6 +56,12 @@
             find-packages
             gnu-package?
 
+            gnu-release?
+            gnu-release-package
+            gnu-release-version
+            gnu-release-directory
+            gnu-release-files
+
             releases
             latest-release
             gnu-package-name->name+version
@@ -189,6 +195,13 @@ network to check in GNU's database."
 ;;; Latest release.
 ;;;
 
+(define-record-type* <gnu-release> gnu-release make-gnu-release
+  gnu-release?
+  (package    gnu-release-package)
+  (version    gnu-release-version)
+  (directory  gnu-release-directory)
+  (files      gnu-release-files))
+
 (define (ftp-server/directory project)
   "Return the FTP server and directory where PROJECT's tarball are
 stored."
@@ -227,9 +240,9 @@ stored."
 (define %alpha-tarball-rx
   (make-regexp "^.*-.*[0-9](-|~)?(alpha|beta|rc|cvs|svn|git)-?[0-9\\.]*\\.tar\\."))
 
-(define (release-file project file)
+(define (release-file? project file)
   "Return #f if FILE is not a release tarball of PROJECT, otherwise return
-PACKAGE-VERSION."
+true."
   (and (not (string-suffix? ".sig" file))
        (and=> (regexp-exec %tarball-rx file)
               (lambda (match)
@@ -237,7 +250,37 @@ PACKAGE-VERSION."
                 (equal? project (match:substring match 1))))
        (not (regexp-exec %alpha-tarball-rx file))
        (let ((s (sans-extension file)))
-         (and (regexp-exec %package-name-rx s) s))))
+         (regexp-exec %package-name-rx s))))
+
+(define (tarball->version tarball)
+  "Return the version TARBALL corresponds to.  TARBALL is a file name like
+\"coreutils-8.23.tar.xz\"."
+  (let-values (((name version)
+                (gnu-package-name->name+version (sans-extension tarball))))
+    version))
+
+(define (coalesce-releases releases)
+  "Coalesce the elements of RELEASES that correspond to the same version."
+  (define (same-version? r1 r2)
+    (string=? (gnu-release-version r1) (gnu-release-version r2)))
+
+  (define (release>? r1 r2)
+    (version>? (gnu-release-version r1) (gnu-release-version r2)))
+
+  (fold (lambda (release result)
+          (match result
+            ((head . tail)
+             (if (same-version? release head)
+                 (cons (gnu-release
+                        (inherit release)
+                        (files (append (gnu-release-files release)
+                                       (gnu-release-files head))))
+                       tail)
+                 (cons release result)))
+            (()
+             (list release))))
+        '()
+        (sort releases release>?)))
 
 (define (releases project)
   "Return the list of releases of PROJECT as a list of release name/directory
@@ -251,7 +294,7 @@ pairs.  Example: (\"mit-scheme-9.0.1\" . \"/gnu/mit-scheme/stable.pkg/9.0.1\").
       (match directories
         (()
          (ftp-close conn)
-         result)
+         (coalesce-releases result))
         ((directory rest ...)
          (let* ((files   (ftp-list conn directory))
                 (subdirs (filter-map (match-lambda
@@ -267,10 +310,15 @@ pairs.  Example: (\"mit-scheme-9.0.1\" . \"/gnu/mit-scheme/stable.pkg/9.0.1\").
                   ;; in /gnu/guile, filter out guile-oops and
                   ;; guile-www; in mit-scheme, filter out binaries.
                   (filter-map (match-lambda
-                                ((file 'file . _)
-                                 (and=> (release-file project file)
-                                        (cut cons <> directory)))
-                                (_ #f))
+                               ((file 'file . _)
+                                (if (release-file? project file)
+                                    (gnu-release
+                                     (package project)
+                                     (version (tarball->version file))
+                                     (directory directory)
+                                     (files (list file)))
+                                    #f))
+                               (_ #f))
                               files)
                   result))))))))
 
@@ -281,6 +329,10 @@ open (resp. close) FTP connections; this can be useful to reuse connections."
   (define (latest a b)
     (if (version>? a b) a b))
 
+  (define (latest-release a b)
+    (if (version>? (gnu-release-version a) (gnu-release-version b))
+        a b))
+
   (define contains-digit?
     (cut string-any char-set:digit <>))
 
@@ -307,14 +359,19 @@ open (resp. close) FTP connections; this can be useful to reuse connections."
         (match subdirs
           (()
            ;; No sub-directories, so assume that tarballs are here.
-           (let ((files (filter-map (match-lambda
-                                     ((file 'file . _)
-                                      (release-file project file))
-                                     (_ #f))
-                                    entries)))
+           (let ((releases (filter-map (match-lambda
+                                        ((file 'file . _)
+                                         (and (release-file? project file)
+                                              (gnu-release
+                                               (package project)
+                                               (version
+                                                (tarball->version file))
+                                               (directory directory)
+                                               (files (list file)))))
+                                        (_ #f))
+                                       entries)))
              (ftp-close conn)
-             (and=> (reduce latest #f files)
-                    (cut cons <> directory))))
+             (reduce latest-release #f (coalesce-releases releases))))
           ((subdirs ...)
            ;; Assume that SUBDIRS correspond to versions, and jump into the
            ;; one with the highest version number.
@@ -346,11 +403,9 @@ open (resp. close) FTP connections; this can be useful to reuse connections."
   "Return an update path for PACKAGE, or #f if no update is needed."
   (and (gnu-package? package)
        (match (latest-release (package-name package))
-         ((name+version . directory)
-          (let-values (((_ new-version)
-                        (package-name->name+version name+version)))
-            (and (version>? name+version (package-full-name package))
-                 `(,new-version . ,directory))))
+         (($ <gnu-release> name version directory)
+          (and (version>? version (package-version package))
+               `(,version . ,directory)))
          (_ #f))))
 
 (define* (download-tarball store project directory version