From 520e3d267ecc3964af301ab9341462e905f234c6 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Tue, 28 Nov 2023 12:34:47 +0100 Subject: guix: Add target-avr?. * guix/utils.scm (target-avr?): New procedure. * tests/utils.scm: Add tests for target-avr? procedure. Change-Id: Iaa0fa97a2b6bc45d45f907f43157f1548a0ba3fa Signed-off-by: Efraim Flashner --- tests/utils.scm | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'tests') diff --git a/tests/utils.scm b/tests/utils.scm index 648e91f242..5664165c85 100644 --- a/tests/utils.scm +++ b/tests/utils.scm @@ -4,6 +4,7 @@ ;;; Copyright © 2016 Mathieu Lirzin ;;; Copyright © 2021 Simon Tournier ;;; Copyright © 2021 Maxime Devos +;;; Copyright © 2023 Foundation Devices, Inc. ;;; ;;; This file is part of GNU Guix. ;;; @@ -329,6 +330,17 @@ (define (test-compression/decompression method run?) ;; However, it isn't 32-bit. ,(format #f "x86_~a-linux-gnu" (expt 2 109))))) +(test-equal "target-avr?" + '(#t #t #t #f #f) + (map target-avr? + '("avr" "avr-unknown-none" + ;; In addition LLVM also uses this form. + "avr-unknown-unknown" + ;; The AVR32 architecture also was made by Atmel/Microchip but it + ;; does not resemble the AVR family, they aren't compatible in any + ;; way. + "avr32" "avr32-unknown-none"))) + (test-end) (false-if-exception (delete-file temp-file)) -- cgit v1.2.3 From 1e47148f46e31eb99ce8ec7bc12232cf50d0ebec Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Fri, 10 Nov 2023 21:37:28 +0100 Subject: daemon: Implement ‘substitute-urls’ RPC. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * nix/libstore/worker-protocol.hh (PROTOCOL_VERSION): Bump. (WorkerOp): Add ‘wopSubstituteURLs’. * nix/nix-daemon/nix-daemon.cc (performOp): Implement it. * guix/store.scm (%protocol-version): Bump. (operation-id): Add ‘substitute-urls’. (substitute-urls): New procedure. * tests/store.scm ("substitute-urls, default") ("substitute-urls, client-specified URLs") ("substitute-urls, disabled"): New tests. Change-Id: I2c0119500c3a1eecfa5ebf32463ffb0f173161de --- guix/store.scm | 18 +++++++++++++++--- nix/libstore/worker-protocol.hh | 5 +++-- nix/nix-daemon/nix-daemon.cc | 17 +++++++++++++++++ tests/store.scm | 25 +++++++++++++++++++++++-- 4 files changed, 58 insertions(+), 7 deletions(-) (limited to 'tests') diff --git a/guix/store.scm b/guix/store.scm index f8e77b2cd9..97c4f32a5b 100644 --- a/guix/store.scm +++ b/guix/store.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2012-2022 Ludovic Courtès +;;; Copyright © 2012-2023 Ludovic Courtès ;;; Copyright © 2018 Jan Nieuwenhuizen ;;; Copyright © 2019, 2020 Mathieu Othacehe ;;; Copyright © 2020 Florian Pelz @@ -145,6 +145,7 @@ (define-module (guix store) path-info-nar-size built-in-builders + substitute-urls references references/cached references* @@ -199,7 +200,7 @@ (define-module (guix store) derivation-log-file log-file)) -(define %protocol-version #x163) +(define %protocol-version #x164) (define %worker-magic-1 #x6e697863) ; "nixc" (define %worker-magic-2 #x6478696f) ; "dxio" @@ -253,7 +254,8 @@ (define-enumerate-type operation-id (query-valid-derivers 33) (optimize-store 34) (verify-store 35) - (built-in-builders 80)) + (built-in-builders 80) + (substitute-urls 81)) (define-enumerate-type hash-algo ;; hash.hh @@ -1780,6 +1782,16 @@ (define-operation (clear-failed-paths (store-path-list items)) This makes sense only when the daemon was started with '--cache-failures'." boolean) +(define substitute-urls + (let ((urls (operation (substitute-urls) + #f + string-list))) + (lambda (store) + "Return the list of currently configured substitutes URLs for STORE, or +#f if the daemon is too old and does not implement this RPC." + (and (>= (store-connection-version store) #x164) + (urls store))))) + ;;; ;;; Per-connection caches. diff --git a/nix/libstore/worker-protocol.hh b/nix/libstore/worker-protocol.hh index ea67b10a5b..ef259db2a0 100644 --- a/nix/libstore/worker-protocol.hh +++ b/nix/libstore/worker-protocol.hh @@ -6,7 +6,7 @@ namespace nix { #define WORKER_MAGIC_1 0x6e697863 #define WORKER_MAGIC_2 0x6478696f -#define PROTOCOL_VERSION 0x163 +#define PROTOCOL_VERSION 0x164 #define GET_PROTOCOL_MAJOR(x) ((x) & 0xff00) #define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff) @@ -44,7 +44,8 @@ typedef enum { wopQueryValidDerivers = 33, wopOptimiseStore = 34, wopVerifyStore = 35, - wopBuiltinBuilders = 80 + wopBuiltinBuilders = 80, + wopSubstituteURLs = 81 } WorkerOp; diff --git a/nix/nix-daemon/nix-daemon.cc b/nix/nix-daemon/nix-daemon.cc index 497de11a04..4cb05c802e 100644 --- a/nix/nix-daemon/nix-daemon.cc +++ b/nix/nix-daemon/nix-daemon.cc @@ -736,6 +736,23 @@ static void performOp(bool trusted, unsigned int clientVersion, break; } + case wopSubstituteURLs: { + startWork(); + Strings urls; + if (settings.get("build-use-substitutes", std::string("false")) == "true") { + /* First check the client-provided substitute URLs, then those + passed to the daemon. */ + auto str = settings.get("untrusted-substitute-urls", std::string("")); + if (str.empty()) { + str = settings.get("substitute-urls", std::string("")); + } + urls = tokenizeString(str); + } + stopWork(); + writeStrings(urls, to); + break; + } + default: throw Error(format("invalid operation %1%") % op); } diff --git a/tests/store.scm b/tests/store.scm index 5df28adf0d..45948f4f43 100644 --- a/tests/store.scm +++ b/tests/store.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès +;;; Copyright © 2012-2021, 2023 Ludovic Courtès ;;; ;;; This file is part of GNU Guix. ;;; @@ -105,7 +105,28 @@ (define %shell "/283gqy39v3g9dxjy26rynl0zls82fmcg-guile-2.0.7/bin/guile"))) (not (direct-store-path? (%store-prefix))))) -(test-skip (if %store 0 15)) +(test-skip (if %store 0 18)) + +(test-equal "substitute-urls, default" + (list (getenv "GUIX_BINARY_SUBSTITUTE_URL")) + (with-store store + (set-build-options store #:use-substitutes? #t) + (substitute-urls store))) + +(test-equal "substitute-urls, client-specified URLs" + '("http://substitutes.example.org" + "http://other.example.org") + (with-store store + (set-build-options store #:use-substitutes? #t + #:substitute-urls '("http://substitutes.example.org" + "http://other.example.org")) + (substitute-urls store))) + +(test-equal "substitute-urls, disabled" + '() + (with-store store + (set-build-options store #:use-substitutes? #f) + (substitute-urls store))) (test-equal "profiles/per-user exists and is not writable" #o755 -- cgit v1.2.3 From 6aade039e1007b5fece031d80aade43e108768a4 Mon Sep 17 00:00:00 2001 From: Efraim Flashner Date: Tue, 28 Nov 2023 12:04:27 +0200 Subject: guix: import: Report go version for go importer. * guix/import/go.scm (go-package, go.mod-go-version): New procedures. (go-module->guix-package): Add the #:go keyword in the generated package definition if the required go is newer than the default go. * tests/go.scm (mock-http-get): Use gexps for package arguments. Change-Id: I8d005740a442330ac307a40a53764c803ceffc4f --- guix/import/go.scm | 31 ++++++++++++++++++++++++++----- tests/go.scm | 6 +++--- 2 files changed, 29 insertions(+), 8 deletions(-) (limited to 'tests') diff --git a/guix/import/go.scm b/guix/import/go.scm index 940cdac4b0..dd9298808d 100644 --- a/guix/import/go.scm +++ b/guix/import/go.scm @@ -29,6 +29,7 @@ (define-module (guix import go) #:use-module (guix git) #:use-module (guix hash) #:use-module (guix i18n) + #:use-module ((guix utils) #:select (version>?)) #:use-module (guix diagnostics) #:use-module (guix import utils) #:use-module (guix import json) @@ -93,6 +94,11 @@ (define-module (guix import go) ;;; Code: +(define (go-package) + "Return the 'go' package. This is a lazy reference so that we don't +depend on (gnu packages golang)." + (module-ref (resolve-interface '(gnu packages golang)) 'go)) + (define http-fetch* ;; Like http-fetch, but memoized and returning the body as a string. (memoize (lambda args @@ -314,7 +320,7 @@ (define-peg-pattern original all (or (and module-path version) module-path)) (define-peg-pattern with all (or (and module-path version) file-path)) (define-peg-pattern replace all (and original => with EOL)) (define-peg-pattern replace-top body - (and (ignore "replace") + (and (ignore "replace") (or (and block-start (* (or replace block-line)) block-end) replace))) ;; RetractSpec = ( Version | "[" Version "," Version "]" ) newline . @@ -378,6 +384,17 @@ (define (require directive requirements) ;; Prevent inlining of this procedure, which is accessed by unit tests. (set! go.mod-requirements go.mod-requirements) +(define (go.mod-go-version go.mod) + "Return the minimum version of go required to specified by GO.MOD." + (let ((go-version (go.mod-directives go.mod 'go))) + (if (null? go-version) + ;; If the go directive is missing, go 1.16 is assumed. + '(version "1.16") + (flatten go-version)))) + +;; Prevent inlining of this procedure, which is accessed by unit tests. +(set! go.mod-go-version go.mod-go-version) + (define-record-type (%make-vcs url-prefix root-regex type) vcs? @@ -610,6 +627,7 @@ (define* (go-module->guix-package module-path #:key available-versions module-path)) (content (fetch-go.mod goproxy module-path version*)) + (min-go-version (second (go.mod-go-version (parse-go.mod content)))) (dependencies+versions (go.mod-requirements (parse-go.mod content))) (dependencies (if pin-versions? dependencies+versions @@ -634,10 +652,13 @@ (define* (go-module->guix-package module-path #:key ,(vcs->origin vcs-type vcs-repo-url version*)) (build-system go-build-system) (arguments - '(#:import-path ,module-path - ,@(if (string=? module-path-sans-suffix root-module-path) - '() - `(#:unpack-path ,root-module-path)))) + (list ,@(if (version>? min-go-version (package-version (go-package))) + `(#:go ,(string->number min-go-version)) + '()) + #:import-path ,module-path + ,@(if (string=? module-path-sans-suffix root-module-path) + '() + `(#:unpack-path ,root-module-path)))) ,@(maybe-propagated-inputs (map (match-lambda ((name version) diff --git a/tests/go.scm b/tests/go.scm index a70a0ddbf5..d2e8846b30 100644 --- a/tests/go.scm +++ b/tests/go.scm @@ -1,6 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2021 François Joulaud -;;; Copyright © 2021 Sarah Morgensen +;;; Copyright © 2021 François Joulaud +;;; Copyright © 2021 Sarah Morgensen ;;; ;;; This file is part of GNU Guix. ;;; @@ -387,7 +387,7 @@ (define (mock-http-get testcase) "0sjjj9z1dhilhpc8pq4154czrb79z9cm044jvn75kxcjv6v5l2m5")))) (build-system go-build-system) (arguments - '(#:import-path "github.com/go-check/check")) + (list #:import-path "github.com/go-check/check")) (propagated-inputs `(("go-github-com-kr-pretty" ,go-github-com-kr-pretty))) (home-page "https://github.com/go-check/check") -- cgit v1.2.3 From b7e3945283daec8d6bc676b659d00ed73b8e82b7 Mon Sep 17 00:00:00 2001 From: Nicolas Graves Date: Thu, 2 Nov 2023 16:16:48 +0100 Subject: guix: import: Add composer importer. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 Co-authored-by: Ludovic Courtès --- Makefile.am | 3 + doc/guix.texi | 20 +++ guix/import/composer.scm | 268 +++++++++++++++++++++++++++++++++++++++ guix/scripts/import.scm | 2 +- guix/scripts/import/composer.scm | 107 ++++++++++++++++ tests/composer.scm | 88 +++++++++++++ 6 files changed, 487 insertions(+), 1 deletion(-) create mode 100644 guix/import/composer.scm create mode 100644 guix/scripts/import/composer.scm create mode 100644 tests/composer.scm (limited to 'tests') diff --git a/Makefile.am b/Makefile.am index 0b733108d4..ee0f5ba4fc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -283,6 +283,7 @@ MODULES = \ guix/search-paths.scm \ guix/packages.scm \ guix/import/cabal.scm \ + guix/import/composer.scm \ guix/import/cpan.scm \ guix/import/cran.scm \ guix/import/crate.scm \ @@ -341,6 +342,7 @@ MODULES = \ guix/scripts/home/import.scm \ guix/scripts/lint.scm \ guix/scripts/challenge.scm \ + guix/scripts/import/composer.scm \ guix/scripts/import/crate.scm \ guix/scripts/import/cpan.scm \ guix/scripts/import/cran.scm \ @@ -509,6 +511,7 @@ SCM_TESTS = \ tests/challenge.scm \ tests/channels.scm \ tests/combinators.scm \ + tests/composer.scm \ tests/containers.scm \ tests/cpan.scm \ tests/cpio.scm \ diff --git a/doc/guix.texi b/doc/guix.texi index 7d7697d318..ffd8ae331d 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -14533,6 +14533,26 @@ repository used by the OCaml community. Additional options include: +@table @code +@item --recursive +@itemx -r +Traverse the dependency graph of the given upstream package recursively +and generate package expressions for all those packages that are not yet +in Guix. +@end table + +@item composer +@cindex Composer +@cindex PHP +Import metadata from the @uref{https://getcomposer.org/, Composer} package +archive used by the PHP community, as in this example: + +@example +guix import composer phpunit/phpunit +@end example + +Additional options include: + @table @code @item --recursive @itemx -r diff --git a/guix/import/composer.scm b/guix/import/composer.scm new file mode 100644 index 0000000000..1ad608964b --- /dev/null +++ b/guix/import/composer.scm @@ -0,0 +1,268 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2019 Julien Lepiller +;;; +;;; 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 . + +(define-module (guix import composer) + #:use-module (ice-9 match) + #:use-module (json) + #:use-module (guix hash) + #:use-module (guix base32) + #:use-module (guix build git) + #:use-module (guix build utils) + #:use-module (guix build-system) + #:use-module (guix build-system composer) + #:use-module (guix import json) + #:use-module (guix import utils) + #:use-module ((guix licenses) #:prefix license:) + #:use-module (guix memoization) + #:use-module (guix packages) + #:use-module (guix serialization) + #:use-module (guix upstream) + #:use-module (guix utils) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-11) + #:use-module (srfi srfi-26) + #:export (composer->guix-package + %composer-updater + composer-recursive-import + + %composer-base-url)) + +(define %composer-base-url + (make-parameter "https://repo.packagist.org")) + +(define (fix-version version) + "Return a fixed version from a version string. For instance, v10.1 -> 10.1" + (cond + ((string-prefix? "version" version) + (if (char-set-contains? char-set:digit (string-ref version 7)) + (substring version 7) + (substring version 8))) + ((string-prefix? "v" version) + (substring version 1)) + (else version))) + +(define (latest-version versions) + (fold (lambda (a b) (if (version>? (fix-version a) (fix-version b)) a b)) + (car versions) versions)) + +(define (json->require dict) + (if dict + (let loop ((result '()) (require dict)) + (match require + (() result) + ((((? (cut string-contains <> "/") name) . _) + require ...) + (loop (cons name result) require)) + ((_ require ...) (loop result require)) + (_ result))) + '())) + +(define-json-mapping make-composer-source composer-source? + json->composer-source + (type composer-source-type) + (url composer-source-url) + (reference composer-source-reference)) + +(define-json-mapping make-composer-package composer-package? + json->composer-package + (description composer-package-description) + (homepage composer-package-homepage) + (source composer-package-source "source" json->composer-source) + (name composer-package-name "name" php-package-name) + (version composer-package-version "version" fix-version) + (require composer-package-require "require" json->require) + (dev-require composer-package-dev-require "require-dev" json->require) + (license composer-package-license "license" + (lambda (vector) + (let ((l (map string->license (vector->list vector)))) + (if (eq? (length l) 1) + (car l) + `(list ,@l)))))) + +(define (valid-version? v) + (let ((d (string-downcase v))) + (and (not (string-contains d "dev")) + (not (string-contains d "beta")) + (not (string-contains d "rc"))))) + +(define* (composer-fetch name #:key (version #f)) + "Return a composer-package representation of the Composer metadata for the +package NAME with optional VERSION, or #f on failure." + (let* ((url (string-append (%composer-base-url) "/p/" name ".json")) + (packages (and=> (json-fetch url) + (lambda (pkg) + (let ((pkgs (assoc-ref pkg "packages"))) + (or (assoc-ref pkgs name) pkg)))))) + (if packages + (json->composer-package + (if version + (assoc-ref packages version) + (cdr + (reduce + (lambda (new cur-max) + (match new + (((? valid-version? version) . tail) + (if (version>? (fix-version version) + (fix-version (car cur-max))) + (cons* version tail) + cur-max)) + (_ cur-max))) + (cons* "0.0.0" #f) + packages)))) + #f))) + +(define (php-package-name name) + "Given the NAME of a package on Packagist, return a Guix-compliant name for +the package." + (let ((name (string-join (string-split name #\/) "-"))) + (if (string-prefix? "php-" name) + (snake-case name) + (string-append "php-" (snake-case name))))) + +(define (make-php-sexp composer-package) + "Return the `package' s-expression for a PHP package for the given +COMPOSER-PACKAGE." + (let* ((source (composer-package-source composer-package)) + (dependencies (map php-package-name + (composer-package-require composer-package))) + (dev-dependencies (map php-package-name + (composer-package-dev-require composer-package))) + (git? (equal? (composer-source-type source) "git"))) + ((if git? call-with-temporary-directory call-with-temporary-output-file) + (lambda* (temp #:optional port) + (and (if git? + (begin + (mkdir-p temp) + (git-fetch (composer-source-url source) + (composer-source-reference source) + temp)) + (url-fetch (composer-source-url source) temp)) + `(package + (name ,(composer-package-name composer-package)) + (version ,(composer-package-version composer-package)) + (source + (origin + ,@(if git? + `((method git-fetch) + (uri (git-reference + (url ,(if (string-suffix? + ".git" + (composer-source-url source)) + (string-drop-right + (composer-source-url source) + (string-length ".git")) + (composer-source-url source))) + (commit ,(composer-source-reference source)))) + (file-name (git-file-name name version)) + (sha256 + (base32 + ,(bytevector->nix-base32-string + (file-hash* temp))))) + `((method url-fetch) + (uri ,(composer-source-url source)) + (sha256 (base32 ,(guix-hash-url temp))))))) + (build-system composer-build-system) + ,@(if (null? dependencies) + '() + `((inputs + (list ,@(map string->symbol dependencies))))) + ,@(if (null? dev-dependencies) + '() + `((native-inputs + (list ,@(map string->symbol dev-dependencies))))) + (synopsis "") + (description ,(composer-package-description composer-package)) + (home-page ,(composer-package-homepage composer-package)) + (license ,(or (composer-package-license composer-package) + 'unknown-license!)))))))) + +(define composer->guix-package + (memoize + (lambda* (package-name #:key (version #f) #:allow-other-keys) + "Fetch the metadata for PACKAGE-NAME from packagist.org, and return the +`package' s-expression corresponding to that package and its list of +dependencies, or #f and the empty list on failure." + (let ((package (composer-fetch package-name #:version version))) + (if package + (let* ((dependencies-names (composer-package-require package)) + (dev-dependencies-names (composer-package-dev-require package))) + (values (make-php-sexp package) + (append dependencies-names dev-dependencies-names))) + (values #f '())))))) + +(define (guix-name->composer-name name) + "Given a guix package name, return the name of the package in Packagist." + (if (string-prefix? "php-" name) + (let ((components (string-split (substring name 4) #\-))) + (match components + ((namespace name ...) + (string-append namespace "/" (string-join name "-"))))) + name)) + +(define (guix-package->composer-name package) + "Given a Composer PACKAGE built from Packagist, return the name of the +package in Packagist." + (let ((upstream-name (assoc-ref + (package-properties package) + 'upstream-name)) + (name (package-name package))) + (if upstream-name + upstream-name + (guix-name->composer-name name)))) + +(define (string->license str) + "Convert the string STR into a license object." + (or (spdx-string->license str) + (match str + ("GNU LGPL" 'license:lgpl2.0) + ("GPL" 'license:gpl3) + ((or "BSD" "BSD License") 'license:bsd-3) + ((or "MIT" "MIT license" "Expat license") 'license:expat) + ("Public domain" 'license:public-domain) + ((or "Apache License, Version 2.0" "Apache 2.0") 'license:asl2.0) + (_ 'unknown-license!)))) + +(define (php-package? package) + "Return true if PACKAGE is a PHP package from Packagist." + (and + (eq? (package-build-system package) composer-build-system) + (string-prefix? "php-" (package-name package)))) + +(define (latest-release package) + "Return an for the latest release of PACKAGE." + (let* ((php-name (guix-package->composer-name package)) + (package (composer-fetch php-name)) + (version (composer-package-version package)) + (url (composer-source-url (composer-package-source package)))) + (upstream-source + (package (package-name package)) + (version version) + (urls (list url))))) + +(define %composer-updater + (upstream-updater + (name 'composer) + (description "Updater for Composer packages") + (pred php-package?) + (import latest-release))) + +(define* (composer-recursive-import package-name #:optional version) + (recursive-import package-name + #:version version + #:repo->guix-package composer->guix-package + #:guix-name php-package-name)) diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm index 1e8ffd25ec..d2a1cee56e 100644 --- a/guix/scripts/import.scm +++ b/guix/scripts/import.scm @@ -47,7 +47,7 @@ (define %standard-import-options '()) (define importers '("gnu" "pypi" "cpan" "hackage" "stackage" "egg" "elpa" "gem" "go" "cran" "crate" "texlive" "json" "opam" - "minetest" "elm" "hexpm")) + "minetest" "elm" "hexpm" "composer")) (define (resolve-importer name) (let ((module (resolve-interface diff --git a/guix/scripts/import/composer.scm b/guix/scripts/import/composer.scm new file mode 100644 index 0000000000..412bae6318 --- /dev/null +++ b/guix/scripts/import/composer.scm @@ -0,0 +1,107 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2015 David Thompson +;;; Copyright © 2018 Oleg Pykhalov +;;; +;;; 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 . + +(define-module (guix scripts import composer) + #:use-module (guix ui) + #:use-module (guix utils) + #:use-module (guix scripts) + #:use-module (guix import composer) + #:use-module (guix scripts import) + #: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-composer)) + + +;;; +;;; Command-line options. +;;; + +(define %default-options + '()) + +(define (show-help) + (display (G_ "Usage: guix import composer PACKAGE-NAME +Import and convert the Composer package for PACKAGE-NAME.\n")) + (display (G_ " + -h, --help display this help and exit")) + (display (G_ " + -V, --version display version information and exit")) + (display (G_ " + -r, --recursive generate package expressions for all Composer packages\ + that are not yet in Guix")) + (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 composer"))) + (option '(#\r "recursive") #f #f + (lambda (opt name arg result) + (alist-cons 'recursive #t result))) + %standard-import-options)) + + +;;; +;;; Entry point. +;;; + +(define (guix-import-composer . args) + (define (parse-options) + ;; Return the alist of option values. + (args-fold* args %options + (lambda (opt name arg result) + (leave (G_ "~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) + (if (assoc-ref opts 'recursive) + (map (match-lambda + ((and ('package ('name name) . rest) pkg) + `(define-public ,(string->symbol name) + ,pkg)) + (_ #f)) + (composer-recursive-import package-name)) + (let ((sexp (composer->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 ...) + (leave (G_ "too many arguments~%")))))) diff --git a/tests/composer.scm b/tests/composer.scm new file mode 100644 index 0000000000..9114fef19e --- /dev/null +++ b/tests/composer.scm @@ -0,0 +1,88 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2020 Julien Lepiller +;;; Copyright © 2023 Nicolas Graves +;;; +;;; 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 . + +(define-module (test-composer) + #:use-module (guix import composer) + #:use-module (guix base32) + #:use-module (gcrypt hash) + #:use-module (guix tests http) + #:use-module (guix grafts) + #:use-module (srfi srfi-64) + #:use-module (web client) + #:use-module (ice-9 match)) + +;; Globally disable grafts because they can trigger early builds. +(%graft? #f) + +(define test-json + "{ + \"packages\": { + \"foo/bar\": { + \"0.1\": { + \"name\": \"foo/bar\", + \"description\": \"description\", + \"keywords\": [\"testing\"], + \"homepage\": \"http://example.com\", + \"version\": \"0.1\", + \"license\": [\"BSD-3-Clause\"], + \"source\": { + \"type\": \"url\", + \"url\": \"http://example.com/Bar-0.1.tar.gz\" + }, + \"require\": {}, + \"require-dev\": {\"phpunit/phpunit\": \"1.0.0\"} + } + } + } +}") + +(define test-source + "foobar") + +(test-begin "composer") + +(test-assert "composer->guix-package" + ;; Replace network resources with sample data. + (with-http-server `((200 ,test-json) + (200 ,test-source)) + (parameterize ((%composer-base-url (%local-url)) + (current-http-proxy (%local-url))) + (match (composer->guix-package "foo/bar") + (`(package + (name "php-foo-bar") + (version "0.1") + (source (origin + (method url-fetch) + (uri "http://example.com/Bar-0.1.tar.gz") + (sha256 + (base32 + ,(? string? hash))))) + (build-system composer-build-system) + (native-inputs (list php-phpunit-phpunit)) + (synopsis "") + (description "description") + (home-page "http://example.com") + (license license:bsd-3)) + (string=? (bytevector->nix-base32-string + (call-with-input-string test-source port-sha256)) + hash)) + (x + (pk 'fail x #f)))))) + +(test-end "composer") -- cgit v1.2.3 From d9190abbd20f15ea5b55abdd51e1376f05055850 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Sun, 12 Nov 2023 22:47:43 +0100 Subject: gexp: Add compiler for . * guix/gexp.scm (gexp-input-compiler): New procedure. * tests/gexp.scm ("gexp references non-existent output") ("gexp-input, as first-class input"): New tests. * doc/guix.texi (G-Expressions): Document it. Reviewed-by: Maxim Cournoyer Change-Id: I95b58d6e4d77a54364026b4324fbb00125a9402e --- doc/guix.texi | 38 ++++++++++++++++++++++++++++++++++++++ guix/gexp.scm | 19 ++++++++++++++++++- tests/gexp.scm | 24 ++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/doc/guix.texi b/doc/guix.texi index b742a3d5b2..a760d627eb 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -12197,6 +12197,11 @@ This is like the form above, but referring explicitly to the @var{output} of @var{obj}---this is useful when @var{obj} produces multiple outputs (@pxref{Packages with Multiple Outputs}). +Sometimes a gexp unconditionally refers to the @code{"out"} output, but +the user of that gexp would still like to insert a reference to another +output. The @code{gexp-input} procedure aims to address that. +@xref{gexp-input}. + @item #+@var{obj} @itemx #+@var{obj}:output @itemx (ungexp-native @var{obj}) @@ -12590,6 +12595,39 @@ The example above returns an object that corresponds to the i686 build of Coreutils, regardless of the current value of @code{%current-system}. @end defmac +@anchor{gexp-input} +@deffn {Procedure} gexp-input @var{obj} [@var{output}] [#:native? #f] +Return a @dfn{gexp input} record for the given @var{output} of file-like +object @var{obj}, with @code{#:native?} determining whether this is a +native reference (as with @code{ungexp-native}) or not. + +This procedure is helpful when you want to pass a reference to a +specific output of an object to some procedure that may not know about +that output. For example, assume you have this procedure, which takes +one file-like object: + +@lisp +(define (make-symlink target) + (computed-file "the-symlink" + #~(symlink #$target #$output))) +@end lisp + +Here @code{make-symlink} can only ever refer to the default output of +@var{target}---the @code{"out"} output (@pxref{Packages with Multiple +Outputs}). To have it refer to, say, the @code{"lib"} output of the +@code{hwloc} package, you can call it like so: + +@lisp +(make-symlink (gexp-input hwloc "lib")) +@end lisp + +You can also compose it like any other file-like object: + +@lisp +(make-symlink + (file-append (gexp-input hwloc "lib") "/lib/libhwloc.so")) +@end lisp +@end deffn Of course, in addition to gexps embedded in ``host'' code, there are also modules containing build tools. To make it clear that they are diff --git a/guix/gexp.scm b/guix/gexp.scm index 0fe4f1c98a..a7f4256d24 100644 --- a/guix/gexp.scm +++ b/guix/gexp.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2014-2022 Ludovic Courtès +;;; Copyright © 2014-2023 Ludovic Courtès ;;; Copyright © 2018 Clément Lassieur ;;; Copyright © 2018 Jan Nieuwenhuizen ;;; Copyright © 2019, 2020 Mathieu Othacehe @@ -775,6 +775,23 @@ (define* (gexp-input thing ;convenience procedure whether this should be considered a \"native\" input or not." (%gexp-input thing output native?)) +;; Allow s to be used within gexps. This is useful when willing +;; to force a specific reference to an object, as in (gexp-input hwloc "bin"), +;; which forces a reference to the "bin" output of 'hwloc' instead of leaving +;; it up to the recipient to pick the right output. +(define-gexp-compiler gexp-input-compiler + compiler => (lambda (obj system target) + (match obj + (($ thing output native?) + (lower-object thing system + #:target (and (not native?) target))))) + expander => (lambda (obj lowered output/ignored) + (match obj + (($ thing output native?) + (let ((expand (or (lookup-expander thing) + (lookup-expander lowered)))) + (expand thing lowered output)))))) + ;; Reference to one of the derivation's outputs, for gexps used in ;; derivations. (define-record-type diff --git a/tests/gexp.scm b/tests/gexp.scm index 0e3c446576..871e5f7abb 100644 --- a/tests/gexp.scm +++ b/tests/gexp.scm @@ -393,6 +393,30 @@ (define (match-input thing) (list item)) (null? (lowered-gexp-inputs lexp))))) +(test-equal "gexp references non-existent output" + "no-default-output" + (guard (c ((derivation-missing-output-error? c) + (derivation-name (derivation-error-derivation c)))) + (let* ((obj (computed-file "no-default-output" + #~(mkdir #$output:bar))) + (exp #~(symlink #$obj #$output)) + (drv (run-with-store %store (lower-gexp exp)))) + (pk 'oops! drv #f)))) + +(test-assert "gexp-input, as first-class input" + ;; Insert a record in a gexp as a way to specify which output + ;; of OBJ should be used. + (let* ((obj (computed-file "foo" #~(mkdir #$output:bar))) + (exp #~(list #$(gexp-input obj "bar"))) + (drv (run-with-store %store (lower-object obj))) + (item (derivation->output-path drv "bar")) + (lexp (run-with-store %store (lower-gexp exp)))) + (and (match (lowered-gexp-inputs lexp) + ((input) + (eq? (derivation-input-derivation input) drv))) + (equal? (lowered-gexp-sexp lexp) + `(list ,item))))) + (test-assertm "with-parameters for %current-system" (mlet* %store-monad ((system -> (match (%current-system) ("aarch64-linux" "x86_64-linux") -- cgit v1.2.3 From 11a454f9dae84cc00b977d164dae764454ecb11d Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Mon, 13 Nov 2023 17:43:29 +0100 Subject: gexp: #:references-graphs accepts and honors records. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * guix/gexp.scm (lower-reference-graphs)[tuple->gexp-input]: Add ‘gexp-input?’ case. (gexp->derivation): Update docstring. * doc/guix.texi (G-Expressions): Adjust accordingly. * tests/gexp.scm ("references-file, non-default output"): New test. Reviewed-by: Maxim Cournoyer Change-Id: I595cb75da0867ab8ab44552887dc06ed1d23315e --- doc/guix.texi | 7 +++---- guix/gexp.scm | 12 ++++++++---- tests/gexp.scm | 30 ++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 8 deletions(-) (limited to 'tests') diff --git a/doc/guix.texi b/doc/guix.texi index a760d627eb..f869a6bae4 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -12314,10 +12314,9 @@ When @var{references-graphs} is true, it must be a list of tuples of one of the following forms: @example -(@var{file-name} @var{package}) -(@var{file-name} @var{package} @var{output}) -(@var{file-name} @var{derivation}) -(@var{file-name} @var{derivation} @var{output}) +(@var{file-name} @var{obj}) +(@var{file-name} @var{obj} @var{output}) +(@var{file-name} @var{gexp-input}) (@var{file-name} @var{store-item}) @end example diff --git a/guix/gexp.scm b/guix/gexp.scm index a7f4256d24..29819878fa 100644 --- a/guix/gexp.scm +++ b/guix/gexp.scm @@ -934,6 +934,11 @@ (define* (lower-reference-graphs graphs #:key system target) corresponding or store item." (define tuple->gexp-input (match-lambda + (((? gexp-input? input)) + ;; This case lets users specify the output of interest more + ;; conveniently, for instance by passing (gexp-input hwloc "lib") to + ;; the 'references-file' procedure. + input) ((thing) (%gexp-input thing "out" (not target))) ((thing output) @@ -1152,10 +1157,9 @@ (define* (gexp->derivation name exp When REFERENCES-GRAPHS is true, it must be a list of tuples of one of the following forms: - (FILE-NAME PACKAGE) - (FILE-NAME PACKAGE OUTPUT) - (FILE-NAME DERIVATION) - (FILE-NAME DERIVATION OUTPUT) + (FILE-NAME OBJ) + (FILE-NAME OBJ OUTPUT) + (FILE-NAME GEXP-INPUT) (FILE-NAME STORE-ITEM) The right-hand-side of each element of REFERENCES-GRAPHS is automatically made diff --git a/tests/gexp.scm b/tests/gexp.scm index 871e5f7abb..001786c13c 100644 --- a/tests/gexp.scm +++ b/tests/gexp.scm @@ -1652,6 +1652,36 @@ (define (contents=? file str) read) refs))))))) +(test-assertm "references-file, non-default output" + (let* ((exp #~(begin + (mkdir #$output) + (symlink #$%bootstrap-guile #$output:extra))) + (computed (computed-file "computed" exp + #:guile %bootstrap-guile)) + (refs1 (references-file computed + #:guile %bootstrap-guile)) + ;; Wrap COMPUTE in 'gexp-input' to get the "extra" output. + (refs2 (references-file (gexp-input computed "extra") + #:guile %bootstrap-guile))) + (mlet* %store-monad ((drv0 (lower-object %bootstrap-guile)) + (drv1 (lower-object computed)) + (drv2 (lower-object refs2)) + (drv3 (lower-object refs1))) + (mbegin %store-monad + (built-derivations (list drv2 drv3)) + (mlet %store-monad ((refs ((store-lift requisites) + (list (derivation->output-path + drv1 "extra"))))) + (return + (and (lset= string=? + (call-with-input-file (derivation->output-path drv2) + read) + refs) + (lset= string=? + (call-with-input-file (derivation->output-path drv3) + read) + (list (derivation->output-path drv1)))))))))) + (test-assert "lower-object & gexp-input-error?" (guard (c ((gexp-input-error? c) (gexp-error-invalid-input c))) -- cgit v1.2.3