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:
		
							parent
							
								
									6aee902eaf
								
							
						
					
					
						commit
						a8b927a562
					
				
					 4 changed files with 232 additions and 161 deletions
				
			
		| 
						 | 
					@ -31,6 +31,7 @@
 | 
				
			||||||
            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 @@
 | 
				
			||||||
;;
 | 
					;;
 | 
				
			||||||
;; 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 @@ it, defaulting to full VERSION if a pseudo-version pattern is not recognized."
 | 
				
			||||||
          (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)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -50,6 +50,7 @@
 | 
				
			||||||
  #: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 @@
 | 
				
			||||||
;;; 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 @@ https://godoc.org/golang.org/x/mod/module#hdr-Escaped_Paths)."
 | 
				
			||||||
(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 @@ and VERSION and return an input port."
 | 
				
			||||||
  ;; 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
 | 
					 | 
				
			||||||
      (($ <results> requirements replaced)
 | 
					 | 
				
			||||||
    (let* ((rx-match (regexp-exec %go.mod-replace-directive-rx line))
 | 
					    (let* ((rx-match (regexp-exec %go.mod-replace-directive-rx line))
 | 
				
			||||||
           (module-path (match:substring rx-match 1))
 | 
					           (module-path (match:substring rx-match 1))
 | 
				
			||||||
           (version (match:substring rx-match 3))
 | 
					           (version (match:substring rx-match 3))
 | 
				
			||||||
           (new-module-path (match:substring rx-match 4))
 | 
					           (new-module-path (match:substring rx-match 4))
 | 
				
			||||||
           (new-version (match:substring rx-match 6))
 | 
					           (new-version (match:substring rx-match 6))
 | 
				
			||||||
              (new-replaced (alist-cons module-path version replaced))
 | 
					           (new-replaced (cons (list module-path version) replaced))
 | 
				
			||||||
           (new-requirements
 | 
					           (new-requirements
 | 
				
			||||||
            (if (string-match "^\\.?\\./" new-module-path)
 | 
					            (if (string-match "^\\.?\\./" new-module-path)
 | 
				
			||||||
                requirements
 | 
					                requirements
 | 
				
			||||||
                   (alist-cons new-module-path new-version requirements))))
 | 
					                (cons (list new-module-path new-version) requirements))))
 | 
				
			||||||
         (make-results new-requirements new-replaced)))))
 | 
					      (values new-requirements new-replaced)))
 | 
				
			||||||
  (define (require-directive results line)
 | 
					
 | 
				
			||||||
    "Extract requirement from LINE and add it to RESULTS."
 | 
					  (define (require-directive requirements replaced line)
 | 
				
			||||||
 | 
					    "Extract requirement from LINE and augment the REQUIREMENTS and REPLACED
 | 
				
			||||||
 | 
					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 @@ control system is being used."
 | 
				
			||||||
                         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 @@ control system is being used."
 | 
				
			||||||
     `(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 @@ control system is being used."
 | 
				
			||||||
                     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)
 | 
				
			||||||
 | 
					     ;; Disable output buffering so that the following warning gets printed
 | 
				
			||||||
 | 
					     ;; consistently.
 | 
				
			||||||
 | 
					     (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
 | 
					                         name
 | 
				
			||||||
                           #:goproxy-url goproxy-url))
 | 
					                         (uri->string (http-get-error-uri c))
 | 
				
			||||||
   #:guix-name go-module->guix-package-name))
 | 
					                         (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))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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 @@
 | 
				
			||||||
  #: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_ "
 | 
					 | 
				
			||||||
  -r, --recursive        generate package expressions for all Go modules\
 | 
					 | 
				
			||||||
that are not yet in Guix"))
 | 
					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 @@ Import and convert the Go module for PACKAGE-PATH.\n"))
 | 
				
			||||||
                 (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 @@ Import and convert the Go module for PACKAGE-PATH.\n"))
 | 
				
			||||||
                   (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 @@ Import and convert the Go module for PACKAGE-PATH.\n"))
 | 
				
			||||||
                             (_ #f))
 | 
					                             (_ #f))
 | 
				
			||||||
                           (reverse opts))))
 | 
					                           (reverse opts))))
 | 
				
			||||||
    (match args
 | 
					    (match args
 | 
				
			||||||
      ((module-name)
 | 
					      ((spec)                         ;e.g., github.com/golang/protobuf@v1.3.1
 | 
				
			||||||
 | 
					       (receive (name version)
 | 
				
			||||||
 | 
					           (package-name->name+version spec)
 | 
				
			||||||
 | 
					         (let ((arguments (list name
 | 
				
			||||||
 | 
					                                #:goproxy (assoc-ref opts 'goproxy)
 | 
				
			||||||
 | 
					                                #:version version
 | 
				
			||||||
 | 
					                                #:pin-versions?
 | 
				
			||||||
 | 
					                                (assoc-ref opts 'pin-versions?))))
 | 
				
			||||||
           (if (assoc-ref opts 'recursive)
 | 
					           (if (assoc-ref opts 'recursive)
 | 
				
			||||||
 | 
					               ;; Recursive import.
 | 
				
			||||||
               (map (match-lambda
 | 
					               (map (match-lambda
 | 
				
			||||||
                      ((and ('package ('name name) . rest) pkg)
 | 
					                      ((and ('package ('name name) . rest) pkg)
 | 
				
			||||||
                       `(define-public ,(string->symbol name)
 | 
					                       `(define-public ,(string->symbol name)
 | 
				
			||||||
                          ,pkg))
 | 
					                          ,pkg))
 | 
				
			||||||
                      (_ #f))
 | 
					                      (_ #f))
 | 
				
			||||||
                (go-module-recursive-import module-name
 | 
					                    (apply go-module-recursive-import arguments))
 | 
				
			||||||
                                            #:goproxy-url
 | 
					               ;; Single import.
 | 
				
			||||||
                                            (or (assoc-ref opts 'goproxy)
 | 
					               (let ((sexp (apply go-module->guix-package arguments)))
 | 
				
			||||||
                                                "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
 | 
					                 (unless sexp
 | 
				
			||||||
                   (leave (G_ "failed to download meta-data for module '~a'~%")
 | 
					                   (leave (G_ "failed to download meta-data for module '~a'~%")
 | 
				
			||||||
                          module-name))
 | 
					                          module-name))
 | 
				
			||||||
             sexp)))
 | 
					                 sexp)))))
 | 
				
			||||||
      (()
 | 
					      (()
 | 
				
			||||||
       (leave (G_ "too few arguments~%")))
 | 
					       (leave (G_ "too few arguments~%")))
 | 
				
			||||||
      ((many ...)
 | 
					      ((many ...)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										62
									
								
								tests/go.scm
									
										
									
									
									
								
							
							
						
						
									
										62
									
								
								tests/go.scm
									
										
									
									
									
								
							| 
						 | 
					@ -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 @@ require github.com/kr/pretty v0.2.1
 | 
				
			||||||
      ("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 @@ require github.com/kr/pretty v0.2.1
 | 
				
			||||||
  "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,36 +192,37 @@ require github.com/kr/pretty v0.2.1
 | 
				
			||||||
    (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")
 | 
				
			||||||
 | 
					   ("github.com/go-check/check" "v0.0.0-20140225173054-eb6ee6f84d0a"))
 | 
				
			||||||
 fixture-go-mod-complete)
 | 
					 fixture-go-mod-complete)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
;;; End-to-end tests for (guix import go)
 | 
					;;; End-to-end tests for (guix import go)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Reference in a new issue