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:
parent
140b304815
commit
3aae8145a7
|
@ -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 \
|
||||
|
|
|
@ -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}.
|
||||
|
|
|
@ -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)))))
|
|
@ -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
|
||||
|
|
|
@ -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~%"))))))
|
Loading…
Reference in New Issue