import: pypi: Also guess dependencies from *.egg-info/requires.txt.

* guix/import/pypi.scm (guess-requirements): Extract "requires.txt" from the
egg-info directory in addition to "requirements.txt"; strip off version
constraints; use call-with-temporary-directory.
This commit is contained in:
Ricardo Wurmus 2018-08-30 15:02:10 +02:00 committed by Ricardo Wurmus
parent a3ece51a29
commit e37f889404
No known key found for this signature in database
GPG Key ID: 197A5888235FACAC
1 changed files with 31 additions and 23 deletions

View File

@ -3,6 +3,7 @@
;;; Copyright © 2015 Cyril Roelandt <tipecaml@gmail.com> ;;; Copyright © 2015 Cyril Roelandt <tipecaml@gmail.com>
;;; Copyright © 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com> ;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
;;; Copyright © 2018 Ricardo Wurmus <rekado@elephly.net>
;;; ;;;
;;; This file is part of GNU Guix. ;;; This file is part of GNU Guix.
;;; ;;;
@ -36,7 +37,8 @@
#:use-module (guix utils) #:use-module (guix utils)
#:use-module ((guix build utils) #:use-module ((guix build utils)
#:select ((package-name->name+version #:select ((package-name->name+version
. hyphen-package-name->name+version))) . hyphen-package-name->name+version)
find-files))
#:use-module (guix import utils) #:use-module (guix import utils)
#:use-module ((guix download) #:prefix download:) #:use-module ((guix download) #:prefix download:)
#:use-module (guix import json) #:use-module (guix import json)
@ -114,9 +116,9 @@ package definition."
`((propagated-inputs (,'quasiquote ,package-inputs)))))) `((propagated-inputs (,'quasiquote ,package-inputs))))))
(define (guess-requirements source-url wheel-url tarball) (define (guess-requirements source-url wheel-url tarball)
"Given SOURCE-URL, WHEEL-URL and a TARBALL of the package, return a list of "Given SOURCE-URL, WHEEL-URL and a TARBALL of the package, return a list
the required packages specified in the requirements.txt file. TARBALL will be of the required packages specified in the requirements.txt file. TARBALL will
extracted in the current directory, and will be deleted." be extracted in a temporary directory."
(define (tarball-directory url) (define (tarball-directory url)
;; Given the URL of the package's tarball, return the name of the directory ;; Given the URL of the package's tarball, return the name of the directory
@ -140,8 +142,8 @@ cannot determine package dependencies"))
;; file, remove everything other than the actual name of the required ;; file, remove everything other than the actual name of the required
;; package, and return it. ;; package, and return it.
(string-take s (string-take s
(or (string-index s #\space) (or (string-index s (lambda (chr) (member chr '(#\space #\> #\= #\<))))
(string-length s)))) (string-length s))))
(define (comment? line) (define (comment? line)
;; Return #t if the given LINE is a comment, #f otherwise. ;; Return #t if the given LINE is a comment, #f otherwise.
@ -197,31 +199,37 @@ cannot determine package dependencies"))
(read-wheel-metadata temp)) (read-wheel-metadata temp))
#f)))) #f))))
(define (guess-requirements-from-source) (define (guess-requirements-from-source)
;; Return the package's requirements by guessing them from the source. ;; Return the package's requirements by guessing them from the source.
(let ((dirname (tarball-directory source-url))) (let ((dirname (tarball-directory source-url)))
(if (string? dirname) (if (string? dirname)
(let* ((req-file (string-append dirname "/requirements.txt")) (call-with-temporary-directory
(exit-code (system* "tar" "xf" tarball req-file))) (lambda (dir)
;; TODO: support more formats. (let* ((pypi-name (string-take dirname (string-rindex dirname #\-)))
(if (zero? exit-code) (req-files (list (string-append dirname "/requirements.txt")
(dynamic-wind (string-append dirname "/" pypi-name ".egg-info"
(const #t) "/requires.txt")))
(lambda () (exit-codes (map (lambda (file-name)
(read-requirements req-file)) (parameterize ((current-error-port (%make-void-port "rw+"))
(lambda () (current-output-port (%make-void-port "rw+")))
(delete-file req-file) (system* "tar" "xf" tarball "-C" dir file-name)))
(rmdir dirname))) req-files)))
(begin ;; Only one of these files needs to exist.
(warning (G_ "'tar xf' failed with exit code ~a\n") (if (any zero? exit-codes)
exit-code) (match (find-files dir)
'()))) ((file . _)
(read-requirements file))
(()
(warning (G_ "No requirements file found.\n"))))
(begin
(warning (G_ "Failed to extract requirements files\n"))
'())))))
'()))) '())))
;; First, try to compute the requirements using the wheel, since that is the ;; First, try to compute the requirements using the wheel, since that is the
;; most reliable option. If a wheel is not provided for this package, try ;; most reliable option. If a wheel is not provided for this package, try
;; getting them by reading the "requirements.txt" file from the source. Note ;; getting them by reading either the "requirements.txt" file or the
;; "requires.txt" from the egg-info directory from the source tarball. Note
;; that "requirements.txt" is not mandatory, so this is likely to fail. ;; that "requirements.txt" is not mandatory, so this is likely to fail.
(or (guess-requirements-from-wheel) (or (guess-requirements-from-wheel)
(guess-requirements-from-source))) (guess-requirements-from-source)))