gnu-maintenance.scm 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Ludovic Courtès <ludo@gnu.org>
  3. ;;; Copyright © 2012, 2013 Nikita Karetnikov <nikita@karetnikov.org>
  4. ;;;
  5. ;;; This file is part of GNU Guix.
  6. ;;;
  7. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  8. ;;; under the terms of the GNU General Public License as published by
  9. ;;; the Free Software Foundation; either version 3 of the License, or (at
  10. ;;; your option) any later version.
  11. ;;;
  12. ;;; GNU Guix is distributed in the hope that it will be useful, but
  13. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;;; GNU General Public License for more details.
  16. ;;;
  17. ;;; You should have received a copy of the GNU General Public License
  18. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  19. (define-module (guix gnu-maintenance)
  20. #:use-module (web uri)
  21. #:use-module (web client)
  22. #:use-module (web response)
  23. #:use-module (sxml simple)
  24. #:use-module (ice-9 regex)
  25. #:use-module (ice-9 match)
  26. #:use-module (srfi srfi-1)
  27. #:use-module (srfi srfi-11)
  28. #:use-module (srfi srfi-26)
  29. #:use-module (rnrs io ports)
  30. #:use-module (system foreign)
  31. #:use-module (guix http-client)
  32. #:use-module (guix ftp-client)
  33. #:use-module (guix utils)
  34. #:use-module (guix memoization)
  35. #:use-module (guix records)
  36. #:use-module (guix upstream)
  37. #:use-module (guix packages)
  38. #:use-module (guix zlib)
  39. #:export (gnu-package-name
  40. gnu-package-mundane-name
  41. gnu-package-copyright-holder
  42. gnu-package-savannah
  43. gnu-package-fsd
  44. gnu-package-language
  45. gnu-package-logo
  46. gnu-package-doc-category
  47. gnu-package-doc-summary
  48. gnu-package-doc-description
  49. gnu-package-doc-urls
  50. gnu-package-download-url
  51. official-gnu-packages
  52. find-package
  53. gnu-package?
  54. release-file?
  55. releases
  56. latest-release
  57. gnu-release-archive-types
  58. gnu-package-name->name+version
  59. %gnu-updater
  60. %gnu-ftp-updater
  61. %xorg-updater
  62. %kernel.org-updater))
  63. ;;; Commentary:
  64. ;;;
  65. ;;; Code for dealing with the maintenance of GNU packages, such as
  66. ;;; auto-updates.
  67. ;;;
  68. ;;; Code:
  69. ;;;
  70. ;;; List of GNU packages.
  71. ;;;
  72. (define %gnumaint-base-url
  73. "https://web.cvs.savannah.gnu.org/viewvc/*checkout*/www/www/prep/gnumaint/")
  74. (define %package-list-url
  75. (string->uri
  76. (string-append %gnumaint-base-url "rec/gnupackages.rec")))
  77. (define %package-description-url
  78. ;; This file contains package descriptions in recutils format.
  79. ;; See <https://lists.gnu.org/archive/html/guix-devel/2013-10/msg00071.html>
  80. ;; and <https://lists.gnu.org/archive/html/guix-devel/2018-06/msg00362.html>.
  81. (string->uri
  82. (string-append %gnumaint-base-url "rec/pkgblurbs.rec")))
  83. (define-record-type* <gnu-package-descriptor>
  84. gnu-package-descriptor
  85. make-gnu-package-descriptor
  86. gnu-package-descriptor?
  87. (name gnu-package-name)
  88. (mundane-name gnu-package-mundane-name)
  89. (copyright-holder gnu-package-copyright-holder)
  90. (savannah gnu-package-savannah)
  91. (fsd gnu-package-fsd)
  92. (language gnu-package-language) ; list of strings
  93. (logo gnu-package-logo)
  94. (doc-category gnu-package-doc-category)
  95. (doc-summary gnu-package-doc-summary)
  96. (doc-description gnu-package-doc-description) ; taken from 'pkgdescr.txt'
  97. (doc-urls gnu-package-doc-urls) ; list of strings
  98. (download-url gnu-package-download-url))
  99. (define* (official-gnu-packages
  100. #:optional (fetch http-fetch/cached))
  101. "Return a list of records, which are GNU packages. Use FETCH,
  102. to fetch the list of GNU packages over HTTP."
  103. (define (read-records port)
  104. ;; Return a list of alists. Each alist contains fields of a GNU
  105. ;; package.
  106. (let loop ((alist (recutils->alist port))
  107. (result '()))
  108. (if (null? alist)
  109. (reverse result)
  110. (loop (recutils->alist port)
  111. ;; Ignore things like "%rec" (info "(recutils) Record
  112. ;; Descriptors").
  113. (if (assoc-ref alist "package")
  114. (cons alist result)
  115. result)))))
  116. (define official-description
  117. (let ((db (read-records (fetch %package-description-url #:text? #t))))
  118. (lambda (name)
  119. ;; Return the description found upstream for package NAME, or #f.
  120. (and=> (find (lambda (alist)
  121. (equal? name (assoc-ref alist "package")))
  122. db)
  123. (lambda (record)
  124. (let ((field (assoc-ref record "blurb")))
  125. ;; The upstream description file uses "redirect PACKAGE" as
  126. ;; a blurb in cases where the description of the two
  127. ;; packages should be considered the same (e.g., GTK+ has
  128. ;; "redirect gnome".) This is usually not acceptable for
  129. ;; us because we prefer to have distinct descriptions in
  130. ;; such cases. Thus, ignore the 'blurb' field when that
  131. ;; happens.
  132. (and field
  133. (not (string-prefix? "redirect " field))
  134. field)))))))
  135. (map (lambda (alist)
  136. (let ((name (assoc-ref alist "package")))
  137. (alist->record `(("description" . ,(official-description name))
  138. ,@alist)
  139. make-gnu-package-descriptor
  140. (list "package" "mundane_name" "copyright_holder"
  141. "savannah" "fsd" "language" "logo"
  142. "doc_category" "doc_summary" "description"
  143. "doc_url"
  144. "download_url")
  145. '("doc_url" "language"))))
  146. (let* ((port (fetch %package-list-url #:text? #t))
  147. (lst (read-records port)))
  148. (close-port port)
  149. lst)))
  150. (define (find-package name)
  151. "Find GNU package called NAME and return it. Return #f if it was not
  152. found."
  153. (find (lambda (package)
  154. (string=? name (gnu-package-name package)))
  155. (official-gnu-packages)))
  156. (define gnu-package?
  157. (let ((official-gnu-packages (memoize official-gnu-packages)))
  158. (mlambdaq (package)
  159. "Return true if PACKAGE is a GNU package. This procedure may access the
  160. network to check in GNU's database."
  161. (define (mirror-type url)
  162. (let ((uri (string->uri url)))
  163. (and (eq? (uri-scheme uri) 'mirror)
  164. (cond
  165. ((member (uri-host uri)
  166. '("gnu" "gnupg" "gcc" "gnome"))
  167. ;; Definitely GNU.
  168. 'gnu)
  169. ((equal? (uri-host uri) "cran")
  170. ;; Possibly GNU: mirror://cran could be either GNU R itself
  171. ;; or a non-GNU package.
  172. #f)
  173. (else
  174. ;; Definitely non-GNU.
  175. 'non-gnu)))))
  176. (define (gnu-home-page? package)
  177. (letrec-syntax ((>> (syntax-rules ()
  178. ((_ value proc)
  179. (and=> value proc))
  180. ((_ value proc rest ...)
  181. (and=> value
  182. (lambda (next)
  183. (>> (proc next) rest ...)))))))
  184. (>> package package-home-page
  185. string->uri uri-host
  186. (lambda (host)
  187. (member host '("www.gnu.org" "gnu.org"))))))
  188. (or (gnu-home-page? package)
  189. (let ((url (and=> (package-source package) origin-uri))
  190. (name (package-upstream-name package)))
  191. (case (and (string? url) (mirror-type url))
  192. ((gnu) #t)
  193. ((non-gnu) #f)
  194. (else
  195. (and (member name (map gnu-package-name (official-gnu-packages)))
  196. #t))))))))
  197. ;;;
  198. ;;; Latest FTP release.
  199. ;;;
  200. (define (ftp-server/directory package)
  201. "Return the FTP server and directory where PACKAGE's tarball are stored."
  202. (let ((name (package-upstream-name package)))
  203. (values (or (assoc-ref (package-properties package) 'ftp-server)
  204. "ftp.gnu.org")
  205. (or (assoc-ref (package-properties package) 'ftp-directory)
  206. (string-append "/gnu/" name)))))
  207. (define %tarball-rx
  208. ;; The .zip extensions is notably used for freefont-ttf.
  209. ;; The "-src" pattern is for "TeXmacs-1.0.7.9-src.tar.gz".
  210. ;; The "-gnu[0-9]" pattern is for "icecat-38.4.0-gnu1.tar.bz2".
  211. (make-regexp "^([^.]+)-([0-9]|[^-])+(-(src|gnu[0-9]))?\\.(tar\\.|zip$)"))
  212. (define %alpha-tarball-rx
  213. (make-regexp "^.*-.*[0-9](-|~)?(alpha|beta|rc|cvs|svn|git)-?[0-9\\.]*\\.tar\\."))
  214. (define (release-file? project file)
  215. "Return #f if FILE is not a release tarball of PROJECT, otherwise return
  216. true."
  217. (and (not (member (file-extension file) '("sig" "sign" "asc")))
  218. (and=> (regexp-exec %tarball-rx file)
  219. (lambda (match)
  220. ;; Filter out unrelated files, like `guile-www-1.1.1'.
  221. ;; Case-insensitive for things like "TeXmacs" vs. "texmacs".
  222. ;; The "-src" suffix is for "freefont-src-20120503.tar.gz".
  223. (and=> (match:substring match 1)
  224. (lambda (name)
  225. (or (string-ci=? name project)
  226. (string-ci=? name
  227. (string-append project
  228. "-src")))))))
  229. (not (regexp-exec %alpha-tarball-rx file))
  230. (let ((s (tarball-sans-extension file)))
  231. (regexp-exec %package-name-rx s))))
  232. (define (tarball->version tarball)
  233. "Return the version TARBALL corresponds to. TARBALL is a file name like
  234. \"coreutils-8.23.tar.xz\"."
  235. (let-values (((name version)
  236. (gnu-package-name->name+version
  237. (tarball-sans-extension tarball))))
  238. version))
  239. (define* (releases project
  240. #:key
  241. (server "ftp.gnu.org")
  242. (directory (string-append "/gnu/" project)))
  243. "Return the list of <upstream-release> of PROJECT as a list of release
  244. name/directory pairs."
  245. ;; TODO: Parse something like fencepost.gnu.org:/gd/gnuorg/packages-ftp.
  246. (define conn (ftp-open server))
  247. (let loop ((directories (list directory))
  248. (result '()))
  249. (match directories
  250. (()
  251. (ftp-close conn)
  252. (coalesce-sources result))
  253. ((directory rest ...)
  254. (let* ((files (ftp-list conn directory))
  255. (subdirs (filter-map (match-lambda
  256. ((name 'directory . _) name)
  257. (_ #f))
  258. files)))
  259. (define (file->url file)
  260. (string-append "ftp://" server directory "/" file))
  261. (define (file->source file)
  262. (let ((url (file->url file)))
  263. (upstream-source
  264. (package project)
  265. (version (tarball->version file))
  266. (urls (list url))
  267. (signature-urls (list (string-append url ".sig"))))))
  268. (loop (append (map (cut string-append directory "/" <>)
  269. subdirs)
  270. rest)
  271. (append
  272. ;; Filter out signatures, deltas, and files which
  273. ;; are potentially not releases of PROJECT--e.g.,
  274. ;; in /gnu/guile, filter out guile-oops and
  275. ;; guile-www; in mit-scheme, filter out binaries.
  276. (filter-map (match-lambda
  277. ((file 'file . _)
  278. (and (release-file? project file)
  279. (file->source file)))
  280. (_ #f))
  281. files)
  282. result)))))))
  283. (define* (latest-ftp-release project
  284. #:key
  285. (server "ftp.gnu.org")
  286. (directory (string-append "/gnu/" project))
  287. (keep-file? (const #t))
  288. (file->signature (cut string-append <> ".sig"))
  289. (ftp-open ftp-open) (ftp-close ftp-close))
  290. "Return an <upstream-source> for the latest release of PROJECT on SERVER
  291. under DIRECTORY, or #f. Use FTP-OPEN and FTP-CLOSE to open (resp. close) FTP
  292. connections; this can be useful to reuse connections.
  293. KEEP-FILE? is a predicate to decide whether to enter a directory and to
  294. consider a given file (source tarball) as a valid candidate based on its name.
  295. FILE->SIGNATURE must be a procedure; it is passed a source file URL and must
  296. return the corresponding signature URL, or #f it signatures are unavailable."
  297. (define (latest a b)
  298. (if (version>? a b) a b))
  299. (define (latest-release a b)
  300. (if (version>? (upstream-source-version a) (upstream-source-version b))
  301. a b))
  302. (define patch-directory-name?
  303. ;; Return #t for patch directory names such as 'bash-4.2-patches'.
  304. (cut string-suffix? "patches" <>))
  305. (define conn (ftp-open server))
  306. (define (file->url directory file)
  307. (string-append "ftp://" server directory "/" file))
  308. (define (file->source directory file)
  309. (let ((url (file->url directory file)))
  310. (upstream-source
  311. (package project)
  312. (version (tarball->version file))
  313. (urls (list url))
  314. (signature-urls (match (file->signature url)
  315. (#f #f)
  316. (sig (list sig)))))))
  317. (let loop ((directory directory)
  318. (result #f))
  319. (let* ((entries (ftp-list conn directory))
  320. ;; Filter out things like /gnupg/patches. Filter out "w32"
  321. ;; directories as found on ftp.gnutls.org.
  322. (subdirs (filter-map (match-lambda
  323. (((? patch-directory-name? dir)
  324. 'directory . _)
  325. #f)
  326. (("w32" 'directory . _)
  327. #f)
  328. (("unstable" 'directory . _)
  329. ;; As seen at ftp.gnupg.org/gcrypt/pinentry.
  330. #f)
  331. ((directory 'directory . _)
  332. directory)
  333. (_ #f))
  334. entries))
  335. ;; Whether or not SUBDIRS is empty, compute the latest releases
  336. ;; for the current directory. This is necessary for packages
  337. ;; such as 'sharutils' that have a sub-directory that contains
  338. ;; only an older release.
  339. (releases (filter-map (match-lambda
  340. ((file 'file . _)
  341. (and (release-file? project file)
  342. (keep-file? file)
  343. (file->source directory file)))
  344. (_ #f))
  345. entries)))
  346. ;; Assume that SUBDIRS correspond to versions, and jump into the
  347. ;; one with the highest version number.
  348. (let* ((release (reduce latest-release #f
  349. (coalesce-sources releases)))
  350. (result (if (and result release)
  351. (latest-release release result)
  352. (or release result)))
  353. (target (reduce latest #f subdirs)))
  354. (if target
  355. (loop (string-append directory "/" target)
  356. result)
  357. (begin
  358. (ftp-close conn)
  359. result))))))
  360. (define* (latest-release package
  361. #:key
  362. (server "ftp.gnu.org")
  363. (directory (string-append "/gnu/" package)))
  364. "Return the <upstream-source> for the latest version of PACKAGE or #f.
  365. PACKAGE must be the canonical name of a GNU package."
  366. (latest-ftp-release package
  367. #:server server
  368. #:directory directory))
  369. (define-syntax-rule (false-if-ftp-error exp)
  370. "Return #f if an FTP error is raise while evaluating EXP; return the result
  371. of EXP otherwise."
  372. (catch 'ftp-error
  373. (lambda ()
  374. exp)
  375. (lambda (key port . rest)
  376. (if (ftp-connection? port)
  377. (ftp-close port)
  378. (close-port port))
  379. #f)))
  380. (define (latest-release* package)
  381. "Like 'latest-release', but (1) take a <package> object, and (2) ignore FTP
  382. errors that might occur when PACKAGE is not actually a GNU package, or not
  383. hosted on ftp.gnu.org, or not under that name (this is the case for
  384. \"emacs-auctex\", for instance.)"
  385. (let-values (((server directory)
  386. (ftp-server/directory package)))
  387. (false-if-ftp-error (latest-release (package-upstream-name package)
  388. #:server server
  389. #:directory directory))))
  390. ;;;
  391. ;;; Latest HTTP release.
  392. ;;;
  393. (define (html->sxml port)
  394. "Read HTML from PORT and return the corresponding SXML tree."
  395. (let ((str (get-string-all port)))
  396. (catch #t
  397. (lambda ()
  398. ;; XXX: This is the poor developer's HTML-to-XML converter. It's good
  399. ;; enough for directory listings at <https://kernel.org/pub> but if
  400. ;; needed we could resort to (htmlprag) from Guile-Lib.
  401. (call-with-input-string (string-replace-substring str "<hr>" "<hr />")
  402. xml->sxml))
  403. (const '(html))))) ;parse error
  404. (define (html-links sxml)
  405. "Return the list of links found in SXML, the SXML tree of an HTML page."
  406. (let loop ((sxml sxml)
  407. (links '()))
  408. (match sxml
  409. (('a ('@ attributes ...) body ...)
  410. (match (assq 'href attributes)
  411. (#f (fold loop links body))
  412. (('href url) (fold loop (cons url links) body))))
  413. ((tag ('@ _ ...) body ...)
  414. (fold loop links body))
  415. ((tag body ...)
  416. (fold loop links body))
  417. (_
  418. links))))
  419. (define* (latest-html-release package
  420. #:key
  421. (base-url "https://kernel.org/pub")
  422. (directory (string-append "/" package))
  423. (file->signature (cut string-append <> ".sig")))
  424. "Return an <upstream-source> for the latest release of PACKAGE (a string) on
  425. SERVER under DIRECTORY, or #f. BASE-URL should be the URL of an HTML page,
  426. typically a directory listing as found on 'https://kernel.org/pub'.
  427. FILE->SIGNATURE must be a procedure; it is passed a source file URL and must
  428. return the corresponding signature URL, or #f it signatures are unavailable."
  429. (let* ((uri (string->uri (string-append base-url directory "/")))
  430. (port (http-fetch/cached uri #:ttl 3600))
  431. (sxml (html->sxml port)))
  432. (define (url->release url)
  433. (and (string=? url (basename url)) ;relative reference?
  434. (release-file? package url)
  435. (let-values (((name version)
  436. (package-name->name+version
  437. (tarball-sans-extension url)
  438. #\-)))
  439. (upstream-source
  440. (package name)
  441. (version version)
  442. (urls (list (string-append base-url directory "/" url)))
  443. (signature-urls
  444. (list (string-append base-url directory "/"
  445. (file-sans-extension url)
  446. ".sign")))))))
  447. (define candidates
  448. (filter-map url->release (html-links sxml)))
  449. (close-port port)
  450. (match candidates
  451. (() #f)
  452. ((first . _)
  453. ;; Select the most recent release and return it.
  454. (reduce (lambda (r1 r2)
  455. (if (version>? (upstream-source-version r1)
  456. (upstream-source-version r2))
  457. r1 r2))
  458. first
  459. (coalesce-sources candidates))))))
  460. ;;;
  461. ;;; Updaters.
  462. ;;;
  463. (define %gnu-file-list-uri
  464. ;; URI of the file list for ftp.gnu.org.
  465. (string->uri "https://ftp.gnu.org/find.txt.gz"))
  466. (define ftp.gnu.org-files
  467. (mlambda ()
  468. "Return the list of files available at ftp.gnu.org."
  469. ;; XXX: Memoize the whole procedure to work around the fact that
  470. ;; 'http-fetch/cached' caches the gzipped version.
  471. (define (trim-leading-components str)
  472. ;; Trim the leading ".", if any, in "./gnu/foo".
  473. (string-trim str (char-set #\.)))
  474. (define (string->lines str)
  475. (string-tokenize str (char-set-complement (char-set #\newline))))
  476. ;; Since https://ftp.gnu.org honors 'If-Modified-Since', the hard-coded
  477. ;; TTL can be relatively short.
  478. (let ((port (http-fetch/cached %gnu-file-list-uri #:ttl (* 15 60))))
  479. (map trim-leading-components
  480. (call-with-gzip-input-port port
  481. (compose string->lines get-string-all))))))
  482. (define (latest-gnu-release package)
  483. "Return the latest release of PACKAGE, a GNU package available via
  484. ftp.gnu.org.
  485. This method does not rely on FTP access at all; instead, it browses the file
  486. list available from %GNU-FILE-LIST-URI over HTTP(S)."
  487. (let-values (((server directory)
  488. (ftp-server/directory package))
  489. ((name)
  490. (package-upstream-name package)))
  491. (let* ((files (ftp.gnu.org-files))
  492. (relevant (filter (lambda (file)
  493. (and (string-prefix? "/gnu" file)
  494. (string-contains file directory)
  495. (release-file? name (basename file))))
  496. files)))
  497. (match (sort relevant (lambda (file1 file2)
  498. (version>? (tarball-sans-extension
  499. (basename file1))
  500. (tarball-sans-extension
  501. (basename file2)))))
  502. ((and tarballs (reference _ ...))
  503. (let* ((version (tarball->version reference))
  504. (tarballs (filter (lambda (file)
  505. (string=? (tarball-sans-extension
  506. (basename file))
  507. (tarball-sans-extension
  508. (basename reference))))
  509. tarballs)))
  510. (upstream-source
  511. (package name)
  512. (version version)
  513. (urls (map (lambda (file)
  514. (string-append "mirror://gnu/"
  515. (string-drop file
  516. (string-length "/gnu/"))))
  517. tarballs))
  518. (signature-urls (map (cut string-append <> ".sig") urls)))))
  519. (()
  520. #f)))))
  521. (define %package-name-rx
  522. ;; Regexp for a package name, e.g., "foo-X.Y". Since TeXmacs uses
  523. ;; "TeXmacs-X.Y-src", the `-src' suffix is allowed.
  524. (make-regexp "^(.*)-(([0-9]|\\.)+)(-src)?"))
  525. (define (gnu-package-name->name+version name+version)
  526. "Return the package name and version number extracted from NAME+VERSION."
  527. (let ((match (regexp-exec %package-name-rx name+version)))
  528. (if (not match)
  529. (values name+version #f)
  530. (values (match:substring match 1) (match:substring match 2)))))
  531. (define gnome-package?
  532. (url-prefix-predicate "mirror://gnome/"))
  533. (define (pure-gnu-package? package)
  534. "Return true if PACKAGE is a non-Emacs and non-GNOME GNU package. This
  535. excludes AucTeX, for instance, whose releases are now uploaded to
  536. elpa.gnu.org, and all the GNOME packages; EMMS is included though, because its
  537. releases are on gnu.org."
  538. (and (or (not (string-prefix? "emacs-" (package-name package)))
  539. (gnu-hosted? package))
  540. (not (gnome-package? package))
  541. (gnu-package? package)))
  542. (define gnu-hosted?
  543. (url-prefix-predicate "mirror://gnu/"))
  544. (define (latest-xorg-release package)
  545. "Return the latest release of PACKAGE, the name of an X.org package."
  546. (let ((uri (string->uri (origin-uri (package-source package)))))
  547. (false-if-ftp-error
  548. (latest-ftp-release
  549. (package-name package)
  550. #:server "ftp.freedesktop.org"
  551. #:directory
  552. (string-append "/pub/xorg/" (dirname (uri-path uri)))))))
  553. (define (latest-kernel.org-release package)
  554. "Return the latest release of PACKAGE, the name of a kernel.org package."
  555. (define %kernel.org-base
  556. ;; This URL and sub-directories thereof are nginx-generated directory
  557. ;; listings suitable for 'latest-html-release'.
  558. "https://mirrors.edge.kernel.org/pub")
  559. (define (file->signature file)
  560. (string-append (file-sans-extension file) ".sign"))
  561. (let* ((uri (string->uri (origin-uri (package-source package))))
  562. (package (package-upstream-name package))
  563. (directory (dirname (uri-path uri))))
  564. (latest-html-release package
  565. #:base-url %kernel.org-base
  566. #:directory directory
  567. #:file->signature file->signature)))
  568. (define %gnu-updater
  569. ;; This is for everything at ftp.gnu.org.
  570. (upstream-updater
  571. (name 'gnu)
  572. (description "Updater for GNU packages")
  573. (pred gnu-hosted?)
  574. (latest latest-gnu-release)))
  575. (define %gnu-ftp-updater
  576. ;; This is for GNU packages taken from alternate locations, such as
  577. ;; alpha.gnu.org, ftp.gnupg.org, etc. It is obsolescent.
  578. (upstream-updater
  579. (name 'gnu-ftp)
  580. (description "Updater for GNU packages only available via FTP")
  581. (pred (lambda (package)
  582. (and (not (gnu-hosted? package))
  583. (pure-gnu-package? package))))
  584. (latest latest-release*)))
  585. (define %xorg-updater
  586. (upstream-updater
  587. (name 'xorg)
  588. (description "Updater for X.org packages")
  589. (pred (url-prefix-predicate "mirror://xorg/"))
  590. (latest latest-xorg-release)))
  591. (define %kernel.org-updater
  592. (upstream-updater
  593. (name 'kernel.org)
  594. (description "Updater for packages hosted on kernel.org")
  595. (pred (url-prefix-predicate "mirror://kernel.org/"))
  596. (latest latest-kernel.org-release)))
  597. ;;; gnu-maintenance.scm ends here