guix-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

01/01: gnu: Add crate-recursive-import.


From: guix-commits
Subject: 01/01: gnu: Add crate-recursive-import.
Date: Thu, 19 Sep 2019 20:35:23 -0400 (EDT)

leungbk pushed a commit to branch crate-recursive-import
in repository guix.

commit 751bf2367edf54015792f339dcaca797cd7da937
Author: Brian Leung <address@hidden>
Date:   Sat Jul 20 21:35:14 2019 +0200

    gnu: Add crate-recursive-import.
    
    * guix/import/crate.scm (crate-recursive-import): New variable.
    * guix/script/import/crate.scm: Add recursive option.
    * guix/tests/crate.scm (crate-recursive-import): New test.
    ---
---
 guix/import/crate.scm         | 131 +++++++++++++++++---------------
 guix/import/utils.scm         |  16 ++--
 guix/scripts/import/crate.scm |  32 ++++++--
 tests/crate.scm               | 173 ++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 273 insertions(+), 79 deletions(-)

diff --git a/guix/import/crate.scm b/guix/import/crate.scm
index f6057db..5e81c01 100644
--- a/guix/import/crate.scm
+++ b/guix/import/crate.scm
@@ -38,6 +38,7 @@
   #:use-module (srfi srfi-2)
   #:use-module (srfi srfi-26)
   #:export (crate->guix-package
+            crate-recursive-import
             guix-package->crate-name
             %crate-updater))
 
@@ -147,78 +148,86 @@ VERSION, CARGO-INPUTS, CARGO-DEVELOPMENT-INPUTS, 
HOME-PAGE, SYNOPSIS, DESCRIPTIO
 and LICENSE."
   (let* ((port (http-fetch (crate-uri name version)))
          (guix-name (crate-name->package-name name))
-         (cargo-inputs (map crate-name->package-name cargo-inputs))
-         (cargo-development-inputs (map crate-name->package-name
+         (inputs (map crate-name->package-name cargo-inputs))
+         (development-inputs (map crate-name->package-name
                                         cargo-development-inputs))
          (pkg `(package
-                   (name ,guix-name)
-                   (version ,version)
-                   (source (origin
-                             (method url-fetch)
-                             (uri (crate-uri ,name version))
-                             (file-name (string-append name "-" version 
".tar.gz"))
-                             (sha256
-                              (base32
-                               ,(bytevector->nix-base32-string (port-sha256 
port))))))
-                   (build-system cargo-build-system)
-                   ,@(maybe-arguments (append (maybe-cargo-inputs cargo-inputs)
-                                              (maybe-cargo-development-inputs
-                                                cargo-development-inputs)))
-                   (home-page ,(match home-page
-                                 (() "")
-                                 (_ home-page)))
-                   (synopsis ,synopsis)
-                   (description ,(beautify-description description))
-                   (license ,(match license
-                               (() #f)
-                               ((license) license)
-                               (_ `(list ,@license)))))))
-         (close-port port)
-         pkg))
+                 (name ,guix-name)
+                 (version ,version)
+                 (source (origin
+                           (method url-fetch)
+                           (uri (crate-uri ,name version))
+                           (file-name (string-append name "-" version 
".tar.gz"))
+                           (sha256
+                            (base32
+                             ,(bytevector->nix-base32-string (port-sha256 
port))))))
+                 (build-system cargo-build-system)
+                 ,@(maybe-arguments (append (maybe-cargo-inputs inputs)
+                                            (maybe-cargo-development-inputs
+                                             development-inputs)))
+                 (home-page ,(match home-page
+                               (() "")
+                               (_ home-page)))
+                 (synopsis ,synopsis)
+                 (description ,(beautify-description description))
+                 (license ,(match license
+                             (() #f)
+                             ((license) license)
+                             (_ `(list ,@license)))))))
+    (close-port port)
+    (values pkg
+            (lset-union equal? cargo-inputs cargo-development-inputs))))
 
 (define %dual-license-rx
   ;; Dual licensing is represented by a string such as "MIT OR Apache-2.0".
   ;; This regexp matches that.
   (make-regexp "^(.*) OR (.*)$"))
 
-(define (crate->guix-package crate-name)
-  "Fetch the metadata for CRATE-NAME from crates.io, and return the
-`package' s-expression corresponding to that package, or #f on failure."
-  (define (string->license string)
-    (match (regexp-exec %dual-license-rx string)
-      (#f (list (spdx-string->license string)))
-      (m  (list (spdx-string->license (match:substring m 1))
-                (spdx-string->license (match:substring m 2))))))
+(define (string->license string)
+  (match (regexp-exec %dual-license-rx string)
+    (#f (list (spdx-string->license string)))
+    (m  (list (spdx-string->license (match:substring m 1))
+              (spdx-string->license (match:substring m 2))))))
+
+(define (normal-dependency? dependency)
+  (eq? (crate-dependency-kind dependency) 'normal))
 
-  (define (normal-dependency? dependency)
-    (eq? (crate-dependency-kind dependency) 'normal))
+(define crate->guix-package
+  (memoize
+   (lambda (crate-name)
+     "Fetch the metadata for CRATE-NAME from crates.io, and return the
+`package' s-expression corresponding to that package, or #f on failure."
+     (define crate
+       (lookup-crate crate-name))
 
-  (define crate
-    (lookup-crate crate-name))
+     (and crate
+          (let* ((version        (find (lambda (version)
+                                         (string=? (crate-version-number 
version)
+                                                   (crate-latest-version 
crate)))
+                                       (crate-versions crate)))
+                 (dependencies   (crate-version-dependencies version))
+                 (dep-crates     (filter normal-dependency? dependencies))
+                 (dev-dep-crates (remove normal-dependency? dependencies))
+                 (cargo-inputs   (sort (map crate-dependency-id dep-crates)
+                                       string-ci<?))
+                 (cargo-development-inputs
+                  (sort (map crate-dependency-id dev-dep-crates)
+                        string-ci<?)))
+            (make-crate-sexp #:name crate-name
+                             #:version (crate-version-number version)
+                             #:cargo-inputs cargo-inputs
+                             #:cargo-development-inputs 
cargo-development-inputs
+                             #:home-page (or (crate-home-page crate)
+                                             (crate-repository crate))
+                             #:synopsis (crate-description crate)
+                             #:description (crate-description crate)
+                             #:license (and=> (crate-version-license version)
+                                              string->license)))))))
 
-  (and crate
-       (let* ((version        (find (lambda (version)
-                                      (string=? (crate-version-number version)
-                                                (crate-latest-version crate)))
-                                    (crate-versions crate)))
-              (dependencies   (crate-version-dependencies version))
-              (dep-crates     (filter normal-dependency? dependencies))
-              (dev-dep-crates (remove normal-dependency? dependencies))
-              (cargo-inputs   (sort (map crate-dependency-id dep-crates)
-                                    string-ci<?))
-              (cargo-development-inputs
-               (sort (map crate-dependency-id dev-dep-crates)
-                     string-ci<?)))
-         (make-crate-sexp #:name crate-name
-                          #:version (crate-version-number version)
-                          #:cargo-inputs cargo-inputs
-                          #:cargo-development-inputs cargo-development-inputs
-                          #:home-page (or (crate-home-page crate)
-                                          (crate-repository crate))
-                          #:synopsis (crate-description crate)
-                          #:description (crate-description crate)
-                          #:license (and=> (crate-version-license version)
-                                           string->license)))))
+(define* (crate-recursive-import package-name)
+  (recursive-import package-name #f
+                    #:repo->guix-package (lambda (name _) (crate->guix-package 
name))
+                    #:guix-name crate-name->package-name))
 
 (define (guix-package->crate-name package)
   "Return the crate name of PACKAGE."
diff --git a/guix/import/utils.scm b/guix/import/utils.scm
index 252875e..e58f5cb 100644
--- a/guix/import/utils.scm
+++ b/guix/import/utils.scm
@@ -381,16 +381,16 @@ dependencies."
       ((prev (next . rest) done)
        (define (handle? dep)
          (and
-           (not (equal? dep next))
-           (not (member dep done))
-           (not (exists? dep))))
+          (not (equal? dep next))
+          (not (member dep done))
+          (not (exists? dep))))
        (receive (package . dependencies) (repo->guix-package next repo)
          (list
-           (if package package '()) ;; default #f on failure would interrupt
-           (if package
-             (lset-union equal? rest (filter handle? (car dependencies)))
-             rest)
-           (cons next done))))
+          (or package next)
+          (if package
+              (lset-union equal? rest (filter handle? (car dependencies)))
+              rest)
+          (cons next done))))
       ((prev '() done)
        (list #f '() done))))
 
diff --git a/guix/scripts/import/crate.scm b/guix/scripts/import/crate.scm
index cab9a43..9970b1a 100644
--- a/guix/scripts/import/crate.scm
+++ b/guix/scripts/import/crate.scm
@@ -27,6 +27,7 @@
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-11)
   #:use-module (srfi srfi-37)
+  #:use-module (srfi srfi-41)
   #:use-module (ice-9 match)
   #:use-module (ice-9 format)
   #:export (guix-import-crate))
@@ -45,6 +46,8 @@ Import and convert the crate.io package for PACKAGE-NAME.\n"))
   (display (G_ "
   -h, --help             display this help and exit"))
   (display (G_ "
+  -r, --recursive        import packages recursively"))
+  (display (G_ "
   -V, --version          display version information and exit"))
   (newline)
   (show-bug-report-information))
@@ -58,6 +61,9 @@ Import and convert the crate.io package for PACKAGE-NAME.\n"))
          (option '(#\V "version") #f #f
                  (lambda args
                    (show-version-and-exit "guix import crate")))
+         (option '(#\r "recursive") #f #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'recursive #t result)))
          %standard-import-options))
 
 
@@ -83,11 +89,27 @@ Import and convert the crate.io package for 
PACKAGE-NAME.\n"))
                            (reverse opts))))
     (match args
       ((package-name)
-       (let ((sexp (crate->guix-package package-name)))
-         (unless sexp
-           (leave (G_ "failed to download meta-data for package '~a'~%")
-                  package-name))
-         sexp))
+       (if (assoc-ref opts 'recursive)
+           ;; Recursive import
+           (map (match-lambda
+                  ((and ('package ('name name) . rest) pkg)
+                   `(define-public ,(string->symbol name)
+                      ,pkg))
+                  ((and string? pkg-name)
+                   ;; (format #f (G_ "failed to download meta-data for package 
'~a'") dep-name)
+                   (string-append "failed to download meta-data for package '"
+                                  pkg-name
+                                  "'"))
+                  (_ #f))
+                (reverse
+                 (stream->list
+                  (crate-recursive-import package-name))))
+           ;; Single import
+           (let ((sexp (crate->guix-package package-name)))
+             (unless sexp
+               (leave (G_ "failed to download meta-data for package '~a'~%")
+                      package-name))
+             sexp)))
       (()
        (leave (G_ "too few arguments~%")))
       ((many ...)
diff --git a/tests/crate.scm b/tests/crate.scm
index c14862a..8e7b0bd 100644
--- a/tests/crate.scm
+++ b/tests/crate.scm
@@ -26,9 +26,10 @@
   #:use-module (guix tests)
   #:use-module (ice-9 iconv)
   #:use-module (ice-9 match)
+  #:use-module (srfi srfi-41)
   #:use-module (srfi srfi-64))
 
-(define test-crate
+(define test-foo-crate
   "{
   \"crate\": {
     \"max_version\": \"1.0.0\",
@@ -50,16 +51,81 @@
   }
 }")
 
-(define test-dependencies
+(define test-foo-dependencies
   "{
   \"dependencies\": [
      {
        \"crate_id\": \"bar\",
        \"kind\": \"normal\",
+     },
+     {
+       \"crate_id\": \"baz\",
+       \"kind\": \"normal\",
+     }
+  ]
+}")
+
+(define test-bar-crate
+  "{
+  \"crate\": {
+    \"max_version\": \"1.0.0\",
+    \"name\": \"bar\",
+    \"description\": \"summary\",
+    \"homepage\": \"http://example.com\";,
+    \"repository\": \"http://example.com\";,
+    \"keywords\": [\"dummy\" \"test\"],
+    \"categories\": [\"test\"]
+    \"actual_versions\": [
+      { \"id\": \"bar\",
+        \"num\": \"1.0.0\",
+        \"license\": \"MIT OR Apache-2.0\",
+        \"links\": {
+          \"dependencies\": \"/api/v1/crates/bar/1.0.0/dependencies\"
+        }
+      }
+    ]
+    \"license\": \"MIT OR Apache-2.0\",
+  }
+}")
+
+(define test-bar-dependencies
+  "{
+  \"dependencies\": [
+     {
+       \"crate_id\": \"baz\",
+       \"kind\": \"normal\",
      }
   ]
 }")
 
+(define test-baz-crate
+  "{
+  \"crate\": {
+    \"max_version\": \"1.0.0\",
+    \"name\": \"baz\",
+    \"description\": \"summary\",
+    \"homepage\": \"http://example.com\";,
+    \"repository\": \"http://example.com\";,
+    \"keywords\": [\"dummy\" \"test\"],
+    \"categories\": [\"test\"]
+    \"actual_versions\": [
+      { \"id\": \"baz\",
+        \"num\": \"1.0.0\",
+        \"license\": \"MIT OR Apache-2.0\",
+        \"links\": {
+          \"dependencies\": \"/api/v1/crates/baz/1.0.0/dependencies\"
+        }
+      }
+    ]
+    \"license\": \"MIT OR Apache-2.0\",
+  }
+}")
+
+(define test-baz-dependencies
+  "{
+\"dependencies\": []
+}")
+
 (define test-source-hash
   "")
 
@@ -79,14 +145,14 @@
          (lambda (url . rest)
            (match url
              ("https://crates.io/api/v1/crates/foo";
-              (open-input-string test-crate))
+              (open-input-string test-foo-crate))
              ("https://crates.io/api/v1/crates/foo/1.0.0/download";
               (set! test-source-hash
                 (bytevector->nix-base32-string
                  (sha256 (string->bytevector "empty file\n" "utf-8"))))
               (open-input-string "empty file\n"))
              ("https://crates.io/api/v1/crates/foo/1.0.0/dependencies";
-              (open-input-string test-dependencies))
+              (open-input-string test-foo-dependencies))
              (_ (error "Unexpected URL: " url)))))
     (match (crate->guix-package "foo")
       (('package
@@ -102,7 +168,8 @@
          ('build-system 'cargo-build-system)
          ('arguments
           ('quasiquote
-           ('#:cargo-inputs (("rust-bar" ('unquote rust-bar))))))
+           ('#:cargo-inputs (("rust-bar" ('unquote rust-bar))
+                             ("rust-baz" ('unquote rust-baz))))))
          ('home-page "http://example.com";)
          ('synopsis "summary")
          ('description "summary")
@@ -111,4 +178,100 @@
       (x
        (pk 'fail x #f)))))
 
+(test-assert "cargo-recursive-import"
+  ;; Replace network resources with sample data.
+  (mock ((guix http-client) http-fetch
+         (lambda (url . rest)
+           (match url
+             ("https://crates.io/api/v1/crates/foo";
+              (open-input-string test-foo-crate))
+             ("https://crates.io/api/v1/crates/foo/1.0.0/download";
+              (set! test-source-hash
+                    (bytevector->nix-base32-string
+                     (sha256 (string->bytevector "empty file\n" "utf-8"))))
+              (open-input-string "empty file\n"))
+             ("https://crates.io/api/v1/crates/foo/1.0.0/dependencies";
+              (open-input-string test-foo-dependencies))
+             ("https://crates.io/api/v1/crates/bar";
+              (open-input-string test-bar-crate))
+             ("https://crates.io/api/v1/crates/bar/1.0.0/download";
+              (set! test-source-hash
+                    (bytevector->nix-base32-string
+                     (sha256 (string->bytevector "empty file\n" "utf-8"))))
+              (open-input-string "empty file\n"))
+             ("https://crates.io/api/v1/crates/bar/1.0.0/dependencies";
+              (open-input-string test-bar-dependencies))
+             ("https://crates.io/api/v1/crates/baz";
+              (open-input-string test-baz-crate))
+             ("https://crates.io/api/v1/crates/baz/1.0.0/download";
+              (set! test-source-hash
+                    (bytevector->nix-base32-string
+                     (sha256 (string->bytevector "empty file\n" "utf-8"))))
+              (open-input-string "empty file\n"))
+             ("https://crates.io/api/v1/crates/baz/1.0.0/dependencies";
+              (open-input-string test-baz-dependencies))
+             (_ (error "Unexpected URL: " url)))))
+        (match (stream->list (crate-recursive-import "foo"))
+          ((('package
+              ('name "rust-foo")
+              ('version (? string? ver))
+              ('source
+               ('origin
+                 ('method 'url-fetch)
+                 ('uri ('crate-uri "foo" 'version))
+                 ('file-name
+                  ('string-append 'name "-" 'version ".tar.gz"))
+                 ('sha256
+                  ('base32
+                   (? string? hash)))))
+              ('build-system 'cargo-build-system)
+              ('arguments
+               ('quasiquote
+                ('#:cargo-inputs (("rust-bar" ('unquote rust-bar))
+                                  ("rust-baz" ('unquote rust-baz))))))
+              ('home-page "http://example.com";)
+              ('synopsis "summary")
+              ('description "summary")
+              ('license ('list 'license:expat 'license:asl2.0)))
+            ('package
+              ('name "rust-bar")
+              ('version (? string? ver))
+              ('source
+               ('origin
+                 ('method 'url-fetch)
+                 ('uri ('crate-uri "bar" 'version))
+                 ('file-name
+                  ('string-append 'name "-" 'version ".tar.gz"))
+                 ('sha256
+                  ('base32
+                   (? string? hash)))))
+              ('build-system 'cargo-build-system)
+              ('arguments
+               ('quasiquote
+                ('#:cargo-inputs (("rust-baz" ('unquote rust-baz))))))
+              ('home-page "http://example.com";)
+              ('synopsis "summary")
+              ('description "summary")
+              ('license ('list 'license:expat 'license:asl2.0)))
+            ('package
+              ('name "rust-baz")
+              ('version (? string? ver))
+              ('source
+               ('origin
+                 ('method 'url-fetch)
+                 ('uri ('crate-uri "baz" 'version))
+                 ('file-name
+                  ('string-append 'name "-" 'version ".tar.gz"))
+                 ('sha256
+                  ('base32
+                   (? string? hash)))))
+              ('build-system 'cargo-build-system)
+              ('home-page "http://example.com";)
+              ('synopsis "summary")
+              ('description "summary")
+              ('license ('list 'license:expat 'license:asl2.0))))
+           #t)
+          (x
+           (pk 'fail x #f)))))
+
 (test-end "crate")



reply via email to

[Prev in Thread] Current Thread [Next in Thread]