From e83c6d009fb0cdefe7c4fa66c8a8c6b1c2071d61 Mon Sep 17 00:00:00 2001 From: David Thompson Date: Sun, 26 Jul 2015 22:01:54 -0400 Subject: build: ruby: Rewrite build system to use gem archives. Co-Authored-By: Pjotr Prins * guix/build-system/ruby.scm (lower): Remove git dependency. (rubygems-uri): New procedure. * guix/build/ruby-build-system (gitify): Delete. (unpack): Use 'gem unpack' utility. (check): Add docstring. (build): Repack modified gem. (install): Rebuild unpacked gem and install it. (%standard-phases): Remove gitify and build phases. * gnu/packages/ruby.scm (ruby-hoe, ruby-rake-compiler, ruby-i18n, ruby-rspec-support, ruby-rspec-core, ruby-diff-lcs-for-rspec, ruby-rspec-expectations, ruby-rspec-mocks, ruby-rspec, bundler, ruby-useragent, ruby-bacon, ruby-arel, ruby-connection-pool, ruby-net-http-persistent, ruby-minitest, ruby-minitest-sprint, ruby-minitest-bacon, ruby-daemons, ruby-git, ruby-slop, ruby-multipart-post): Convert to new build system. * doc/guix.texi (ruby-build-system): Document the gem archive requirement. --- guix/build-system/ruby.scm | 40 ++++++++++++---------- guix/build/ruby-build-system.scm | 72 +++++++++++++++++++++++++++++----------- 2 files changed, 74 insertions(+), 38 deletions(-) (limited to 'guix') diff --git a/guix/build-system/ruby.scm b/guix/build-system/ruby.scm index 135eda665b..8142e8551a 100644 --- a/guix/build-system/ruby.scm +++ b/guix/build-system/ruby.scm @@ -26,10 +26,16 @@ #:use-module (guix build-system) #:use-module (guix build-system gnu) #:use-module (ice-9 match) - #:export (%ruby-build-system-modules + #:export (rubygems-uri + %ruby-build-system-modules ruby-build ruby-build-system)) +(define (rubygems-uri name version) + "Return a URI string for the gem archive for the release corresponding to +NAME and VERSION." + (string-append "https://rubygems.org/downloads/" name "-" version ".gem")) + (define %ruby-build-system-modules ;; Build-side modules imported by default. `((guix build ruby-build-system) @@ -50,24 +56,22 @@ (define private-keywords '(#:source #:target #:ruby #:inputs #:native-inputs)) - (let ((version-control (resolve-interface '(gnu packages version-control)))) - (and (not target) ;XXX: no cross-compilation - (bag - (name name) - (system system) - (host-inputs `(,@(if source - `(("source" ,source)) - '()) - ,@inputs + (and (not target) ;XXX: no cross-compilation + (bag + (name name) + (system system) + (host-inputs `(,@(if source + `(("source" ,source)) + '()) + ,@inputs - ;; Keep the standard inputs of 'gnu-build-system'. - ,@(standard-packages))) - (build-inputs `(("ruby" ,ruby) - ("git" ,(module-ref version-control 'git)) - ,@native-inputs)) - (outputs outputs) - (build ruby-build) - (arguments (strip-keyword-arguments private-keywords arguments)))))) + ;; Keep the standard inputs of 'gnu-build-system'. + ,@(standard-packages))) + (build-inputs `(("ruby" ,ruby) + ,@native-inputs)) + (outputs outputs) + (build ruby-build) + (arguments (strip-keyword-arguments private-keywords arguments))))) (define* (ruby-build store name inputs #:key diff --git a/guix/build/ruby-build-system.scm b/guix/build/ruby-build-system.scm index 307ac919dd..90fab92f6a 100644 --- a/guix/build/ruby-build-system.scm +++ b/guix/build/ruby-build-system.scm @@ -21,6 +21,7 @@ #:use-module ((guix build gnu-build-system) #:prefix gnu:) #:use-module (guix build utils) #:use-module (ice-9 match) + #:use-module (ice-9 popen) #:use-module (ice-9 regex) #:use-module (srfi srfi-1) #:use-module (srfi srfi-26) @@ -40,41 +41,72 @@ directory." ((file-name . _) file-name) (() (error "No files matching pattern: " pattern)))) -;; Most gemspecs assume that builds are taking place within a git repository -;; by include calls to 'git ls-files'. In order for these gemspecs to work -;; as-is, every file in the source tree is added to the staging area. -(define gitify - (lambda _ - (and (zero? (system* "git" "init")) - (zero? (system* "git" "add" "."))))) +(define* (unpack #:key source #:allow-other-keys) + "Unpack the gem SOURCE and enter the resulting directory." + (and (zero? (system* "gem" "unpack" source)) + (begin + ;; The unpacked gem directory is named the same as the archive, sans + ;; the ".gem" extension. + (chdir (match:substring (string-match "^(.*)\\.gem$" + (basename source)) + 1)) + #t))) -(define build - (lambda _ - (match (find-files "." "\\.gemspec$") - ;; No gemspec, try 'rake gem' instead. - (() - (zero? (system* "rake" "gem"))) - ;; Build the first matching gemspec. - ((gemspec . _) - (zero? (system* "gem" "build" gemspec)))))) +(define* (build #:key source #:allow-other-keys) + "Build a new gem using the gemspec from the SOURCE gem." + + ;; Remove the original gemspec, if present, and replace it with a new one. + ;; This avoids issues with upstream gemspecs requiring tools such as git to + ;; generate the files list. + (let ((gemspec (or (false-if-exception + (first-matching-file "\\.gemspec$")) + ;; Make new gemspec if one wasn't shipped. + ".gemspec"))) + + (when (file-exists? gemspec) (delete-file gemspec)) + + ;; Extract gemspec from source gem. + (let ((pipe (open-pipe* OPEN_READ "gem" "spec" "--ruby" source))) + (dynamic-wind + (const #t) + (lambda () + (call-with-output-file gemspec + (lambda (out) + ;; 'gem spec' writes to stdout, but 'gem build' only reads + ;; gemspecs from a file, so we redirect the output to a file. + (while (not (eof-object? (peek-char pipe))) + (write-char (read-char pipe) out)))) + #t) + (lambda () + (close-pipe pipe)))) + + ;; Build a new gem from the current working directory. This also allows any + ;; dynamic patching done in previous phases to be present in the installed + ;; gem. + (zero? (system* "gem" "build" gemspec)))) (define* (check #:key tests? test-target #:allow-other-keys) + "Run the gem's test suite rake task TEST-TARGET. Skip the tests if TESTS? +is #f." (if tests? (zero? (system* "rake" test-target)) #t)) -(define* (install #:key source inputs outputs (gem-flags '()) +(define* (install #:key inputs outputs (gem-flags '()) #:allow-other-keys) + "Install the gem archive SOURCE to the output store item. Additional +GEM-FLAGS are passed to the 'gem' invokation, if present." (let* ((ruby-version (match:substring (string-match "ruby-(.*)\\.[0-9]$" (assoc-ref inputs "ruby")) 1)) (out (assoc-ref outputs "out")) (gem-home (string-append out "/lib/ruby/gems/" ruby-version ".0"))) + (setenv "GEM_HOME" gem-home) (mkdir-p gem-home) - (zero? (apply system* "gem" "install" "--local" - (first-matching-file "\\.gem$") + (zero? (apply system* "gem" "install" (first-matching-file "\\.gem$") + "--local" "--ignore-dependencies" ;; Executables should go into /bin, not /lib/ruby/gems. "--bindir" (string-append out "/bin") gem-flags)))) @@ -82,8 +114,8 @@ directory." (define %standard-phases (modify-phases gnu:%standard-phases (delete 'configure) - (add-after 'unpack 'gitify gitify) (replace 'build build) + (replace 'unpack unpack) (replace 'install install) (replace 'check check))) -- cgit v1.2.3