import: Add Ruby gem importer.

* gnu/scripts/import.scm (importers): Add "gem".
* gnu/import/gem.scm: New file.
* gnu/scripts/import/gem.scm: New file.
* Makefile.am (MODULES): Add them.
* guix.texi ("invoking guix import"): Document it.
This commit is contained in:
David Thompson 2015-08-16 21:15:45 -04:00
parent 140b304815
commit 3aae8145a7
5 changed files with 244 additions and 2 deletions

View File

@ -221,7 +221,8 @@ MODULES += \
guix/import/pypi.scm \
guix/scripts/import/pypi.scm \
guix/import/cpan.scm \
guix/scripts/import/cpan.scm
guix/scripts/import/gem.scm \
guix/import/gem.scm
SCM_TESTS += \
tests/pypi.scm \

View File

@ -3894,6 +3894,25 @@ package:
guix import pypi itsdangerous
@end example
@item gem
@cindex gem
Import meta-data from @uref{https://rubygems.org/,
RubyGems}@footnote{This functionality requires Guile-JSON to be
installed. @xref{Requirements}.}. Information is taken from the
JSON-formatted description available at @code{rubygems.org} and includes
most relevant information, including runtime dependencies. There are
some caveats, however. The meta-data doesn't distinguish between
synopses and descriptions, so the same string is used for both fields.
Additionally, the details of non-Ruby dependencies required to build
native extensions is unavailable and left as an exercise to the
packager.
The command below imports meta-data for the @code{rails} Ruby package:
@example
guix import gem rails
@end example
@item cpan
@cindex CPAN
Import meta-data from @uref{https://www.metacpan.org/, MetaCPAN}.

131
guix/import/gem.scm Normal file
View File

@ -0,0 +1,131 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2015 David Thompson <davet@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
;;; GNU Guix is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or (at
;;; your option) any later version.
;;;
;;; GNU Guix is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
(define-module (guix import gem)
#:use-module (ice-9 match)
#:use-module (ice-9 pretty-print)
#:use-module (rnrs bytevectors)
#:use-module (json)
#:use-module (web uri)
#:use-module (guix import utils)
#:use-module (guix import json)
#:use-module (guix packages)
#:use-module (guix licenses)
#:use-module (guix base32)
#:export (gem->guix-package))
(define (rubygems-fetch name)
"Return an alist representation of the RubyGems metadata for the package NAME,
or #f on failure."
(json-fetch
(string-append "https://rubygems.org/api/v1/gems/" name ".json")))
(define (ruby-package-name name)
"Given the NAME of a package on RubyGems, return a Guix-compliant name for
the package."
(if (string-prefix? "ruby-" name)
(snake-case name)
(string-append "ruby-" (snake-case name))))
(define (hex-string->bytevector str)
"Convert the hexadecimal encoded string STR to a bytevector."
(define hex-char->int
(match-lambda
(#\0 0)
(#\1 1)
(#\2 2)
(#\3 3)
(#\4 4)
(#\5 5)
(#\6 6)
(#\7 7)
(#\8 8)
(#\9 9)
(#\a 10)
(#\b 11)
(#\c 12)
(#\d 13)
(#\e 14)
(#\f 15)))
(define (read-byte i)
(let ((j (* 2 i)))
(+ (hex-char->int (string-ref str (1+ j)))
(* (hex-char->int (string-ref str j)) 16))))
(let* ((len (/ (string-length str) 2))
(bv (make-bytevector len)))
(let loop ((i 0))
(if (= i len)
bv
(begin
(bytevector-u8-set! bv i (read-byte i))
(loop (1+ i)))))))
(define (make-gem-sexp name version hash home-page description
dependencies licenses)
"Return the `package' s-expression for a Ruby package with the given NAME,
VERSION, HASH, HOME-PAGE, DESCRIPTION, DEPENDENCIES, and LICENSES."
`(package
(name ,(ruby-package-name name))
(version ,version)
(source (origin
(method url-fetch)
(uri (rubygems-uri ,name version))
(sha256
(base32
,(bytevector->nix-base32-string
(hex-string->bytevector hash))))))
(build-system ruby-build-system)
,@(if (null? dependencies)
'()
`((propagated-inputs
(,'quasiquote
,(map (lambda (name)
`(,name
(,'unquote
,(string->symbol name))))
dependencies)))))
(synopsis ,description) ; nothing better to use
(description ,description)
(home-page ,home-page)
(license ,(match licenses
((license) (license->symbol license))
(_ (map license->symbol licenses))))))
(define* (gem->guix-package package-name #:optional version)
"Fetch the metadata for PACKAGE-NAME from rubygems.org, and return the
`package' s-expression corresponding to that package, or #f on failure."
(let ((package (rubygems-fetch package-name)))
(and package
(let ((name (assoc-ref package "name"))
(version (assoc-ref package "version"))
(hash (assoc-ref package "sha"))
(description (assoc-ref package "info"))
(home-page (assoc-ref package "homepage_uri"))
(dependencies (map (lambda (dep)
(let ((name (assoc-ref dep "name")))
(if (string=? name "bundler")
"bundler" ; special case, no prefix
(ruby-package-name name))))
(assoc-ref* package "dependencies"
"runtime")))
(licenses (map string->license
(assoc-ref package "licenses"))))
(make-gem-sexp name version hash home-page
description dependencies licenses)))))

View File

@ -73,7 +73,7 @@ rather than \\n."
;;; Entry point.
;;;
(define importers '("gnu" "nix" "pypi" "cpan" "hackage" "elpa"))
(define importers '("gnu" "nix" "pypi" "cpan" "hackage" "elpa" "gem"))
(define (resolve-importer name)
(let ((module (resolve-interface

View File

@ -0,0 +1,91 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2015 David Thompson <davet@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
;;; GNU Guix is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or (at
;;; your option) any later version.
;;;
;;; GNU Guix is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
(define-module (guix scripts import gem)
#:use-module (guix ui)
#:use-module (guix utils)
#:use-module (guix import gem)
#:use-module (guix scripts import)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-11)
#:use-module (srfi srfi-37)
#:use-module (ice-9 match)
#:use-module (ice-9 format)
#:export (guix-import-gem))
;;;
;;; Command-line options.
;;;
(define %default-options
'())
(define (show-help)
(display (_ "Usage: guix import gem PACKAGE-NAME
Import and convert the RubyGems package for PACKAGE-NAME.\n"))
(display (_ "
-h, --help display this help and exit"))
(display (_ "
-V, --version display version information and exit"))
(newline)
(show-bug-report-information))
(define %options
;; Specification of the command-line options.
(cons* (option '(#\h "help") #f #f
(lambda args
(show-help)
(exit 0)))
(option '(#\V "version") #f #f
(lambda args
(show-version-and-exit "guix import pypi")))
%standard-import-options))
;;;
;;; Entry point.
;;;
(define (guix-import-gem . args)
(define (parse-options)
;; Return the alist of option values.
(args-fold* args %options
(lambda (opt name arg result)
(leave (_ "~A: unrecognized option~%") name))
(lambda (arg result)
(alist-cons 'argument arg result))
%default-options))
(let* ((opts (parse-options))
(args (filter-map (match-lambda
(('argument . value)
value)
(_ #f))
(reverse opts))))
(match args
((package-name)
(let ((sexp (gem->guix-package package-name)))
(unless sexp
(leave (_ "failed to download meta-data for package '~a'~%")
package-name))
sexp))
(()
(leave (_ "too few arguments~%")))
((many ...)
(leave (_ "too many arguments~%"))))))