summaryrefslogtreecommitdiff
path: root/guix/import
diff options
context:
space:
mode:
Diffstat (limited to 'guix/import')
-rw-r--r--guix/import/cran.scm154
-rw-r--r--guix/import/crate.scm8
-rw-r--r--guix/import/egg.scm51
-rw-r--r--guix/import/elpa.scm84
-rw-r--r--guix/import/gem.scm8
-rw-r--r--guix/import/git.scm22
-rw-r--r--guix/import/github.scm52
-rw-r--r--guix/import/gnu.scm3
-rw-r--r--guix/import/go.scm91
-rw-r--r--guix/import/hackage.scm31
-rw-r--r--guix/import/minetest.scm74
-rw-r--r--guix/import/opam.scm25
-rw-r--r--guix/import/print.scm110
-rw-r--r--guix/import/pypi.scm82
-rw-r--r--guix/import/stackage.scm112
-rw-r--r--guix/import/texlive.scm307
-rw-r--r--guix/import/utils.scm17
17 files changed, 746 insertions, 485 deletions
diff --git a/guix/import/cran.scm b/guix/import/cran.scm
index f649928c5a..7a73c11382 100644
--- a/guix/import/cran.scm
+++ b/guix/import/cran.scm
@@ -1,8 +1,9 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ricardo Wurmus <rekado@elephly.net>
-;;; Copyright © 2015, 2016, 2017, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2015, 2016, 2017, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
;;; Copyright © 2020 Martin Becze <mjbecze@riseup.net>
+;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -34,9 +35,10 @@
#:use-module (web uri)
#:use-module (guix memoization)
#:use-module (guix http-client)
- #:use-module (gcrypt hash)
+ #:use-module (guix diagnostics)
+ #:use-module (guix hash)
+ #:use-module (guix i18n)
#:use-module (guix store)
- #:use-module ((guix serialization) #:select (write-file))
#:use-module (guix base32)
#:use-module ((guix download) #:select (download-to-store))
#:use-module (guix import utils)
@@ -135,9 +137,9 @@
(map (lambda (name)
(case (%input-style)
((specification)
- (list name (list 'unquote (list 'specification->package name))))
+ `(specification->package ,name))
(else
- (list name (list 'unquote (string->symbol name))))))
+ (string->symbol name))))
(sort names string-ci<?)))
(define* (maybe-inputs package-inputs #:optional (type 'inputs))
@@ -147,15 +149,15 @@ package definition."
(()
'())
((package-inputs ...)
- `((,type (,'quasiquote ,(format-inputs package-inputs)))))))
+ `((,type (list ,@(format-inputs package-inputs)))))))
(define %cran-url "https://cran.r-project.org/web/packages/")
(define %cran-canonical-url "https://cran.r-project.org/package=")
(define %bioconductor-url "https://bioconductor.org/packages/")
-;; The latest Bioconductor release is 3.13. Bioconductor packages should be
+;; The latest Bioconductor release is 3.14. Bioconductor packages should be
;; updated together.
-(define %bioconductor-version "3.13")
+(define %bioconductor-version "3.14")
(define* (bioconductor-packages-list-url #:optional type)
(string-append "https://bioconductor.org/packages/"
@@ -171,11 +173,11 @@ package definition."
release."
(let ((url (string->uri (bioconductor-packages-list-url type))))
(guard (c ((http-get-error? c)
- (format (current-error-port)
- "error: failed to retrieve list of packages from ~s: ~a (~s)~%"
- (uri->string (http-get-error-uri c))
- (http-get-error-code c)
- (http-get-error-reason c))
+ (warning (G_ "failed to retrieve list of packages \
+from ~a: ~a (~a)~%")
+ (uri->string (http-get-error-uri c))
+ (http-get-error-code c)
+ (http-get-error-reason c))
#f))
;; Split the big list on empty lines, then turn each chunk into an
;; alist of attributes.
@@ -194,17 +196,6 @@ bioconductor package NAME, or #F if the package is unknown."
(bioconductor-packages-list type))
(cut assoc-ref <> "Version")))
-;; XXX taken from (guix scripts hash)
-(define (vcs-file? file stat)
- (case (stat:type stat)
- ((directory)
- (member (basename file) '(".bzr" ".git" ".hg" ".svn" "CVS")))
- ((regular)
- ;; Git sub-modules have a '.git' file that is a regular text file.
- (string=? (basename file) ".git"))
- (else
- #f)))
-
;; Little helper to download URLs only once.
(define download
(memoize
@@ -227,27 +218,61 @@ bioconductor package NAME, or #F if the package is unknown."
(let ((store-directory
(add-to-store store (basename url) #t "sha256" dir)))
(values store-directory changeset)))))))
- (else (download-to-store store url)))))))
+ (else
+ (match url
+ ((? string?)
+ (download-to-store store url))
+ ((urls ...)
+ ;; Try all the URLs. A use case where this is useful is when one
+ ;; of the URLs is the /Archive CRAN URL.
+ (any (cut download-to-store store <>) urls)))))))))
+
+(define (fetch-description-from-tarball url)
+ "Fetch the tarball at URL, extra its 'DESCRIPTION' file, parse it, and
+return the resulting alist."
+ (match (download url)
+ (#f #f)
+ (tarball
+ (call-with-temporary-directory
+ (lambda (dir)
+ (parameterize ((current-error-port (%make-void-port "rw+"))
+ (current-output-port (%make-void-port "rw+")))
+ (and (zero? (system* "tar" "--wildcards" "-x"
+ "--strip-components=1"
+ "-C" dir
+ "-f" tarball "*/DESCRIPTION"))
+ (description->alist
+ (call-with-input-file (string-append dir "/DESCRIPTION")
+ read-string)))))))))
-(define (fetch-description repository name)
+(define* (fetch-description repository name #:optional version)
"Return an alist of the contents of the DESCRIPTION file for the R package
-NAME in the given REPOSITORY, or #f in case of failure. NAME is
+NAME at VERSION in the given REPOSITORY, or #f in case of failure. NAME is
case-sensitive."
(case repository
((cran)
- (let ((url (string-append %cran-url name "/DESCRIPTION")))
- (guard (c ((http-get-error? c)
- (format (current-error-port)
- "error: failed to retrieve package information \
-from ~s: ~a (~s)~%"
- (uri->string (http-get-error-uri c))
- (http-get-error-code c)
- (http-get-error-reason c))
- #f))
- (let* ((port (http-fetch url))
- (result (description->alist (read-string port))))
- (close-port port)
- result))))
+ (guard (c ((http-get-error? c)
+ (warning (G_ "failed to retrieve package information \
+from ~a: ~a (~a)~%")
+ (uri->string (http-get-error-uri c))
+ (http-get-error-code c)
+ (http-get-error-reason c))
+ #f))
+ ;; When VERSION is true, we have to download the tarball to get at its
+ ;; 'DESCRIPTION' file; only the latest one is directly accessible over
+ ;; HTTP.
+ (if version
+ (let ((urls (list (string-append "mirror://cran/src/contrib/"
+ name "_" version ".tar.gz")
+ (string-append "mirror://cran/src/contrib/Archive/"
+ name "/"
+ name "_" version ".tar.gz"))))
+ (fetch-description-from-tarball urls))
+ (let* ((url (string-append %cran-url name "/DESCRIPTION"))
+ (port (http-fetch url))
+ (result (description->alist (read-string port))))
+ (close-port port)
+ result))))
((bioconductor)
;; Currently, the bioconductor project does not offer a way to access a
;; package's DESCRIPTION file over HTTP, so we determine the version,
@@ -256,22 +281,13 @@ from ~s: ~a (~s)~%"
(and (latest-bioconductor-package-version name) #t)
(and (latest-bioconductor-package-version name 'annotation) 'annotation)
(and (latest-bioconductor-package-version name 'experiment) 'experiment)))
+ ;; TODO: Honor VERSION.
(version (latest-bioconductor-package-version name type))
(url (car (bioconductor-uri name version type)))
- (tarball (download url)))
- (call-with-temporary-directory
- (lambda (dir)
- (parameterize ((current-error-port (%make-void-port "rw+"))
- (current-output-port (%make-void-port "rw+")))
- (and (zero? (system* "tar" "--wildcards" "-x"
- "--strip-components=1"
- "-C" dir
- "-f" tarball "*/DESCRIPTION"))
- (and=> (description->alist (with-input-from-file
- (string-append dir "/DESCRIPTION") read-string))
- (lambda (meta)
- (if (boolean? type) meta
- (cons `(bioconductor-type . ,type) meta))))))))))
+ (meta (fetch-description-from-tarball url)))
+ (if (boolean? type)
+ meta
+ (cons `(bioconductor-type . ,type) meta))))
((git)
(and (string-prefix? "http" name)
;; Download the git repository at "NAME"
@@ -437,16 +453,6 @@ reference the pkg-config tool."
(define (needs-knitr? meta)
(member "knitr" (listify meta "VignetteBuilder")))
-;; XXX adapted from (guix scripts hash)
-(define (file-hash file select? recursive?)
- ;; Compute the hash of FILE.
- (if recursive?
- (let-values (((port get-hash) (open-sha256-port)))
- (write-file file port #:select? select?)
- (force-output port)
- (get-hash))
- (call-with-input-file file port-sha256)))
-
(define (description->package repository meta)
"Return the `package' s-expression for an R package published on REPOSITORY
from the alist META, which was derived from the R package's DESCRIPTION file."
@@ -484,11 +490,11 @@ from the alist META, which was derived from the R package's DESCRIPTION file."
((bioconductor)
(list (assoc-ref meta 'bioconductor-type)))
(else '())))
- ((url rest ...) url)
+ ((urls ...) urls)
((? string? url) url)
(_ #f)))))
- (git? (assoc-ref meta 'git))
- (hg? (assoc-ref meta 'hg))
+ (git? (if (assoc-ref meta 'git) #true #false))
+ (hg? (if (assoc-ref meta 'hg) #true #false))
(source (download source-url #:method (cond
(git? 'git)
(hg? 'hg)
@@ -544,12 +550,7 @@ from the alist META, which was derived from the R package's DESCRIPTION file."
(sha256
(base32
,(bytevector->nix-base32-string
- (case repository
- ((git)
- (file-hash source (negate vcs-file?) #t))
- ((hg)
- (file-hash source (negate vcs-file?) #t))
- (else (file-sha256 source))))))))
+ (file-hash* source #:recursive? (or git? hg?)))))))
,@(if (not (and git? hg?
(equal? (string-append "r-" name)
(cran-guix-name name))))
@@ -591,7 +592,7 @@ from the alist META, which was derived from the R package's DESCRIPTION file."
(lambda* (package-name #:key (repo 'cran) version)
"Fetch the metadata for PACKAGE-NAME from REPO and return the `package'
s-expression corresponding to that package, or #f on failure."
- (let ((description (fetch-description repo package-name)))
+ (let ((description (fetch-description repo package-name version)))
(if description
(description->package repo description)
(case repo
@@ -609,8 +610,9 @@ s-expression corresponding to that package, or #f on failure."
(&message
(message "couldn't find meta-data for R package")))))))))))
-(define* (cran-recursive-import package-name #:key (repo 'cran))
+(define* (cran-recursive-import package-name #:key (repo 'cran) version)
(recursive-import package-name
+ #:version version
#:repo repo
#:repo->guix-package cran->guix-package
#:guix-name cran-guix-name))
diff --git a/guix/import/crate.scm b/guix/import/crate.scm
index 287ffd2536..c76d7e9c1a 100644
--- a/guix/import/crate.scm
+++ b/guix/import/crate.scm
@@ -1,6 +1,6 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2016 David Craven <david@craven.ch>
-;;; Copyright © 2019, 2020 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2019, 2020 Martin Becze <mjbecze@riseup.net>
;;; Copyright © 2021 Nicolas Goaziou <mail@nicolasgoaziou.fr>
;;;
@@ -79,7 +79,10 @@
(number crate-version-number "num") ;string
(download-path crate-version-download-path "dl_path") ;string
(readme-path crate-version-readme-path "readme_path") ;string
- (license crate-version-license "license") ;string
+ (license crate-version-license "license" ;string | #f
+ (match-lambda
+ ('null #f)
+ ((? string? str) str)))
(links crate-version-links)) ;alist
;; Crate dependency. Each dependency (each edge in the graph) is annotated as
@@ -198,6 +201,7 @@ and LICENSE."
(description ,(beautify-description description))
(license ,(match license
(() #f)
+ (#f #f)
((license) license)
(_ `(list ,@license)))))))
(close-port port)
diff --git a/guix/import/egg.scm b/guix/import/egg.scm
index 89e7a9160d..0b88020554 100644
--- a/guix/import/egg.scm
+++ b/guix/import/egg.scm
@@ -1,6 +1,7 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
;;; Copyright © 2021 Tobias Geerinckx-Rice <me@tobias.gr>
+;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -51,10 +52,10 @@
;;;
;;; The following happens under the hood:
;;;
-;;; * <git://code.call-cc.org/eggs-5-latest> is a Git repository that contains
-;;; the latest version of all CHICKEN eggs. We look clone this repository
-;;; and retrieve the latest version number, and the PACKAGE.egg file, which
-;;; contains a list of lists containing metadata about the egg.
+;;; * <git://code.call-cc.org/eggs-5-all> is a Git repository that contains
+;;; all versions of all CHICKEN eggs. We look clone this repository and, by
+;;; default, retrieve the latest version number, and the PACKAGE.egg file,
+;;; which contains a list of lists containing metadata about the egg.
;;;
;;; * All the eggs are stored as tarballs at
;;; <https://code.call-cc.org/egg-tarballs/5>, so we grab the tarball for
@@ -96,7 +97,7 @@ NAME."
(define (eggs-repository)
"Update or fetch the latest version of the eggs repository and return the path
to the repository."
- (let* ((url "git://code.call-cc.org/eggs-5-latest")
+ (let* ((url "git://code.call-cc.org/eggs-5-all")
(directory commit _ (update-cached-checkout url)))
directory))
@@ -112,12 +113,13 @@ to the repository."
(last directory)
#f)))
-(define* (egg-metadata name #:optional file)
- "Return the package metadata file for the egg NAME, or if FILE is specified,
-return the package metadata in FILE."
+(define* (egg-metadata name #:key (version #f) (file #f))
+ "Return the package metadata file for the egg NAME at version VERSION, or if
+FILE is specified, return the package metadata in FILE."
(call-with-input-file (or file
(string-append (egg-directory name) "/"
- (find-latest-version name)
+ (or version
+ (find-latest-version name))
"/" name ".egg"))
read))
@@ -173,10 +175,11 @@ return the package metadata in FILE."
;;; Egg importer.
;;;
-(define* (egg->guix-package name #:key (file #f) (source #f))
- "Import a CHICKEN egg called NAME from either the given .egg FILE, or from
-the latest NAME metadata downloaded from the official repository if FILE is #f.
-Return a <package> record or #f on failure.
+(define* (egg->guix-package name version #:key (file #f) (source #f))
+ "Import a CHICKEN egg called NAME from either the given .egg FILE, or from the
+latest NAME metadata downloaded from the official repository if FILE is #f.
+Return a <package> record or #f on failure. If VERSION is specified, import
+the particular version from the egg repository.
SOURCE is a ``file-like'' object containing the source code corresponding to
the egg. If SOURCE is not specified, the latest tarball for egg NAME will be
@@ -186,8 +189,8 @@ Specifying the SOURCE argument is mainly useful for developing a CHICKEN egg
locally. Note that if FILE and SOURCE are specified, recursive import will
not work."
(define egg-content (if file
- (egg-metadata name file)
- (egg-metadata name)))
+ (egg-metadata name #:file file)
+ (egg-metadata name #:version version)))
(if (not egg-content)
(values #f '()) ; egg doesn't exist
(let* ((version* (or (assoc-ref egg-content 'version)
@@ -247,12 +250,9 @@ not work."
(let ((name (prettify-name (extract-name name))))
;; Dependencies are sometimes specified as symbols and sometimes
;; as strings
- (list (string-append (if system? "" package-name-prefix)
- name)
- (list 'unquote
- (string->symbol (string-append
- (if system? "" package-name-prefix)
- name))))))
+ (string->symbol (string-append
+ (if system? "" package-name-prefix)
+ name))))
(define egg-propagated-inputs
(let ((dependencies (assoc-ref egg-content 'dependencies)))
@@ -291,7 +291,7 @@ not work."
'())
((inputs ...)
(list (list input-type
- (list 'quasiquote inputs))))))
+ `(list ,@inputs))))))
(values
`(package
@@ -319,17 +319,18 @@ not work."
(license ,egg-licenses))
(filter (lambda (name)
(not (member name '("srfi-4"))))
- (map (compose guix-name->egg-name first)
+ (map (compose guix-name->egg-name symbol->string)
(append egg-propagated-inputs
egg-native-inputs)))))))
(define egg->guix-package/m ;memoized variant
(memoize egg->guix-package))
-(define (egg-recursive-import package-name)
+(define* (egg-recursive-import package-name #:optional version)
(recursive-import package-name
+ #:version version
#:repo->guix-package (lambda* (name #:key version repo)
- (egg->guix-package/m name))
+ (egg->guix-package/m name version))
#:guix-name egg-name->guix-name))
diff --git a/guix/import/elpa.scm b/guix/import/elpa.scm
index 96ebc17af1..ea77a7c244 100644
--- a/guix/import/elpa.scm
+++ b/guix/import/elpa.scm
@@ -5,6 +5,7 @@
;;; Copyright © 2020 Martin Becze <mjbecze@riseup.net>
;;; Copyright © 2020 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
+;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -37,15 +38,17 @@
#:use-module (guix import utils)
#:use-module (guix http-client)
#:use-module (guix git)
+ #:use-module (guix hash)
#:use-module ((guix serialization) #:select (write-file))
#:use-module (guix store)
#:use-module (guix ui)
- #:use-module (gcrypt hash)
#:use-module (guix base32)
#:use-module (guix upstream)
#:use-module (guix packages)
+ #:use-module (guix memoization)
#:use-module ((guix utils) #:select (call-with-temporary-output-file))
#:export (elpa->guix-package
+ guix-package->elpa-name
%elpa-updater
elpa-recursive-import))
@@ -228,27 +231,6 @@ keywords to values."
(close-port port)
(data->recipe (cons ':name data))))
-;; XXX adapted from (guix scripts hash)
-(define (file-hash file select? recursive?)
- ;; Compute the hash of FILE.
- (if recursive?
- (let-values (((port get-hash) (open-sha256-port)))
- (write-file file port #:select? select?)
- (force-output port)
- (get-hash))
- (call-with-input-file file port-sha256)))
-
-;; XXX taken from (guix scripts hash)
-(define (vcs-file? file stat)
- (case (stat:type stat)
- ((directory)
- (member (basename file) '(".bzr" ".git" ".hg" ".svn" "CVS")))
- ((regular)
- ;; Git sub-modules have a '.git' file that is a regular text file.
- (string=? (basename file) ".git"))
- (else
- #f)))
-
(define (git-repository->origin recipe url)
"Fetch origin details from the Git repository at URL for the provided MELPA
RECIPE."
@@ -270,7 +252,7 @@ RECIPE."
(sha256
(base32
,(bytevector->nix-base32-string
- (file-hash directory (negate vcs-file?) #t)))))))
+ (file-hash* directory #:recursive? #true)))))))
(define* (melpa-recipe->origin recipe)
"Fetch origin details from the MELPA recipe and associated repository for
@@ -337,9 +319,10 @@ the package named PACKAGE-NAME."
type '<elpa-package>'."
(define melpa-recipe
- (if (eq? repo 'melpa)
- (package-name->melpa-recipe (elpa-package-name pkg))
- #f))
+ ;; XXX: Call 'identity' to work around a Guile 3.0.[5-7] compiler bug:
+ ;; <https://bugs.gnu.org/48368>.
+ (and (eq? (identity repo) 'melpa)
+ (package-name->melpa-recipe (elpa-package-name pkg))))
(define name (elpa-package-name pkg))
@@ -352,9 +335,7 @@ type '<elpa-package>'."
(elpa-package-inputs pkg))))
(define dependencies
- (map (lambda (n)
- (let ((new-n (elpa-name->package-name n)))
- (list new-n (list 'unquote (string->symbol new-n)))))
+ (map (compose string->symbol elpa-name->package-name)
dependencies-names))
(define (maybe-inputs input-type inputs)
@@ -362,8 +343,7 @@ type '<elpa-package>'."
(()
'())
((inputs ...)
- (list (list input-type
- (list 'quasiquote inputs))))))
+ (list (list input-type `(list ,@inputs))))))
(define melpa-source
(melpa-recipe->origin melpa-recipe))
@@ -381,7 +361,8 @@ type '<elpa-package>'."
(sha256
(base32
,(if tarball
- (bytevector->nix-base32-string (file-sha256 tarball))
+ (bytevector->nix-base32-string
+ (file-hash* tarball #:recursive? #false))
"failed to download package")))))))
(build-system emacs-build-system)
,@(maybe-inputs 'propagated-inputs dependencies)
@@ -390,7 +371,7 @@ type '<elpa-package>'."
'())
(home-page ,(elpa-package-home-page pkg))
(synopsis ,(elpa-package-synopsis pkg))
- (description ,(elpa-package-description pkg))
+ (description ,(beautify-description (elpa-package-description pkg)))
(license ,license))
dependencies-names))
@@ -414,14 +395,18 @@ type '<elpa-package>'."
;;; Updates.
;;;
+(define (guix-package->elpa-name package)
+ "Given a Guix package, PACKAGE, return the upstream name on ELPA."
+ (or (and=> (package-properties package)
+ (cut assq-ref <> 'upstream-name))
+ (if (string-prefix? "emacs-" (package-name package))
+ (string-drop (package-name package) 6)
+ (package-name package))))
+
(define (latest-release package)
"Return an <upstream-release> for the latest release of PACKAGE."
- (define name
- (if (string-prefix? "emacs-" (package-name package))
- (string-drop (package-name package) 6)
- (package-name package)))
-
- (define repo 'gnu)
+ (define name (guix-package->elpa-name package))
+ (define repo (elpa-repository package))
(match (elpa-package-info name repo)
(#f
@@ -440,11 +425,20 @@ type '<elpa-package>'."
(urls (list url))
(signature-urls (list (string-append url ".sig"))))))))
-(define package-from-gnu.org?
- (url-predicate (lambda (url)
- (let ((uri (string->uri url)))
- (and uri
- (string=? (uri-host uri) "elpa.gnu.org"))))))
+(define elpa-repository
+ (memoize
+ (url-predicate (lambda (url)
+ (let ((uri (string->uri url)))
+ (and uri
+ (cond
+ ((string=? (uri-host uri) "elpa.gnu.org")
+ 'gnu)
+ ((string=? (uri-host uri) "elpa.nongnu.org")
+ 'nongnu)
+ (else #f))))))))
+
+(define (package-from-elpa-repository? package)
+ (member (elpa-repository package) '(gnu nongnu)))
(define %elpa-updater
;; The ELPA updater. We restrict it to packages hosted on elpa.gnu.org
@@ -452,7 +446,7 @@ type '<elpa-package>'."
(upstream-updater
(name 'elpa)
(description "Updater for ELPA packages")
- (pred package-from-gnu.org?)
+ (pred package-from-elpa-repository?)
(latest latest-release)))
(define elpa-guix-name (cut guix-name "emacs-" <>))
diff --git a/guix/import/gem.scm b/guix/import/gem.scm
index 418d716be6..0e5bb7e635 100644
--- a/guix/import/gem.scm
+++ b/guix/import/gem.scm
@@ -4,6 +4,7 @@
;;; Copyright © 2018 Oleg Pykhalov <go.wigust@gmail.com>
;;; Copyright © 2020, 2021 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2020 Martin Becze <mjbecze@riseup.net>
+;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -110,12 +111,7 @@ VERSION, HASH, HOME-PAGE, DESCRIPTION, DEPENDENCIES, and LICENSES."
,@(if (null? dependencies)
'()
`((propagated-inputs
- (,'quasiquote
- ,(map (lambda (name)
- `(,name
- (,'unquote
- ,(string->symbol name))))
- dependencies)))))
+ (list ,@(map string->symbol dependencies)))))
(synopsis ,synopsis)
(description ,description)
(home-page ,home-page)
diff --git a/guix/import/git.scm b/guix/import/git.scm
index 1eb219f3fe..4cf404677c 100644
--- a/guix/import/git.scm
+++ b/guix/import/git.scm
@@ -1,6 +1,7 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
+;;; Copyright © 2022 Maxime Devos <maximedevos@telenet.be>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -34,6 +35,7 @@
#:use-module (srfi srfi-26)
#:use-module (srfi srfi-34)
#:use-module (srfi srfi-35)
+ #:use-module (srfi srfi-71)
#:export (%generic-git-updater
;; For tests.
@@ -172,21 +174,21 @@ repository at URL."
(values version tag)))))))
(define (latest-git-tag-version package)
- "Given a PACKAGE, return the latest version of it, or #f if the latest version
-could not be determined."
+ "Given a PACKAGE, return the latest version of it and the corresponding git
+tag, or #false and #false if the latest version could not be determined."
(guard (c ((or (git-no-tags-error? c) (git-no-valid-tags-error? c))
(warning (or (package-field-location package 'source)
(package-location package))
(G_ "~a for ~a~%")
(condition-message c)
(package-name package))
- #f)
+ (values #f #f))
((eq? (exception-kind c) 'git-error)
(warning (or (package-field-location package 'source)
(package-location package))
(G_ "failed to fetch Git repository for ~a~%")
(package-name package))
- #f))
+ (values #f #f)))
(let* ((source (package-source package))
(url (git-reference-url (origin-uri source)))
(property (cute assq-ref (package-properties package) <>)))
@@ -208,14 +210,16 @@ could not be determined."
"Return an <upstream-source> for the latest release of PACKAGE."
(let* ((name (package-name package))
(old-version (package-version package))
- (url (git-reference-url (origin-uri (package-source package))))
- (new-version (latest-git-tag-version package)))
-
- (and new-version
+ (old-reference (origin-uri (package-source package)))
+ (new-version new-version-tag (latest-git-tag-version package)))
+ (and new-version new-version-tag
(upstream-source
(package name)
(version new-version)
- (urls (list url))))))
+ (urls (git-reference
+ (url (git-reference-url old-reference))
+ (commit new-version-tag)
+ (recursive? (git-reference-recursive? old-reference))))))))
(define %generic-git-updater
(upstream-updater
diff --git a/guix/import/github.scm b/guix/import/github.scm
index 888b148ffb..8c1898c0c5 100644
--- a/guix/import/github.scm
+++ b/guix/import/github.scm
@@ -4,6 +4,7 @@
;;; Copyright © 2018 Eric Bavier <bavier@member.fsf.org>
;;; Copyright © 2019 Arun Isaac <arunisaac@systemreboot.net>
;;; Copyright © 2019 Efraim Flashner <efraim@flashner.co.il>
+;;; Copyright © 2022 Maxime Devos <maximedevos@telenet.be>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -25,6 +26,7 @@
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-26)
#:use-module (srfi srfi-34)
+ #:use-module (srfi srfi-71)
#:use-module (guix utils)
#:use-module (guix i18n)
#:use-module (guix diagnostics)
@@ -37,7 +39,10 @@
#:use-module (guix upstream)
#:use-module (guix http-client)
#:use-module (web uri)
- #:export (%github-updater))
+ #:export (%github-api %github-updater))
+
+;; For tests.
+(define %github-api (make-parameter "https://api.github.com"))
(define (find-extension url)
"Return the extension of the archive e.g. '.tar.gz' given a URL, or
@@ -148,11 +153,11 @@ tags show up in the \"Releases\" tab of the web UI. For instance,
'https://api.github.com/repos/aconchillo/guile-json/releases' returns the
empty list."
(define release-url
- (string-append "https://api.github.com/repos/"
+ (string-append (%github-api) "/repos/"
(github-user-slash-repository url)
"/releases"))
(define tag-url
- (string-append "https://api.github.com/repos/"
+ (string-append (%github-api) "/repos/"
(github-user-slash-repository url)
"/tags"))
@@ -181,12 +186,15 @@ empty list."
(x x)))))
(define (latest-released-version url package-name)
- "Return a string of the newest released version name given a string URL like
+ "Return the newest released version and its tag given a string URL like
'https://github.com/arq5x/bedtools2/archive/v2.24.0.tar.gz' and the name of
-the package e.g. 'bedtools2'. Return #f if there is no releases"
+the package e.g. 'bedtools2'. Return #f (two values) if there are no
+releases."
(define (pre-release? x)
(assoc-ref x "prerelease"))
+ ;; This procedure returns (version . tag) pair, or #f
+ ;; if RELEASE doesn't seyem to correspond to a version.
(define (release->version release)
(let ((tag (or (assoc-ref release "tag_name") ;a "release"
(assoc-ref release "name"))) ;a tag
@@ -197,22 +205,22 @@ the package e.g. 'bedtools2'. Return #f if there is no releases"
((and (< name-length (string-length tag))
(string=? (string-append package-name "-")
(substring tag 0 (+ name-length 1))))
- (substring tag (+ name-length 1)))
+ (cons (substring tag (+ name-length 1)) tag))
;; some tags start with a "v" e.g. "v0.25.0"
;; or with the word "version" e.g. "version.2.1"
;; where some are just the version number
((string-prefix? "version" tag)
- (if (char-set-contains? char-set:digit (string-ref tag 7))
- (substring tag 7)
- (substring tag 8)))
+ (cons (if (char-set-contains? char-set:digit (string-ref tag 7))
+ (substring tag 7)
+ (substring tag 8)) tag))
((string-prefix? "v" tag)
- (substring tag 1))
+ (cons (substring tag 1) tag))
;; Finally, reject tags that don't start with a digit:
;; they may not represent a release.
((and (not (string-null? tag))
(char-set-contains? char-set:digit
(string-ref tag 0)))
- tag)
+ (cons tag tag))
(else #f))))
(let* ((json (and=> (fetch-releases-or-tags url)
@@ -229,14 +237,14 @@ https://github.com/settings/tokens"))
(match (remove pre-release? json)
(() json) ; keep everything
(releases releases)))
- version>?)
- ((latest-release . _) latest-release)
- (() #f)))))
+ (lambda (x y) (version>? (car x) (car y))))
+ (((latest-version . tag) . _) (values latest-version tag))
+ (() (values #f #f))))))
(define (latest-release pkg)
"Return an <upstream-source> for the latest release of PKG."
- (define (origin-github-uri origin)
- (match (origin-uri origin)
+ (define (github-uri uri)
+ (match uri
((? string? url)
url) ;surely a github.com URL
((? download:git-reference? ref)
@@ -244,14 +252,20 @@ https://github.com/settings/tokens"))
((urls ...)
(find (cut string-contains <> "github.com") urls))))
- (let* ((source-uri (origin-github-uri (package-source pkg)))
+ (let* ((original-uri (origin-uri (package-source pkg)))
+ (source-uri (github-uri original-uri))
(name (package-name pkg))
- (newest-version (latest-released-version source-uri name)))
+ (newest-version version-tag
+ (latest-released-version source-uri name)))
(if newest-version
(upstream-source
(package name)
(version newest-version)
- (urls (list (updated-github-url pkg newest-version))))
+ (urls (if (download:git-reference? original-uri)
+ (download:git-reference
+ (inherit original-uri)
+ (commit version-tag))
+ (list (updated-github-url pkg newest-version)))))
#f))) ; On GitHub but no proper releases
(define %github-updater
diff --git a/guix/import/gnu.scm b/guix/import/gnu.scm
index 51d5b77d34..2b9b71feb0 100644
--- a/guix/import/gnu.scm
+++ b/guix/import/gnu.scm
@@ -100,7 +100,8 @@ download policy (see 'download-tarball' for details.)"
(file-sha256 tarball))))))
(build-system gnu-build-system)
(synopsis ,(gnu-package-doc-summary package))
- (description ,(gnu-package-doc-description package))
+ (description ,(beautify-description
+ (gnu-package-doc-description package)))
(home-page ,(match (gnu-package-doc-urls package)
((head . tail) (qualified-url head))))
(license find-by-yourself!)))
diff --git a/guix/import/go.scm b/guix/import/go.scm
index 9769b557ae..d00c13475a 100644
--- a/guix/import/go.scm
+++ b/guix/import/go.scm
@@ -3,7 +3,7 @@
;;; Copyright © 2020 Helio Machado <0x2b3bfa0+guix@googlemail.com>
;;; Copyright © 2021 François Joulaud <francois.joulaud@radiofrance.com>
;;; Copyright © 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com>
-;;; Copyright © 2021 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2021-2022 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
;;; Copyright © 2021 Simon Tournier <zimon.toutoune@gmail.com>
@@ -26,6 +26,7 @@
(define-module (guix import go)
#:use-module (guix build-system go)
#:use-module (guix git)
+ #:use-module (guix hash)
#:use-module (guix i18n)
#:use-module (guix diagnostics)
#:use-module (guix import utils)
@@ -36,11 +37,11 @@
#:use-module ((guix licenses) #:prefix license:)
#:use-module (guix memoization)
#:autoload (htmlprag) (html->sxml) ;from Guile-Lib
- #:autoload (guix git) (update-cached-checkout)
- #:autoload (gcrypt hash) (open-hash-port hash-algorithm sha256)
#:autoload (guix serialization) (write-file)
#:autoload (guix base32) (bytevector->nix-base32-string)
#:autoload (guix build utils) (mkdir-p)
+ #:autoload (gcrypt hash) (hash-algorithm sha256)
+ #:use-module (ice-9 format)
#:use-module (ice-9 match)
#:use-module (ice-9 peg)
#:use-module (ice-9 rdelim)
@@ -54,6 +55,7 @@
#:use-module (srfi srfi-11)
#:use-module (srfi srfi-26)
#:use-module (srfi srfi-34)
+ #:use-module (srfi srfi-35)
#:use-module (sxml match)
#:use-module ((sxml xpath) #:renamer (lambda (s)
(if (eq? 'filter s)
@@ -474,7 +476,7 @@ Optionally include a VERSION string to append to the name."
because goproxy servers don't currently provide all the information needed to
build a package."
(define (go-import->module-meta content-text)
- (match (string-split content-text #\space)
+ (match (string-tokenize content-text char-set:graphic)
((root-path vcs repo-url)
(make-module-meta root-path (string->symbol vcs)
(strip-.git-suffix/maybe repo-url)))))
@@ -499,25 +501,6 @@ source."
goproxy
(module-meta-repo-root meta-data)))
-;; XXX: Copied from (guix scripts hash).
-(define (vcs-file? file stat)
- (case (stat:type stat)
- ((directory)
- (member (basename file) '(".bzr" ".git" ".hg" ".svn" "CVS")))
- ((regular)
- ;; Git sub-modules have a '.git' file that is a regular text file.
- (string=? (basename file) ".git"))
- (else
- #f)))
-
-;; XXX: Adapted from 'file-hash' in (guix scripts hash).
-(define* (file-hash file #:optional (algorithm (hash-algorithm sha256)))
- ;; Compute the hash of FILE.
- (let-values (((port get-hash) (open-hash-port algorithm)))
- (write-file file port #:select? (negate vcs-file?))
- (force-output port)
- (get-hash)))
-
(define* (git-checkout-hash url reference algorithm)
"Return the ALGORITHM hash of the checkout of URL at REFERENCE, a commit or
tag."
@@ -536,7 +519,7 @@ tag."
(update-cached-checkout url
#:ref
`(tag-or-commit . ,reference)))))
- (file-hash checkout algorithm)))
+ (file-hash* checkout #:algorithm algorithm #:recursive? #true)))
(define (vcs->origin vcs-type vcs-repo-url version)
"Generate the `origin' block of a package depending on what type of source
@@ -588,6 +571,34 @@ control system is being used."
(formatted-message (G_ "unsupported vcs type '~a' for package '~a'")
vcs-type vcs-repo-url)))))
+(define (strip-v-prefix version)
+ "Strip from VERSION the \"v\" prefix that Go uses."
+ (string-trim version #\v))
+
+(define (ensure-v-prefix version)
+ "Add a \"v\" prefix to VERSION if it does not already have one."
+ (if (string-prefix? "v" version)
+ version
+ (string-append "v" version)))
+
+(define (validate-version version available-versions module-path)
+ "Raise an error if VERSION is not among AVAILABLE-VERSIONS, unless VERSION
+is a pseudo-version. Return VERSION."
+ ;; Pseudo-versions do not appear in the versions list; skip the
+ ;; following check.
+ (if (or (go-pseudo-version? version)
+ (member version available-versions))
+ version
+ (raise
+ (make-compound-condition
+ (formatted-message (G_ "version ~a of ~a is not available~%")
+ version module-path available-versions)
+ (condition (&fix-hint
+ (hint (format #f (G_ "Pick one of the following \
+available versions:~{ ~a~}.")
+ (map strip-v-prefix
+ available-versions)))))))))
+
(define* (go-module->guix-package module-path #:key
(goproxy "https://proxy.golang.org")
version
@@ -596,22 +607,18 @@ control system is being used."
The meta-data is fetched from the GOPROXY server and https://pkg.go.dev/.
When VERSION is unspecified, the latest version available is used."
(let* ((available-versions (go-module-available-versions goproxy module-path))
- (version* (or version
- (go-module-version-string goproxy module-path))) ;latest
- ;; Elide the "v" prefix Go uses.
- (strip-v-prefix (cut string-trim <> #\v))
- ;; Pseudo-versions do not appear in the versions list; skip the
- ;; following check.
- (_ (unless (or (go-pseudo-version? version*)
- (member version* available-versions))
- (error (format #f "error: version ~s is not available
-hint: use one of the following available versions ~a\n"
- version* available-versions))))
+ (version* (validate-version
+ (or (and version (ensure-v-prefix version))
+ (go-module-version-string goproxy module-path)) ;latest
+ available-versions
+ module-path))
(content (fetch-go.mod goproxy module-path version*))
(dependencies+versions (go.mod-requirements (parse-go.mod content)))
(dependencies (if pin-versions?
dependencies+versions
(map car dependencies+versions)))
+ (module-path-sans-suffix
+ (match:prefix (string-match "([\\./]v[0-9]+)?$" module-path)))
(guix-name (go-module->guix-package-name module-path))
(root-module-path (module-path->repository-root module-path))
;; The VCS type and URL are not included in goproxy information. For
@@ -631,7 +638,7 @@ hint: use one of the following available versions ~a\n"
(build-system go-build-system)
(arguments
'(#:import-path ,module-path
- ,@(if (string=? module-path root-module-path)
+ ,@(if (string=? module-path-sans-suffix root-module-path)
'()
`(#:unpack-path ,root-module-path))))
,@(maybe-propagated-inputs
@@ -645,10 +652,10 @@ hint: use one of the following available versions ~a\n"
(synopsis ,synopsis)
(description ,(and=> description beautify-description))
(license ,(match (list->licenses licenses)
- (() #f) ;unknown license
- ((license) ;a single license
+ (() #f) ;unknown license
+ ((license) ;a single license
license)
- ((license ...) ;a list of licenses
+ ((license ...) ;a list of licenses
`(list ,@license)))))
(if pin-versions?
dependencies+versions
@@ -668,12 +675,6 @@ This package and its dependencies won't be imported.~%")
(uri->string (http-get-error-uri c))
(http-get-error-code c)
(http-get-error-reason c))
- (values #f '()))
- (else
- (warning (G_ "Failed to import package ~s.
-reason: ~s.~%")
- package-name
- (exception-args c))
(values #f '())))
(apply go-module->guix-package args)))))
diff --git a/guix/import/hackage.scm b/guix/import/hackage.scm
index f94a1e7087..b94f4169d4 100644
--- a/guix/import/hackage.scm
+++ b/guix/import/hackage.scm
@@ -5,6 +5,7 @@
;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2019 Robert Vollmert <rob@vllmrt.net>
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
+;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -32,7 +33,7 @@
#:use-module ((guix utils) #:select (package-name->name+version
canonical-newline-port))
#:use-module (guix http-client)
- #:use-module ((guix import utils) #:select (factorize-uri recursive-import))
+ #:use-module (guix import utils)
#:use-module (guix import cabal)
#:use-module (guix store)
#:use-module (gcrypt hash)
@@ -40,6 +41,7 @@
#:use-module (guix memoization)
#:use-module (guix upstream)
#:use-module (guix packages)
+ #:autoload (guix build-system haskell) (hackage-uri)
#:use-module ((guix utils) #:select (call-with-temporary-output-file))
#:export (%hackage-url
hackage->guix-package
@@ -54,8 +56,8 @@
hackage-package?))
(define ghc-standard-libraries
- ;; List of libraries distributed with ghc (8.6.5).
- ;; Contents of ...-ghc-8.6.5/lib/ghc-8.6.5.
+ ;; List of libraries distributed with ghc (as of 8.10.7).
+ ;; Contents of …-ghc-8.10.7/lib/ghc-8.10.7
'("ghc"
"cabal" ;; in the output of `ghc-pkg list` Cabal is uppercased, but
;; hackage-name->package-name takes this into account.
@@ -67,6 +69,7 @@
"containers"
"deepseq"
"directory"
+ "exceptions"
"filepath"
"ghc"
"ghc-boot"
@@ -120,12 +123,12 @@ version is returned."
(string-append package-name-prefix (string-downcase name))))
(define guix-package->hackage-name
- (let ((uri-rx (make-regexp "https?://hackage.haskell.org/package/([^/]+)/.*"))
+ (let ((uri-rx (make-regexp "(https?://hackage.haskell.org|mirror://hackage)/package/([^/]+)/.*"))
(name-rx (make-regexp "(.*)-[0-9\\.]+")))
(lambda (package)
"Given a Guix package name, return the corresponding Hackage name."
(let* ((source-url (and=> (package-source package) origin-uri))
- (name (match:substring (regexp-exec uri-rx source-url) 1)))
+ (name (match:substring (regexp-exec uri-rx source-url) 2)))
(match (regexp-exec name-rx name)
(#f name)
(m (match:substring m 1)))))))
@@ -265,14 +268,12 @@ the hash of the Cabal file."
hackage-dependencies))
(define dependencies
- (map (lambda (name)
- (list name (list 'unquote (string->symbol name))))
+ (map string->symbol
(map hackage-name->package-name
hackage-dependencies)))
(define native-dependencies
- (map (lambda (name)
- (list name (list 'unquote (string->symbol name))))
+ (map string->symbol
(map hackage-name->package-name
hackage-native-dependencies)))
@@ -282,8 +283,8 @@ the hash of the Cabal file."
'())
((inputs ...)
(list (list input-type
- (list 'quasiquote inputs))))))
-
+ `(list ,@inputs))))))
+
(define (maybe-arguments)
(match (append (if (not include-test-dependencies?)
'(#:tests? #f)
@@ -302,7 +303,7 @@ the hash of the Cabal file."
(version ,version)
(source (origin
(method url-fetch)
- (uri (string-append ,@(factorize-uri source-url version)))
+ (uri (hackage-uri ,name version))
(sha256
(base32
,(if tarball
@@ -314,7 +315,7 @@ the hash of the Cabal file."
,@(maybe-arguments)
(home-page ,(cabal-package-home-page cabal))
(synopsis ,(cabal-package-synopsis cabal))
- (description ,(cabal-package-description cabal))
+ (description ,(beautify-description (cabal-package-description cabal)))
(license ,(string->license (cabal-package-license cabal))))
(append hackage-dependencies hackage-native-dependencies))))
@@ -352,7 +353,7 @@ respectively."
#:guix-name hackage-name->package-name))
(define hackage-package?
- (let ((hackage-rx (make-regexp "https?://hackage.haskell.org")))
+ (let ((hackage-rx (make-regexp "(https?://hackage.haskell.org|mirror://hackage/)")))
(url-predicate (cut regexp-exec hackage-rx <>))))
(define (latest-release package)
@@ -366,7 +367,7 @@ respectively."
(hackage-cabal-url hackage-name))
#f)
((_ *** ("version" (version)))
- (let ((url (hackage-source-url hackage-name version)))
+ (let ((url (hackage-uri hackage-name version)))
(upstream-source
(package (package-name package))
(version version)
diff --git a/guix/import/minetest.scm b/guix/import/minetest.scm
index ba86c60bfd..3b2cdcdcac 100644
--- a/guix/import/minetest.scm
+++ b/guix/import/minetest.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;; Copyright © 2021, 2022 Maxime Devos <maximedevos@telenet.be>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -25,6 +25,8 @@
#:use-module (srfi srfi-2)
#:use-module (srfi srfi-11)
#:use-module (srfi srfi-26)
+ #:use-module ((guix packages) #:prefix package:)
+ #:use-module (guix upstream)
#:use-module (guix utils)
#:use-module (guix ui)
#:use-module (guix i18n)
@@ -36,15 +38,20 @@
#:use-module (json)
#:use-module (guix base32)
#:use-module (guix git)
+ #:use-module ((guix git-download) #:prefix download:)
+ #:use-module (guix hash)
#:use-module (guix store)
#:export (%default-sort-key
%contentdb-api
json->package
contentdb-fetch
elaborate-contentdb-name
+ minetest-package?
+ latest-minetest-release
minetest->guix-package
minetest-recursive-import
- sort-packages))
+ sort-packages
+ %minetest-updater))
;; The ContentDB API is documented at
;; <https://content.minetest.net>.
@@ -280,14 +287,6 @@ results. The return value is a list of <package-keys> records."
(with-store store
(latest-repository-commit store url #:ref ref)))
-;; XXX adapted from (guix scripts hash)
-(define (file-hash file)
- "Compute the hash of FILE."
- (let-values (((port get-hash) (open-sha256-port)))
- (write-file file port)
- (force-output port)
- (get-hash)))
-
(define (make-minetest-sexp author/name version repository commit
inputs home-page synopsis
description media-license license)
@@ -308,15 +307,19 @@ MEDIA-LICENSE and LICENSE."
;; The git commit is not always available.
,(and commit
(bytevector->nix-base32-string
- (file-hash
+ (file-hash*
(download-git-repository repository
- `(commit . ,commit)))))))
+ `(commit . ,commit))
+ ;; 'download-git-repository' already filtered out the '.git'
+ ;; directory.
+ #:select? (const #true)
+ #:recursive? #true)))))
(file-name (git-file-name name version))))
(build-system minetest-mod-build-system)
,@(maybe-propagated-inputs (map contentdb->package-name inputs))
(home-page ,home-page)
(synopsis ,(delete-cr synopsis))
- (description ,(delete-cr description))
+ (description ,(beautify-description (delete-cr description)))
(license ,(if (eq? media-license license)
license
`(list ,media-license ,license)))
@@ -345,6 +348,17 @@ official Minetest forum and the Git repository (if any)."
(substring title 1)
title))
+(define (version-style version)
+ "Determine the kind of version number VERSION is -- a date, or a conventional
+conventional version number."
+ (define dots? (->bool (string-index version #\.)))
+ (define hyphens? (->bool (string-index version #\-)))
+ (match (cons dots? hyphens?)
+ ((#true . #false) 'regular) ; something like "0.1"
+ ((#false . #false) 'regular) ; single component version number
+ ((#true . #true) 'regular) ; result of 'git-version'
+ ((#false . #true) 'date))) ; something like "2021-01-25"
+
;; If the default sort key is changed, make sure to modify 'show-help'
;; in (guix scripts import minetest) appropriately as well.
(define %default-sort-key "score")
@@ -466,3 +480,37 @@ list of AUTHOR/NAME strings."
(recursive-import author/name
#:repo->guix-package minetest->guix-package*
#:guix-name contentdb->package-name))
+
+(define (minetest-package? pkg)
+ "Is PKG a Minetest mod on ContentDB?"
+ (and (string-prefix? "minetest-" (package:package-name pkg))
+ (assq-ref (package:package-properties pkg) 'upstream-name)))
+
+(define (latest-minetest-release pkg)
+ "Return an <upstream-source> for the latest release of the package PKG,
+or #false if the latest release couldn't be determined."
+ (define author/name
+ (assq-ref (package:package-properties pkg) 'upstream-name))
+ (define contentdb-package (contentdb-fetch author/name)) ; TODO warn if #f?
+ (define release (latest-release author/name))
+ (define source (package:package-source pkg))
+ (and contentdb-package release
+ (release-commit release) ; not always set
+ ;; Only continue if both the old and new version number are both
+ ;; dates or regular version numbers, as two different styles confuses
+ ;; the logic for determining which version is newer.
+ (eq? (version-style (release-version release))
+ (version-style (package:package-version pkg)))
+ (upstream-source
+ (package (package:package-name pkg))
+ (version (release-version release))
+ (urls (download:git-reference
+ (url (package-repository contentdb-package))
+ (commit (release-commit release)))))))
+
+(define %minetest-updater
+ (upstream-updater
+ (name 'minetest)
+ (description "Updater for Minetest packages on ContentDB")
+ (pred minetest-package?)
+ (latest latest-minetest-release)))
diff --git a/guix/import/opam.scm b/guix/import/opam.scm
index fe13d29f03..a6f6fe8c9f 100644
--- a/guix/import/opam.scm
+++ b/guix/import/opam.scm
@@ -2,6 +2,7 @@
;;; Copyright © 2018 Julien Lepiller <julien@lepiller.eu>
;;; Copyright © 2020 Martin Becze <mjbecze@riseup.net>
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
+;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
;;; Copyright © 2021 Alice Brenon <alice.brenon@ens-lyon.fr>
;;;
;;; This file is part of GNU Guix.
@@ -230,7 +231,8 @@ path to the repository."
(('list-pat . stuff) stuff)
(('string-pat stuff) stuff)
(('multiline-string stuff) stuff)
- (('dict records ...) records))
+ (('dict records ...) records)
+ (_ #f))
acc))))
#f file))
@@ -305,10 +307,8 @@ path to the repository."
(map dependency->native-input depends)))
(define (dependency-list->inputs lst)
- (map
- (lambda (dependency)
- (list dependency (list 'unquote (string->symbol dependency))))
- (ocaml-names->guix-names lst)))
+ (map string->symbol
+ (ocaml-names->guix-names lst)))
(define* (opam-fetch name #:optional (repositories-specs '("opam")))
(or (fold (lambda (repository others)
@@ -318,11 +318,11 @@ path to the repository."
(_ others)))
#f
(filter-map get-opam-repository repositories-specs))
- (leave (G_ "package '~a' not found~%") name)))
+ (warning (G_ "opam: package '~a' not found~%") name)))
-(define* (opam->guix-package name #:key (repo '()) version)
- "Import OPAM package NAME from REPOSITORIES (a list of names, URLs or local
-paths, always including OPAM's official repository). Return a 'package' sexp
+(define* (opam->guix-package name #:key (repo 'opam) version)
+ "Import OPAM package NAME from REPOSITORY (a directory name) or, if
+REPOSITORY is #f, from the official OPAM repository. Return a 'package' sexp
or #f on failure."
(and-let* ((with-opam (if (member "opam" repo) repo (cons "opam" repo)))
(opam-file (opam-fetch name with-opam))
@@ -361,17 +361,18 @@ or #f on failure."
'ocaml-build-system))
,@(if (null? inputs)
'()
- `((propagated-inputs ,(list 'quasiquote inputs))))
+ `((propagated-inputs (list ,@inputs))))
,@(if (null? native-inputs)
'()
- `((native-inputs ,(list 'quasiquote native-inputs))))
+ `((native-inputs (list ,@native-inputs))))
,@(if (equal? name (guix-name->opam-name (ocaml-name->guix-name name)))
'()
`((properties
,(list 'quasiquote `((upstream-name . ,name))))))
(home-page ,(metadata-ref opam-content "homepage"))
(synopsis ,(metadata-ref opam-content "synopsis"))
- (description ,(metadata-ref opam-content "description"))
+ (description ,(beautify-description
+ (metadata-ref opam-content "description")))
(license ,(spdx-string->license
(metadata-ref opam-content "license"))))
(filter
diff --git a/guix/import/print.scm b/guix/import/print.scm
index 0310739b3a..66016145cb 100644
--- a/guix/import/print.scm
+++ b/guix/import/print.scm
@@ -1,5 +1,6 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2017, 2020 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2021 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -25,14 +26,20 @@
#:use-module (guix build-system)
#:use-module (gnu packages)
#:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-26)
#:use-module (guix import utils)
#:use-module (ice-9 control)
#:use-module (ice-9 match)
#:export (package->code))
-;; FIXME: the quasiquoted arguments field may contain embedded package
-;; objects, e.g. in #:disallowed-references; they will just be printed with
-;; their usual #<package ...> representation, not as variable names.
+(define (redundant-input-labels? inputs)
+ "Return #t if input labels in the INPUTS list are redundant."
+ (every (match-lambda
+ ((label (? package? package) . _)
+ (string=? label (package-name package)))
+ (_ #f))
+ inputs))
+
(define (package->code package)
"Return an S-expression representing the source code that produces PACKAGE
when evaluated."
@@ -72,6 +79,11 @@ when evaluated."
(file-type (quote ,(search-path-specification-file-type spec)))
(file-pattern ,(search-path-specification-file-pattern spec))))
+ (define (factorized-uri-code uri version)
+ (match (factorize-uri uri version)
+ ((? string? uri) uri)
+ ((factorized ...) `(string-append ,@factorized))))
+
(define (source->code source version)
(let ((uri (origin-uri source))
(method (origin-method source))
@@ -89,9 +101,14 @@ when evaluated."
(guix hg-download)
(guix svn-download)))
(procedure-name method)))
- (uri (string-append ,@(match (factorize-uri uri version)
- ((? string? uri) (list uri))
- (factorized factorized))))
+ (uri ,(if version
+ (match uri
+ ((? string? uri)
+ (factorized-uri-code uri version))
+ ((lst ...)
+ `(list
+ ,@(map (cut factorized-uri-code <> version) uri))))
+ uri))
,(if (equal? (content-hash-algorithm hash) 'sha256)
`(sha256 (base32 ,(bytevector->nix-base32-string
(content-hash-value hash))))
@@ -101,24 +118,62 @@ when evaluated."
;; FIXME: in order to be able to throw away the directory prefix,
;; we just assume that the patch files can be found with
;; "search-patches".
- ,@(if (null? patches) '()
- `((patches (search-patches ,@(map basename patches))))))))
+ ,@(cond ((null? patches)
+ '())
+ ((every string? patches)
+ `((patches (search-patches ,@(map basename patches)))))
+ (else
+ `((patches (list ,@(map (match-lambda
+ ((? string? file)
+ `(search-patch ,file))
+ ((? origin? origin)
+ (source->code origin #f)))
+ patches)))))))))
+
+ (define (variable-reference module name)
+ ;; FIXME: using '@ certainly isn't pretty, but it avoids having to import
+ ;; the individual package modules.
+ (list '@ module name))
+
+ (define (object->code obj quoted?)
+ (match obj
+ ((? package? package)
+ (let* ((module (package-module-name package))
+ (name (variable-name package module)))
+ (if quoted?
+ (list 'unquote (variable-reference module name))
+ (variable-reference module name))))
+ ((? origin? origin)
+ (let ((code (source->code origin #f)))
+ (if quoted?
+ (list 'unquote code)
+ code)))
+ ((lst ...)
+ (let ((lst (map (cut object->code <> #t) lst)))
+ (if quoted?
+ lst
+ (list 'quasiquote lst))))
+ (obj
+ obj)))
- (define (package-lists->code lsts)
- (list 'quasiquote
- (map (match-lambda
- ((? symbol? s)
- (list (symbol->string s) (list 'unquote s)))
- ((label pkg . out)
- (let ((mod (package-module-name pkg)))
- (cons* label
- ;; FIXME: using '@ certainly isn't pretty, but it
- ;; avoids having to import the individual package
- ;; modules.
- (list 'unquote
- (list '@ mod (variable-name pkg mod)))
- out))))
- lsts)))
+ (define (inputs->code inputs)
+ (if (redundant-input-labels? inputs)
+ `(list ,@(map (match-lambda ;no need for input labels ("new style")
+ ((_ package)
+ (let* ((module (package-module-name package))
+ (name (variable-name package module)))
+ (variable-reference module name)))
+ ((_ package output)
+ (let* ((module (package-module-name package))
+ (name (variable-name package module)))
+ (list 'quasiquote
+ (list
+ (list 'unquote
+ (variable-reference module name))
+ output)))))
+ inputs))
+ (list 'quasiquote ;preserve input labels (deprecated)
+ (object->code inputs #t))))
(let ((name (package-name package))
(version (package-version package))
@@ -154,19 +209,20 @@ when evaluated."
'-build-system)))
,@(match arguments
(() '())
- (args `((arguments ,(list 'quasiquote args)))))
+ (_ `((arguments
+ ,(list 'quasiquote (object->code arguments #t))))))
,@(match outputs
(("out") '())
(outs `((outputs (list ,@outs)))))
,@(match native-inputs
(() '())
- (pkgs `((native-inputs ,(package-lists->code pkgs)))))
+ (pkgs `((native-inputs ,(inputs->code pkgs)))))
,@(match inputs
(() '())
- (pkgs `((inputs ,(package-lists->code pkgs)))))
+ (pkgs `((inputs ,(inputs->code pkgs)))))
,@(match propagated-inputs
(() '())
- (pkgs `((propagated-inputs ,(package-lists->code pkgs)))))
+ (pkgs `((propagated-inputs ,(inputs->code pkgs)))))
,@(if (lset= string=? supported-systems %supported-systems)
'()
`((supported-systems (list ,@supported-systems))))
diff --git a/guix/import/pypi.scm b/guix/import/pypi.scm
index b7859c8341..b4284f5c33 100644
--- a/guix/import/pypi.scm
+++ b/guix/import/pypi.scm
@@ -1,7 +1,7 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2014 David Thompson <davet@gnu.org>
;;; Copyright © 2015 Cyril Roelandt <tipecaml@gmail.com>
-;;; Copyright © 2015, 2016, 2017, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2015, 2016, 2017, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2019 Maxim Cournoyer <maxim.cournoyer@gmail.com>
@@ -10,6 +10,7 @@
;;; Copyright © 2020 Arun Isaac <arunisaac@systemreboot.net>
;;; Copyright © 2020 Martin Becze <mjbecze@riseup.net>
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
+;;; Copyright © 2021 Marius Bakke <marius@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -113,7 +114,7 @@
(url distribution-url) ;string
(digests distribution-digests) ;list of string pairs
(file-name distribution-file-name "filename") ;string
- (has-signature? distribution-has-signature? "hash_sig") ;Boolean
+ (has-signature? distribution-has-signature? "has_sig") ;Boolean
(package-type distribution-package-type "packagetype") ;"bdist_wheel" | ...
(python-version distribution-package-python-version
"python_version"))
@@ -128,27 +129,30 @@
missing-source-error?
(package missing-source-error-package))
-(define (latest-source-release pypi-package)
- "Return the latest source release for PYPI-PACKAGE."
- (let ((releases (assoc-ref (pypi-project-releases pypi-package)
- (project-info-version
- (pypi-project-info pypi-package)))))
+(define (latest-version project)
+ "Return the latest version of PROJECT, a <pypi-project> record."
+ (project-info-version (pypi-project-info project)))
+
+(define* (source-release pypi-package
+ #:optional (version (latest-version pypi-package)))
+ "Return the source release of VERSION for PYPI-PACKAGE, a <pypi-project>
+record, by default the latest version."
+ (let ((releases (or (assoc-ref (pypi-project-releases pypi-package) version)
+ '())))
(or (find (lambda (release)
(string=? "sdist" (distribution-package-type release)))
releases)
(raise (condition (&missing-source-error
(package pypi-package)))))))
-(define (latest-wheel-release pypi-package)
+(define* (wheel-release pypi-package
+ #:optional (version (latest-version pypi-package)))
"Return the url of the wheel for the latest release of pypi-package,
or #f if there isn't any."
- (let ((releases (assoc-ref (pypi-project-releases pypi-package)
- (project-info-version
- (pypi-project-info pypi-package)))))
- (or (find (lambda (release)
- (string=? "bdist_wheel" (distribution-package-type release)))
- releases)
- #f)))
+ (let ((releases (assoc-ref (pypi-project-releases pypi-package) version)))
+ (find (lambda (release)
+ (string=? "bdist_wheel" (distribution-package-type release)))
+ releases)))
(define (python->package-name name)
"Given the NAME of a package on PyPI, return a Guix-compliant name for the
@@ -185,7 +189,7 @@ the input field."
(()
'())
((package-inputs ...)
- `((,input-type (,'quasiquote ,package-inputs))))))
+ `((,input-type (list ,@package-inputs))))))
(define %requirement-name-regexp
;; Regexp to match the requirement name in a requirement specification.
@@ -404,15 +408,8 @@ return the unaltered list of upstream dependency names."
(remove (cut string=? "argparse" <>) deps))
(define (requirement->package-name/sort deps)
- (sort
- (map (lambda (input)
- (let ((guix-name (python->package-name input)))
- (list guix-name (list 'unquote (string->symbol guix-name)))))
- deps)
- (lambda args
- (match args
- (((a _ ...) (b _ ...))
- (string-ci<? a b))))))
+ (map string->symbol
+ (sort (map python->package-name deps) string-ci<?)))
(define process-requirements
(compose requirement->package-name/sort strip-argparse))
@@ -426,7 +423,7 @@ return the unaltered list of upstream dependency names."
"Return the `package' s-expression for a python package with the given NAME,
VERSION, SOURCE-URL, HOME-PAGE, SYNOPSIS, DESCRIPTION, and LICENSE."
(define (maybe-upstream-name name)
- (if (string-match ".*\\-[0-9]+" (pk name))
+ (if (string-match ".*\\-[0-9]+" name)
`((properties ,`'(("upstream-name" . ,name))))
'()))
@@ -474,7 +471,7 @@ VERSION, SOURCE-URL, HOME-PAGE, SYNOPSIS, DESCRIPTION, and LICENSE."
,@(maybe-inputs native-inputs 'native-inputs)
(home-page ,home-page)
(synopsis ,synopsis)
- (description ,description)
+ (description ,(beautify-description description))
(license ,(license->symbol license)))
upstream-dependencies))))))))
@@ -484,18 +481,17 @@ VERSION, SOURCE-URL, HOME-PAGE, SYNOPSIS, DESCRIPTION, and LICENSE."
"Fetch the metadata for PACKAGE-NAME from pypi.org, and return the
`package' s-expression corresponding to that package, or #f on failure."
(let* ((project (pypi-fetch package-name))
- (info (and project (pypi-project-info project))))
+ (info (and=> project pypi-project-info))
+ (version (or version (and=> project latest-version))))
(and project
(guard (c ((missing-source-error? c)
(let ((package (missing-source-error-package c)))
(leave (G_ "no source release for pypi package ~a ~a~%")
- (project-info-name info)
- (project-info-version info)))))
- (make-pypi-sexp (project-info-name info)
- (project-info-version info)
- (and=> (latest-source-release project)
+ (project-info-name info) version))))
+ (make-pypi-sexp (project-info-name info) version
+ (and=> (source-release project version)
distribution-url)
- (and=> (latest-wheel-release project)
+ (and=> (wheel-release project version)
distribution-url)
(project-info-home-page info)
(project-info-summary info)
@@ -503,8 +499,9 @@ VERSION, SOURCE-URL, HOME-PAGE, SYNOPSIS, DESCRIPTION, and LICENSE."
(string->license
(project-info-license info)))))))))
-(define (pypi-recursive-import package-name)
+(define* (pypi-recursive-import package-name #:optional version)
(recursive-import package-name
+ #:version version
#:repo->guix-package pypi->guix-package
#:guix-name python->package-name))
@@ -537,12 +534,19 @@ VERSION, SOURCE-URL, HOME-PAGE, SYNOPSIS, DESCRIPTION, and LICENSE."
(guard (c ((missing-source-error? c) #f))
(let* ((info (pypi-project-info pypi-package))
(version (project-info-version info))
- (url (distribution-url
- (latest-source-release pypi-package))))
+ (dist (source-release pypi-package))
+ (url (distribution-url dist)))
(upstream-source
+ (urls (list url))
+ (signature-urls
+ (if (distribution-has-signature? dist)
+ (list (string-append url ".asc"))
+ #f))
+ (input-changes
+ (changed-inputs package
+ (pypi->guix-package pypi-name)))
(package (package-name package))
- (version version)
- (urls (list url))))))))
+ (version version)))))))
(define %pypi-updater
(upstream-updater
diff --git a/guix/import/stackage.scm b/guix/import/stackage.scm
index 731e69651e..49be982a7f 100644
--- a/guix/import/stackage.scm
+++ b/guix/import/stackage.scm
@@ -3,6 +3,7 @@
;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2020 Martin Becze <mjbecze@riseup.net>
;;; Copyright © 2021 Xinglu Chem <public@yoctocell.xyz>
+;;; Copyright © 2021 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -21,19 +22,18 @@
(define-module (guix import stackage)
#:use-module (ice-9 match)
- #:use-module (ice-9 regex)
- #:use-module (ice-9 control)
+ #:use-module (json)
#:use-module (srfi srfi-1)
- #:use-module (srfi srfi-26)
#:use-module (srfi srfi-34)
#:use-module (srfi srfi-35)
- #:use-module (srfi srfi-43)
#:use-module (guix import json)
#:use-module (guix import hackage)
#:use-module (guix import utils)
#:use-module (guix memoization)
#:use-module (guix packages)
#:use-module (guix upstream)
+ #:use-module (guix diagnostics)
+ #:use-module (guix i18n)
#:export (%stackage-url
stackage->guix-package
stackage-recursive-import
@@ -47,15 +47,31 @@
(define %stackage-url
(make-parameter "https://www.stackage.org"))
-;; Latest LTS version compatible with GHC 8.6.5.
-(define %default-lts-version "14.27")
+;; Latest LTS version compatible with current GHC.
+(define %default-lts-version "18.14")
-(define (lts-info-packages lts-info)
- "Returns the alist of packages contained in LTS-INFO."
- (or (assoc-ref lts-info "packages") '()))
+(define-json-mapping <stackage-lts> make-stackage-lts
+ stackage-lts?
+ json->stackage-lts
+ (snapshot stackage-lts-snapshot "snapshot" json->snapshot)
+ (packages stackage-lts-packages "packages"
+ (lambda (vector)
+ (map json->stackage-package (vector->list vector)))))
-(define (leave-with-message fmt . args)
- (raise (condition (&message (message (apply format #f fmt args))))))
+(define-json-mapping <snapshot> make-snapshot
+ stackage-snapshot?
+ json->snapshot
+ (name snapshot-name)
+ (ghc-version snapshot-ghc-version)
+ (compiler snapshot-compiler))
+
+(define-json-mapping <stackage-package> make-stackage-package
+ stackage-package?
+ json->stackage-package
+ (origin stackage-package-origin)
+ (name stackage-package-name)
+ (version stackage-package-version)
+ (synopsis stackage-package-synopsis))
(define stackage-lts-info-fetch
;; "Retrieve the information about the LTS Stackage release VERSION."
@@ -65,21 +81,15 @@
"/lts-" (if (string-null? version)
%default-lts-version
version)))
- (lts-info (json-fetch url)))
- (if lts-info
- (reverse lts-info)
- (leave-with-message "LTS release version not found: ~a" version))))))
-
-(define (stackage-package-name pkg-info)
- (assoc-ref pkg-info "name"))
-
-(define (stackage-package-version pkg-info)
- (assoc-ref pkg-info "version"))
+ (lts-info (and=> (json-fetch url) json->stackage-lts)))
+ (or lts-info
+ (raise (formatted-message (G_ "LTS release version not found: ~a")
+ version)))))))
-(define (lts-package-version pkgs-info name)
- "Return the version of the package with upstream NAME included in PKGS-INFO."
+(define (lts-package-version packages name)
+ "Return the version of the package with upstream NAME included in PACKAGES."
(let ((pkg (find (lambda (pkg) (string=? (stackage-package-name pkg) name))
- (vector->list pkgs-info))))
+ packages)))
(stackage-package-version pkg)))
@@ -96,21 +106,22 @@
#:key
(include-test-dependencies? #t)
(lts-version %default-lts-version)
- (packages-info
- (lts-info-packages
+ (packages
+ (stackage-lts-packages
(stackage-lts-info-fetch lts-version))))
"Fetch Cabal file for PACKAGE-NAME from hackage.haskell.org. The retrieved
version corresponds to the version of PACKAGE-NAME specified in the LTS-VERSION
release at stackage.org. Return the `package' S-expression corresponding to
that package, or #f on failure. PACKAGES-INFO is the alist with the packages
included in the Stackage LTS release."
- (let* ((version (lts-package-version packages-info package-name))
+ (let* ((version (lts-package-version packages package-name))
(name-version (hackage-name-version package-name version)))
(if name-version
(hackage->guix-package name-version
#:include-test-dependencies?
include-test-dependencies?)
- (leave-with-message "~a: Stackage package not found" package-name))))))
+ (raise (formatted-message (G_ "~a: Stackage package not found")
+ package-name)))))))
(define (stackage-recursive-import package-name . args)
(recursive-import package-name
@@ -124,43 +135,46 @@ included in the Stackage LTS release."
;;;
(define latest-lts-release
- (let ((pkgs-info
- (mlambda () (lts-info-packages
- (stackage-lts-info-fetch %default-lts-version)))))
- (lambda* (package)
+ (let ((packages
+ (mlambda ()
+ (stackage-lts-packages
+ (stackage-lts-info-fetch %default-lts-version)))))
+ (lambda* (pkg)
"Return an <upstream-source> for the latest Stackage LTS release of
PACKAGE or #f if the package is not included in the Stackage LTS release."
- (let* ((hackage-name (guix-package->hackage-name package))
- (version (lts-package-version (pkgs-info) hackage-name))
+ (let* ((hackage-name (guix-package->hackage-name pkg))
+ (version (lts-package-version (packages) hackage-name))
(name-version (hackage-name-version hackage-name version)))
(match (and=> name-version hackage-fetch)
- (#f (format (current-error-port)
- "warning: failed to parse ~a~%"
- (hackage-cabal-url hackage-name))
- #f)
+ (#f
+ (warning (G_ "failed to parse ~a~%")
+ (hackage-cabal-url hackage-name))
+ #f)
(_ (let ((url (hackage-source-url hackage-name version)))
(upstream-source
- (package (package-name package))
+ (package (package-name pkg))
(version version)
- (urls (list url))))))))))
+ (urls (list url))
+ (input-changes
+ (changed-inputs
+ pkg
+ (stackage->guix-package hackage-name #:packages (packages))))))))))))
-(define (stackage-package? package)
- "Whether PACKAGE is available on the default Stackage LTS release."
+(define (stackage-lts-package? package)
+ "Return whether PACKAGE is available on the default Stackage LTS release."
(and (hackage-package? package)
- (let ((packages (lts-info-packages
+ (let ((packages (stackage-lts-packages
(stackage-lts-info-fetch %default-lts-version)))
(hackage-name (guix-package->hackage-name package)))
- (vector-any identity
- (vector-map
- (lambda (_ metadata)
- (string=? (cdr (list-ref metadata 2)) hackage-name))
- packages)))))
+ (find (lambda (package)
+ (string=? (stackage-package-name package) hackage-name))
+ packages))))
(define %stackage-updater
(upstream-updater
(name 'stackage)
(description "Updater for Stackage LTS packages")
- (pred stackage-package?)
+ (pred stackage-lts-package?)
(latest latest-lts-release)))
;;; stackage.scm ends here
diff --git a/guix/import/texlive.scm b/guix/import/texlive.scm
index 18d8b95ee0..c741555928 100644
--- a/guix/import/texlive.scm
+++ b/guix/import/texlive.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2017 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2017, 2021, 2022 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;;
;;; This file is part of GNU Guix.
@@ -18,19 +18,18 @@
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
(define-module (guix import texlive)
+ #:use-module (ice-9 ftw)
#:use-module (ice-9 match)
- #:use-module (sxml simple)
- #:use-module (sxml xpath)
- #:use-module (srfi srfi-11)
+ #:use-module (ice-9 rdelim)
#:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-2)
+ #:use-module (srfi srfi-11)
#:use-module (srfi srfi-26)
- #:use-module (srfi srfi-34)
- #:use-module (web uri)
- #:use-module (guix diagnostics)
- #:use-module (guix i18n)
- #:use-module (guix http-client)
#:use-module (gcrypt hash)
+ #:use-module (guix derivations)
#:use-module (guix memoization)
+ #:use-module (guix monads)
+ #:use-module (guix gexp)
#:use-module (guix store)
#:use-module (guix base32)
#:use-module (guix serialization)
@@ -39,24 +38,16 @@
#:use-module (guix utils)
#:use-module (guix upstream)
#:use-module (guix packages)
- #:use-module (gnu packages)
#:use-module (guix build-system texlive)
- #:export (texlive->guix-package
-
- fetch-sxml
- sxml->package))
+ #:export (files-differ?
+ texlive->guix-package
+ texlive-recursive-import))
;;; Commentary:
;;;
-;;; Generate a package declaration template for the latest version of a
-;;; package on CTAN, using the XML output produced by the XML API to the CTAN
-;;; database at http://www.ctan.org/xml/1.2/
-;;;
-;;; Instead of taking the packages from CTAN, however, we fetch the sources
-;;; from the SVN repository of the Texlive project. We do this because CTAN
-;;; only keeps a single version of each package whereas we can access any
-;;; version via SVN. Unfortunately, this means that the importer is really
-;;; just a Texlive importer, not a generic CTAN importer.
+;;; Generate a package declaration template for corresponding package in the
+;;; Tex Live Package Database (tlpdb). We fetch all sources from different
+;;; locations in the SVN repository of the Texlive project.
;;;
;;; Code:
@@ -79,6 +70,8 @@
("bsd4" 'bsd-4)
("opl" 'opl1.0+)
("ofl" 'silofl1.1)
+
+ ("lpplgpl" `(list lppl gpl1+))
("lppl" 'lppl)
("lppl1" 'lppl1.0+) ; usually means "or later"
("lppl1.2" 'lppl1.2+) ; usually means "or later"
@@ -107,91 +100,211 @@
("cc-by-nc-nd-4" 'non-free)
((x) (string->license x))
((lst ...) `(list ,@(map string->license lst)))
- (_ #f)))
-
-(define (fetch-sxml name)
- "Return an sxml representation of the package information contained in the
-XML description of the CTAN package or #f in case of failure."
- ;; This API always returns the latest release of the module.
- (let ((url (string-append "http://www.ctan.org/xml/1.2/pkg/" name)))
- (guard (c ((http-get-error? c)
- (format (current-error-port)
- "error: failed to retrieve package information \
-from ~s: ~a (~s)~%"
- (uri->string (http-get-error-uri c))
- (http-get-error-code c)
- (http-get-error-reason c))
- #f))
- (xml->sxml (http-fetch url)
- #:trim-whitespace? #t))))
+ (x `(error unknown-license ,x))))
-(define (guix-name component name)
+(define (guix-name name)
"Return a Guix package name for a given Texlive package NAME."
- (string-append "texlive-" component "-"
+ (string-append "texlive-"
(string-map (match-lambda
(#\_ #\-)
(#\. #\-)
(chr (char-downcase chr)))
name)))
-(define* (sxml->package sxml #:optional (component "latex"))
- "Return the `package' s-expression for a Texlive package from the SXML
-expression describing it."
- (define (sxml-value path)
- (match ((sxpath path) sxml)
- (() #f)
- ((val) val)))
+(define (tlpdb-file)
+ (define texlive-bin
+ ;; Resolve this variable lazily so that (gnu packages ...) does not end up
+ ;; in the closure of this module.
+ (module-ref (resolve-interface '(gnu packages tex))
+ 'texlive-bin))
+
(with-store store
- (let* ((id (sxml-value '(entry @ id *text*)))
- (synopsis (sxml-value '(entry caption *text*)))
- (version (or (sxml-value '(entry version @ number *text*))
- (sxml-value '(entry version @ date *text*))))
- (license (match ((sxpath '(entry license @ type *text*)) sxml)
- ((license) (string->license license))
- ((lst ...) (map string->license lst))))
- (home-page (string-append "http://www.ctan.org/pkg/" id))
- (ref (texlive-ref component id))
- (checkout (download-svn-to-store store ref)))
- (unless checkout
- (warning (G_ "Could not determine source location. \
-Please manually specify the source field.~%")))
- `(package
- (name ,(guix-name component id))
- (version ,version)
- (source ,(if checkout
- `(origin
- (method svn-fetch)
- (uri (texlive-ref ,component ,id))
- (sha256
- (base32
- ,(bytevector->nix-base32-string
- (let-values (((port get-hash) (open-sha256-port)))
- (write-file checkout port)
- (force-output port)
- (get-hash))))))
- #f))
- (build-system texlive-build-system)
- (arguments ,`(,'quote (#:tex-directory ,(string-join (list component id) "/"))))
- (home-page ,home-page)
- (synopsis ,synopsis)
- (description ,(string-trim-both
- (string-join
- (map string-trim-both
- (string-split
- (beautify-description
- (sxml->string (or (sxml-value '(entry description))
- '())))
- #\newline)))))
- (license ,(match license
- ((lst ...) `(list ,@lst))
- (license license)))))))
+ (run-with-store store
+ (mlet* %store-monad
+ ((drv (lower-object texlive-bin))
+ (built (built-derivations (list drv))))
+ (match (derivation->output-paths drv)
+ (((names . items) ...)
+ (return (string-append (first items)
+ "/share/tlpkg/texlive.tlpdb"))))))))
+
+(define tlpdb
+ (memoize
+ (lambda ()
+ (let ((file (tlpdb-file))
+ (fields
+ '((name . string)
+ (shortdesc . string)
+ (longdesc . string)
+ (catalogue-license . string)
+ (catalogue-ctan . string)
+ (srcfiles . list)
+ (runfiles . list)
+ (docfiles . list)
+ (depend . simple-list)))
+ (record
+ (lambda* (key value alist #:optional (type 'string))
+ (let ((new
+ (or (and=> (assoc-ref alist key)
+ (lambda (existing)
+ (cond
+ ((eq? type 'string)
+ (string-append existing " " value))
+ ((or (eq? type 'list) (eq? type 'simple-list))
+ (cons value existing)))))
+ (cond
+ ((eq? type 'string)
+ value)
+ ((or (eq? type 'list) (eq? type 'simple-list))
+ (list value))))))
+ (acons key new (alist-delete key alist))))))
+ (call-with-input-file file
+ (lambda (port)
+ (let loop ((all (list))
+ (current (list))
+ (last-property #false))
+ (let ((line (read-line port)))
+ (cond
+ ((eof-object? line) all)
+
+ ;; End of record.
+ ((string-null? line)
+ (loop (cons (cons (assoc-ref current 'name) current)
+ all)
+ (list) #false))
+
+ ;; Continuation of a list
+ ((and (zero? (string-index line #\space)) last-property)
+ ;; Erase optional second part of list values like
+ ;; "details=Readme" for files
+ (let ((plain-value (first
+ (string-split
+ (string-trim-both line) #\space))))
+ (loop all (record last-property
+ plain-value
+ current
+ 'list)
+ last-property)))
+ (else
+ (or (and-let* ((space (string-index line #\space))
+ (key (string->symbol (string-take line space)))
+ (value (string-drop line (1+ space)))
+ (field-type (assoc-ref fields key)))
+ ;; Erase second part of list keys like "size=29"
+ (cond
+ ((eq? field-type 'list)
+ (loop all current key))
+ (else
+ (loop all (record key value current field-type) key))))
+ (loop all current #false))))))))))))
+
+(define* (files-differ? directory package-name
+ #:key
+ (package-database tlpdb)
+ (type #false)
+ (direction 'missing))
+ "Return a list of files in DIRECTORY that differ from the expected installed
+files for PACKAGE-NAME according to the PACKAGE-DATABASE. By default all
+files considered, but this can be restricted by setting TYPE to 'runfiles,
+'docfiles, or 'srcfiles. The names of files that are missing from DIRECTORY
+are returned; by setting DIRECTION to anything other than 'missing, the names
+of those files are returned that are unexpectedly installed."
+ (define (strip-directory-prefix file-name)
+ (string-drop file-name (1+ (string-length directory))))
+ (let* ((data (or (assoc-ref (package-database) package-name)
+ (error (format #false
+ "~a is not a valid package name in the TeX Live package database."
+ package-name))))
+ (files (if type
+ (or (assoc-ref data type) (list))
+ (append (or (assoc-ref data 'runfiles) (list))
+ (or (assoc-ref data 'docfiles) (list))
+ (or (assoc-ref data 'srcfiles) (list)))))
+ (existing (file-system-fold
+ (const #true) ;enter?
+ (lambda (path stat result) (cons path result)) ;leaf
+ (lambda (path stat result) result) ;down
+ (lambda (path stat result) result) ;up
+ (lambda (path stat result) result) ;skip
+ (lambda (path stat errno result) result) ;error
+ (list)
+ directory)))
+ (if (eq? direction 'missing)
+ (lset-difference string=?
+ files (map strip-directory-prefix existing))
+ ;; List files that are installed but should not be.
+ (lset-difference string=?
+ (map strip-directory-prefix existing) files))))
+
+(define (files->directories files)
+ (define name->parts (cut string-split <> #\/))
+ (map (cut string-join <> "/" 'suffix)
+ (delete-duplicates (map (lambda (file)
+ (drop-right (name->parts file) 1))
+ (sort files string<))
+ ;; Remove sub-directories, i.e. more specific
+ ;; entries with the same prefix.
+ (lambda (x y) (every equal? x y)))))
+
+(define (tlpdb->package name package-database)
+ (and-let* ((data (assoc-ref package-database name))
+ (dirs (files->directories
+ (map (lambda (dir)
+ (string-drop dir (string-length "texmf-dist/")))
+ (append (or (assoc-ref data 'docfiles) (list))
+ (or (assoc-ref data 'runfiles) (list))
+ (or (assoc-ref data 'srcfiles) (list))))))
+ (name (guix-name name))
+ (version (number->string %texlive-revision))
+ (ref (svn-multi-reference
+ (url (string-append "svn://www.tug.org/texlive/tags/"
+ %texlive-tag "/Master/texmf-dist"))
+ (locations dirs)
+ (revision %texlive-revision)))
+ (source (with-store store
+ (download-multi-svn-to-store
+ store ref (string-append name "-svn-multi-checkout")))))
+ (values
+ `(package
+ (inherit (simple-texlive-package
+ ,name
+ (list ,@dirs)
+ (base32
+ ,(bytevector->nix-base32-string
+ (let-values (((port get-hash) (open-sha256-port)))
+ (write-file source port)
+ (force-output port)
+ (get-hash))))
+ ,@(if (assoc-ref data 'srcfiles) '() '(#:trivial? #true))))
+ ,@(or (and=> (assoc-ref data 'depend)
+ (lambda (inputs)
+ `((propagated-inputs
+ (list ,@(map (lambda (tex-name)
+ (let ((name (guix-name tex-name)))
+ (string->symbol name)))
+ inputs))))))
+ '())
+ ,@(or (and=> (assoc-ref data 'catalogue-ctan)
+ (lambda (url)
+ `((home-page ,(string-append "https://ctan.org" url)))))
+ '((home-page "https://www.tug.org/texlive/")))
+ (synopsis ,(assoc-ref data 'shortdesc))
+ (description ,(beautify-description
+ (assoc-ref data 'longdesc)))
+ (license ,(string->license
+ (assoc-ref data 'catalogue-license))))
+ (or (assoc-ref data 'depend) (list)))))
(define texlive->guix-package
(memoize
- (lambda* (package-name #:optional (component "latex"))
- "Fetch the metadata for PACKAGE-NAME from REPO and return the `package'
+ (lambda* (name #:key repo version (package-database tlpdb))
+ "Find the metadata for NAME in the tlpdb and return the `package'
s-expression corresponding to that package, or #f on failure."
- (and=> (fetch-sxml package-name)
- (cut sxml->package <> component)))))
+ (tlpdb->package name (package-database)))))
+
+(define (texlive-recursive-import name)
+ (recursive-import name
+ #:repo->guix-package texlive->guix-package
+ #:guix-name guix-name))
-;;; ctan.scm ends here
+;;; texlive.scm ends here
diff --git a/guix/import/utils.scm b/guix/import/utils.scm
index a180742ca3..1c3cfa3e0b 100644
--- a/guix/import/utils.scm
+++ b/guix/import/utils.scm
@@ -9,6 +9,7 @@
;;; Copyright © 2020 Martin Becze <mjbecze@riseup.net>
;;; Copyright © 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
+;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -39,6 +40,7 @@
#:use-module (guix store)
#:use-module (guix download)
#:use-module (guix sets)
+ #:use-module (guix ui)
#:use-module (gnu packages)
#:use-module (ice-9 match)
#:use-module (ice-9 rdelim)
@@ -152,6 +154,7 @@ of the string VERSION is replaced by the symbol 'version."
("CC0-1.0" 'license:cc0)
("CC-BY-2.0" 'license:cc-by2.0)
("CC-BY-3.0" 'license:cc-by3.0)
+ ("CC-BY-4.0" 'license:cc-by4.0)
("CC-BY-SA-2.0" 'license:cc-by-sa2.0)
("CC-BY-SA-3.0" 'license:cc-by-sa3.0)
("CC-BY-SA-4.0" 'license:cc-by-sa4.0)
@@ -163,6 +166,7 @@ of the string VERSION is replaced by the symbol 'version."
("EPL-1.0" 'license:epl1.0)
("MIT" 'license:expat)
("FTL" 'license:freetype)
+ ("Freetype" 'license:freetype)
("GFDL-1.1" 'license:fdl1.1+)
("GFDL-1.2" 'license:fdl1.2+)
("GFDL-1.3" 'license:fdl1.3+)
@@ -179,6 +183,7 @@ of the string VERSION is replaced by the symbol 'version."
("GPL-3.0-only" 'license:gpl3)
("GPL-3.0+" 'license:gpl3+)
("GPL-3.0-or-later" 'license:gpl3+)
+ ("HPND" 'license:hpnd)
("ISC" 'license:isc)
("IJG" 'license:ijg)
("Imlib2" 'license:imlib2)
@@ -231,9 +236,10 @@ to in the (guix licenses) module, or #f if there is no such known license."
with dashes."
(string-join (string-split (string-downcase str) #\_) "-"))
-(define (beautify-description description)
- "Improve the package DESCRIPTION by turning a beginning sentence fragment
-into a proper sentence and by using two spaces between sentences."
+(define* (beautify-description description #:optional (length 80))
+ "Improve the package DESCRIPTION by turning a beginning sentence fragment into
+a proper sentence and by using two spaces between sentences, and wrap lines at
+LENGTH characters."
(let ((cleaned (cond
((string-prefix? "A " description)
(string-append "This package provides a"
@@ -248,8 +254,9 @@ into a proper sentence and by using two spaces between sentences."
(string-length "Functions"))))
(else description))))
;; Use double spacing between sentences
- (regexp-substitute/global #f "\\. \\b"
- cleaned 'pre ". " 'post)))
+ (fill-paragraph (regexp-substitute/global #f "\\. \\b"
+ cleaned 'pre ". " 'post)
+ length)))
(define* (package-names->package-inputs names #:optional (output #f))
"Given a list of PACKAGE-NAMES or (PACKAGE-NAME VERSION) pairs, and an