import: go: Add an option to use pinned versions.

The ability to pin versions is handy when having to deal to packages that
bootstrap themselves through a chain of former versions.  Not using pinned
versions in these case could introduce dependency cycles.

* guix/build-system/go.scm (guix)
(%go-version-rx): Rename to...
(%go-pseudo-version-rx): ... this.  Simplify the regular expression, which in
turns makes it more robust.
* guix/build-system/go.scm (go-version->git-ref): Adjust following the above
rename.
(go-pseudo-version?): New predicate.
(go-module-latest-version): Rename to ...
(go-module-version-string): ... this.  Rename goproxy-url argument to just
goproxy.  Add a VERSION keyword argument, update docstring and adjust to have
it used.
(go-module-available-versions): New procedure.
(%go.mod-require-directive-rx): Document regexp.
(parse-go.mod): Harmonize the way dependencies are recorded to a list of lists
rather than a list of pairs, as done for other importers.  Rewrite to directly pass
multiple values rather than a record object.  Filter the replaced modules in a
functional style.
(go-module->guix-package): Add docstring.
[version, pin-versions?]: New arguments.  Rename the GOPROXY-URL argument to
GOPROXY.  Adjust to the new returned value of fetch-go.mod, which is a string.
Fail when the provided version doesn't exist.  Return a list dependencies and
their versions when in pinned versions mode, else just the dependencies.
(go-module-recursive-import)[version, pin-versions?]: New arguments.
Honor the new arguments and guard against network errors.
* guix/scripts/import/go.scm (%default-options): Register a default value for
the goproxy argument.
(show-help): Document that a version can be specified.  Remove the --version
argument and add a --pin-versions argument.
(%options)[version]: Remove option.
[pin-versions]: Add option.
(guix-import-go): Adjust so the version provided from the module name is
honored, along the new pin-versions? argument.
* tests/go.scm: Adjust and add new tests.
This commit is contained in:
Maxim Cournoyer 2021-03-19 16:41:51 -04:00
parent 6aee902eaf
commit a8b927a562
No known key found for this signature in database
GPG key ID: 1260E46482E63562
4 changed files with 232 additions and 161 deletions

View file

@ -31,6 +31,7 @@ (define-module (guix build-system go)
go-build go-build
go-build-system go-build-system
go-pseudo-version?
go-version->git-ref)) go-version->git-ref))
;; Commentary: ;; Commentary:
@ -40,17 +41,19 @@ (define-module (guix build-system go)
;; ;;
;; Code: ;; Code:
(define %go-version-rx (define %go-pseudo-version-rx
;; Match only the end of the version string; this is so that matching the
;; more complex leading semantic version pattern is not required.
(make-regexp (string-append (make-regexp (string-append
"(v?[0-9]\\.[0-9]\\.[0-9])" ;"v" prefix can be omitted in version prefix "([0-9]{14}-)" ;timestamp
"(-|-pre\\.0\\.|-0\\.)" ;separator "([0-9A-Fa-f]{12})" ;commit hash
"([0-9]{14})-" ;timestamp "(\\+incompatible)?$"))) ;optional +incompatible tag
"([0-9A-Fa-f]{12})"))) ;commit hash
(define (go-version->git-ref version) (define (go-version->git-ref version)
"Parse VERSION, a \"pseudo-version\" as defined at "Parse VERSION, a \"pseudo-version\" as defined at
<https://golang.org/ref/mod#pseudo-versions>, and extract the commit hash from <https://golang.org/ref/mod#pseudo-versions>, and extract the commit hash from
it, defaulting to full VERSION if a pseudo-version pattern is not recognized." it, defaulting to full VERSION (stripped from the \"+incompatible\" suffix if
present) if a pseudo-version pattern is not recognized."
;; A module version like v1.2.3 is introduced by tagging a revision in the ;; A module version like v1.2.3 is introduced by tagging a revision in the
;; underlying source repository. Untagged revisions can be referred to ;; underlying source repository. Untagged revisions can be referred to
;; using a "pseudo-version" like v0.0.0-yyyymmddhhmmss-abcdefabcdef, where ;; using a "pseudo-version" like v0.0.0-yyyymmddhhmmss-abcdefabcdef, where
@ -65,11 +68,16 @@ (define (go-version->git-ref version)
(if (string-suffix? "+incompatible" version) (if (string-suffix? "+incompatible" version)
(string-drop-right version 13) (string-drop-right version 13)
version)) version))
(match (regexp-exec %go-version-rx version))) (match (regexp-exec %go-pseudo-version-rx version)))
(if match (if match
(match:substring match 4) (match:substring match 2)
version))) version)))
(define (go-pseudo-version? version)
"True if VERSION is a Go pseudo-version, i.e., a version string made of a
commit hash and its date rather than a proper release tag."
(regexp-exec %go-pseudo-version-rx version))
(define %go-build-system-modules (define %go-build-system-modules
;; Build-side modules imported and used by default. ;; Build-side modules imported and used by default.
`((guix build go-build-system) `((guix build go-build-system)

View file

@ -50,6 +50,7 @@ (define-module (guix import go)
#:use-module (srfi srfi-9) #:use-module (srfi srfi-9)
#:use-module (srfi srfi-11) #:use-module (srfi srfi-11)
#:use-module (srfi srfi-26) #:use-module (srfi srfi-26)
#:use-module (srfi srfi-34)
#:use-module (sxml match) #:use-module (sxml match)
#:use-module ((sxml xpath) #:renamer (lambda (s) #:use-module ((sxml xpath) #:renamer (lambda (s)
(if (eq? 'filter s) (if (eq? 'filter s)
@ -92,9 +93,7 @@ (define-module (guix import go)
;;; assumption that there will be no collision. ;;; assumption that there will be no collision.
;;; TODO list ;;; TODO list
;;; - get correct hash in vcs->origin ;;; - get correct hash in vcs->origin for Mercurial and Subversion
;;; - print partial result during recursive imports (need to catch
;;; exceptions)
;;; Code: ;;; Code:
@ -121,12 +120,26 @@ (define (escape occurrence)
(define (go.pkg.dev-info name) (define (go.pkg.dev-info name)
(http-fetch* (string-append "https://pkg.go.dev/" name))) (http-fetch* (string-append "https://pkg.go.dev/" name)))
(define (go-module-latest-version goproxy-url module-path) (define* (go-module-version-string goproxy name #:key version)
"Fetch the version number of the latest version for MODULE-PATH from the "Fetch the version string of the latest version for NAME from the given
given GOPROXY-URL server." GOPROXY server, or for VERSION when specified."
(assoc-ref (json-fetch* (format #f "~a/~a/@latest" goproxy-url (let ((file (if version
(go-path-escape module-path))) (string-append "@v/" version ".info")
"Version")) "@latest")))
(assoc-ref (json-fetch* (format #f "~a/~a/~a"
goproxy (go-path-escape name) file))
"Version")))
(define* (go-module-available-versions goproxy name)
"Retrieve the available versions for a given module from the module proxy.
Versions are being returned **unordered** and may contain different versioning
styles for the same package."
(let* ((url (string-append goproxy "/" (go-path-escape name) "/@v/list"))
(body (http-fetch* url))
(versions (remove string-null? (string-split body #\newline))))
(if (null? versions)
(list (go-module-version-string goproxy name)) ;latest version
versions)))
(define (go-package-licenses name) (define (go-package-licenses name)
"Retrieve the list of licenses that apply to NAME, a Go package or module "Retrieve the list of licenses that apply to NAME, a Go package or module
@ -238,119 +251,119 @@ (define %go.mod-require-directive-rx
;; the end. ;; the end.
(make-regexp (make-regexp
(string-append (string-append
"^[[:blank:]]*" "^[[:blank:]]*([^[:blank:]]+)[[:blank:]]+" ;the module path
"([^[:blank:]]+)[[:blank:]]+([^[:blank:]]+)" "([^[:blank:]]+)" ;the version
"([[:blank:]]+//.*)?"))) "([[:blank:]]+//.*)?"))) ;an optional comment
(define %go.mod-replace-directive-rx (define %go.mod-replace-directive-rx
;; ReplaceSpec = ModulePath [ Version ] "=>" FilePath newline ;; ReplaceSpec = ModulePath [ Version ] "=>" FilePath newline
;; | ModulePath [ Version ] "=>" ModulePath Version newline . ;; | ModulePath [ Version ] "=>" ModulePath Version newline .
(make-regexp (make-regexp
(string-append (string-append
"([^[:blank:]]+)([[:blank:]]+([^[:blank:]]+))?" "([^[:blank:]]+)" ;the module path
"[[:blank:]]+" "=>" "[[:blank:]]+" "([[:blank:]]+([^[:blank:]]+))?" ;optional version
"([^[:blank:]]+)([[:blank:]]+([^[:blank:]]+))?"))) "[[:blank:]]+=>[[:blank:]]+"
"([^[:blank:]]+)" ;the file or module path
"([[:blank:]]+([^[:blank:]]+))?"))) ;the version (if a module path)
(define (parse-go.mod content) (define (parse-go.mod content)
"Parse the go.mod file CONTENT, returning a list of requirements." "Parse the go.mod file CONTENT, returning a list of requirements."
(define-record-type <results>
(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 ;; We parse only a subset of https://golang.org/ref/mod#go-mod-file-grammar
;; which we think necessary for our use case. ;; which we think necessary for our use case.
(define (toplevel results) (define (toplevel requirements replaced)
"Main parser, RESULTS is a pair of alist serving as accumulator for "This is the main parser. The results are accumulated in THE REQUIREMENTS
all encountered requirements and replacements." and REPLACED lists."
(let ((line (read-line))) (let ((line (read-line)))
(cond (cond
((eof-object? line) ((eof-object? line)
;; parsing ended, give back the result ;; parsing ended, give back the result
results) (values requirements replaced))
((string=? line "require (") ((string=? line "require (")
;; a require block begins, delegate parsing to IN-REQUIRE ;; a require block begins, delegate parsing to IN-REQUIRE
(in-require results)) (in-require requirements replaced))
((string=? line "replace (") ((string=? line "replace (")
;; a replace block begins, delegate parsing to IN-REPLACE ;; a replace block begins, delegate parsing to IN-REPLACE
(in-replace results)) (in-replace requirements replaced))
((string-prefix? "require " line) ((string-prefix? "require " line)
;; a standalone require directive ;; a require directive by itself
(let* ((stripped-line (string-drop line 8)) (let* ((stripped-line (string-drop line 8)))
(new-results (require-directive results stripped-line))) (call-with-values
(toplevel new-results))) (lambda ()
(require-directive requirements replaced stripped-line))
toplevel)))
((string-prefix? "replace " line) ((string-prefix? "replace " line)
;; a standalone replace directive ;; a replace directive by itself
(let* ((stripped-line (string-drop line 8)) (let* ((stripped-line (string-drop line 8)))
(new-results (replace-directive results stripped-line))) (call-with-values
(toplevel new-results))) (lambda ()
(replace-directive requirements replaced stripped-line))
toplevel)))
(#t (#t
;; unrecognised line, ignore silently ;; unrecognised line, ignore silently
(toplevel results))))) (toplevel requirements replaced)))))
(define (in-require results) (define (in-require requirements replaced)
(let ((line (read-line))) (let ((line (read-line)))
(cond (cond
((eof-object? line) ((eof-object? line)
;; this should never happen here but we ignore silently ;; this should never happen here but we ignore silently
results) (values requirements replaced))
((string=? line ")") ((string=? line ")")
;; end of block, coming back to toplevel ;; end of block, coming back to toplevel
(toplevel results)) (toplevel requirements replaced))
(#t (#t
(in-require (require-directive results line)))))) (call-with-values (lambda ()
(require-directive requirements replaced line))
in-require)))))
(define (in-replace results) (define (in-replace requirements replaced)
(let ((line (read-line))) (let ((line (read-line)))
(cond (cond
((eof-object? line) ((eof-object? line)
;; this should never happen here but we ignore silently ;; this should never happen here but we ignore silently
results) (values requirements replaced))
((string=? line ")") ((string=? line ")")
;; end of block, coming back to toplevel ;; end of block, coming back to toplevel
(toplevel results)) (toplevel requirements replaced))
(#t (#t
(in-replace (replace-directive results line)))))) (call-with-values (lambda ()
(replace-directive requirements replaced line))
in-replace)))))
(define (replace-directive results line) (define (replace-directive requirements replaced line)
"Extract replaced modules and new requirements from replace directive "Extract replaced modules and new requirements from the replace directive
in LINE and add to RESULTS." in LINE and add them to the REQUIREMENTS and REPLACED lists."
(match results (let* ((rx-match (regexp-exec %go.mod-replace-directive-rx line))
(($ <results> requirements replaced) (module-path (match:substring rx-match 1))
(let* ((rx-match (regexp-exec %go.mod-replace-directive-rx line)) (version (match:substring rx-match 3))
(module-path (match:substring rx-match 1)) (new-module-path (match:substring rx-match 4))
(version (match:substring rx-match 3)) (new-version (match:substring rx-match 6))
(new-module-path (match:substring rx-match 4)) (new-replaced (cons (list module-path version) replaced))
(new-version (match:substring rx-match 6)) (new-requirements
(new-replaced (alist-cons module-path version replaced)) (if (string-match "^\\.?\\./" new-module-path)
(new-requirements requirements
(if (string-match "^\\.?\\./" new-module-path) (cons (list new-module-path new-version) requirements))))
requirements (values new-requirements new-replaced)))
(alist-cons new-module-path new-version requirements))))
(make-results new-requirements new-replaced))))) (define (require-directive requirements replaced line)
(define (require-directive results line) "Extract requirement from LINE and augment the REQUIREMENTS and REPLACED
"Extract requirement from LINE and add it to RESULTS." lists."
(let* ((rx-match (regexp-exec %go.mod-require-directive-rx line)) (let* ((rx-match (regexp-exec %go.mod-require-directive-rx line))
(module-path (match:substring rx-match 1)) (module-path (match:substring rx-match 1))
;; we saw double-quoted string in the wild without escape ;; Double-quoted strings were seen in the wild without escape
;; sequences so we just trim the quotes ;; sequences; trim the quotes to be on the safe side.
(module-path (string-trim-both module-path #\")) (module-path (string-trim-both module-path #\"))
(version (match:substring rx-match 2))) (version (match:substring rx-match 2)))
(match results (values (cons (list module-path version) requirements) replaced)))
(($ <results> requirements replaced)
(make-results (alist-cons module-path version requirements) replaced)))))
(let ((results (with-input-from-string content (with-input-from-string content
(lambda _ (lambda ()
(toplevel (make-results '() '())))))) (receive (requirements replaced)
(match results (toplevel '() '())
(($ <results> requirements replaced) ;; At last remove the replaced modules from the requirements list.
;; At last we remove replaced modules from the requirements list (remove (lambda (r)
(fold (assoc (car r) replaced))
(lambda (replacedelem requirements) requirements)))))
(alist-delete! (car replacedelem) requirements))
requirements
replaced)))))
;; Prevent inlining of this procedure, which is accessed by unit tests. ;; Prevent inlining of this procedure, which is accessed by unit tests.
(set! parse-go.mod parse-go.mod) (set! parse-go.mod parse-go.mod)
@ -553,17 +566,32 @@ (define (vcs->origin vcs-type vcs-repo-url version)
vcs-type vcs-repo-url))))) vcs-type vcs-repo-url)))))
(define* (go-module->guix-package module-path #:key (define* (go-module->guix-package module-path #:key
(goproxy-url "https://proxy.golang.org")) (goproxy "https://proxy.golang.org")
(let* ((latest-version (go-module-latest-version goproxy-url module-path)) version
(content (fetch-go.mod goproxy-url module-path latest-version)) pin-versions?)
(dependencies (map car (parse-go.mod content))) "Return the package S-expression corresponding to MODULE-PATH at VERSION, a Go package.
The meta-data is fetched from the GOPROXY server and https://pkg.go.dev/.
When VERSION is unspecified, the latest version available is used."
(let* ((available-versions (go-module-available-versions goproxy module-path))
(version* (or version
(go-module-version-string goproxy module-path))) ;latest
;; Pseudo-versions do not appear in the versions list; skip the
;; following check.
(_ (unless (or (go-pseudo-version? version*)
(member version* available-versions))
(error (format #f "error: version ~s is not available
hint: use one of the following available versions ~a\n"
version* available-versions))))
(content (fetch-go.mod goproxy module-path version*))
(dependencies+versions (parse-go.mod content))
(dependencies (map car dependencies+versions))
(guix-name (go-module->guix-package-name module-path)) (guix-name (go-module->guix-package-name module-path))
(root-module-path (module-path->repository-root module-path)) (root-module-path (module-path->repository-root module-path))
;; The VCS type and URL are not included in goproxy information. For ;; The VCS type and URL are not included in goproxy information. For
;; this we need to fetch it from the official module page. ;; this we need to fetch it from the official module page.
(meta-data (fetch-module-meta-data root-module-path)) (meta-data (fetch-module-meta-data root-module-path))
(vcs-type (module-meta-vcs meta-data)) (vcs-type (module-meta-vcs meta-data))
(vcs-repo-url (module-meta-data-repo-url meta-data goproxy-url)) (vcs-repo-url (module-meta-data-repo-url meta-data goproxy))
(synopsis (go-package-synopsis root-module-path)) (synopsis (go-package-synopsis root-module-path))
(description (go-package-description module-path)) (description (go-package-description module-path))
(licenses (go-package-licenses module-path))) (licenses (go-package-licenses module-path)))
@ -571,14 +599,14 @@ (define* (go-module->guix-package module-path #:key
`(package `(package
(name ,guix-name) (name ,guix-name)
;; Elide the "v" prefix Go uses ;; Elide the "v" prefix Go uses
(version ,(string-trim latest-version #\v)) (version ,(string-trim version* #\v))
(source (source
,(vcs->origin vcs-type vcs-repo-url latest-version)) ,(vcs->origin vcs-type vcs-repo-url version*))
(build-system go-build-system) (build-system go-build-system)
(arguments (arguments
'(#:import-path ,root-module-path)) '(#:import-path ,root-module-path))
,@(maybe-propagated-inputs ,@(maybe-propagated-inputs (map go-module->guix-package-name
(map go-module->guix-package-name dependencies)) dependencies))
(home-page ,(format #f "https://~a" root-module-path)) (home-page ,(format #f "https://~a" root-module-path))
(synopsis ,synopsis) (synopsis ,synopsis)
(description ,(and=> description beautify-description)) (description ,(and=> description beautify-description))
@ -588,16 +616,37 @@ (define* (go-module->guix-package module-path #:key
license) license)
((license ...) ;a list of licenses ((license ...) ;a list of licenses
`(list ,@license))))) `(list ,@license)))))
dependencies))) (if pin-versions?
dependencies+versions
dependencies))))
(define go-module->guix-package* (memoize go-module->guix-package)) (define go-module->guix-package* (memoize go-module->guix-package))
(define* (go-module-recursive-import package-name (define* (go-module-recursive-import package-name
#:key (goproxy-url "https://proxy.golang.org")) #:key (goproxy "https://proxy.golang.org")
version
pin-versions?)
(recursive-import (recursive-import
package-name package-name
#:repo->guix-package (lambda* (name . _) #:repo->guix-package
(go-module->guix-package* (lambda* (name #:key version repo)
name ;; Disable output buffering so that the following warning gets printed
#:goproxy-url goproxy-url)) ;; consistently.
#:guix-name go-module->guix-package-name)) (setvbuf (current-error-port) 'none)
(guard (c ((http-get-error? c)
(warning (G_ "Failed to import package ~s.
reason: ~s could not be fetched: HTTP error ~a (~s).
This package and its dependencies won't be imported.~%")
name
(uri->string (http-get-error-uri c))
(http-get-error-code c)
(http-get-error-reason c))
(values '() '())))
(receive (package-sexp dependencies)
(go-module->guix-package* name #:goproxy goproxy
#:version version
#:pin-versions? pin-versions?)
(values package-sexp dependencies))))
#:guix-name go-module->guix-package-name
#:version version))

View file

@ -1,5 +1,6 @@
;;; GNU Guix --- Functional package management for GNU ;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2020 Katherine Cox-Buday <cox.katherine.e@gmail.com> ;;; Copyright © 2020 Katherine Cox-Buday <cox.katherine.e@gmail.com>
;;; Copyright © 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;; ;;;
;;; This file is part of GNU Guix. ;;; This file is part of GNU Guix.
;;; ;;;
@ -27,28 +28,30 @@ (define-module (guix scripts import go)
#:use-module (srfi srfi-37) #:use-module (srfi srfi-37)
#:use-module (ice-9 match) #:use-module (ice-9 match)
#:use-module (ice-9 format) #:use-module (ice-9 format)
#:use-module (ice-9 receive)
#:export (guix-import-go)) #:export (guix-import-go))
;;; ;;;
;;; Command-line options. ;;; Command-line options.
;;; ;;;
(define %default-options (define %default-options
'()) '((goproxy . "https://proxy.golang.org")))
(define (show-help) (define (show-help)
(display (G_ "Usage: guix import go PACKAGE-PATH (display (G_ "Usage: guix import go PACKAGE-PATH[@VERSION]
Import and convert the Go module for PACKAGE-PATH.\n")) Import and convert the Go module for PACKAGE-PATH. Optionally, a version
can be specified after the arobas (@) character.\n"))
(display (G_ " (display (G_ "
-h, --help display this help and exit")) -h, --help display this help and exit"))
(display (G_ " (display (G_ "
-V, --version display version information and exit")) -r, --recursive generate package expressions for all Go modules
(display (G_ " that are not yet in Guix"))
-r, --recursive generate package expressions for all Go modules\
that are not yet in Guix"))
(display (G_ " (display (G_ "
-p, --goproxy=GOPROXY specify which goproxy server to use")) -p, --goproxy=GOPROXY specify which goproxy server to use"))
(display (G_ "
--pin-versions use the exact versions of a module's dependencies"))
(newline) (newline)
(show-bug-report-information)) (show-bug-report-information))
@ -58,9 +61,6 @@ (define %options
(lambda args (lambda args
(show-help) (show-help)
(exit 0))) (exit 0)))
(option '(#\V "version") #f #f
(lambda args
(show-version-and-exit "guix import go")))
(option '(#\r "recursive") #f #f (option '(#\r "recursive") #f #f
(lambda (opt name arg result) (lambda (opt name arg result)
(alist-cons 'recursive #t result))) (alist-cons 'recursive #t result)))
@ -69,9 +69,12 @@ (define %options
(alist-cons 'goproxy (alist-cons 'goproxy
(string->symbol arg) (string->symbol arg)
(alist-delete 'goproxy result)))) (alist-delete 'goproxy result))))
(option '("pin-versions") #f #f
(lambda (opt name arg result)
(alist-cons 'pin-versions? #t result)))
%standard-import-options)) %standard-import-options))
;;; ;;;
;;; Entry point. ;;; Entry point.
;;; ;;;
@ -93,25 +96,28 @@ (define (parse-options)
(_ #f)) (_ #f))
(reverse opts)))) (reverse opts))))
(match args (match args
((module-name) ((spec) ;e.g., github.com/golang/protobuf@v1.3.1
(if (assoc-ref opts 'recursive) (receive (name version)
(map (match-lambda (package-name->name+version spec)
((and ('package ('name name) . rest) pkg) (let ((arguments (list name
`(define-public ,(string->symbol name) #:goproxy (assoc-ref opts 'goproxy)
,pkg)) #:version version
(_ #f)) #:pin-versions?
(go-module-recursive-import module-name (assoc-ref opts 'pin-versions?))))
#:goproxy-url (if (assoc-ref opts 'recursive)
(or (assoc-ref opts 'goproxy) ;; Recursive import.
"https://proxy.golang.org"))) (map (match-lambda
(let ((sexp (go-module->guix-package module-name ((and ('package ('name name) . rest) pkg)
#:goproxy-url `(define-public ,(string->symbol name)
(or (assoc-ref opts 'goproxy) ,pkg))
"https://proxy.golang.org")))) (_ #f))
(unless sexp (apply go-module-recursive-import arguments))
(leave (G_ "failed to download meta-data for module '~a'~%") ;; Single import.
module-name)) (let ((sexp (apply go-module->guix-package arguments)))
sexp))) (unless sexp
(leave (G_ "failed to download meta-data for module '~a'~%")
module-name))
sexp)))))
(() (()
(leave (G_ "too few arguments~%"))) (leave (G_ "too few arguments~%")))
((many ...) ((many ...)

View file

@ -19,7 +19,7 @@
;;; Summary ;;; Summary
;; Tests for guix/import/go.scm ;; Tests for guix/import/go.scm
(define-module (test-import-go) (define-module (tests-import-go)
#:use-module (guix base32) #:use-module (guix base32)
#:use-module (guix build-system go) #:use-module (guix build-system go)
#:use-module (guix import go) #:use-module (guix import go)
@ -147,7 +147,8 @@ (define fixtures-go-check-test
("https://pkg.go.dev/github.com/go-check/check" ("https://pkg.go.dev/github.com/go-check/check"
. ,pkg.go.dev) . ,pkg.go.dev)
("https://pkg.go.dev/github.com/go-check/check?tab=licenses" ("https://pkg.go.dev/github.com/go-check/check?tab=licenses"
. ,pkg.go.dev-licence)))) . ,pkg.go.dev-licence)
("https://proxy.golang.org/github.com/go-check/check/@v/list" . ""))))
(test-begin "go") (test-begin "go")
@ -169,6 +170,12 @@ (define fixtures-go-check-test
"daa7c04131f5" "daa7c04131f5"
(go-version->git-ref "v1.2.4-0.20191109021931-daa7c04131f5")) (go-version->git-ref "v1.2.4-0.20191109021931-daa7c04131f5"))
(test-assert "go-pseudo-version? multi-digit version number"
(go-pseudo-version? "v1.23.1-0.20200526195155-81db48ad09cc"))
(test-assert "go-pseudo-version? semantic version with rc"
(go-pseudo-version? "v1.4.0-rc.4.0.20200313231945-b860323f09d0"))
;;; Unit tests for (guix import go) ;;; Unit tests for (guix import go)
(test-equal "go-path-escape" (test-equal "go-path-escape"
@ -185,37 +192,38 @@ (define (inf? p1 p2)
(sort ((@@ (guix import go) parse-go.mod) input) inf?))) (sort ((@@ (guix import go) parse-go.mod) input) inf?)))
(testing-parse-mod "parse-go.mod-simple" (testing-parse-mod "parse-go.mod-simple"
'(("good/thing" . "v1.4.5") '(("good/thing" "v1.4.5")
("new/thing/v2" . "v2.3.4") ("new/thing/v2" "v2.3.4")
("other/thing" . "v1.0.2")) ("other/thing" "v1.0.2"))
fixture-go-mod-simple) fixture-go-mod-simple)
(testing-parse-mod "parse-go.mod-with-block" (testing-parse-mod "parse-go.mod-with-block"
'(("A" . "v1") '(("A" "v1")
("B" . "v1.0.0") ("B" "v1.0.0")
("C" . "v1.0.0") ("C" "v1.0.0")
("D" . "v1.2.3") ("D" "v1.2.3")
("E" . "dev")) ("E" "dev"))
fixture-go-mod-with-block) fixture-go-mod-with-block)
(testing-parse-mod "parse-go.mod-complete" (testing-parse-mod
'(("github.com/corp/arbitrary-repo" . "v0.0.2") "parse-go.mod-complete"
("quoted.example.com/abitrary/repo" . "v0.0.2") '(("github.com/corp/arbitrary-repo" "v0.0.2")
("one.example.com/abitrary/repo" . "v1.1.111") ("quoted.example.com/abitrary/repo" "v0.0.2")
("hub.jazz.net/git/user/project/sub/directory" . "v1.1.19") ("one.example.com/abitrary/repo" "v1.1.111")
("hub.jazz.net/git/user/project" . "v1.1.18") ("hub.jazz.net/git/user/project/sub/directory" "v1.1.19")
("launchpad.net/~user/project/branch/sub/directory" . "v1.1.17") ("hub.jazz.net/git/user/project" "v1.1.18")
("launchpad.net/~user/project/branch" . "v1.1.16") ("launchpad.net/~user/project/branch/sub/directory" "v1.1.17")
("launchpad.net/project/series/sub/directory" . "v1.1.15") ("launchpad.net/~user/project/branch" "v1.1.16")
("launchpad.net/project/series" . "v1.1.14") ("launchpad.net/project/series/sub/directory" "v1.1.15")
("launchpad.net/project" . "v1.1.13") ("launchpad.net/project/series" "v1.1.14")
("bitbucket.org/user/project/sub/directory" . "v1.11.21") ("launchpad.net/project" "v1.1.13")
("bitbucket.org/user/project" . "v1.11.20") ("bitbucket.org/user/project/sub/directory" "v1.11.21")
("k8s.io/kubernetes/subproject" . "v1.1.101") ("bitbucket.org/user/project" "v1.11.20")
("github.com/user/project/sub/directory" . "v1.1.12") ("k8s.io/kubernetes/subproject" "v1.1.101")
("github.com/user/project" . "v1.1.11") ("github.com/user/project/sub/directory" "v1.1.12")
("github.com/go-check/check" . "v0.0.0-20140225173054-eb6ee6f84d0a")) ("github.com/user/project" "v1.1.11")
fixture-go-mod-complete) ("github.com/go-check/check" "v0.0.0-20140225173054-eb6ee6f84d0a"))
fixture-go-mod-complete)
;;; End-to-end tests for (guix import go) ;;; End-to-end tests for (guix import go)
(define (mock-http-fetch testcase) (define (mock-http-fetch testcase)