diff options
| author | Nicolas Graves <ngraves@ngraves.fr> | 2023-11-02 16:16:48 +0100 |
|---|---|---|
| committer | Ludovic Courtès <ludo@gnu.org> | 2023-12-18 23:16:28 +0100 |
| commit | b7e3945283daec8d6bc676b659d00ed73b8e82b7 (patch) | |
| tree | 1f9c8511898585a00a0ea5b020865db15039339f | |
| parent | 32d4f40589e32cbac6549c50962011084f13d9fc (diff) | |
guix: import: Add composer importer.
* guix/import/composer.scm: New file.
* guix/scripts/import/composer.scm: New file.
* guix/tests/composer.scm: New file.
* Makefile.am: Add them.
* guix/scripts/import.scm: Add composer importer.
* doc/guix.texi (Invoking guix import): Mention it.
Change-Id: I44a89b8cc80ef5b4a3cd15e8fbba4a18c1cea0b1
Co-authored-by: Julien Lepiller <julien@lepiller.eu>
Co-authored-by: Ludovic Courtès <ludo@gnu.org>
| -rw-r--r-- | Makefile.am | 3 | ||||
| -rw-r--r-- | doc/guix.texi | 20 | ||||
| -rw-r--r-- | guix/import/composer.scm | 268 | ||||
| -rw-r--r-- | guix/scripts/import.scm | 2 | ||||
| -rw-r--r-- | guix/scripts/import/composer.scm | 107 | ||||
| -rw-r--r-- | tests/composer.scm | 88 |
6 files changed, 487 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am index 0b733108d43..ee0f5ba4fc6 100644 --- a/Makefile.am +++ b/Makefile.am | |||
| @@ -283,6 +283,7 @@ MODULES = \ | |||
| 283 | guix/search-paths.scm \ | 283 | guix/search-paths.scm \ |
| 284 | guix/packages.scm \ | 284 | guix/packages.scm \ |
| 285 | guix/import/cabal.scm \ | 285 | guix/import/cabal.scm \ |
| 286 | guix/import/composer.scm \ | ||
| 286 | guix/import/cpan.scm \ | 287 | guix/import/cpan.scm \ |
| 287 | guix/import/cran.scm \ | 288 | guix/import/cran.scm \ |
| 288 | guix/import/crate.scm \ | 289 | guix/import/crate.scm \ |
| @@ -341,6 +342,7 @@ MODULES = \ | |||
| 341 | guix/scripts/home/import.scm \ | 342 | guix/scripts/home/import.scm \ |
| 342 | guix/scripts/lint.scm \ | 343 | guix/scripts/lint.scm \ |
| 343 | guix/scripts/challenge.scm \ | 344 | guix/scripts/challenge.scm \ |
| 345 | guix/scripts/import/composer.scm \ | ||
| 344 | guix/scripts/import/crate.scm \ | 346 | guix/scripts/import/crate.scm \ |
| 345 | guix/scripts/import/cpan.scm \ | 347 | guix/scripts/import/cpan.scm \ |
| 346 | guix/scripts/import/cran.scm \ | 348 | guix/scripts/import/cran.scm \ |
| @@ -509,6 +511,7 @@ SCM_TESTS = \ | |||
| 509 | tests/challenge.scm \ | 511 | tests/challenge.scm \ |
| 510 | tests/channels.scm \ | 512 | tests/channels.scm \ |
| 511 | tests/combinators.scm \ | 513 | tests/combinators.scm \ |
| 514 | tests/composer.scm \ | ||
| 512 | tests/containers.scm \ | 515 | tests/containers.scm \ |
| 513 | tests/cpan.scm \ | 516 | tests/cpan.scm \ |
| 514 | tests/cpio.scm \ | 517 | tests/cpio.scm \ |
diff --git a/doc/guix.texi b/doc/guix.texi index 7d7697d3181..ffd8ae331d7 100644 --- a/doc/guix.texi +++ b/doc/guix.texi | |||
| @@ -14539,6 +14539,26 @@ Additional options include: | |||
| 14539 | Traverse the dependency graph of the given upstream package recursively | 14539 | Traverse the dependency graph of the given upstream package recursively |
| 14540 | and generate package expressions for all those packages that are not yet | 14540 | and generate package expressions for all those packages that are not yet |
| 14541 | in Guix. | 14541 | in Guix. |
| 14542 | @end table | ||
| 14543 | |||
| 14544 | @item composer | ||
| 14545 | @cindex Composer | ||
| 14546 | @cindex PHP | ||
| 14547 | Import metadata from the @uref{https://getcomposer.org/, Composer} package | ||
| 14548 | archive used by the PHP community, as in this example: | ||
| 14549 | |||
| 14550 | @example | ||
| 14551 | guix import composer phpunit/phpunit | ||
| 14552 | @end example | ||
| 14553 | |||
| 14554 | Additional options include: | ||
| 14555 | |||
| 14556 | @table @code | ||
| 14557 | @item --recursive | ||
| 14558 | @itemx -r | ||
| 14559 | Traverse the dependency graph of the given upstream package recursively | ||
| 14560 | and generate package expressions for all those packages that are not yet | ||
| 14561 | in Guix. | ||
| 14542 | @item --repo | 14562 | @item --repo |
| 14543 | By default, packages are searched in the official OPAM repository. This | 14563 | By default, packages are searched in the official OPAM repository. This |
| 14544 | option, which can be used more than once, lets you add other repositories | 14564 | option, which can be used more than once, lets you add other repositories |
diff --git a/guix/import/composer.scm b/guix/import/composer.scm new file mode 100644 index 00000000000..1ad608964b1 --- /dev/null +++ b/guix/import/composer.scm | |||
| @@ -0,0 +1,268 @@ | |||
| 1 | ;;; GNU Guix --- Functional package management for GNU | ||
| 2 | ;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu> | ||
| 3 | ;;; | ||
| 4 | ;;; This file is part of GNU Guix. | ||
| 5 | ;;; | ||
| 6 | ;;; GNU Guix is free software; you can redistribute it and/or modify it | ||
| 7 | ;;; under the terms of the GNU General Public License as published by | ||
| 8 | ;;; the Free Software Foundation; either version 3 of the License, or (at | ||
| 9 | ;;; your option) any later version. | ||
| 10 | ;;; | ||
| 11 | ;;; GNU Guix is distributed in the hope that it will be useful, but | ||
| 12 | ;;; WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | ;;; GNU General Public License for more details. | ||
| 15 | ;;; | ||
| 16 | ;;; You should have received a copy of the GNU General Public License | ||
| 17 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | |||
| 19 | (define-module (guix import composer) | ||
| 20 | #:use-module (ice-9 match) | ||
| 21 | #:use-module (json) | ||
| 22 | #:use-module (guix hash) | ||
| 23 | #:use-module (guix base32) | ||
| 24 | #:use-module (guix build git) | ||
| 25 | #:use-module (guix build utils) | ||
| 26 | #:use-module (guix build-system) | ||
| 27 | #:use-module (guix build-system composer) | ||
| 28 | #:use-module (guix import json) | ||
| 29 | #:use-module (guix import utils) | ||
| 30 | #:use-module ((guix licenses) #:prefix license:) | ||
| 31 | #:use-module (guix memoization) | ||
| 32 | #:use-module (guix packages) | ||
| 33 | #:use-module (guix serialization) | ||
| 34 | #:use-module (guix upstream) | ||
| 35 | #:use-module (guix utils) | ||
| 36 | #:use-module (srfi srfi-1) | ||
| 37 | #:use-module (srfi srfi-11) | ||
| 38 | #:use-module (srfi srfi-26) | ||
| 39 | #:export (composer->guix-package | ||
| 40 | %composer-updater | ||
| 41 | composer-recursive-import | ||
| 42 | |||
| 43 | %composer-base-url)) | ||
| 44 | |||
| 45 | (define %composer-base-url | ||
| 46 | (make-parameter "https://repo.packagist.org")) | ||
| 47 | |||
| 48 | (define (fix-version version) | ||
| 49 | "Return a fixed version from a version string. For instance, v10.1 -> 10.1" | ||
| 50 | (cond | ||
| 51 | ((string-prefix? "version" version) | ||
| 52 | (if (char-set-contains? char-set:digit (string-ref version 7)) | ||
| 53 | (substring version 7) | ||
| 54 | (substring version 8))) | ||
| 55 | ((string-prefix? "v" version) | ||
| 56 | (substring version 1)) | ||
| 57 | (else version))) | ||
| 58 | |||
| 59 | (define (latest-version versions) | ||
| 60 | (fold (lambda (a b) (if (version>? (fix-version a) (fix-version b)) a b)) | ||
| 61 | (car versions) versions)) | ||
| 62 | |||
| 63 | (define (json->require dict) | ||
| 64 | (if dict | ||
| 65 | (let loop ((result '()) (require dict)) | ||
| 66 | (match require | ||
| 67 | (() result) | ||
| 68 | ((((? (cut string-contains <> "/") name) . _) | ||
| 69 | require ...) | ||
| 70 | (loop (cons name result) require)) | ||
| 71 | ((_ require ...) (loop result require)) | ||
| 72 | (_ result))) | ||
| 73 | '())) | ||
| 74 | |||
| 75 | (define-json-mapping <composer-source> make-composer-source composer-source? | ||
| 76 | json->composer-source | ||
| 77 | (type composer-source-type) | ||
| 78 | (url composer-source-url) | ||
| 79 | (reference composer-source-reference)) | ||
| 80 | |||
| 81 | (define-json-mapping <composer-package> make-composer-package composer-package? | ||
| 82 | json->composer-package | ||
| 83 | (description composer-package-description) | ||
| 84 | (homepage composer-package-homepage) | ||
| 85 | (source composer-package-source "source" json->composer-source) | ||
| 86 | (name composer-package-name "name" php-package-name) | ||
| 87 | (version composer-package-version "version" fix-version) | ||
| 88 | (require composer-package-require "require" json->require) | ||
| 89 | (dev-require composer-package-dev-require "require-dev" json->require) | ||
| 90 | (license composer-package-license "license" | ||
| 91 | (lambda (vector) | ||
| 92 | (let ((l (map string->license (vector->list vector)))) | ||
| 93 | (if (eq? (length l) 1) | ||
| 94 | (car l) | ||
| 95 | `(list ,@l)))))) | ||
| 96 | |||
| 97 | (define (valid-version? v) | ||
| 98 | (let ((d (string-downcase v))) | ||
| 99 | (and (not (string-contains d "dev")) | ||
| 100 | (not (string-contains d "beta")) | ||
| 101 | (not (string-contains d "rc"))))) | ||
| 102 | |||
| 103 | (define* (composer-fetch name #:key (version #f)) | ||
| 104 | "Return a composer-package representation of the Composer metadata for the | ||
| 105 | package NAME with optional VERSION, or #f on failure." | ||
| 106 | (let* ((url (string-append (%composer-base-url) "/p/" name ".json")) | ||
| 107 | (packages (and=> (json-fetch url) | ||
| 108 | (lambda (pkg) | ||
| 109 | (let ((pkgs (assoc-ref pkg "packages"))) | ||
| 110 | (or (assoc-ref pkgs name) pkg)))))) | ||
| 111 | (if packages | ||
| 112 | (json->composer-package | ||
| 113 | (if version | ||
| 114 | (assoc-ref packages version) | ||
| 115 | (cdr | ||
| 116 | (reduce | ||
| 117 | (lambda (new cur-max) | ||
| 118 | (match new | ||
| 119 | (((? valid-version? version) . tail) | ||
| 120 | (if (version>? (fix-version version) | ||
| 121 | (fix-version (car cur-max))) | ||
| 122 | (cons* version tail) | ||
| 123 | cur-max)) | ||
| 124 | (_ cur-max))) | ||
| 125 | (cons* "0.0.0" #f) | ||
| 126 | packages)))) | ||
| 127 | #f))) | ||
| 128 | |||
| 129 | (define (php-package-name name) | ||
| 130 | "Given the NAME of a package on Packagist, return a Guix-compliant name for | ||
| 131 | the package." | ||
| 132 | (let ((name (string-join (string-split name #\/) "-"))) | ||
| 133 | (if (string-prefix? "php-" name) | ||
| 134 | (snake-case name) | ||
| 135 | (string-append "php-" (snake-case name))))) | ||
| 136 | |||
| 137 | (define (make-php-sexp composer-package) | ||
| 138 | "Return the `package' s-expression for a PHP package for the given | ||
| 139 | COMPOSER-PACKAGE." | ||
| 140 | (let* ((source (composer-package-source composer-package)) | ||
| 141 | (dependencies (map php-package-name | ||
| 142 | (composer-package-require composer-package))) | ||
| 143 | (dev-dependencies (map php-package-name | ||
| 144 | (composer-package-dev-require composer-package))) | ||
| 145 | (git? (equal? (composer-source-type source) "git"))) | ||
| 146 | ((if git? call-with-temporary-directory call-with-temporary-output-file) | ||
| 147 | (lambda* (temp #:optional port) | ||
| 148 | (and (if git? | ||
| 149 | (begin | ||
| 150 | (mkdir-p temp) | ||
| 151 | (git-fetch (composer-source-url source) | ||
| 152 | (composer-source-reference source) | ||
| 153 | temp)) | ||
| 154 | (url-fetch (composer-source-url source) temp)) | ||
| 155 | `(package | ||
| 156 | (name ,(composer-package-name composer-package)) | ||
| 157 | (version ,(composer-package-version composer-package)) | ||
| 158 | (source | ||
| 159 | (origin | ||
| 160 | ,@(if git? | ||
| 161 | `((method git-fetch) | ||
| 162 | (uri (git-reference | ||
| 163 | (url ,(if (string-suffix? | ||
| 164 | ".git" | ||
| 165 | (composer-source-url source)) | ||
| 166 | (string-drop-right | ||
| 167 | (composer-source-url source) | ||
| 168 | (string-length ".git")) | ||
| 169 | (composer-source-url source))) | ||
| 170 | (commit ,(composer-source-reference source)))) | ||
| 171 | (file-name (git-file-name name version)) | ||
| 172 | (sha256 | ||
| 173 | (base32 | ||
| 174 | ,(bytevector->nix-base32-string | ||
| 175 | (file-hash* temp))))) | ||
| 176 | `((method url-fetch) | ||
| 177 | (uri ,(composer-source-url source)) | ||
| 178 | (sha256 (base32 ,(guix-hash-url temp))))))) | ||
| 179 | (build-system composer-build-system) | ||
| 180 | ,@(if (null? dependencies) | ||
| 181 | '() | ||
| 182 | `((inputs | ||
| 183 | (list ,@(map string->symbol dependencies))))) | ||
| 184 | ,@(if (null? dev-dependencies) | ||
| 185 | '() | ||
| 186 | `((native-inputs | ||
| 187 | (list ,@(map string->symbol dev-dependencies))))) | ||
| 188 | (synopsis "") | ||
| 189 | (description ,(composer-package-description composer-package)) | ||
| 190 | (home-page ,(composer-package-homepage composer-package)) | ||
| 191 | (license ,(or (composer-package-license composer-package) | ||
| 192 | 'unknown-license!)))))))) | ||
| 193 | |||
| 194 | (define composer->guix-package | ||
| 195 | (memoize | ||
| 196 | (lambda* (package-name #:key (version #f) #:allow-other-keys) | ||
| 197 | "Fetch the metadata for PACKAGE-NAME from packagist.org, and return the | ||
| 198 | `package' s-expression corresponding to that package and its list of | ||
| 199 | dependencies, or #f and the empty list on failure." | ||
| 200 | (let ((package (composer-fetch package-name #:version version))) | ||
| 201 | (if package | ||
| 202 | (let* ((dependencies-names (composer-package-require package)) | ||
| 203 | (dev-dependencies-names (composer-package-dev-require package))) | ||
| 204 | (values (make-php-sexp package) | ||
| 205 | (append dependencies-names dev-dependencies-names))) | ||
| 206 | (values #f '())))))) | ||
| 207 | |||
| 208 | (define (guix-name->composer-name name) | ||
| 209 | "Given a guix package name, return the name of the package in Packagist." | ||
| 210 | (if (string-prefix? "php-" name) | ||
| 211 | (let ((components (string-split (substring name 4) #\-))) | ||
| 212 | (match components | ||
| 213 | ((namespace name ...) | ||
| 214 | (string-append namespace "/" (string-join name "-"))))) | ||
| 215 | name)) | ||
| 216 | |||
| 217 | (define (guix-package->composer-name package) | ||
| 218 | "Given a Composer PACKAGE built from Packagist, return the name of the | ||
| 219 | package in Packagist." | ||
| 220 | (let ((upstream-name (assoc-ref | ||
| 221 | (package-properties package) | ||
| 222 | 'upstream-name)) | ||
| 223 | (name (package-name package))) | ||
| 224 | (if upstream-name | ||
| 225 | upstream-name | ||
| 226 | (guix-name->composer-name name)))) | ||
| 227 | |||
| 228 | (define (string->license str) | ||
| 229 | "Convert the string STR into a license object." | ||
| 230 | (or (spdx-string->license str) | ||
| 231 | (match str | ||
| 232 | ("GNU LGPL" 'license:lgpl2.0) | ||
| 233 | ("GPL" 'license:gpl3) | ||
| 234 | ((or "BSD" "BSD License") 'license:bsd-3) | ||
| 235 | ((or "MIT" "MIT license" "Expat license") 'license:expat) | ||
| 236 | ("Public domain" 'license:public-domain) | ||
| 237 | ((or "Apache License, Version 2.0" "Apache 2.0") 'license:asl2.0) | ||
| 238 | (_ 'unknown-license!)))) | ||
| 239 | |||
| 240 | (define (php-package? package) | ||
| 241 | "Return true if PACKAGE is a PHP package from Packagist." | ||
| 242 | (and | ||
| 243 | (eq? (package-build-system package) composer-build-system) | ||
| 244 | (string-prefix? "php-" (package-name package)))) | ||
| 245 | |||
| 246 | (define (latest-release package) | ||
| 247 | "Return an <upstream-source> for the latest release of PACKAGE." | ||
| 248 | (let* ((php-name (guix-package->composer-name package)) | ||
| 249 | (package (composer-fetch php-name)) | ||
| 250 | (version (composer-package-version package)) | ||
| 251 | (url (composer-source-url (composer-package-source package)))) | ||
| 252 | (upstream-source | ||
| 253 | (package (package-name package)) | ||
| 254 | (version version) | ||
| 255 | (urls (list url))))) | ||
| 256 | |||
| 257 | (define %composer-updater | ||
| 258 | (upstream-updater | ||
| 259 | (name 'composer) | ||
| 260 | (description "Updater for Composer packages") | ||
| 261 | (pred php-package?) | ||
| 262 | (import latest-release))) | ||
| 263 | |||
| 264 | (define* (composer-recursive-import package-name #:optional version) | ||
| 265 | (recursive-import package-name | ||
| 266 | #:version version | ||
| 267 | #:repo->guix-package composer->guix-package | ||
| 268 | #:guix-name php-package-name)) | ||
diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm index 1e8ffd25ec3..d2a1cee56e8 100644 --- a/guix/scripts/import.scm +++ b/guix/scripts/import.scm | |||
| @@ -47,7 +47,7 @@ | |||
| 47 | 47 | ||
| 48 | (define importers '("gnu" "pypi" "cpan" "hackage" "stackage" "egg" "elpa" | 48 | (define importers '("gnu" "pypi" "cpan" "hackage" "stackage" "egg" "elpa" |
| 49 | "gem" "go" "cran" "crate" "texlive" "json" "opam" | 49 | "gem" "go" "cran" "crate" "texlive" "json" "opam" |
| 50 | "minetest" "elm" "hexpm")) | 50 | "minetest" "elm" "hexpm" "composer")) |
| 51 | 51 | ||
| 52 | (define (resolve-importer name) | 52 | (define (resolve-importer name) |
| 53 | (let ((module (resolve-interface | 53 | (let ((module (resolve-interface |
diff --git a/guix/scripts/import/composer.scm b/guix/scripts/import/composer.scm new file mode 100644 index 00000000000..412bae6318b --- /dev/null +++ b/guix/scripts/import/composer.scm | |||
| @@ -0,0 +1,107 @@ | |||
| 1 | ;;; GNU Guix --- Functional package management for GNU | ||
| 2 | ;;; Copyright © 2015 David Thompson <davet@gnu.org> | ||
| 3 | ;;; Copyright © 2018 Oleg Pykhalov <go.wigust@gmail.com> | ||
| 4 | ;;; | ||
| 5 | ;;; This file is part of GNU Guix. | ||
| 6 | ;;; | ||
| 7 | ;;; GNU Guix is free software; you can redistribute it and/or modify it | ||
| 8 | ;;; under the terms of the GNU General Public License as published by | ||
| 9 | ;;; the Free Software Foundation; either version 3 of the License, or (at | ||
| 10 | ;;; your option) any later version. | ||
| 11 | ;;; | ||
| 12 | ;;; GNU Guix is distributed in the hope that it will be useful, but | ||
| 13 | ;;; WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | ;;; GNU General Public License for more details. | ||
| 16 | ;;; | ||
| 17 | ;;; You should have received a copy of the GNU General Public License | ||
| 18 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | |||
| 20 | (define-module (guix scripts import composer) | ||
| 21 | #:use-module (guix ui) | ||
| 22 | #:use-module (guix utils) | ||
| 23 | #:use-module (guix scripts) | ||
| 24 | #:use-module (guix import composer) | ||
| 25 | #:use-module (guix scripts import) | ||
| 26 | #:use-module (srfi srfi-1) | ||
| 27 | #:use-module (srfi srfi-11) | ||
| 28 | #:use-module (srfi srfi-37) | ||
| 29 | #:use-module (srfi srfi-41) | ||
| 30 | #:use-module (ice-9 match) | ||
| 31 | #:use-module (ice-9 format) | ||
| 32 | #:export (guix-import-composer)) | ||
| 33 | |||
| 34 | |||
| 35 | ;;; | ||
| 36 | ;;; Command-line options. | ||
| 37 | ;;; | ||
| 38 | |||
| 39 | (define %default-options | ||
| 40 | '()) | ||
| 41 | |||
| 42 | (define (show-help) | ||
| 43 | (display (G_ "Usage: guix import composer PACKAGE-NAME | ||
| 44 | Import and convert the Composer package for PACKAGE-NAME.\n")) | ||
| 45 | (display (G_ " | ||
| 46 | -h, --help display this help and exit")) | ||
| 47 | (display (G_ " | ||
| 48 | -V, --version display version information and exit")) | ||
| 49 | (display (G_ " | ||
| 50 | -r, --recursive generate package expressions for all Composer packages\ | ||
| 51 | that are not yet in Guix")) | ||
| 52 | (newline) | ||
| 53 | (show-bug-report-information)) | ||
| 54 | |||
| 55 | (define %options | ||
| 56 | ;; Specification of the command-line options. | ||
| 57 | (cons* (option '(#\h "help") #f #f | ||
| 58 | (lambda args | ||
| 59 | (show-help) | ||
| 60 | (exit 0))) | ||
| 61 | (option '(#\V "version") #f #f | ||
| 62 | (lambda args | ||
| 63 | (show-version-and-exit "guix import composer"))) | ||
| 64 | (option '(#\r "recursive") #f #f | ||
| 65 | (lambda (opt name arg result) | ||
| 66 | (alist-cons 'recursive #t result))) | ||
| 67 | %standard-import-options)) | ||
| 68 | |||
| 69 | |||
| 70 | ;;; | ||
| 71 | ;;; Entry point. | ||
| 72 | ;;; | ||
| 73 | |||
| 74 | (define (guix-import-composer . args) | ||
| 75 | (define (parse-options) | ||
| 76 | ;; Return the alist of option values. | ||
| 77 | (args-fold* args %options | ||
| 78 | (lambda (opt name arg result) | ||
| 79 | (leave (G_ "~A: unrecognized option~%") name)) | ||
| 80 | (lambda (arg result) | ||
| 81 | (alist-cons 'argument arg result)) | ||
| 82 | %default-options)) | ||
| 83 | |||
| 84 | (let* ((opts (parse-options)) | ||
| 85 | (args (filter-map (match-lambda | ||
| 86 | (('argument . value) | ||
| 87 | value) | ||
| 88 | (_ #f)) | ||
| 89 | (reverse opts)))) | ||
| 90 | (match args | ||
| 91 | ((package-name) | ||
| 92 | (if (assoc-ref opts 'recursive) | ||
| 93 | (map (match-lambda | ||
| 94 | ((and ('package ('name name) . rest) pkg) | ||
| 95 | `(define-public ,(string->symbol name) | ||
| 96 | ,pkg)) | ||
| 97 | (_ #f)) | ||
| 98 | (composer-recursive-import package-name)) | ||
| 99 | (let ((sexp (composer->guix-package package-name))) | ||
| 100 | (unless sexp | ||
| 101 | (leave (G_ "failed to download meta-data for package '~a'~%") | ||
| 102 | package-name)) | ||
| 103 | sexp))) | ||
| 104 | (() | ||
| 105 | (leave (G_ "too few arguments~%"))) | ||
| 106 | ((many ...) | ||
| 107 | (leave (G_ "too many arguments~%")))))) | ||
diff --git a/tests/composer.scm b/tests/composer.scm new file mode 100644 index 00000000000..9114fef19ed --- /dev/null +++ b/tests/composer.scm | |||
| @@ -0,0 +1,88 @@ | |||
| 1 | ;;; GNU Guix --- Functional package management for GNU | ||
| 2 | ;;; Copyright © 2020 Julien Lepiller <julien@lepiller.eu> | ||
| 3 | ;;; Copyright © 2023 Nicolas Graves <ngraves@ngraves.fr> | ||
| 4 | ;;; | ||
| 5 | ;;; This file is part of GNU Guix. | ||
| 6 | ;;; | ||
| 7 | ;;; GNU Guix is free software; you can redistribute it and/or modify it | ||
| 8 | ;;; under the terms of the GNU General Public License as published by | ||
| 9 | ;;; the Free Software Foundation; either version 3 of the License, or (at | ||
| 10 | ;;; your option) any later version. | ||
| 11 | ;;; | ||
| 12 | ;;; GNU Guix is distributed in the hope that it will be useful, but | ||
| 13 | ;;; WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | ;;; GNU General Public License for more details. | ||
| 16 | ;;; | ||
| 17 | ;;; You should have received a copy of the GNU General Public License | ||
| 18 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | |||
| 20 | (define-module (test-composer) | ||
| 21 | #:use-module (guix import composer) | ||
| 22 | #:use-module (guix base32) | ||
| 23 | #:use-module (gcrypt hash) | ||
| 24 | #:use-module (guix tests http) | ||
| 25 | #:use-module (guix grafts) | ||
| 26 | #:use-module (srfi srfi-64) | ||
| 27 | #:use-module (web client) | ||
| 28 | #:use-module (ice-9 match)) | ||
| 29 | |||
| 30 | ;; Globally disable grafts because they can trigger early builds. | ||
| 31 | (%graft? #f) | ||
| 32 | |||
| 33 | (define test-json | ||
| 34 | "{ | ||
| 35 | \"packages\": { | ||
| 36 | \"foo/bar\": { | ||
| 37 | \"0.1\": { | ||
| 38 | \"name\": \"foo/bar\", | ||
| 39 | \"description\": \"description\", | ||
| 40 | \"keywords\": [\"testing\"], | ||
| 41 | \"homepage\": \"http://example.com\", | ||
| 42 | \"version\": \"0.1\", | ||
| 43 | \"license\": [\"BSD-3-Clause\"], | ||
| 44 | \"source\": { | ||
| 45 | \"type\": \"url\", | ||
| 46 | \"url\": \"http://example.com/Bar-0.1.tar.gz\" | ||
| 47 | }, | ||
| 48 | \"require\": {}, | ||
| 49 | \"require-dev\": {\"phpunit/phpunit\": \"1.0.0\"} | ||
| 50 | } | ||
| 51 | } | ||
| 52 | } | ||
| 53 | }") | ||
| 54 | |||
| 55 | (define test-source | ||
| 56 | "foobar") | ||
| 57 | |||
| 58 | (test-begin "composer") | ||
| 59 | |||
| 60 | (test-assert "composer->guix-package" | ||
| 61 | ;; Replace network resources with sample data. | ||
| 62 | (with-http-server `((200 ,test-json) | ||
| 63 | (200 ,test-source)) | ||
| 64 | (parameterize ((%composer-base-url (%local-url)) | ||
| 65 | (current-http-proxy (%local-url))) | ||
| 66 | (match (composer->guix-package "foo/bar") | ||
| 67 | (`(package | ||
| 68 | (name "php-foo-bar") | ||
| 69 | (version "0.1") | ||
| 70 | (source (origin | ||
| 71 | (method url-fetch) | ||
| 72 | (uri "http://example.com/Bar-0.1.tar.gz") | ||
| 73 | (sha256 | ||
| 74 | (base32 | ||
| 75 | ,(? string? hash))))) | ||
| 76 | (build-system composer-build-system) | ||
| 77 | (native-inputs (list php-phpunit-phpunit)) | ||
| 78 | (synopsis "") | ||
| 79 | (description "description") | ||
| 80 | (home-page "http://example.com") | ||
| 81 | (license license:bsd-3)) | ||
| 82 | (string=? (bytevector->nix-base32-string | ||
| 83 | (call-with-input-string test-source port-sha256)) | ||
| 84 | hash)) | ||
| 85 | (x | ||
| 86 | (pk 'fail x #f)))))) | ||
| 87 | |||
| 88 | (test-end "composer") | ||
