import: pypi: Gracefully handle non-existent packages.

Fixes <http://bugs.gnu.org/18831>.
Reported by Ian Denhardt <ian@zenhack.net>.

* guix/import/pypi.scm (url-fetch, json-fetch, pypi-fetch): Augment
  docstring to mention #f on failure.
  (pypi->guix-package): Likewise, and actually return #f on failure.
* guix/scripts/import/pypi.scm (guix-import-pypi): Call 'leave' when
  'pypi->guix-package' returns #f.
This commit is contained in:
Ludovic Courtès 2014-11-05 17:56:39 +01:00
parent 63854bcbb1
commit 467a3c93db
2 changed files with 20 additions and 14 deletions

View File

@ -89,12 +89,12 @@ recursively apply the procedure to the sub-list."
(_ #f))) (_ #f)))
(define (url-fetch url file-name) (define (url-fetch url file-name)
"Save the contents of URL to FILE-NAME." "Save the contents of URL to FILE-NAME. Return #f on failure."
(parameterize ((current-output-port (current-error-port))) (parameterize ((current-output-port (current-error-port)))
(build:url-fetch url file-name))) (build:url-fetch url file-name)))
(define (json-fetch url) (define (json-fetch url)
"Return an alist representation of the JSON resource URL." "Return an alist representation of the JSON resource URL, or #f on failure."
(call-with-temporary-output-file (call-with-temporary-output-file
(lambda (temp port) (lambda (temp port)
(and (url-fetch url temp) (and (url-fetch url temp)
@ -102,7 +102,8 @@ recursively apply the procedure to the sub-list."
(call-with-input-file temp json->scm)))))) (call-with-input-file temp json->scm))))))
(define (pypi-fetch name) (define (pypi-fetch name)
"Return an alist representation of the PyPI metadata for the package NAME." "Return an alist representation of the PyPI metadata for the package NAME,
or #f on failure."
(json-fetch (string-append "https://pypi.python.org/pypi/" name "/json"))) (json-fetch (string-append "https://pypi.python.org/pypi/" name "/json")))
(define (latest-source-release pypi-package) (define (latest-source-release pypi-package)
@ -160,8 +161,9 @@ VERSION, SOURCE-URL, HOME-PAGE, SYNOPSIS, DESCRIPTION, and LICENSE."
(define (pypi->guix-package package-name) (define (pypi->guix-package package-name)
"Fetch the metadata for PACKAGE-NAME from pypi.python.org, and return the "Fetch the metadata for PACKAGE-NAME from pypi.python.org, and return the
`package' s-expression corresponding to that package." `package' s-expression corresponding to that package, or #f on failure."
(let ((package (pypi-fetch package-name))) (let ((package (pypi-fetch package-name)))
(and package
(let ((name (assoc-ref* package "info" "name")) (let ((name (assoc-ref* package "info" "name"))
(version (assoc-ref* package "info" "version")) (version (assoc-ref* package "info" "version"))
(release (assoc-ref (latest-source-release package) "url")) (release (assoc-ref (latest-source-release package) "url"))
@ -170,4 +172,4 @@ VERSION, SOURCE-URL, HOME-PAGE, SYNOPSIS, DESCRIPTION, and LICENSE."
(home-page (assoc-ref* package "info" "home_page")) (home-page (assoc-ref* package "info" "home_page"))
(license (string->license (assoc-ref* package "info" "license")))) (license (string->license (assoc-ref* package "info" "license"))))
(make-pypi-sexp name version release home-page synopsis (make-pypi-sexp name version release home-page synopsis
description license)))) description license)))))

View File

@ -80,4 +80,8 @@ Import and convert the PyPI package for PACKAGE-NAME.\n"))
(reverse opts)))) (reverse opts))))
(match args (match args
((package-name) ((package-name)
(pypi->guix-package package-name))))) (let ((sexp (pypi->guix-package package-name)))
(unless sexp
(leave (_ "failed to download meta-data for package '~a'~%")
package-name))
sexp)))))