import: pypi: Allow imports of a specific version.

* guix/import/pypi.scm (latest-version): New procedure.
(latest-source-release): Rename to...
(source-release): ... this.  Add 'version' parameter.
(latest-wheel-release): Rename to...
(wheel-release): ... this.  Add 'version' parameter.
(pypi->guix-package): Honor 'version' parameter.
(pypi-recursive-import): Add 'version' parameter and honor it.
* guix/scripts/import/pypi.scm (guix-import-pypi): Expect a spec.  Pass
it to 'package-name->name+version'.  Pass the 'version' parameter.
* tests/pypi.scm ("pypi->guix-package, no wheel"): Exercise
the #:version parameter.
* doc/guix.texi (Invoking guix import): Document it.
This commit is contained in:
Ludovic Courtès 2021-10-28 22:14:40 +02:00
parent 650dcc18e7
commit b20cd80ff1
No known key found for this signature in database
GPG key ID: 090B11993D9AEBB5
4 changed files with 59 additions and 42 deletions

View file

@ -11723,13 +11723,19 @@ information, including package dependencies. For maximum efficiency, it
is recommended to install the @command{unzip} utility, so that the is recommended to install the @command{unzip} utility, so that the
importer can unzip Python wheels and gather data from them. importer can unzip Python wheels and gather data from them.
The command below imports metadata for the @code{itsdangerous} Python The command below imports metadata for the latest version of the
package: @code{itsdangerous} Python package:
@example @example
guix import pypi itsdangerous guix import pypi itsdangerous
@end example @end example
You can also ask for a specific version:
@example
guix import pypi itsdangerous@@1.1.0
@end example
@table @code @table @code
@item --recursive @item --recursive
@itemx -r @itemx -r

View file

@ -128,27 +128,30 @@ (define-condition-type &missing-source-error &error
missing-source-error? missing-source-error?
(package missing-source-error-package)) (package missing-source-error-package))
(define (latest-source-release pypi-package) (define (latest-version project)
"Return the latest source release for PYPI-PACKAGE." "Return the latest version of PROJECT, a <pypi-project> record."
(let ((releases (assoc-ref (pypi-project-releases pypi-package) (project-info-version (pypi-project-info project)))
(project-info-version
(pypi-project-info pypi-package))))) (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) (or (find (lambda (release)
(string=? "sdist" (distribution-package-type release))) (string=? "sdist" (distribution-package-type release)))
releases) releases)
(raise (condition (&missing-source-error (raise (condition (&missing-source-error
(package pypi-package))))))) (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, "Return the url of the wheel for the latest release of pypi-package,
or #f if there isn't any." or #f if there isn't any."
(let ((releases (assoc-ref (pypi-project-releases pypi-package) (let ((releases (assoc-ref (pypi-project-releases pypi-package) version)))
(project-info-version (find (lambda (release)
(pypi-project-info pypi-package))))) (string=? "bdist_wheel" (distribution-package-type release)))
(or (find (lambda (release) releases)))
(string=? "bdist_wheel" (distribution-package-type release)))
releases)
#f)))
(define (python->package-name name) (define (python->package-name name)
"Given the NAME of a package on PyPI, return a Guix-compliant name for the "Given the NAME of a package on PyPI, return a Guix-compliant name for the
@ -484,18 +487,17 @@ (define pypi->guix-package
"Fetch the metadata for PACKAGE-NAME from pypi.org, and return the "Fetch the metadata for PACKAGE-NAME from pypi.org, and return the
`package' s-expression corresponding to that package, or #f on failure." `package' s-expression corresponding to that package, or #f on failure."
(let* ((project (pypi-fetch package-name)) (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 (and project
(guard (c ((missing-source-error? c) (guard (c ((missing-source-error? c)
(let ((package (missing-source-error-package c))) (let ((package (missing-source-error-package c)))
(leave (G_ "no source release for pypi package ~a ~a~%") (leave (G_ "no source release for pypi package ~a ~a~%")
(project-info-name info) (project-info-name info) version))))
(project-info-version info))))) (make-pypi-sexp (project-info-name info) version
(make-pypi-sexp (project-info-name info) (and=> (source-release project version)
(project-info-version info)
(and=> (latest-source-release project)
distribution-url) distribution-url)
(and=> (latest-wheel-release project) (and=> (wheel-release project version)
distribution-url) distribution-url)
(project-info-home-page info) (project-info-home-page info)
(project-info-summary info) (project-info-summary info)
@ -503,8 +505,9 @@ (define pypi->guix-package
(string->license (string->license
(project-info-license info))))))))) (project-info-license info)))))))))
(define (pypi-recursive-import package-name) (define* (pypi-recursive-import package-name #:optional version)
(recursive-import package-name (recursive-import package-name
#:version version
#:repo->guix-package pypi->guix-package #:repo->guix-package pypi->guix-package
#:guix-name python->package-name)) #:guix-name python->package-name))
@ -538,7 +541,7 @@ (define (latest-release package)
(let* ((info (pypi-project-info pypi-package)) (let* ((info (pypi-project-info pypi-package))
(version (project-info-version info)) (version (project-info-version info))
(url (distribution-url (url (distribution-url
(latest-source-release pypi-package)))) (source-release pypi-package))))
(upstream-source (upstream-source
(urls (list url)) (urls (list url))
(input-changes (input-changes

View file

@ -27,6 +27,7 @@ (define-module (guix scripts import pypi)
#:use-module (srfi srfi-1) #:use-module (srfi srfi-1)
#:use-module (srfi srfi-11) #:use-module (srfi srfi-11)
#:use-module (srfi srfi-37) #:use-module (srfi srfi-37)
#:use-module (srfi srfi-71)
#:use-module (ice-9 match) #:use-module (ice-9 match)
#:use-module (ice-9 format) #:use-module (ice-9 format)
#:export (guix-import-pypi)) #:export (guix-import-pypi))
@ -83,21 +84,22 @@ (define (parse-options)
(_ #f)) (_ #f))
(reverse opts)))) (reverse opts))))
(match args (match args
((package-name) ((spec)
(if (assoc-ref opts 'recursive) (let ((name version (package-name->name+version spec)))
;; Recursive import (if (assoc-ref opts 'recursive)
(map (match-lambda ;; Recursive import
((and ('package ('name name) . rest) pkg) (map (match-lambda
`(define-public ,(string->symbol name) ((and ('package ('name name) . rest) pkg)
,pkg)) `(define-public ,(string->symbol name)
(_ #f)) ,pkg))
(pypi-recursive-import package-name)) (_ #f))
;; Single import (pypi-recursive-import name version))
(let ((sexp (pypi->guix-package package-name))) ;; Single import
(unless sexp (let ((sexp (pypi->guix-package name #:version version)))
(leave (G_ "failed to download meta-data for package '~a'~%") (unless sexp
package-name)) (leave (G_ "failed to download meta-data for package '~a'~%")
sexp))) name))
sexp))))
(() (()
(leave (G_ "too few arguments~%"))) (leave (G_ "too few arguments~%")))
((many ...) ((many ...)

View file

@ -260,9 +260,15 @@ (define test-metadata-with-extras-jedi "\
('synopsis "summary") ('synopsis "summary")
('description "summary") ('description "summary")
('license 'license:lgpl2.0)) ('license 'license:lgpl2.0))
(string=? (bytevector->nix-base32-string (and (string=? (bytevector->nix-base32-string
test-source-hash) test-source-hash)
hash)) hash)
(equal? (pypi->guix-package "foo" #:version "1.0.0")
(pypi->guix-package "foo"))
(catch 'quit
(lambda ()
(pypi->guix-package "foo" #:version "42"))
(const #t))))
(x (x
(pk 'fail x #f)))))) (pk 'fail x #f))))))