1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
3 ;;; Copyright © 2012, 2013 Nikita Karetnikov <nikita@karetnikov.org>
4 ;;; Copyright © 2021 Simon Tournier <zimon.toutoune@gmail.com>
6 ;;; This file is part of GNU Guix.
8 ;;; GNU Guix is free software; you can redistribute it and/or modify it
9 ;;; under the terms of the GNU General Public License as published by
10 ;;; the Free Software Foundation; either version 3 of the License, or (at
11 ;;; your option) any later version.
13 ;;; GNU Guix is distributed in the hope that it will be useful, but
14 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;;; GNU General Public License for more details.
18 ;;; You should have received a copy of the GNU General Public License
19 ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
21 (define-module (guix gnu-maintenance)
22 #:use-module (web uri)
23 #:use-module (web client)
24 #:use-module (web response)
25 #:use-module (sxml simple)
26 #:use-module (ice-9 regex)
27 #:use-module (ice-9 match)
28 #:use-module (srfi srfi-1)
29 #:use-module (srfi srfi-11)
30 #:use-module (srfi srfi-26)
31 #:use-module (srfi srfi-34)
32 #:use-module (rnrs io ports)
33 #:use-module (system foreign)
34 #:use-module ((guix http-client) #:hide (open-socket-for-uri))
35 #:use-module (guix ftp-client)
36 #:use-module (guix utils)
37 #:use-module (guix memoization)
38 #:use-module (guix records)
39 #:use-module (guix upstream)
40 #:use-module (guix packages)
41 #:autoload (zlib) (call-with-gzip-input-port)
42 #:autoload (htmlprag) (html->sxml) ;from Guile-Lib
43 #:export (gnu-package-name
44 gnu-package-mundane-name
45 gnu-package-copyright-holder
50 gnu-package-doc-category
51 gnu-package-doc-summary
52 gnu-package-doc-description
54 gnu-package-download-url
63 gnu-release-archive-types
64 gnu-package-name->name+version
72 %generic-html-updater))
76 ;;; Code for dealing with the maintenance of GNU packages, such as
83 ;;; List of GNU packages.
86 (define %gnumaint-base-url
87 "https://web.cvs.savannah.gnu.org/viewvc/*checkout*/www/www/prep/gnumaint/")
89 (define %package-list-url
91 (string-append %gnumaint-base-url "rec/gnupackages.rec")))
93 (define %package-description-url
94 ;; This file contains package descriptions in recutils format.
95 ;; See <https://lists.gnu.org/archive/html/guix-devel/2013-10/msg00071.html>
96 ;; and <https://lists.gnu.org/archive/html/guix-devel/2018-06/msg00362.html>.
98 (string-append %gnumaint-base-url "rec/pkgblurbs.rec")))
100 (define-record-type* <gnu-package-descriptor>
101 gnu-package-descriptor
102 make-gnu-package-descriptor
104 gnu-package-descriptor?
106 (name gnu-package-name)
107 (mundane-name gnu-package-mundane-name)
108 (copyright-holder gnu-package-copyright-holder)
109 (savannah gnu-package-savannah)
110 (fsd gnu-package-fsd)
111 (language gnu-package-language) ; list of strings
112 (logo gnu-package-logo)
113 (doc-category gnu-package-doc-category)
114 (doc-summary gnu-package-doc-summary)
115 (doc-description gnu-package-doc-description) ; taken from 'pkgdescr.txt'
116 (doc-urls gnu-package-doc-urls) ; list of strings
117 (download-url gnu-package-download-url))
119 (define* (official-gnu-packages
120 #:optional (fetch http-fetch/cached))
121 "Return a list of records, which are GNU packages. Use FETCH,
122 to fetch the list of GNU packages over HTTP."
123 (define (read-records port)
124 ;; Return a list of alists. Each alist contains fields of a GNU
126 (let loop ((alist (recutils->alist port))
130 (loop (recutils->alist port)
132 ;; Ignore things like "%rec" (info "(recutils) Record
134 (if (assoc-ref alist "package")
138 (define official-description
139 (let ((db (read-records (fetch %package-description-url #:text? #t))))
141 ;; Return the description found upstream for package NAME, or #f.
142 (and=> (find (lambda (alist)
143 (equal? name (assoc-ref alist "package")))
146 (let ((field (assoc-ref record "blurb")))
147 ;; The upstream description file uses "redirect PACKAGE" as
148 ;; a blurb in cases where the description of the two
149 ;; packages should be considered the same (e.g., GTK+ has
150 ;; "redirect gnome".) This is usually not acceptable for
151 ;; us because we prefer to have distinct descriptions in
152 ;; such cases. Thus, ignore the 'blurb' field when that
155 (not (string-prefix? "redirect " field))
159 (let ((name (assoc-ref alist "package")))
160 (alist->record `(("description" . ,(official-description name))
162 make-gnu-package-descriptor
163 (list "package" "mundane_name" "copyright_holder"
164 "savannah" "fsd" "language" "logo"
165 "doc_category" "doc_summary" "description"
168 '("doc_url" "language"))))
169 (let* ((port (fetch %package-list-url #:text? #t))
170 (lst (read-records port)))
174 (define (find-package name)
175 "Find GNU package called NAME and return it. Return #f if it was not
177 (find (lambda (package)
178 (string=? name (gnu-package-name package)))
179 (official-gnu-packages)))
182 (let ((official-gnu-packages (memoize official-gnu-packages)))
184 "Return true if PACKAGE is a GNU package. This procedure may access the
185 network to check in GNU's database."
186 (define (mirror-type url)
187 (let ((uri (string->uri url)))
188 (and (eq? (uri-scheme uri) 'mirror)
190 ((member (uri-host uri)
191 '("gnu" "gnupg" "gcc" "gnome"))
194 ((equal? (uri-host uri) "cran")
195 ;; Possibly GNU: mirror://cran could be either GNU R itself
196 ;; or a non-GNU package.
199 ;; Definitely non-GNU.
202 (define (gnu-home-page? package)
203 (letrec-syntax ((>> (syntax-rules ()
206 ((_ value proc rest ...)
209 (>> (proc next) rest ...)))))))
210 (>> package package-home-page
213 (member host '("www.gnu.org" "gnu.org"))))))
215 (or (gnu-home-page? package)
216 (match (package-source package)
218 (let ((url (origin-uri origin))
219 (name (package-upstream-name package)))
220 (case (and (string? url) (mirror-type url))
224 (and (member name (map gnu-package-name (official-gnu-packages)))
230 ;;; Latest FTP release.
233 (define (ftp-server/directory package)
234 "Return the FTP server and directory where PACKAGE's tarball are stored."
235 (let ((name (package-upstream-name package)))
236 (values (or (assoc-ref (package-properties package) 'ftp-server)
238 (or (assoc-ref (package-properties package) 'ftp-directory)
239 (string-append "/gnu/" name)))))
242 ;; The .zip extensions is notably used for freefont-ttf.
243 ;; The "-src" pattern is for "TeXmacs-1.0.7.9-src.tar.gz".
244 ;; The "-gnu[0-9]" pattern is for "icecat-38.4.0-gnu1.tar.bz2".
245 ;; Accept underscores as in "PKG_1.2.tar.gz" for some non-GNU packages.
246 ;; Accept 'v' or 'V' prefix as in 'PKG-v2.3.tgz'.
247 (make-regexp "^([^.]+)[-_][vV]?([0-9]|[^-])+(-(src|[sS]ource|gnu[0-9]))?\\.(tar\\.|tgz|zip$)"))
249 (define %alpha-tarball-rx
250 (make-regexp "^.*-.*[0-9](-|~)?(alpha|beta|rc|RC|cvs|svn|git)-?[0-9\\.]*\\.tar\\."))
252 (define (release-file? project file)
253 "Return #f if FILE is not a release tarball of PROJECT, otherwise return
255 (and (not (member (file-extension file)
257 "md5sum" "sha1sum" "sha256sum")))
258 (and=> (regexp-exec %tarball-rx file)
260 ;; Filter out unrelated files, like `guile-www-1.1.1'.
261 ;; Case-insensitive for things like "TeXmacs" vs. "texmacs".
262 ;; The "-src" suffix is for "freefont-src-20120503.tar.gz".
263 (and=> (match:substring match 1)
265 (or (string-ci=? name project)
267 (string-append project
269 (not (regexp-exec %alpha-tarball-rx file))
270 (let ((s (tarball-sans-extension file)))
271 (regexp-exec %package-name-rx s))))
273 (define (tarball->version tarball)
274 "Return the version TARBALL corresponds to. TARBALL is a file name like
275 \"coreutils-8.23.tar.xz\"."
276 (let-values (((name version)
277 (gnu-package-name->name+version
278 (tarball-sans-extension tarball))))
281 (define* (releases project
283 (server "ftp.gnu.org")
284 (directory (string-append "/gnu/" project)))
285 "Return the list of <upstream-release> of PROJECT as a list of release
286 name/directory pairs."
287 ;; TODO: Parse something like fencepost.gnu.org:/gd/gnuorg/packages-ftp.
288 (define conn (ftp-open server))
290 (let loop ((directories (list directory))
295 (coalesce-sources result))
296 ((directory rest ...)
297 (let* ((files (ftp-list conn directory))
298 (subdirs (filter-map (match-lambda
299 ((name 'directory . _) name)
302 (define (file->url file)
303 (string-append "ftp://" server directory "/" file))
305 (define (file->source file)
306 (let ((url (file->url file)))
309 (version (tarball->version file))
311 (signature-urls (list (string-append url ".sig"))))))
313 (loop (append (map (cut string-append directory "/" <>)
317 ;; Filter out signatures, deltas, and files which
318 ;; are potentially not releases of PROJECT--e.g.,
319 ;; in /gnu/guile, filter out guile-oops and
320 ;; guile-www; in mit-scheme, filter out binaries.
321 (filter-map (match-lambda
323 (and (release-file? project file)
324 (file->source file)))
329 (define* (latest-ftp-release project
331 (server "ftp.gnu.org")
332 (directory (string-append "/gnu/" project))
333 (file->signature (cut string-append <> ".sig")))
334 "Return an <upstream-source> for the latest release of PROJECT on SERVER
335 under DIRECTORY, or #f. Use FTP-OPEN and FTP-CLOSE to open (resp. close) FTP
336 connections; this can be useful to reuse connections.
338 FILE->SIGNATURE must be a procedure; it is passed a source file URL and must
339 return the corresponding signature URL, or #f it signatures are unavailable."
341 (if (version>? a b) a b))
343 (define (latest-release a b)
344 (if (version>? (upstream-source-version a) (upstream-source-version b))
347 (define patch-directory-name?
348 ;; Return #t for patch directory names such as 'bash-4.2-patches'.
349 (cut string-suffix? "patches" <>))
351 (define conn (ftp-open server #:timeout 5))
353 (define (file->url directory file)
354 (string-append "ftp://" server directory "/" file))
356 (define (file->source directory file)
357 (let ((url (file->url directory file)))
360 (version (tarball->version file))
362 (signature-urls (match (file->signature url)
364 (sig (list sig)))))))
366 (let loop ((directory directory)
368 (let* ((entries (catch 'ftp-error
369 (lambda _ (ftp-list conn directory))
372 ;; Filter out things like /gnupg/patches. Filter out "w32"
373 ;; directories as found on ftp.gnutls.org.
374 (subdirs (filter-map (match-lambda
375 (((? patch-directory-name? dir)
378 (("w32" 'directory . _)
380 (("unstable" 'directory . _)
381 ;; As seen at ftp.gnupg.org/gcrypt/pinentry.
383 ((directory 'directory . _)
388 ;; Whether or not SUBDIRS is empty, compute the latest releases
389 ;; for the current directory. This is necessary for packages
390 ;; such as 'sharutils' that have a sub-directory that contains
391 ;; only an older release.
392 (releases (filter-map (match-lambda
394 (and (release-file? project file)
395 (file->source directory file)))
399 ;; Assume that SUBDIRS correspond to versions, and jump into the
400 ;; one with the highest version number.
401 (let* ((release (reduce latest-release #f
402 (coalesce-sources releases)))
403 (result (if (and result release)
404 (latest-release release result)
405 (or release result)))
406 (target (reduce latest #f subdirs)))
408 (loop (string-append directory "/" target)
414 (define* (latest-release package
416 (server "ftp.gnu.org")
417 (directory (string-append "/gnu/" package)))
418 "Return the <upstream-source> for the latest version of PACKAGE or #f.
419 PACKAGE must be the canonical name of a GNU package."
420 (latest-ftp-release package
422 #:directory directory))
424 (define-syntax-rule (false-if-ftp-error exp)
425 "Return #f if an FTP error is raise while evaluating EXP; return the result
430 (lambda (key port . rest)
431 (if (ftp-connection? port)
436 (define (latest-release* package)
437 "Like 'latest-release', but (1) take a <package> object, and (2) ignore FTP
438 errors that might occur when PACKAGE is not actually a GNU package, or not
439 hosted on ftp.gnu.org, or not under that name (this is the case for
440 \"emacs-auctex\", for instance.)"
441 (let-values (((server directory)
442 (ftp-server/directory package)))
443 (false-if-ftp-error (latest-release (package-upstream-name package)
445 #:directory directory))))
449 ;;; Latest HTTP release.
452 (define (html-links sxml)
453 "Return the list of links found in SXML, the SXML tree of an HTML page."
454 (let loop ((sxml sxml)
457 (('a ('@ attributes ...) body ...)
458 (match (assq 'href attributes)
459 (#f (fold loop links body))
460 (('href url) (fold loop (cons url links) body))))
461 ((tag ('@ _ ...) body ...)
462 (fold loop links body))
464 (fold loop links body))
468 (define* (latest-html-release package
470 (base-url "https://kernel.org/pub")
471 (directory (string-append "/" package))
473 "Return an <upstream-source> for the latest release of PACKAGE (a string) on
474 SERVER under DIRECTORY, or #f. BASE-URL should be the URL of an HTML page,
475 typically a directory listing as found on 'https://kernel.org/pub'.
477 When FILE->SIGNATURE is omitted or #f, guess the detached signature file name,
478 if any. Otherwise, FILE->SIGNATURE must be a procedure; it is passed a source
479 file URL and must return the corresponding signature URL, or #f it signatures
481 (let* ((uri (string->uri (if (string-null? directory)
483 (string-append base-url directory "/"))))
484 (port (http-fetch/cached uri #:ttl 3600))
485 (sxml (html->sxml port))
486 (links (delete-duplicates (html-links sxml))))
487 (define (file->signature/guess url)
488 (let ((base (basename url)))
490 (any (lambda (extension)
491 (and (string=? (string-append base extension)
493 (string-append url extension)))
494 '(".asc" ".sig" ".sign")))
497 (define (url->release url)
498 (let* ((base (basename url))
499 (url (if (string=? base url)
500 (string-append base-url directory "/" url)
502 (and (release-file? package base)
503 (let ((version (tarball->version base)))
509 (list ((or file->signature file->signature/guess) url))))))))
512 (filter-map url->release links))
518 ;; Select the most recent release and return it.
519 (reduce (lambda (r1 r2)
520 (if (version>? (upstream-source-version r1)
521 (upstream-source-version r2))
524 (coalesce-sources candidates))))))
531 (define %gnu-file-list-uri
532 ;; URI of the file list for ftp.gnu.org.
533 (string->uri "https://ftp.gnu.org/find.txt.gz"))
535 (define ftp.gnu.org-files
537 "Return the list of files available at ftp.gnu.org."
539 ;; XXX: Memoize the whole procedure to work around the fact that
540 ;; 'http-fetch/cached' caches the gzipped version.
542 (define (trim-leading-components str)
543 ;; Trim the leading ".", if any, in "./gnu/foo".
544 (string-trim str (char-set #\.)))
546 (define (string->lines str)
547 (string-tokenize str (char-set-complement (char-set #\newline))))
549 ;; Since https://ftp.gnu.org honors 'If-Modified-Since', the hard-coded
550 ;; TTL can be relatively short.
551 (let ((port (http-fetch/cached %gnu-file-list-uri #:ttl (* 15 60))))
552 (map trim-leading-components
553 (call-with-gzip-input-port port
554 (compose string->lines get-string-all))))))
556 (define (latest-gnu-release package)
557 "Return the latest release of PACKAGE, a GNU package available via
560 This method does not rely on FTP access at all; instead, it browses the file
561 list available from %GNU-FILE-LIST-URI over HTTP(S)."
562 (let-values (((server directory)
563 (ftp-server/directory package))
565 (package-upstream-name package)))
566 (let* ((files (ftp.gnu.org-files))
567 (relevant (filter (lambda (file)
568 (and (string-prefix? "/gnu" file)
569 (string-contains file directory)
570 (release-file? name (basename file))))
572 (match (sort relevant (lambda (file1 file2)
573 (version>? (tarball-sans-extension
575 (tarball-sans-extension
577 ((and tarballs (reference _ ...))
578 (let* ((version (tarball->version reference))
579 (tarballs (filter (lambda (file)
580 (string=? (tarball-sans-extension
582 (tarball-sans-extension
583 (basename reference))))
588 (urls (map (lambda (file)
589 (string-append "mirror://gnu/"
591 (string-length "/gnu/"))))
593 (signature-urls (map (cut string-append <> ".sig") urls)))))
597 (define %package-name-rx
598 ;; Regexp for a package name, e.g., "foo-X.Y". Since TeXmacs uses
599 ;; "TeXmacs-X.Y-src", the `-src' suffix is allowed.
600 (make-regexp "^(.*)[-_][vV]?(([0-9]|\\.)+)(-src|\\.src|\\.orig)?"))
602 (define (gnu-package-name->name+version name+version)
603 "Return the package name and version number extracted from NAME+VERSION."
604 (let ((match (regexp-exec %package-name-rx name+version)))
606 (values name+version #f)
607 (values (match:substring match 1) (match:substring match 2)))))
609 (define gnome-package?
610 (url-prefix-predicate "mirror://gnome/"))
612 (define (pure-gnu-package? package)
613 "Return true if PACKAGE is a non-Emacs and non-GNOME GNU package. This
614 excludes AucTeX, for instance, whose releases are now uploaded to
615 elpa.gnu.org, GNU Radio, which has releases at www.gnuradio.org, and all the
616 GNOME packages; EMMS is included though, because its releases are on gnu.org."
617 (and (or (not (string-prefix? "emacs-" (package-name package)))
618 (gnu-hosted? package))
619 (not (gnome-package? package))
620 (not (string-prefix? "gnuradio" (package-name package)))
621 (gnu-package? package)))
624 (url-prefix-predicate "mirror://gnu/"))
626 (define (url-prefix-rewrite old new)
627 "Return a one-argument procedure that rewrites URL prefix OLD to NEW."
629 (if (and url (string-prefix? old url))
630 (string-append new (string-drop url (string-length old)))
633 (define (adjusted-upstream-source source rewrite-url)
634 "Rewrite URLs in SOURCE by apply REWRITE-URL to each of them."
637 (urls (map rewrite-url (upstream-source-urls source)))
638 (signature-urls (and=> (upstream-source-signature-urls source)
640 (map rewrite-url urls))))))
642 (define %savannah-base
643 ;; One of the Savannah mirrors listed at
644 ;; <http://download0.savannah.gnu.org/mirmon/savannah/> that serves valid
645 ;; HTML (unlike <https://download.savannah.nongnu.org/releases>.)
646 "https://nongnu.freemirror.org/nongnu")
648 (define (latest-savannah-release package)
649 "Return the latest release of PACKAGE."
650 (let* ((uri (string->uri
651 (match (origin-uri (package-source package))
652 ((? string? uri) uri)
653 ((uri mirrors ...) uri))))
654 (package (package-upstream-name package))
655 (directory (dirname (uri-path uri)))
656 (rewrite (url-prefix-rewrite %savannah-base
657 "mirror://savannah")))
658 ;; Note: We use the default 'file->signature', which adds ".sig", ".asc",
659 ;; or whichever detached signature naming scheme PACKAGE uses.
660 (and=> (latest-html-release package
661 #:base-url %savannah-base
662 #:directory directory)
663 (cut adjusted-upstream-source <> rewrite))))
665 (define (latest-sourceforge-release package)
666 "Return the latest release of PACKAGE."
667 (define (uri-append uri extension)
668 ;; Return URI with EXTENSION appended.
669 (build-uri (uri-scheme uri)
670 #:host (uri-host uri)
671 #:path (string-append (uri-path uri) extension)))
673 (define (valid-uri? uri port)
674 ;; Return true if URI is reachable.
676 (case (response-code (http-head uri #:port port #:keep-alive? #t))
680 (let* ((name (package-upstream-name package))
681 (base (string-append "https://sourceforge.net/projects/"
683 (url (string-append base "/latest/download"))
684 (uri (string->uri url))
685 (port (false-if-exception (open-socket-for-uri uri)))
687 (http-head uri #:port port #:keep-alive? #t))))
692 (= 302 (response-code response))
693 (response-location response)
694 (match (string-tokenize (uri-path (response-location response))
695 (char-set-complement (char-set #\/)))
697 (let* ((path (string-join components "/"))
698 (url (string-append "mirror://sourceforge/" path)))
699 (and (release-file? name (basename path))
701 ;; Take the heavy-handed approach of probing 3 additional
702 ;; URLs. XXX: Would be nicer if this could be avoided.
703 (let* ((loc (response-location response))
704 (sig (any (lambda (extension)
705 (let ((uri (uri-append loc extension)))
706 (and (valid-uri? uri port)
707 (string-append url extension))))
708 '(".asc" ".sig" ".sign"))))
711 (version (tarball->version (basename path)))
713 (signature-urls (and sig (list sig)))))))))))
716 (close-port port))))))
718 (define (latest-xorg-release package)
719 "Return the latest release of PACKAGE."
720 (let ((uri (string->uri (origin-uri (package-source package)))))
723 (package-name package)
724 #:server "ftp.freedesktop.org"
726 (string-append "/pub/xorg/" (dirname (uri-path uri)))))))
728 (define (latest-kernel.org-release package)
729 "Return the latest release of PACKAGE, the name of a kernel.org package."
730 (define %kernel.org-base
731 ;; This URL and sub-directories thereof are nginx-generated directory
732 ;; listings suitable for 'latest-html-release'.
733 "https://mirrors.edge.kernel.org/pub")
735 (define (file->signature file)
736 (string-append (file-sans-extension file) ".sign"))
738 (let* ((uri (string->uri
739 (match (origin-uri (package-source package))
740 ((? string? uri) uri)
741 ((uri mirrors ...) uri))))
742 (package (package-upstream-name package))
743 (directory (dirname (uri-path uri)))
744 (rewrite (url-prefix-rewrite %kernel.org-base
745 "mirror://kernel.org")))
746 (and=> (latest-html-release package
747 #:base-url %kernel.org-base
748 #:directory directory
749 #:file->signature file->signature)
750 (cut adjusted-upstream-source <> rewrite))))
752 (define html-updatable-package?
753 ;; Return true if the given package may be handled by the generic HTML
755 (let ((hosting-sites '("github.com" "github.io" "gitlab.com"
756 "notabug.org" "sr.ht"
757 "gforge.inria.fr" "gitlab.inria.fr"
758 "ftp.gnu.org" "download.savannah.gnu.org"
759 "pypi.org" "crates.io" "rubygems.org"
760 "bioconductor.org")))
762 (url-predicate (lambda (url)
763 (match (string->uri url)
766 (let ((scheme (uri-scheme uri))
767 (host (uri-host uri)))
768 (and (memq scheme '(http https))
769 (not (member host hosting-sites)))))))))
772 (or (assoc-ref (package-properties package) 'release-monitoring-url)
773 (http-url? package)))))
775 (define (latest-html-updatable-release package)
776 "Return the latest release of PACKAGE. Do that by crawling the HTML page of
777 the directory containing its source tarball."
778 (let* ((uri (string->uri
779 (match (origin-uri (package-source package))
780 ((? string? url) url)
782 (custom (assoc-ref (package-properties package)
783 'release-monitoring-url))
785 (string-append (symbol->string (uri-scheme uri))
786 "://" (uri-host uri))))
787 (directory (if custom
789 (dirname (uri-path uri))))
790 (package (package-upstream-name package)))
793 (guard (c ((http-get-error? c) #f))
794 (latest-html-release package
796 #:directory directory)))
798 ;; Return false and move on upon connection failures and bogus HTTP
800 (unless (memq key '(gnutls-error tls-certificate-error
802 bad-header bad-header-component))
803 (apply throw key args))
807 ;; This is for everything at ftp.gnu.org.
810 (description "Updater for GNU packages")
812 (latest latest-gnu-release)))
814 (define %gnu-ftp-updater
815 ;; This is for GNU packages taken from alternate locations, such as
816 ;; alpha.gnu.org, ftp.gnupg.org, etc. It is obsolescent.
819 (description "Updater for GNU packages only available via FTP")
820 (pred (lambda (package)
821 (and (not (gnu-hosted? package))
822 (pure-gnu-package? package))))
823 (latest latest-release*)))
825 (define %savannah-updater
828 (description "Updater for packages hosted on savannah.gnu.org")
829 (pred (url-prefix-predicate "mirror://savannah/"))
830 (latest latest-savannah-release)))
832 (define %sourceforge-updater
835 (description "Updater for packages hosted on sourceforge.net")
836 (pred (url-prefix-predicate "mirror://sourceforge/"))
837 (latest latest-sourceforge-release)))
839 (define %xorg-updater
842 (description "Updater for X.org packages")
843 (pred (url-prefix-predicate "mirror://xorg/"))
844 (latest latest-xorg-release)))
846 (define %kernel.org-updater
849 (description "Updater for packages hosted on kernel.org")
850 (pred (url-prefix-predicate "mirror://kernel.org/"))
851 (latest latest-kernel.org-release)))
853 (define %generic-html-updater
856 (description "Updater that crawls HTML pages.")
857 (pred html-updatable-package?)
858 (latest latest-html-updatable-release)))
860 ;;; gnu-maintenance.scm ends here