From: David Thompson <dthompson2@worcester.edu>
To: Cyril Roelandt <tipecaml@gmail.com>, guix-devel@gnu.org
Subject: Re: [PATCH] import: pypi: detect requirements from requirements.txt.
Date: Sat, 07 Mar 2015 19:41:14 -0500 [thread overview]
Message-ID: <87y4n82udx.fsf@fsf.org> (raw)
In-Reply-To: <1425772288-8771-1-git-send-email-tipecaml@gmail.com>
Awesome! :)
How about this for the commit log:
"import: pypi: Detect inputs."
?
Cyril Roelandt <tipecaml@gmail.com> writes:
> * guix/import/pypi.scm (compute-inputs, guess-requirements): New functions.
"New procedures."
> ---
> guix/import/pypi.scm | 146 ++++++++++++++++++++++++++++++++++++++++-----------
> 1 file changed, 115 insertions(+), 31 deletions(-)
>
> diff --git a/guix/import/pypi.scm b/guix/import/pypi.scm
> index 8567cad..9ac3342 100644
> --- a/guix/import/pypi.scm
> +++ b/guix/import/pypi.scm
> @@ -21,6 +21,7 @@
> #:use-module (ice-9 match)
> #:use-module (ice-9 pretty-print)
> #:use-module (ice-9 regex)
> + #:use-module ((ice-9 rdelim) #:select (read-line))
> #:use-module (srfi srfi-1)
> #:use-module (rnrs bytevectors)
> #:use-module (json)
> @@ -77,42 +78,125 @@ or #f on failure."
> with dashes."
> (string-join (string-split (string-downcase str) #\_) "-"))
>
> -(define (guix-hash-url url)
> - "Download the resource at URL and return the hash in nix-base32 format."
> - (call-with-temporary-output-file
> - (lambda (temp port)
> - (and (url-fetch url temp)
> - (bytevector->nix-base32-string
> - (call-with-input-file temp port-sha256))))))
> +(define (guix-hash-url filename)
> + "Return the hash of FILENAME in nix-base32 format."
> + (bytevector->nix-base32-string
> + (call-with-input-file filename port-sha256)))
> +
> +(define (guix-name name)
> + (if (string-prefix? "python-" name)
> + (snake-case name)
> + (string-append "python-" (snake-case name))))
> +
> +(define (maybe-inputs guix-name inputs)
> + (match inputs
> + (()
> + '())
> + ((inputs ...)
> + (list (list guix-name
> + (list 'quasiquote inputs))))))
How about:
`((,guix-name ,(list 'quasiquote inputs)))
Or:
`((,guix-name (,'quasiquote ,inputs)))
> +
> +(define (guess-requirements source-url tarball)
> + "Given SOURCE-URL and a TARBALL of the package, return a list of the required
> +packages specified in the requirements.txt file."
> +
> + (define (tarball-directory url)
> + "Given the URL of the package's tarball, return the name of the directory
> +that will be created upon decompressing it."
> + ;; TODO: Support more archive formats.
> + (let ((basename (substring url (+ 1 (string-rindex url #\/)))))
> + (cond
> + ((string-suffix? ".tar.gz" basename)
> + (string-drop-right basename 7))
> + ((string-suffix? ".tar.bz2" basename)
> + (string-drop-right basename 8))
> + (else #f))))
> +
> + (define (read-requirements requirements-file)
> + "Given REQUIREMENTS-FILE, a Python requirements.txt file, return a list of
> +name/variable pairs describing the requirements."
> + (call-with-input-file requirements-file
> + (lambda (port)
> + (let loop ((result '()))
> + (let ((line (read-line port)))
> + (if (eof-object? line)
> + result
> + (loop (if (or (string-null? line)
> + (eq? (string-ref line 0) #\#))
For readability, consider extracting `(eq? (string-ref line 0) #\#)` to
an inner procedure named 'comment?'
> + result
> + (let ((input (guix-name (clean-requirement line))))
> + ;; Argparse has been part of Python since 2.7.
> + (if (string=? input "python-argparse")
> + result
> + (cons input result)))))))))))
There's a lot of nested 'if' forms here. I think it could be
restructured into a more readable 'cond' by moving these conditionals
outside of the call to 'loop' and filtering out "python-argpase" as a
final step rather than doing it while you are still reading the file.
> +
> + (define (clean-requirement s)
> + "Given a requirement LINE, as can be found in a Python requirements.txt
> +file, remove everything other than the actual name of the required package, and
> +return it."
> + (string-take s
> + (or (string-index s (lambda (c)
> + (member c '(#\< #\> #\= #\#))))
> + (string-length s))))
> +
> + (let* ((dirname (tarball-directory source-url))
> + (req-file (if (string? dirname)
> + (string-append dirname "/requirements.txt")
> + #f)))
(and (string? dirname) (string-append dirname "/requirements.txt"))
> + (if (and (string? req-file)
If 'dirname' was a string, then 'req-file' is certainly a string, so I
think you can just test dirname above and never go down this code path
if it isn't a string.
> + ;; TODO: support more formats.
> + (zero? (system* "tar" "xf" tarball req-file)))
> + (dynamic-wind
> + (const #t)
> + (lambda ()
> + (read-requirements req-file))
> + (lambda ()
> + (delete-file req-file)
> + (rmdir dirname)))
> + '())))
> +
> +(define (compute-inputs source-url tarball)
> + "Given the SOURCE-URL of an already downloaded TARBALL, return a list of
> +name/variable pairs describing the required inputs of this package."
> + (sort
> + (map (lambda (input)
> + (list input (list 'unquote (string->symbol input))))
> + (append '("python-setuptools")
> + (guess-requirements source-url tarball)))
> + (lambda args
> + (match args
> + (((a _ ...) (b _ ...))
> + (string-ci<? a b))))))
>
> (define (make-pypi-sexp name version source-url home-page synopsis
> description license)
> "Return the `package' s-expression for a python package with the given NAME,
> VERSION, SOURCE-URL, HOME-PAGE, SYNOPSIS, DESCRIPTION, and LICENSE."
> - `(package
> - (name ,(if (string-prefix? "python-" name)
> - (snake-case name)
> - (string-append "python-" (snake-case name))))
> - (version ,version)
> - (source (origin
> - (method url-fetch)
> - (uri (string-append ,@(factorize-uri source-url version)))
> - (sha256
> - (base32
> - ,(guix-hash-url source-url)))))
> - (build-system python-build-system)
> - (inputs
> - `(("python-setuptools" ,python-setuptools)))
> - (home-page ,home-page)
> - (synopsis ,synopsis)
> - (description ,description)
> - (license ,(assoc-ref `((,lgpl2.0 . lgpl2.0)
> - (,gpl3 . gpl3)
> - (,bsd-3 . bsd-3)
> - (,expat . expat)
> - (,public-domain . public-domain)
> - (,asl2.0 . asl2.0))
> - license))))
> + (call-with-temporary-output-file
> + (lambda (temp port)
> + (and (url-fetch source-url temp)
> + `(package
> + (name ,(guix-name name))
> + (version ,version)
> + (source (origin
> + (method url-fetch)
> + (uri (string-append ,@(factorize-uri source-url version)))
> + (sha256
> + (base32
> + ,(guix-hash-url temp)))))
> + (build-system python-build-system)
> + ,@(maybe-inputs 'inputs
> + (compute-inputs source-url temp))
Fix identation: |------------^
> + (home-page ,home-page)
> + (synopsis ,synopsis)
> + (description ,description)
> + (license ,(assoc-ref `((,lgpl2.0 . lgpl2.0)
> + (,gpl3 . gpl3)
> + (,bsd-3 . bsd-3)
> + (,expat . expat)
> + (,public-domain . public-domain)
> + (,asl2.0 . asl2.0))
> + license)))))))
>
> (define (pypi->guix-package package-name)
> "Fetch the metadata for PACKAGE-NAME from pypi.python.org, and return the
> --
> 1.8.4.rc3
>
>
Hope the above wasn't overwhelming. Could you send an updated patch?
Thanks for working on this!
--
David Thompson
Web Developer - Free Software Foundation - http://fsf.org
GPG Key: 0FF1D807
Support the FSF: https://fsf.org/donate
next prev parent reply other threads:[~2015-03-08 0:41 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-03-07 23:51 [PATCH] import: pypi: detect requirements from requirements.txt Cyril Roelandt
2015-03-08 0:41 ` David Thompson [this message]
2015-03-22 21:05 ` [PATCH] import: pypi: Detect inputs Cyril Roelandt
2015-03-26 13:15 ` Ludovic Courtès
2015-03-27 12:36 ` David Thompson
2015-03-29 13:46 ` Ludovic Courtès
2015-06-04 22:56 ` Cyril Roelandt
2015-06-07 20:03 ` Ludovic Courtès
2015-06-15 1:25 ` Cyril Roelandt
2015-06-18 10:45 ` Amirouche Boubekki
2015-06-19 15:32 ` Christopher Allan Webber
2015-06-20 18:01 ` Amirouche Boubekki
2015-06-21 20:56 ` Ludovic Courtès
2015-06-21 21:32 ` Amirouche Boubekki
2015-06-23 21:04 ` Cyril Roelandt
2015-06-24 19:49 ` Ludovic Courtès
2015-06-24 21:42 ` Cyril Roelandt
2015-03-22 21:05 ` [PATCH] import: pypi: detect requirements from requirements.txt Cyril Roelandt
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://guix.gnu.org/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87y4n82udx.fsf@fsf.org \
--to=dthompson2@worcester.edu \
--cc=guix-devel@gnu.org \
--cc=tipecaml@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/guix.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).