From c05ceaf2b650d090cf39a048193505cb4e6bd257 Mon Sep 17 00:00:00 2001 From: Maxime Devos Date: Sat, 20 Feb 2021 22:04:59 +0100 Subject: tests: do not hard code HTTP ports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, test cases could fail if some process was listening at a hard-coded port. This patch eliminates most of these potential failures, by automatically assigning an unbound port. This should allow for building multiple guix trees in parallel outside a build container, though this is currently untested. The test "home-page: Connection refused" in tests/lint.scm still hardcodes port 9999, however. * guix/tests/http.scm (http-server-can-listen?): remove now unused procedure. (%http-server-port): default to port 0, meaning the OS will automatically choose a port. (open-http-server-socket): remove the false statement claiming this procedure is exported and also return the allocated port number. (%local-url): raise an error if the port is obviously unbound. (call-with-http-server): set %http-server-port to the allocated port while the thunk is called. * tests/derivations.scm: adjust test cases to use automatically assign a port. As there is no risk of a port conflict now, do not make any tests conditional upon 'http-server-can-listen?' anymore. * tests/elpa.scm: likewise. * tests/lint.scm: likewise, and add a TODO comment about a port that is still hard-coded. * tests/texlive.scm: likewise. Signed-off-by: Ludovic Courtès --- tests/derivations.scm | 41 +++++------- tests/elpa.scm | 3 - tests/lint.scm | 179 +++++++++++++++++++++++--------------------------- tests/texlive.scm | 3 - 4 files changed, 97 insertions(+), 129 deletions(-) (limited to 'tests') diff --git a/tests/derivations.scm b/tests/derivations.scm index 9f1104a887..cd165d1be6 100644 --- a/tests/derivations.scm +++ b/tests/derivations.scm @@ -77,9 +77,6 @@ (lambda (e1 e2) (string. - (let* ((text (random-text)) - (drv (derivation %store "world" - "builtin:download" '() - #:env-vars `(("url" - . ,(object->string (%local-url)))) - #:hash-algo 'sha256 - #:hash (gcrypt:sha256 (string->utf8 text))))) - (and (with-http-server `((200 ,text)) - (build-derivations %store (list drv))) - (with-http-server `((200 ,text)) - (build-derivations %store (list drv) - (build-mode check))) - (string=? (call-with-input-file (derivation->output-path drv) - get-string-all) - text)))) + (let* ((text (random-text))) + (with-http-server `((200 ,text)) + (let ((drv (derivation %store "world" + "builtin:download" '() + #:env-vars `(("url" + . ,(object->string (%local-url)))) + #:hash-algo 'sha256 + #:hash (gcrypt:sha256 (string->utf8 text))))) + (and drv (build-derivations %store (list drv)) + (with-http-server `((200 ,text)) + (build-derivations %store (list drv) + (build-mode check))) + (string=? (call-with-input-file (derivation->output-path drv) + get-string-all) + text)))))) (test-equal "derivation-name" "foo-0.0" diff --git a/tests/elpa.scm b/tests/elpa.scm index a008cf993c..01ef948b2e 100644 --- a/tests/elpa.scm +++ b/tests/elpa.scm @@ -40,9 +40,6 @@ nil "Integrated environment for *TeX*" tar ((:url . "http://www.gnu.org/software/auctex/"))]))) -;; Avoid collisions with other tests. -(%http-server-port 10300) - (test-begin "elpa") (define (eval-test-with-elpa pkg) diff --git a/tests/lint.scm b/tests/lint.scm index 7c24611934..b92053fd5f 100644 --- a/tests/lint.scm +++ b/tests/lint.scm @@ -62,7 +62,6 @@ ;; Test the linter. ;; Avoid collisions with other tests. -(%http-server-port 9999) (define %null-sha256 ;; SHA256 of the empty string. @@ -500,16 +499,16 @@ (home-page "http://does-not-exist")))) (warning-contains? "domain not found" (check-home-page pkg)))) -(test-skip (if (http-server-can-listen?) 0 1)) -(test-equal "home-page: Connection refused" - "URI http://localhost:9999/foo/bar unreachable: Connection refused" - (let ((pkg (package - (inherit (dummy-package "x")) - (home-page (%local-url))))) - (single-lint-warning-message - (check-home-page pkg)))) +(parameterize ((%http-server-port 9999)) + ;; TODO skip this test if some process is currently listening at 9999 + (test-equal "home-page: Connection refused" + "URI http://localhost:9999/foo/bar unreachable: Connection refused" + (let ((pkg (package + (inherit (dummy-package "x")) + (home-page (%local-url))))) + (single-lint-warning-message + (check-home-page pkg))))) -(test-skip (if (http-server-can-listen?) 0 1)) (test-equal "home-page: 200" '() (with-http-server `((200 ,%long-string)) @@ -518,10 +517,10 @@ (home-page (%local-url))))) (check-home-page pkg)))) -(test-skip (if (http-server-can-listen?) 0 1)) -(test-equal "home-page: 200 but short length" - "URI http://localhost:9999/foo/bar returned suspiciously small file (18 bytes)" - (with-http-server `((200 "This is too small.")) +(with-http-server `((200 "This is too small.")) + (test-equal "home-page: 200 but short length" + (format #f "URI ~a returned suspiciously small file (18 bytes)" + (%local-url)) (let ((pkg (package (inherit (dummy-package "x")) (home-page (%local-url))))) @@ -529,54 +528,51 @@ (single-lint-warning-message (check-home-page pkg))))) -(test-skip (if (http-server-can-listen?) 0 1)) -(test-equal "home-page: 404" - "URI http://localhost:9999/foo/bar not reachable: 404 (\"Such is life\")" - (with-http-server `((404 ,%long-string)) +(with-http-server `((404 ,%long-string)) + (test-equal "home-page: 404" + (format #f "URI ~a not reachable: 404 (\"Such is life\")" (%local-url)) (let ((pkg (package (inherit (dummy-package "x")) (home-page (%local-url))))) (single-lint-warning-message (check-home-page pkg))))) -(test-skip (if (http-server-can-listen?) 0 1)) -(test-equal "home-page: 301, invalid" - "invalid permanent redirect from http://localhost:9999/foo/bar" - (with-http-server `((301 ,%long-string)) +(with-http-server `((301 ,%long-string)) + (test-equal "home-page: 301, invalid" + (format #f "invalid permanent redirect from ~a" (%local-url)) (let ((pkg (package (inherit (dummy-package "x")) (home-page (%local-url))))) (single-lint-warning-message (check-home-page pkg))))) -(test-skip (if (http-server-can-listen?) 0 1)) -(test-equal "home-page: 301 -> 200" - "permanent redirect from http://localhost:10000/foo/bar to http://localhost:9999/foo/bar" - (with-http-server `((200 ,%long-string)) - (let* ((initial-url (%local-url)) - (redirect (build-response #:code 301 - #:headers - `((location - . ,(string->uri initial-url)))))) - (parameterize ((%http-server-port (+ 1 (%http-server-port)))) - (with-http-server `((,redirect "")) +(with-http-server `((200 ,%long-string)) + (let* ((initial-url (%local-url)) + (redirect (build-response #:code 301 + #:headers + `((location + . ,(string->uri initial-url)))))) + (parameterize ((%http-server-port 0)) + (with-http-server `((,redirect "")) + (test-equal "home-page: 301 -> 200" + (format #f "permanent redirect from ~a to ~a" + (%local-url) initial-url) (let ((pkg (package (inherit (dummy-package "x")) (home-page (%local-url))))) (single-lint-warning-message (check-home-page pkg)))))))) -(test-skip (if (http-server-can-listen?) 0 1)) -(test-equal "home-page: 301 -> 404" - "URI http://localhost:10000/foo/bar not reachable: 404 (\"Such is life\")" - (with-http-server '((404 "booh!")) - (let* ((initial-url (%local-url)) - (redirect (build-response #:code 301 - #:headers - `((location - . ,(string->uri initial-url)))))) - (parameterize ((%http-server-port (+ 1 (%http-server-port)))) - (with-http-server `((,redirect "")) +(with-http-server `((404 "booh!")) + (let* ((initial-url (%local-url)) + (redirect (build-response #:code 301 + #:headers + `((location + . ,(string->uri initial-url)))))) + (parameterize ((%http-server-port 0)) + (with-http-server `((,redirect "")) + (test-equal "home-page: 301 -> 404" + (format #f "URI ~a not reachable: 404 (\"Such is life\")" (%local-url)) (let ((pkg (package (inherit (dummy-package "x")) (home-page (%local-url))))) @@ -706,7 +702,6 @@ (sha256 %null-sha256)))))) (check-source-unstable-tarball pkg))) -(test-skip (if (http-server-can-listen?) 0 1)) (test-equal "source: 200" '() (with-http-server `((200 ,%long-string)) @@ -718,10 +713,10 @@ (sha256 %null-sha256)))))) (check-source pkg)))) -(test-skip (if (http-server-can-listen?) 0 1)) -(test-equal "source: 200 but short length" - "URI http://localhost:9999/foo/bar returned suspiciously small file (18 bytes)" - (with-http-server '((200 "This is too small.")) +(with-http-server '((200 "This is too small.")) + (test-equal "source: 200 but short length" + (format #f "URI ~a returned suspiciously small file (18 bytes)" + (%local-url)) (let ((pkg (package (inherit (dummy-package "x")) (source (origin @@ -733,10 +728,10 @@ (and (? lint-warning?) second-warning)) (lint-warning-message second-warning)))))) -(test-skip (if (http-server-can-listen?) 0 1)) -(test-equal "source: 404" - "URI http://localhost:9999/foo/bar not reachable: 404 (\"Such is life\")" - (with-http-server `((404 ,%long-string)) +(with-http-server `((404 ,%long-string)) + (test-equal "source: 404" + (format #f "URI ~a not reachable: 404 (\"Such is life\")" + (%local-url)) (let ((pkg (package (inherit (dummy-package "x")) (source (origin @@ -748,7 +743,6 @@ (and (? lint-warning?) second-warning)) (lint-warning-message second-warning)))))) -(test-skip (if (http-server-can-listen?) 0 1)) (test-equal "source: 404 and 200" '() (with-http-server `((404 ,%long-string)) @@ -765,17 +759,17 @@ ;; list. (check-source pkg))))))) -(test-skip (if (http-server-can-listen?) 0 1)) -(test-equal "source: 301 -> 200" - "permanent redirect from http://localhost:10000/foo/bar to http://localhost:9999/foo/bar" - (with-http-server `((200 ,%long-string)) - (let* ((initial-url (%local-url)) - (redirect (build-response #:code 301 - #:headers - `((location - . ,(string->uri initial-url)))))) - (parameterize ((%http-server-port (+ 1 (%http-server-port)))) - (with-http-server `((,redirect "")) +(with-http-server `((200 ,%long-string)) + (let* ((initial-url (%local-url)) + (redirect (build-response #:code 301 + #:headers + `((location + . ,(string->uri initial-url)))))) + (parameterize ((%http-server-port 0)) + (with-http-server `((,redirect "")) + (test-equal "source: 301 -> 200" + (format #f "permanent redirect from ~a to ~a" + (%local-url) initial-url) (let ((pkg (package (inherit (dummy-package "x")) (source (origin @@ -787,17 +781,17 @@ (and (? lint-warning?) second-warning)) (lint-warning-message second-warning))))))))) -(test-skip (if (http-server-can-listen?) 0 1)) -(test-equal "source, git-reference: 301 -> 200" - "permanent redirect from http://localhost:10000/foo/bar to http://localhost:9999/foo/bar" - (with-http-server `((200 ,%long-string)) - (let* ((initial-url (%local-url)) - (redirect (build-response #:code 301 - #:headers - `((location - . ,(string->uri initial-url)))))) - (parameterize ((%http-server-port (+ 1 (%http-server-port)))) - (with-http-server `((,redirect "")) +(with-http-server `((200 ,%long-string)) + (let* ((initial-url (%local-url)) + (redirect (build-response #:code 301 + #:headers + `((location + . ,(string->uri initial-url)))))) + (parameterize ((%http-server-port 0)) + (with-http-server `((,redirect "")) + (test-equal "source, git-reference: 301 -> 200" + (format #f "permanent redirect from ~a to ~a" + (%local-url) initial-url) (let ((pkg (dummy-package "x" (source (origin @@ -807,17 +801,17 @@ (sha256 %null-sha256)))))) (single-lint-warning-message (check-source pkg)))))))) -(test-skip (if (http-server-can-listen?) 0 1)) -(test-equal "source: 301 -> 404" - "URI http://localhost:10000/foo/bar not reachable: 404 (\"Such is life\")" - (with-http-server '((404 "booh!")) - (let* ((initial-url (%local-url)) - (redirect (build-response #:code 301 - #:headers - `((location - . ,(string->uri initial-url)))))) - (parameterize ((%http-server-port (+ 1 (%http-server-port)))) - (with-http-server `((,redirect "")) +(with-http-server '((404 "booh!")) + (let* ((initial-url (%local-url)) + (redirect (build-response #:code 301 + #:headers + `((location + . ,(string->uri initial-url)))))) + (parameterize ((%http-server-port 0)) + (with-http-server `((,redirect "")) + (test-equal "source: 301 -> 404" + (format #f "URI ~a not reachable: 404 (\"Such is life\")" + (%local-url)) (let ((pkg (package (inherit (dummy-package "x")) (source (origin @@ -847,7 +841,6 @@ (single-lint-warning-message (check-mirror-url (dummy-package "x" (source source)))))) -(test-skip (if (http-server-can-listen?) 0 1)) (test-equal "github-url" '() (with-http-server `((200 ,%long-string)) @@ -859,7 +852,6 @@ (sha256 %null-sha256))))))) (let ((github-url "https://github.com/foo/bar/bar-1.0.tar.gz")) - (test-skip (if (http-server-can-listen?) 0 1)) (test-equal "github-url: one suggestion" (string-append "URL should be '" github-url "'") @@ -873,7 +865,7 @@ #:headers `((location . ,(string->uri initial-url)))))) - (parameterize ((%http-server-port (+ 1 (%http-server-port)))) + (parameterize ((%http-server-port 0)) (with-http-server `((,redirect "")) (single-lint-warning-message (check-github-url @@ -883,7 +875,6 @@ (uri (%local-url)) (sha256 %null-sha256)))))))))))) - (test-skip (if (http-server-can-listen?) 0 1)) (test-equal "github-url: already the correct github url" '() (check-github-url @@ -1007,7 +998,6 @@ '() (check-formatting (dummy-package "x"))) -(test-skip (if (http-server-can-listen?) 0 1)) (test-assert "archival: missing content" (let* ((origin (origin (method url-fetch) @@ -1019,7 +1009,6 @@ (source origin))))))) (warning-contains? "not archived" warnings))) -(test-skip (if (http-server-can-listen?) 0 1)) (test-equal "archival: content available" '() (let* ((origin (origin @@ -1033,7 +1022,6 @@ (parameterize ((%swh-base-url (%local-url))) (check-archival (dummy-package "x" (source origin))))))) -(test-skip (if (http-server-can-listen?) 0 1)) (test-assert "archival: missing revision" (let* ((origin (origin (method git-fetch) @@ -1053,7 +1041,6 @@ (check-archival (dummy-package "x" (source origin))))))) (warning-contains? "scheduled" warnings))) -(test-skip (if (http-server-can-listen?) 0 1)) (test-equal "archival: revision available" '() (let* ((origin (origin @@ -1069,7 +1056,6 @@ (parameterize ((%swh-base-url (%local-url))) (check-archival (dummy-package "x" (source origin))))))) -(test-skip (if (http-server-can-listen?) 0 1)) (test-assert "archival: rate limit reached" ;; We should get a single warning stating that the rate limit was reached, ;; and nothing more, in particular no other HTTP requests. @@ -1091,7 +1077,6 @@ (string-contains (single-lint-warning-message warnings) "rate limit reached"))) -(test-skip (if (http-server-can-listen?) 0 1)) (test-assert "haskell-stackage" (let* ((stackage (string-append "{ \"packages\": [{" " \"name\":\"x\"," diff --git a/tests/texlive.scm b/tests/texlive.scm index f7e5515c4c..a6f08046a8 100644 --- a/tests/texlive.scm +++ b/tests/texlive.scm @@ -69,9 +69,6 @@ (keyval (@ (value "tests") (key "topic"))) "\n null\n"))) -;; Avoid collisions with other tests. -(%http-server-port 10200) - (test-equal "fetch-sxml: returns SXML for valid XML" sxml (with-http-server `((200 ,xml)) -- cgit 1.4.1 From 02e2e093e858e8a0ca7bd66c1f1f6fd0a1705edb Mon Sep 17 00:00:00 2001 From: Katherine Cox-Buday Date: Thu, 22 Oct 2020 19:40:17 -0500 Subject: import: Add Go importer. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds a 'guix import go' command. * doc/guix.texi (Requirements): Mention Guile-Lib dependency. (Invoking guix import): Document 'guix import go'. * gnu/packages/package-management.scm (guix)[inputs, propagated-inputs]: Add GUILE-LIB. * guix/self.scm (compiled-guix)[guile-lib]: New variable. [dependencies]: Add it. (specification->package): Add "guile-lib". * guix/build-system/go.scm (go-version->git-ref): New procedure. * guix/import/go.scm, guix/scripts/import/go.scm, tests/go.scm: New files. * guix/scripts/import.scm: Declare subcommand guix import go * po/guix/POTFILES.in: Add 'guix/scripts/import/go.scm'. * Makefile.am (MODULES): Add 'guix/import/go.scm' and 'guix/scripts/import/go.scm'. (SCM_TESTS): Add 'tests/go.scm'. Co-Authored-By: Helio Machado <0x2b3bfa0@gmail.com> Co-Authored-By: Francois Joulaud Co-Authored-By: Maxim Cournoyer Co-Authored-by: Ludovic Courtès --- Makefile.am | 3 + doc/guix.texi | 26 ++ gnu/packages/package-management.scm | 3 + guix/build-system/go.scm | 35 ++- guix/import/go.scm | 501 ++++++++++++++++++++++++++++++++++++ guix/scripts/import.scm | 2 +- guix/scripts/import/go.scm | 118 +++++++++ guix/self.scm | 6 +- po/guix/POTFILES.in | 1 + tests/go.scm | 281 ++++++++++++++++++++ 10 files changed, 973 insertions(+), 3 deletions(-) create mode 100644 guix/import/go.scm create mode 100644 guix/scripts/import/go.scm create mode 100644 tests/go.scm (limited to 'tests') diff --git a/Makefile.am b/Makefile.am index 0f87c958f7..f40d9509be 100644 --- a/Makefile.am +++ b/Makefile.am @@ -251,6 +251,7 @@ MODULES = \ guix/import/github.scm \ guix/import/gnome.scm \ guix/import/gnu.scm \ + guix/import/go.scm \ guix/import/hackage.scm \ guix/import/json.scm \ guix/import/kde.scm \ @@ -294,6 +295,7 @@ MODULES = \ guix/scripts/import/elpa.scm \ guix/scripts/import/gem.scm \ guix/scripts/import/gnu.scm \ + guix/scripts/import/go.scm \ guix/scripts/import/hackage.scm \ guix/scripts/import/json.scm \ guix/scripts/import/nix.scm \ @@ -455,6 +457,7 @@ SCM_TESTS = \ tests/git-authenticate.scm \ tests/glob.scm \ tests/gnu-maintenance.scm \ + tests/go.scm \ tests/grafts.scm \ tests/graph.scm \ tests/gremlin.scm \ diff --git a/doc/guix.texi b/doc/guix.texi index f01e7ca89d..77aafafd97 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -862,6 +862,10 @@ substitutes (@pxref{Invoking guix publish}). @uref{https://ngyro.com/software/guile-semver.html, Guile-Semver} for the @code{crate} importer (@pxref{Invoking guix import}). +@item +@uref{https://www.nongnu.org/guile-lib/doc/ref/htmlprag/, Guile-Lib} for +the @code{go} importer (@pxref{Invoking guix import}). + @item When @url{http://www.bzip.org, libbz2} is available, @command{guix-daemon} can use it to compress build logs. @@ -11494,6 +11498,28 @@ Select the given repository (a repository name). Possible values include: of coq packages. @end itemize @end table + +@item go +@cindex go +Import metadata for a Go module using +@uref{https://proxy.golang.org, proxy.golang.org}. + +This importer is highly experimental. See the source code for more info +about the current state. + +@example +guix import go gopkg.in/yaml.v2 +@end example + +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 @end table The structure of the @command{guix import} code is modular. It would be diff --git a/gnu/packages/package-management.scm b/gnu/packages/package-management.scm index 60aa3f8624..9bf24f8533 100644 --- a/gnu/packages/package-management.scm +++ b/gnu/packages/package-management.scm @@ -304,6 +304,7 @@ $(prefix)/etc/init.d\n"))) '((assoc-ref inputs "guile")))) (avahi (assoc-ref inputs "guile-avahi")) (gcrypt (assoc-ref inputs "guile-gcrypt")) + (guile-lib (assoc-ref inputs "guile-lib")) (json (assoc-ref inputs "guile-json")) (sqlite (assoc-ref inputs "guile-sqlite3")) (zlib (assoc-ref inputs "guile-zlib")) @@ -367,6 +368,7 @@ $(prefix)/etc/init.d\n"))) `(("guile-avahi" ,guile-avahi))) ("guile-gcrypt" ,guile-gcrypt) ("guile-json" ,guile-json-4) + ("guile-lib" ,guile-lib) ("guile-sqlite3" ,guile-sqlite3) ("guile-zlib" ,guile-zlib) ("guile-lzlib" ,guile-lzlib) @@ -422,6 +424,7 @@ $(prefix)/etc/init.d\n"))) `(("guile-avahi" ,guile-avahi))) ("guile-gcrypt" ,guile-gcrypt) ("guile-json" ,guile-json-4) + ("guile-lib" ,guile-lib) ("guile-sqlite3" ,guile-sqlite3) ("guile-ssh" ,guile-ssh) ("guile-git" ,guile-git) diff --git a/guix/build-system/go.scm b/guix/build-system/go.scm index f8ebaefb27..0e2c1cd2ee 100644 --- a/guix/build-system/go.scm +++ b/guix/build-system/go.scm @@ -26,9 +26,12 @@ #:use-module (guix build-system gnu) #:use-module (guix packages) #:use-module (ice-9 match) + #:use-module (ice-9 regex) #:export (%go-build-system-modules go-build - go-build-system)) + go-build-system + + go-version->git-ref)) ;; Commentary: ;; @@ -37,6 +40,36 @@ ;; ;; Code: +(define %go-version-rx + (make-regexp (string-append + "(v?[0-9]\\.[0-9]\\.[0-9])" ;"v" prefix can be omitted in version prefix + "(-|-pre\\.0\\.|-0\\.)" ;separator + "([0-9]{14})-" ;timestamp + "([0-9A-Fa-f]{12})"))) ;commit hash + +(define (go-version->git-ref version) + "Parse VERSION, a \"pseudo-version\" as defined at +, and extract the commit hash from +it, defaulting to full VERSION if a pseudo-version pattern is not recognized." + ;; A module version like v1.2.3 is introduced by tagging a revision in the + ;; underlying source repository. Untagged revisions can be referred to + ;; using a "pseudo-version" like v0.0.0-yyyymmddhhmmss-abcdefabcdef, where + ;; the time is the commit time in UTC and the final suffix is the prefix of + ;; the commit hash (see: https://golang.org/ref/mod#pseudo-versions). + (let* ((version + ;; If a source code repository has a v2.0.0 or later tag for a file + ;; tree with no go.mod, the version is considered to be part of the + ;; v1 module's available versions and is given an +incompatible + ;; suffix + ;; (see:https://golang.org/cmd/go/#hdr-Module_compatibility_and_semantic_versioning). + (if (string-suffix? "+incompatible" version) + (string-drop-right version 13) + version)) + (match (regexp-exec %go-version-rx version))) + (if match + (match:substring match 4) + version))) + (define %go-build-system-modules ;; Build-side modules imported and used by default. `((guix build go-build-system) diff --git a/guix/import/go.scm b/guix/import/go.scm new file mode 100644 index 0000000000..6b10c60dca --- /dev/null +++ b/guix/import/go.scm @@ -0,0 +1,501 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2020 Katherine Cox-Buday +;;; Copyright © 2020 Helio Machado <0x2b3bfa0+guix@googlemail.com> +;;; Copyright © 2021 François Joulaud +;;; Copyright © 2021 Maxim Cournoyer +;;; +;;; 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 go) + #:use-module (guix build-system go) + #:use-module (guix git) + #:use-module (guix i18n) + #:use-module (guix diagnostics) + #:use-module (guix import utils) + #:use-module (guix import json) + #:use-module (guix packages) + #:use-module ((guix utils) #:select (string-replace-substring)) + #:use-module (guix http-client) + #:use-module ((guix licenses) #:prefix license:) + #:use-module (guix memoization) + #:autoload (htmlprag) (html->sxml) ;from Guile-Lib + #:use-module (ice-9 match) + #:use-module (ice-9 rdelim) + #:use-module (ice-9 receive) + #:use-module (ice-9 regex) + #:use-module ((rnrs io ports) #:select (call-with-port)) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-9) + #:use-module (srfi srfi-11) + #:use-module (srfi srfi-26) + #:use-module (sxml xpath) + #:use-module (web client) + #:use-module (web response) + #:use-module (web uri) + + #:export (go-path-escape + go-module->guix-package + go-module-recursive-import)) + +;;; Commentary: +;;; +;;; (guix import go) attempts to make it easier to create Guix package +;;; declarations for Go modules. +;;; +;;; Modules in Go are a "collection of related Go packages" which are "the +;;; unit of source code interchange and versioning". Modules are generally +;;; hosted in a repository. +;;; +;;; At this point it should handle correctly modules which have only Go +;;; dependencies and are accessible from proxy.golang.org (or configured via +;;; GOPROXY). +;;; +;;; We want it to work more or less this way: +;;; - get latest version for the module from GOPROXY +;;; - infer VCS root repo from which we will check-out source by +;;; + recognising known patterns (like github.com) +;;; + or recognizing .vcs suffix +;;; + or parsing meta tag in HTML served at the URL +;;; + or (TODO) if nothing else works by using zip file served by GOPROXY +;;; - get go.mod from GOPROXY (which is able to synthetize one if needed) +;;; - extract list of dependencies from this go.mod +;;; +;;; The Go module paths are translated to a Guix package name under the +;;; assumption that there will be no collision. + +;;; TODO list +;;; - get correct hash in vcs->origin +;;; - print partial result during recursive imports (need to catch +;;; exceptions) + +;;; Code: + +(define (go-path-escape path) + "Escape a module path by replacing every uppercase letter with an +exclamation mark followed with its lowercase equivalent, as per the module +Escaped Paths specification (see: +https://godoc.org/golang.org/x/mod/module#hdr-Escaped_Paths)." + (define (escape occurrence) + (string-append "!" (string-downcase (match:substring occurrence)))) + (regexp-substitute/global #f "[A-Z]" path 'pre escape 'post)) + +(define (go-module-latest-version goproxy-url module-path) + "Fetch the version number of the latest version for MODULE-PATH from the +given GOPROXY-URL server." + (assoc-ref (json-fetch (format #f "~a/~a/@latest" goproxy-url + (go-path-escape module-path))) + "Version")) + + +(define (go-package-licenses name) + "Retrieve the list of licenses that apply to NAME, a Go package or module +name (e.g. \"github.com/golang/protobuf/proto\"). The data is scraped from +the https://pkg.go.dev/ web site." + (let*-values (((url) (string-append "https://pkg.go.dev/" name + "?tab=licenses")) + ((response body) (http-get url)) + ;; Extract the text contained in a h2 child node of any + ;; element marked with a "License" class attribute. + ((select) (sxpath `(// (* (@ (equal? (class "License")))) + h2 // *text*)))) + (and (eq? (response-code response) 200) + (match (select (html->sxml body)) + (() #f) ;nothing selected + (licenses licenses))))) + +(define (go.pkg.dev-info name) + (http-get (string-append "https://pkg.go.dev/" name))) +(define go.pkg.dev-info* + (memoize go.pkg.dev-info)) + +(define (go-package-description name) + "Retrieve a short description for NAME, a Go package name, +e.g. \"google.golang.org/protobuf/proto\". The data is scraped from the +https://pkg.go.dev/ web site." + (let*-values (((response body) (go.pkg.dev-info* name)) + ;; Extract the text contained in a h2 child node of any + ;; element marked with a "License" class attribute. + ((select) (sxpath + `(// (section + (@ (equal? (class "Documentation-overview")))) + (p 1))))) + (and (eq? (response-code response) 200) + (match (select (html->sxml body)) + (() #f) ;nothing selected + (((p . strings)) + ;; The paragraph text is returned as a list of strings embedding + ;; newline characters. Join them and strip the newline + ;; characters. + (string-delete #\newline (string-join strings))))))) + +(define (go-package-synopsis module-name) + "Retrieve a short synopsis for a Go module named MODULE-NAME, +e.g. \"google.golang.org/protobuf\". The data is scraped from +the https://pkg.go.dev/ web site." + ;; Note: Only the *module* (rather than package) page has the README title + ;; used as a synopsis on the https://pkg.go.dev web site. + (let*-values (((response body) (go.pkg.dev-info* module-name)) + ;; Extract the text contained in a h2 child node of any + ;; element marked with a "License" class attribute. + ((select) (sxpath + `(// (div (@ (equal? (class "UnitReadme-content")))) + // h3 *text*)))) + (and (eq? (response-code response) 200) + (match (select (html->sxml body)) + (() #f) ;nothing selected + ((title more ...) ;title is the first string of the list + (string-trim-both title)))))) + +(define (list->licenses licenses) + "Given a list of LICENSES mostly following the SPDX conventions, return the +corresponding Guix license or 'unknown-license!" + (filter-map (lambda (license) + (and (not (string-null? license)) + (not (any (cut string=? <> license) + '("AND" "OR" "WITH"))) + ;; Adjust the license names scraped from + ;; https://pkg.go.dev to an equivalent SPDX identifier, + ;; if they differ (see: https://github.com/golang/pkgsite + ;; /internal/licenses/licenses.go#L174). + (or (spdx-string->license + (match license + ("BlueOak-1.0" "BlueOak-1.0.0") + ("BSD-0-Clause" "0BSD") + ("BSD-2-Clause" "BSD-2-Clause-FreeBSD") + ("GPL2" "GPL-2.0") + ("GPL3" "GPL-3.0") + ("NIST" "NIST-PD") + (_ license))) + 'unknown-license!))) + licenses)) + +(define (fetch-go.mod goproxy-url module-path version) + "Fetches go.mod from the given GOPROXY-URL server for the given MODULE-PATH +and VERSION." + (let ((url (format #f "~a/~a/@v/~a.mod" goproxy-url + (go-path-escape module-path) + (go-path-escape version)))) + (http-fetch url))) + +(define %go.mod-require-directive-rx + ;; A line in a require directive is composed of a module path and + ;; a version separated by whitespace and an optionnal '//' comment at + ;; the end. + (make-regexp + (string-append + "^[[:blank:]]*" + "([^[:blank:]]+)[[:blank:]]+([^[:blank:]]+)" + "([[:blank:]]+//.*)?"))) + +(define %go.mod-replace-directive-rx + ;; ReplaceSpec = ModulePath [ Version ] "=>" FilePath newline + ;; | ModulePath [ Version ] "=>" ModulePath Version newline . + (make-regexp + (string-append + "([^[:blank:]]+)([[:blank:]]+([^[:blank:]]+))?" + "[[:blank:]]+" "=>" "[[:blank:]]+" + "([^[:blank:]]+)([[:blank:]]+([^[:blank:]]+))?"))) + +(define (parse-go.mod port) + "Parse the go.mod file accessible via the input PORT, returning a list of +requirements." + (define-record-type + (make-results requirements replacements) + results? + (requirements results-requirements) + (replacements results-replacements)) + ;; We parse only a subset of https://golang.org/ref/mod#go-mod-file-grammar + ;; which we think necessary for our use case. + (define (toplevel results) + "Main parser, RESULTS is a pair of alist serving as accumulator for + all encountered requirements and replacements." + (let ((line (read-line port))) + (cond + ((eof-object? line) + ;; parsing ended, give back the result + results) + ((string=? line "require (") + ;; a require block begins, delegate parsing to IN-REQUIRE + (in-require results)) + ((string=? line "replace (") + ;; a replace block begins, delegate parsing to IN-REPLACE + (in-replace results)) + ((string-prefix? "require " line) + ;; a standalone require directive + (let* ((stripped-line (string-drop line 8)) + (new-results (require-directive results stripped-line))) + (toplevel new-results))) + ((string-prefix? "replace " line) + ;; a standalone replace directive + (let* ((stripped-line (string-drop line 8)) + (new-results (replace-directive results stripped-line))) + (toplevel new-results))) + (#t + ;; unrecognised line, ignore silently + (toplevel results))))) + + (define (in-require results) + (let ((line (read-line port))) + (cond + ((eof-object? line) + ;; this should never happen here but we ignore silently + results) + ((string=? line ")") + ;; end of block, coming back to toplevel + (toplevel results)) + (#t + (in-require (require-directive results line)))))) + + (define (in-replace results) + (let ((line (read-line port))) + (cond + ((eof-object? line) + ;; this should never happen here but we ignore silently + results) + ((string=? line ")") + ;; end of block, coming back to toplevel + (toplevel results)) + (#t + (in-replace (replace-directive results line)))))) + + (define (replace-directive results line) + "Extract replaced modules and new requirements from replace directive + in LINE and add to RESULTS." + (match results + (($ requirements replaced) + (let* ((rx-match (regexp-exec %go.mod-replace-directive-rx line)) + (module-path (match:substring rx-match 1)) + (version (match:substring rx-match 3)) + (new-module-path (match:substring rx-match 4)) + (new-version (match:substring rx-match 6)) + (new-replaced (alist-cons module-path version replaced)) + (new-requirements + (if (string-match "^\\.?\\./" new-module-path) + requirements + (alist-cons new-module-path new-version requirements)))) + (make-results new-requirements new-replaced))))) + (define (require-directive results line) + "Extract requirement from LINE and add it to RESULTS." + (let* ((rx-match (regexp-exec %go.mod-require-directive-rx line)) + (module-path (match:substring rx-match 1)) + ;; we saw double-quoted string in the wild without escape + ;; sequences so we just trim the quotes + (module-path (string-trim-both module-path #\")) + (version (match:substring rx-match 2))) + (match results + (($ requirements replaced) + (make-results (alist-cons module-path version requirements) replaced))))) + + (let ((results (toplevel (make-results '() '())))) + (match results + (($ requirements replaced) + ;; At last we remove replaced modules from the requirements list + (fold + (lambda (replacedelem requirements) + (alist-delete! (car replacedelem) requirements)) + requirements + replaced))))) + +;; Prevent inlining of this procedure, which is accessed by unit tests. +(set! parse-go.mod parse-go.mod) + +(define-record-type + (%make-vcs url-prefix root-regex type) + vcs? + (url-prefix vcs-url-prefix) + (root-regex vcs-root-regex) + (type vcs-type)) +(define (make-vcs prefix regexp type) + (%make-vcs prefix (make-regexp regexp) type)) +(define known-vcs + ;; See the following URL for the official Go equivalent: + ;; https://github.com/golang/go/blob/846dce9d05f19a1f53465e62a304dea21b99f910/src/cmd/go/internal/vcs/vcs.go#L1026-L1087 + (list + (make-vcs + "github.com" + "^(github\\.com/[A-Za-z0-9_.\\-]+/[A-Za-z0-9_.\\-]+)(/[A-Za-z0-9_.\\-]+)*$" + 'git) + (make-vcs + "bitbucket.org" + "^(bitbucket\\.org/([A-Za-z0-9_.\\-]+/[A-Za-z0-9_.\\-]+))(/[A-Za-z0-9_.\\-]+)*$" + 'unknown) + (make-vcs + "hub.jazz.net/git/" + "^(hub\\.jazz\\.net/git/[a-z0-9]+/[A-Za-z0-9_.\\-]+)(/[A-Za-z0-9_.\\-]+)*$" + 'git) + (make-vcs + "git.apache.org" + "^(git\\.apache\\.org/[a-z0-9_.\\-]+\\.git)(/[A-Za-z0-9_.\\-]+)*$" + 'git) + (make-vcs + "git.openstack.org" + "^(git\\.openstack\\.org/[A-Za-z0-9_.\\-]+/[A-Za-z0-9_.\\-]+)(\\.git)?\ +(/[A-Za-z0-9_.\\-]+)*$" + 'git))) + +(define (module-path->repository-root module-path) + "Infer the repository root from a module path. Go modules can be +defined at any level of a repository tree, but querying for the meta tag +usually can only be done from the web page at the root of the repository, +hence the need to derive this information." + + ;; For reference, see: https://golang.org/ref/mod#vcs-find. + (define vcs-qualifiers '(".bzr" ".fossil" ".git" ".hg" ".svn")) + + (define (vcs-qualified-module-path->root-repo-url module-path) + (let* ((vcs-qualifiers-group (string-join vcs-qualifiers "|")) + (pattern (format #f "^(.*(~a))(/|$)" vcs-qualifiers-group)) + (m (string-match pattern module-path))) + (and=> m (cut match:substring <> 1)))) + + (or (and=> (find (lambda (vcs) + (string-prefix? (vcs-url-prefix vcs) module-path)) + known-vcs) + (lambda (vcs) + (match:substring (regexp-exec (vcs-root-regex vcs) + module-path) 1))) + (vcs-qualified-module-path->root-repo-url module-path) + module-path)) + +(define (go-module->guix-package-name module-path) + "Converts a module's path to the canonical Guix format for Go packages." + (string-downcase (string-append "go-" (string-replace-substring + (string-replace-substring + module-path + "." "-") + "/" "-")))) + +(define-record-type + (make-module-meta import-prefix vcs repo-root) + module-meta? + (import-prefix module-meta-import-prefix) + (vcs module-meta-vcs) ;a symbol + (repo-root module-meta-repo-root)) + +(define (fetch-module-meta-data module-path) + "Retrieve the module meta-data from its landing page. This is necessary +because goproxy servers don't currently provide all the information needed to +build a package." + ;; + (let* ((port (http-fetch (format #f "https://~a?go-get=1" module-path))) + (select (sxpath `(// head (meta (@ (equal? (name "go-import")))) + // content)))) + (match (select (call-with-port port html->sxml)) + (() #f) ;nothing selected + (((content content-text)) + (match (string-split content-text #\space) + ((root-path vcs repo-url) + (make-module-meta root-path (string->symbol vcs) repo-url))))))) + +(define (module-meta-data-repo-url meta-data goproxy-url) + "Return the URL where the fetcher which will be used can download the +source." + (if (member (module-meta-vcs meta-data) '(fossil mod)) + goproxy-url + (module-meta-repo-root meta-data))) + +(define (vcs->origin vcs-type vcs-repo-url version) + "Generate the `origin' block of a package depending on what type of source +control system is being used." + (case vcs-type + ((git) + (let ((plain-version? (string=? version (go-version->git-ref version))) + (v-prefixed? (string-prefix? "v" version))) + `(origin + (method git-fetch) + (uri (git-reference + (url ,vcs-repo-url) + (commit ,(if (and plain-version? v-prefixed?) + '(string-append "v" version) + '(go-version->git-ref version))))) + (file-name (git-file-name name version)) + (sha256 + (base32 + ;; FIXME: populate hash for git repo checkout + "0000000000000000000000000000000000000000000000000000"))))) + ((hg) + `(origin + (method hg-fetch) + (uri (hg-reference + (url ,vcs-repo-url) + (changeset ,version))) + (file-name (string-append name "-" version "-checkout")) + (sha256 + (base32 + ;; FIXME: populate hash for hg repo checkout + "0000000000000000000000000000000000000000000000000000")))) + ((svn) + `(origin + (method svn-fetch) + (uri (svn-reference + (url ,vcs-repo-url) + (revision (string->number version)))) + (file-name (string-append name "-" version "-checkout")) + (sha256 + (base32 + ;; FIXME: populate hash for svn repo checkout + "0000000000000000000000000000000000000000000000000000")))) + (else + (raise + (formatted-message (G_ "unsupported vcs type '~a' for package '~a'") + vcs-type vcs-repo-url))))) + +(define* (go-module->guix-package module-path #:key + (goproxy-url "https://proxy.golang.org")) + (let* ((latest-version (go-module-latest-version goproxy-url module-path)) + (port (fetch-go.mod goproxy-url module-path latest-version)) + (dependencies (map car (call-with-port port parse-go.mod))) + (guix-name (go-module->guix-package-name module-path)) + (root-module-path (module-path->repository-root module-path)) + ;; The VCS type and URL are not included in goproxy information. For + ;; this we need to fetch it from the official module page. + (meta-data (fetch-module-meta-data root-module-path)) + (vcs-type (module-meta-vcs meta-data)) + (vcs-repo-url (module-meta-data-repo-url meta-data goproxy-url)) + (synopsis (go-package-synopsis root-module-path)) + (description (go-package-description module-path)) + (licenses (go-package-licenses module-path))) + (values + `(package + (name ,guix-name) + ;; Elide the "v" prefix Go uses + (version ,(string-trim latest-version #\v)) + (source + ,(vcs->origin vcs-type vcs-repo-url latest-version)) + (build-system go-build-system) + (arguments + '(#:import-path ,root-module-path)) + ,@(maybe-inputs (map go-module->guix-package-name dependencies)) + (home-page ,(format #f "https://~a" root-module-path)) + (synopsis ,synopsis) + (description ,description) + (license ,(match (and=> licenses list->licenses) + ((license) license) + ((licenses ...) `(list ,@licenses)) + (x x)))) + dependencies))) + +(define go-module->guix-package* (memoize go-module->guix-package)) + +(define* (go-module-recursive-import package-name + #:key (goproxy-url "https://proxy.golang.org")) + (recursive-import + package-name + #:repo->guix-package (lambda* (name . _) + (go-module->guix-package* + name + #:goproxy-url goproxy-url)) + #:guix-name go-module->guix-package-name)) diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm index 0a3863f965..1d2b45d942 100644 --- a/guix/scripts/import.scm +++ b/guix/scripts/import.scm @@ -77,7 +77,7 @@ rather than \\n." ;;; (define importers '("gnu" "nix" "pypi" "cpan" "hackage" "stackage" "elpa" "gem" - "cran" "crate" "texlive" "json" "opam")) + "go" "cran" "crate" "texlive" "json" "opam")) (define (resolve-importer name) (let ((module (resolve-interface diff --git a/guix/scripts/import/go.scm b/guix/scripts/import/go.scm new file mode 100644 index 0000000000..afdba4e8f1 --- /dev/null +++ b/guix/scripts/import/go.scm @@ -0,0 +1,118 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2020 Katherine Cox-Buday +;;; +;;; 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 go) + #:use-module (guix ui) + #:use-module (guix utils) + #:use-module (guix scripts) + #:use-module (guix import go) + #: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-go)) + + +;;; +;;; Command-line options. +;;; + +(define %default-options + '()) + +(define (show-help) + (display (G_ "Usage: guix import go PACKAGE-PATH +Import and convert the Go module for PACKAGE-PATH.\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 Go modules\ + that are not yet in Guix")) + (display (G_ " + -p, --goproxy=GOPROXY specify which goproxy server to use")) + (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 go"))) + (option '(#\r "recursive") #f #f + (lambda (opt name arg result) + (alist-cons 'recursive #t result))) + (option '(#\p "goproxy") #t #f + (lambda (opt name arg result) + (alist-cons 'goproxy + (string->symbol arg) + (alist-delete 'goproxy result)))) + %standard-import-options)) + + +;;; +;;; Entry point. +;;; + +(define (guix-import-go . 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 + ((module-name) + (if (assoc-ref opts 'recursive) + (map (match-lambda + ((and ('package ('name name) . rest) pkg) + `(define-public ,(string->symbol name) + ,pkg)) + (_ #f)) + (go-module-recursive-import module-name + #:goproxy-url + (or (assoc-ref opts 'goproxy) + "https://proxy.golang.org"))) + (let ((sexp (go-module->guix-package module-name + #:goproxy-url + (or (assoc-ref opts 'goproxy) + "https://proxy.golang.org")))) + (unless sexp + (leave (G_ "failed to download meta-data for module '~a'~%") + module-name)) + sexp))) + (() + (leave (G_ "too few arguments~%"))) + ((many ...) + (leave (G_ "too many arguments~%")))))) diff --git a/guix/self.scm b/guix/self.scm index 35fba1152d..3154d180ac 100644 --- a/guix/self.scm +++ b/guix/self.scm @@ -56,6 +56,7 @@ ("guile-ssh" (ref '(gnu packages ssh) 'guile-ssh)) ("guile-git" (ref '(gnu packages guile) 'guile-git)) ("guile-semver" (ref '(gnu packages guile-xyz) 'guile-semver)) + ("guile-lib" (ref '(gnu packages guile-xyz) 'guile-lib)) ("guile-sqlite3" (ref '(gnu packages guile) 'guile-sqlite3)) ("guile-zlib" (ref '(gnu packages guile) 'guile-zlib)) ("guile-lzlib" (ref '(gnu packages guile) 'guile-lzlib)) @@ -814,6 +815,9 @@ itself." (define guile-ssh (specification->package "guile-ssh")) + (define guile-lib + (specification->package "guile-lib")) + (define guile-git (specification->package "guile-git")) @@ -842,7 +846,7 @@ itself." (append-map transitive-package-dependencies (list guile-gcrypt gnutls guile-git guile-avahi guile-json guile-semver guile-ssh guile-sqlite3 - guile-zlib guile-lzlib guile-zstd))) + guile-lib guile-zlib guile-lzlib guile-zstd))) (define *core-modules* (scheme-node "guix-core" diff --git a/po/guix/POTFILES.in b/po/guix/POTFILES.in index 666e630adf..cbbfe1e76b 100644 --- a/po/guix/POTFILES.in +++ b/po/guix/POTFILES.in @@ -101,6 +101,7 @@ guix/scripts/import/cpan.scm guix/scripts/import/crate.scm guix/scripts/import/gem.scm guix/scripts/import/gnu.scm +guix/scripts/import/go.scm guix/scripts/import/hackage.scm guix/scripts/import/json.scm guix/scripts/import/nix.scm diff --git a/tests/go.scm b/tests/go.scm new file mode 100644 index 0000000000..1df5036838 --- /dev/null +++ b/tests/go.scm @@ -0,0 +1,281 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2021 François Joulaud +;;; +;;; 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 . + +;;; Summary +;; Tests for guix/import/go.scm + +(define-module (test-import-go) + #:use-module (guix base32) + #:use-module (guix build-system go) + #:use-module (guix import go) + #:use-module (guix tests) + #:use-module (ice-9 match) + #:use-module (srfi srfi-19) + #:use-module (srfi srfi-64) + #:use-module (web response)) + +(define parse-go.mod + (@@ (guix import go) parse-go.mod)) + +(define fixture-go-mod-simple + "module my/thing +go 1.12 +require other/thing v1.0.2 +require new/thing/v2 v2.3.4 +exclude old/thing v1.2.3 +replace bad/thing v1.4.5 => good/thing v1.4.5 +") + +(define fixture-go-mod-with-block + "module M + +require ( + A v1 + B v1.0.0 + C v1.0.0 + D v1.2.3 + E dev +) + +exclude D v1.2.3 +") + + +(define fixture-go-mod-complete + "module M + +go 1.13 + +replace github.com/myname/myproject/myapi => ./api + +replace github.com/mymname/myproject/thissdk => ../sdk + +replace launchpad.net/gocheck => github.com/go-check/check v0.0.0-20140225173054-eb6ee6f84d0a + +require ( + github.com/user/project v1.1.11 + github.com/user/project/sub/directory v1.1.12 + bitbucket.org/user/project v1.11.20 + bitbucket.org/user/project/sub/directory v1.11.21 + launchpad.net/project v1.1.13 + launchpad.net/project/series v1.1.14 + launchpad.net/project/series/sub/directory v1.1.15 + launchpad.net/~user/project/branch v1.1.16 + launchpad.net/~user/project/branch/sub/directory v1.1.17 + hub.jazz.net/git/user/project v1.1.18 + hub.jazz.net/git/user/project/sub/directory v1.1.19 + k8s.io/kubernetes/subproject v1.1.101 + one.example.com/abitrary/repo v1.1.111 + two.example.com/abitrary/repo v0.0.2 + \"quoted.example.com/abitrary/repo\" v0.0.2 +) + +replace two.example.com/abitrary/repo => github.com/corp/arbitrary-repo v0.0.2 + +replace ( + golang.org/x/sys => golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a // pinned to release-branch.go1.13 + golang.org/x/tools => golang.org/x/tools v0.0.0-20190821162956-65e3620a7ae7 // pinned to release-branch.go1.13 +) + +") + + + +(define fixture-latest-for-go-check + "{\"Version\":\"v0.0.0-20201130134442-10cb98267c6c\",\"Time\":\"2020-11-30T13:44:42Z\"}") + + +(define fixtures-go-check-test + (let ((version + "{\"Version\":\"v0.0.0-20201130134442-10cb98267c6c\",\"Time\":\"2020-11-30T13:44:42Z\"}") + (go.mod + "module gopkg.in/check.v1 + +go 1.11 + +require github.com/kr/pretty v0.2.1 +") + (go-get + " + + + + + + + + GitHub - go-check/check: Rich testing for the Go language + + + + + + + + + + + + +") + (pkg.go.dev "\n\n\n \n\n\n
\n
\n
\n
\n
\n

\"\"README

\n
\n
\n

Instructions

\n

Install the package with:

\n
go get gopkg.in/check.v1\n
\n
\n
\n
\n
\n
\n

\"\"Documentation

\n
\n
\n
\n

Overview

\n
\n
    \n
    \n

    Package check is a rich testing extension for Go's testing package.

    \n

    For details about the project, see:

    \n
    http://labix.org/gocheck\n
    \n
    \n

    Constants

    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n\n\n") + (pkg.go.dev-licence "\n\n\n\n\n
    \n
    \n

    BSD-2-Clause

    \n

    This is not legal advice. Read disclaimer.

    \n
    Gocheck - A rich testing framework for Go\n \nCopyright line\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met: \n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer. \n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution. \n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n
    \n
    \n
    Source: github.com/go-check/check@v0.0.0-20201128035030-22ab2dfb190c/LICENSE
    \n
    \n \n")) + `(("https://proxy.golang.org/github.com/go-check/check/@v/v0.0.0-20201130134442-10cb98267c6c.mod" + . ,go.mod) + ("https://proxy.golang.org/github.com/go-check/check/@latest" + . ,version) + ("https://github.com/go-check/check?go-get=1" + . ,go-get) + ("https://pkg.go.dev/github.com/go-check/check" + . ,pkg.go.dev) + ("https://pkg.go.dev/github.com/go-check/check?tab=licenses" + . ,pkg.go.dev-licence)))) + +(test-begin "go") + +;;; Unit tests for go build-system + +(test-equal "go-version basic" + "v1.0.2" + (go-version->git-ref "v1.0.2")) + +(test-equal "go-version omited 'v' character" + "v1.0.2" + (go-version->git-ref "v1.0.2")) + +(test-equal "go-version with embeded git-ref" + "65e3620a7ae7" + (go-version->git-ref "v0.0.0-20190821162956-65e3620a7ae7")) + +(test-equal "go-version with complex embeded git-ref" + "daa7c04131f5" + (go-version->git-ref "v1.2.4-0.20191109021931-daa7c04131f5")) + +;;; Unit tests for (guix import go) + +(test-equal "go-path-escape" + "github.com/!azure/!avere" + ((@@ (guix import go) go-path-escape) "github.com/Azure/Avere")) + + +;; We define a function for all similar tests with different go.mod files +(define (testing-parse-mod name expected input) + (define (inf? p1 p2) + (stringguix-package" + '(package + (name "go-github-com-go-check-check") + (version "0.0.0-20201130134442-10cb98267c6c") + (source + (origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/go-check/check.git") + (commit (go-version->git-ref version)))) + (file-name (git-file-name name version)) + (sha256 + (base32 + "0000000000000000000000000000000000000000000000000000")))) + (build-system go-build-system) + (arguments + (quote (#:import-path "github.com/go-check/check"))) + (inputs + (quasiquote (("go-github-com-kr-pretty" + (unquote go-github-com-kr-pretty))))) + (home-page "https://github.com/go-check/check") + (synopsis "Instructions") + (description #f) + (license license:bsd-2)) + + ;; Replace network resources with sample data. + (mock ((web client) http-get + (mock-http-get fixtures-go-check-test)) + (mock ((guix http-client) http-fetch + (mock-http-fetch fixtures-go-check-test)) + (go-module->guix-package "github.com/go-check/check")))) + +(test-end "go") + -- cgit 1.4.1 From d028aef31c9dd05c0390addc3d7f419e41c530ab Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Wed, 10 Mar 2021 17:48:14 +0100 Subject: import: go: Compute the hash of Git checkouts. * guix/import/go.scm (vcs-file?, file-hash, git-checkout-hash): New procedures. (vcs->origin): Use 'git-checkout-hash' in the 'git case. --- guix/import/go.scm | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- tests/go.scm | 23 +++++++++++++++++------ 2 files changed, 65 insertions(+), 8 deletions(-) (limited to 'tests') diff --git a/guix/import/go.scm b/guix/import/go.scm index 6b10c60dca..7452b4c903 100644 --- a/guix/import/go.scm +++ b/guix/import/go.scm @@ -3,6 +3,7 @@ ;;; Copyright © 2020 Helio Machado <0x2b3bfa0+guix@googlemail.com> ;;; Copyright © 2021 François Joulaud ;;; Copyright © 2021 Maxim Cournoyer +;;; Copyright © 2021 Ludovic Courtès ;;; ;;; This file is part of GNU Guix. ;;; @@ -32,6 +33,11 @@ #:use-module ((guix licenses) #:prefix license:) #:use-module (guix memoization) #:autoload (htmlprag) (html->sxml) ;from Guile-Lib + #:autoload (guix git) (update-cached-checkout) + #:autoload (gcrypt hash) (open-hash-port hash-algorithm sha256) + #:autoload (guix serialization) (write-file) + #:autoload (guix base32) (bytevector->nix-base32-string) + #:autoload (guix build utils) (mkdir-p) #:use-module (ice-9 match) #:use-module (ice-9 rdelim) #:use-module (ice-9 receive) @@ -407,6 +413,45 @@ source." goproxy-url (module-meta-repo-root meta-data))) +;; XXX: Copied from (guix scripts hash). +(define (vcs-file? file stat) + (case (stat:type stat) + ((directory) + (member (basename file) '(".bzr" ".git" ".hg" ".svn" "CVS"))) + ((regular) + ;; Git sub-modules have a '.git' file that is a regular text file. + (string=? (basename file) ".git")) + (else + #f))) + +;; XXX: Adapted from 'file-hash' in (guix scripts hash). +(define* (file-hash file #:optional (algorithm (hash-algorithm sha256))) + ;; Compute the hash of FILE. + (let-values (((port get-hash) (open-hash-port algorithm))) + (write-file file port #:select? (negate vcs-file?)) + (force-output port) + (get-hash))) + +(define* (git-checkout-hash url reference algorithm) + "Return the ALGORITHM hash of the checkout of URL at REFERENCE, a commit or +tag." + (define cache + (string-append (or (getenv "TMPDIR") "/tmp") + "/guix-import-go-" + (passwd:name (getpwuid (getuid))))) + + ;; Use a custom cache to avoid cluttering the default one under + ;; ~/.cache/guix, but choose one under /tmp so that it's persistent across + ;; subsequent "guix import" invocations. + (mkdir-p cache) + (chmod cache #o700) + (let-values (((checkout commit _) + (parameterize ((%repository-cache-directory cache)) + (update-cached-checkout url + #:ref + `(tag-or-commit . ,reference))))) + (file-hash checkout algorithm))) + (define (vcs->origin vcs-type vcs-repo-url version) "Generate the `origin' block of a package depending on what type of source control system is being used." @@ -424,8 +469,9 @@ control system is being used." (file-name (git-file-name name version)) (sha256 (base32 - ;; FIXME: populate hash for git repo checkout - "0000000000000000000000000000000000000000000000000000"))))) + ,(bytevector->nix-base32-string + (git-checkout-hash vcs-repo-url (go-version->git-ref version) + (hash-algorithm sha256)))))))) ((hg) `(origin (method hg-fetch) diff --git a/tests/go.scm b/tests/go.scm index 1df5036838..6ab99f508a 100644 --- a/tests/go.scm +++ b/tests/go.scm @@ -23,6 +23,8 @@ #:use-module (guix base32) #:use-module (guix build-system go) #:use-module (guix import go) + #:use-module (guix base32) + #:use-module ((guix utils) #:select (call-with-temporary-directory)) #:use-module (guix tests) #:use-module (ice-9 match) #:use-module (srfi srfi-19) @@ -258,7 +260,7 @@ require github.com/kr/pretty v0.2.1 (file-name (git-file-name name version)) (sha256 (base32 - "0000000000000000000000000000000000000000000000000000")))) + "0sjjj9z1dhilhpc8pq4154czrb79z9cm044jvn75kxcjv6v5l2m5")))) (build-system go-build-system) (arguments (quote (#:import-path "github.com/go-check/check"))) @@ -271,11 +273,20 @@ require github.com/kr/pretty v0.2.1 (license license:bsd-2)) ;; Replace network resources with sample data. - (mock ((web client) http-get - (mock-http-get fixtures-go-check-test)) - (mock ((guix http-client) http-fetch - (mock-http-fetch fixtures-go-check-test)) - (go-module->guix-package "github.com/go-check/check")))) + (call-with-temporary-directory + (lambda (checkout) + (mock ((web client) http-get + (mock-http-get fixtures-go-check-test)) + (mock ((guix http-client) http-fetch + (mock-http-fetch fixtures-go-check-test)) + (mock ((guix git) update-cached-checkout + (lambda* (url #:key ref) + ;; Return an empty directory and its hash. + (values checkout + (nix-base32-string->bytevector + "0sjjj9z1dhilhpc8pq4154czrb79z9cm044jvn75kxcjv6v5l2m5") + #f))) + (go-module->guix-package "github.com/go-check/check"))))))) (test-end "go") -- cgit 1.4.1 From 5cbfddcb59baccf6a3aebd835a01126cca2f1ea5 Mon Sep 17 00:00:00 2001 From: Tobias Geerinckx-Rice Date: Sat, 13 Mar 2021 16:03:08 +0100 Subject: tests: Remove obsolete comment. This follows up on commit c05ceaf2b650d090cf39a048193505cb4e6bd257. * tests/lint.scm: Remove comment. Reported by morgansmith in #guix. --- tests/lint.scm | 2 -- 1 file changed, 2 deletions(-) (limited to 'tests') diff --git a/tests/lint.scm b/tests/lint.scm index b92053fd5f..bd8604f589 100644 --- a/tests/lint.scm +++ b/tests/lint.scm @@ -61,8 +61,6 @@ ;; Test the linter. -;; Avoid collisions with other tests. - (define %null-sha256 ;; SHA256 of the empty string. (base32 -- cgit 1.4.1 From 0d8d499036f632e03f63bdaf36b02861ea52b3e6 Mon Sep 17 00:00:00 2001 From: Leo Famulari Date: Thu, 11 Feb 2021 15:25:42 -0500 Subject: tests: Make the STORE test more robust in a "pure" environment. Otherwise, the test crashes (not fails) when run in `guix environment --pure guix`. Fixes . * tests/store.scm (%shell): Fallback to "/bin/sh". --- tests/store.scm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/store.scm b/tests/store.scm index cda0e0302f..9c25adf5e9 100644 --- a/tests/store.scm +++ b/tests/store.scm @@ -50,7 +50,7 @@ (open-connection-for-tests)) (define %shell - (or (getenv "SHELL") (getenv "CONFIG_SHELL"))) + (or (getenv "SHELL") (getenv "CONFIG_SHELL") "/bin/sh")) (test-begin "store") -- cgit 1.4.1 From 1710e8cb59e2ef6f1e0eb19235b6a4f1b8158bc4 Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Sat, 20 Mar 2021 21:53:27 +0100 Subject: gnu-maintenance: Accept underscores as package/version separators. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes . Reported by Léo Le Bouter . * guix/gnu-maintenance.scm (%tarball-rx, %package-name-rx): Accept underscore as the package/version separator in tarball names. * tests/gnu-maintenance.scm ("release-file?"): Add "mediainfo" test. --- guix/gnu-maintenance.scm | 5 +++-- tests/gnu-maintenance.scm | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'tests') diff --git a/guix/gnu-maintenance.scm b/guix/gnu-maintenance.scm index d9c97beb29..7bd08c1208 100644 --- a/guix/gnu-maintenance.scm +++ b/guix/gnu-maintenance.scm @@ -241,7 +241,8 @@ network to check in GNU's database." ;; The .zip extensions is notably used for freefont-ttf. ;; The "-src" pattern is for "TeXmacs-1.0.7.9-src.tar.gz". ;; The "-gnu[0-9]" pattern is for "icecat-38.4.0-gnu1.tar.bz2". - (make-regexp "^([^.]+)-([0-9]|[^-])+(-(src|gnu[0-9]))?\\.(tar\\.|zip$)")) + ;; Accept underscores as in "PKG_1.2.tar.gz" for some non-GNU packages. + (make-regexp "^([^.]+)[-_]([0-9]|[^-])+(-(src|gnu[0-9]))?\\.(tar\\.|zip$)")) (define %alpha-tarball-rx (make-regexp "^.*-.*[0-9](-|~)?(alpha|beta|rc|RC|cvs|svn|git)-?[0-9\\.]*\\.tar\\.")) @@ -594,7 +595,7 @@ list available from %GNU-FILE-LIST-URI over HTTP(S)." (define %package-name-rx ;; Regexp for a package name, e.g., "foo-X.Y". Since TeXmacs uses ;; "TeXmacs-X.Y-src", the `-src' suffix is allowed. - (make-regexp "^(.*)-(([0-9]|\\.)+)(-src)?")) + (make-regexp "^(.*)[-_](([0-9]|\\.)+)(-src)?")) (define (gnu-package-name->name+version name+version) "Return the package name and version number extracted from NAME+VERSION." diff --git a/tests/gnu-maintenance.scm b/tests/gnu-maintenance.scm index 4f2f1ae943..a3e48a0933 100644 --- a/tests/gnu-maintenance.scm +++ b/tests/gnu-maintenance.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2015 Ludovic Courtès +;;; Copyright © 2015, 2021 Ludovic Courtès ;;; ;;; This file is part of GNU Guix. ;;; @@ -29,7 +29,8 @@ '(("gcc" "gcc-5.3.0.tar.bz2") ("texmacs" "TeXmacs-1.0.7.9-src.tar.gz") ("icecat" "icecat-38.4.0-gnu1.tar.bz2") - ("mit-scheme" "mit-scheme-9.2.tar.gz"))) + ("mit-scheme" "mit-scheme-9.2.tar.gz") + ("mediainfo" "mediainfo_20.09.tar.xz"))) (every (lambda (project+file) (not (apply release-file? project+file))) '(("guile" "guile-www-1.1.1.tar.gz") -- cgit 1.4.1 From a16eb6c5f97f136b678540ba61f12b2c08e43e13 Mon Sep 17 00:00:00 2001 From: Chris Marusich Date: Sat, 20 Feb 2021 17:29:58 -0800 Subject: Add powerpc64le-linux as a supported Guix architecture. This makes powerpc64le-linux a supported architecture for Guix, but not for Guix System. * Makefile.am (SUPPORTED_SYSTEMS): Add an entry for powerpc64le-linux. * etc/guix-install.sh (chk_sys_arch): Same. * guix/packages.scm (%supported-systems): Same. * m4/guix.m4 (GUIX_ASSERT_SUPPORTED_SYSTEM): Same. * tests/guix-build.sh (all_systems): Same. --- Makefile.am | 4 +++- etc/guix-install.sh | 4 ++++ guix/packages.scm | 4 +++- m4/guix.m4 | 3 ++- tests/guix-build.sh | 6 ++++-- 5 files changed, 16 insertions(+), 5 deletions(-) (limited to 'tests') diff --git a/Makefile.am b/Makefile.am index f40d9509be..1c2d45527c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -14,6 +14,7 @@ # Copyright © 2018 Oleg Pykhalov # Copyright © 2018 Alex Vong # Copyright © 2019 Efraim Flashner +# Copyright © 2021 Chris Marusich # # This file is part of GNU Guix. # @@ -799,7 +800,8 @@ SOURCE_TARBALLS = \ $(foreach ext,tar.gz,$(PACKAGE_FULL_TARNAME).$(ext)) # Systems supported by Guix. -SUPPORTED_SYSTEMS ?= x86_64-linux i686-linux armhf-linux aarch64-linux +SUPPORTED_SYSTEMS ?= x86_64-linux i686-linux armhf-linux aarch64-linux \ + powerpc64le-linux # Guix binary tarballs. BINARY_TARBALLS = \ diff --git a/etc/guix-install.sh b/etc/guix-install.sh index 94c04aa646..c84e7b7577 100755 --- a/etc/guix-install.sh +++ b/etc/guix-install.sh @@ -8,6 +8,7 @@ # Copyright © 2020 Simon Tournier # Copyright © 2020 Daniel Brooks # Copyright © 2021 Jakub Kądziołka +# Copyright © 2021 Chris Marusich # # This file is part of GNU Guix. # @@ -187,6 +188,9 @@ chk_sys_arch() armv7l) local arch=armhf ;; + ppc64le | powerpc64le) + local arch=powerpc64le + ;; *) _err "${ERR}Unsupported CPU type: ${arch}" exit 1 diff --git a/guix/packages.scm b/guix/packages.scm index a057a88c63..55e5e70b8c 100644 --- a/guix/packages.scm +++ b/guix/packages.scm @@ -5,6 +5,7 @@ ;;; Copyright © 2016 Alex Kost ;;; Copyright © 2017, 2019, 2020 Efraim Flashner ;;; Copyright © 2019 Marius Bakke +;;; Copyright © 2021 Chris Marusich ;;; ;;; This file is part of GNU Guix. ;;; @@ -345,7 +346,8 @@ name of its URI." (define %supported-systems ;; This is the list of system types that are supported. By default, we ;; expect all packages to build successfully here. - '("x86_64-linux" "i686-linux" "armhf-linux" "aarch64-linux" "mips64el-linux" "i586-gnu")) + '("x86_64-linux" "i686-linux" "armhf-linux" "aarch64-linux" "mips64el-linux" "i586-gnu" + "powerpc64le-linux")) (define %hurd-systems ;; The GNU/Hurd systems for which support is being developed. diff --git a/m4/guix.m4 b/m4/guix.m4 index 90a106add8..05d409a674 100644 --- a/m4/guix.m4 +++ b/m4/guix.m4 @@ -2,6 +2,7 @@ dnl GNU Guix --- Functional package management for GNU dnl Copyright © 2012, 2013, 2014, 2015, 2016, 2018, 2019, 2020, 2021 Ludovic Courtès dnl Copyright © 2014 Mark H Weaver dnl Copyright © 2017 Efraim Flashner +dnl Copyright © 2021 Chris Marusich dnl dnl This file is part of GNU Guix. dnl @@ -88,7 +89,7 @@ courageous and port the GNU System distribution to it (see # Currently only Linux-based systems are supported, and only on some # platforms. case "$guix_system" in - x86_64-linux|i686-linux|armhf-linux|aarch64-linux) + x86_64-linux|i686-linux|armhf-linux|aarch64-linux|powerpc64le-linux) ;; *) if test "x$guix_courageous" = "xyes"; then diff --git a/tests/guix-build.sh b/tests/guix-build.sh index b7602e668c..e20702c521 100644 --- a/tests/guix-build.sh +++ b/tests/guix-build.sh @@ -1,6 +1,7 @@ # GNU Guix --- Functional package management for GNU # Copyright © 2012, 2013, 2014, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès # Copyright © 2020 Marius Bakke +# Copyright © 2021 Chris Marusich # # This file is part of GNU Guix. # @@ -61,8 +62,9 @@ guix build -e '(@@ (gnu packages bootstrap) %bootstrap-guile)' test `guix build sed -s x86_64-linux -d | wc -l` = 1 # Passing multiple '-s' flags. -all_systems="-s x86_64-linux -s i686-linux -s armhf-linux -s aarch64-linux" -test `guix build sed $all_systems -d | sort -u | wc -l` = 4 +all_systems="-s x86_64-linux -s i686-linux -s armhf-linux -s aarch64-linux \ +-s powerpc64le-linux" +test `guix build sed $all_systems -d | sort -u | wc -l` = 5 # Check there's no weird memoization effect leading to erroneous results. # See . -- cgit 1.4.1