summaryrefslogtreecommitdiff
path: root/libgo/go/cmd
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2018-09-24 21:46:21 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2018-09-24 21:46:21 +0000
commitdd931d9b48647e898dc80927c532ae93cc09e192 (patch)
tree71be2295cd79b8a182f6130611658db8628772d5 /libgo/go/cmd
parent779d8a5ad09b01428726ea5a0e6c87bd9ac3c0e4 (diff)
libgo: update to Go 1.11
Reviewed-on: https://go-review.googlesource.com/136435 gotools/: * Makefile.am (mostlyclean-local): Run chmod on check-go-dir to make sure it is writable. (check-go-tools): Likewise. (check-vet): Copy internal/objabi to check-vet-dir. * Makefile.in: Rebuild. From-SVN: r264546
Diffstat (limited to 'libgo/go/cmd')
-rw-r--r--libgo/go/cmd/buildid/buildid.go29
-rw-r--r--libgo/go/cmd/cgo/ast.go3
-rw-r--r--libgo/go/cmd/cgo/doc.go50
-rw-r--r--libgo/go/cmd/cgo/gcc.go147
-rw-r--r--libgo/go/cmd/cgo/godefs.go2
-rw-r--r--libgo/go/cmd/cgo/main.go27
-rw-r--r--libgo/go/cmd/cgo/out.go103
-rw-r--r--libgo/go/cmd/cgo/util.go4
-rw-r--r--libgo/go/cmd/go/alldocs.go1480
-rw-r--r--libgo/go/cmd/go/go_test.go1227
-rw-r--r--libgo/go/cmd/go/go_windows_test.go16
-rw-r--r--libgo/go/cmd/go/internal/base/base.go34
-rw-r--r--libgo/go/cmd/go/internal/base/goflags.go152
-rw-r--r--libgo/go/cmd/go/internal/base/signal_unix.go2
-rw-r--r--libgo/go/cmd/go/internal/bug/bug.go5
-rw-r--r--libgo/go/cmd/go/internal/cache/cache.go15
-rw-r--r--libgo/go/cmd/go/internal/cache/default.go37
-rw-r--r--libgo/go/cmd/go/internal/cache/default_unix_test.go67
-rw-r--r--libgo/go/cmd/go/internal/cfg/cfg.go38
-rw-r--r--libgo/go/cmd/go/internal/clean/clean.go42
-rw-r--r--libgo/go/cmd/go/internal/cmdflag/flag.go36
-rw-r--r--libgo/go/cmd/go/internal/dirhash/hash.go103
-rw-r--r--libgo/go/cmd/go/internal/dirhash/hash_test.go135
-rw-r--r--libgo/go/cmd/go/internal/doc/doc.go2
-rw-r--r--libgo/go/cmd/go/internal/envcmd/env.go37
-rw-r--r--libgo/go/cmd/go/internal/fix/fix.go13
-rw-r--r--libgo/go/cmd/go/internal/fmtcmd/fmt.go12
-rw-r--r--libgo/go/cmd/go/internal/generate/generate.go30
-rw-r--r--libgo/go/cmd/go/internal/get/discovery.go36
-rw-r--r--libgo/go/cmd/go/internal/get/get.go122
-rw-r--r--libgo/go/cmd/go/internal/get/pkg_test.go36
-rw-r--r--libgo/go/cmd/go/internal/get/vcs.go144
-rw-r--r--libgo/go/cmd/go/internal/get/vcs_test.go133
-rw-r--r--libgo/go/cmd/go/internal/help/help.go87
-rw-r--r--libgo/go/cmd/go/internal/help/helpdoc.go71
-rw-r--r--libgo/go/cmd/go/internal/imports/build.go211
-rw-r--r--libgo/go/cmd/go/internal/imports/read.go249
-rw-r--r--libgo/go/cmd/go/internal/imports/read_test.go228
-rw-r--r--libgo/go/cmd/go/internal/imports/scan.go96
-rw-r--r--libgo/go/cmd/go/internal/imports/scan_test.go67
-rw-r--r--libgo/go/cmd/go/internal/imports/tags.go34
-rw-r--r--libgo/go/cmd/go/internal/imports/testdata/import1/x.go3
-rw-r--r--libgo/go/cmd/go/internal/imports/testdata/import1/x1.go9
-rw-r--r--libgo/go/cmd/go/internal/imports/testdata/import1/x_darwin.go3
-rw-r--r--libgo/go/cmd/go/internal/imports/testdata/import1/x_windows.go3
-rw-r--r--libgo/go/cmd/go/internal/list/list.go508
-rw-r--r--libgo/go/cmd/go/internal/load/flag.go28
-rw-r--r--libgo/go/cmd/go/internal/load/path.go16
-rw-r--r--libgo/go/cmd/go/internal/load/pkg.go684
-rw-r--r--libgo/go/cmd/go/internal/load/search.go339
-rw-r--r--libgo/go/cmd/go/internal/load/test.go654
-rw-r--r--libgo/go/cmd/go/internal/modcmd/download.go133
-rw-r--r--libgo/go/cmd/go/internal/modcmd/edit.go382
-rw-r--r--libgo/go/cmd/go/internal/modcmd/graph.go73
-rw-r--r--libgo/go/cmd/go/internal/modcmd/init.go41
-rw-r--r--libgo/go/cmd/go/internal/modcmd/mod.go31
-rw-r--r--libgo/go/cmd/go/internal/modcmd/tidy.go90
-rw-r--r--libgo/go/cmd/go/internal/modcmd/vendor.go200
-rw-r--r--libgo/go/cmd/go/internal/modcmd/verify.go96
-rw-r--r--libgo/go/cmd/go/internal/modcmd/why.go121
-rw-r--r--libgo/go/cmd/go/internal/modconv/convert.go90
-rw-r--r--libgo/go/cmd/go/internal/modconv/convert_test.go186
-rw-r--r--libgo/go/cmd/go/internal/modconv/dep.go74
-rw-r--r--libgo/go/cmd/go/internal/modconv/glide.go42
-rw-r--r--libgo/go/cmd/go/internal/modconv/glock.go24
-rw-r--r--libgo/go/cmd/go/internal/modconv/godeps.go30
-rw-r--r--libgo/go/cmd/go/internal/modconv/modconv.go19
-rw-r--r--libgo/go/cmd/go/internal/modconv/modconv_test.go66
-rw-r--r--libgo/go/cmd/go/internal/modconv/testdata/cockroach.glock41
-rw-r--r--libgo/go/cmd/go/internal/modconv/testdata/cockroach.out31
-rw-r--r--libgo/go/cmd/go/internal/modconv/testdata/dockermachine.godeps159
-rw-r--r--libgo/go/cmd/go/internal/modconv/testdata/dockermachine.out33
-rw-r--r--libgo/go/cmd/go/internal/modconv/testdata/dockerman.glide52
-rw-r--r--libgo/go/cmd/go/internal/modconv/testdata/dockerman.out16
-rw-r--r--libgo/go/cmd/go/internal/modconv/testdata/govmomi.out5
-rw-r--r--libgo/go/cmd/go/internal/modconv/testdata/govmomi.vmanifest46
-rw-r--r--libgo/go/cmd/go/internal/modconv/testdata/juju.out106
-rw-r--r--libgo/go/cmd/go/internal/modconv/testdata/juju.tsv106
-rw-r--r--libgo/go/cmd/go/internal/modconv/testdata/moby.out105
-rw-r--r--libgo/go/cmd/go/internal/modconv/testdata/moby.vconf149
-rw-r--r--libgo/go/cmd/go/internal/modconv/testdata/panicparse.out8
-rw-r--r--libgo/go/cmd/go/internal/modconv/testdata/panicparse.vyml17
-rw-r--r--libgo/go/cmd/go/internal/modconv/testdata/prometheus.out258
-rw-r--r--libgo/go/cmd/go/internal/modconv/testdata/prometheus.vjson1605
-rw-r--r--libgo/go/cmd/go/internal/modconv/testdata/upspin.dep57
-rw-r--r--libgo/go/cmd/go/internal/modconv/testdata/upspin.out8
-rw-r--r--libgo/go/cmd/go/internal/modconv/tsv.go24
-rw-r--r--libgo/go/cmd/go/internal/modconv/vconf.go27
-rw-r--r--libgo/go/cmd/go/internal/modconv/vjson.go29
-rw-r--r--libgo/go/cmd/go/internal/modconv/vmanifest.go29
-rw-r--r--libgo/go/cmd/go/internal/modconv/vyml.go42
-rw-r--r--libgo/go/cmd/go/internal/modfetch/cache.go522
-rw-r--r--libgo/go/cmd/go/internal/modfetch/cache_test.go25
-rw-r--r--libgo/go/cmd/go/internal/modfetch/codehost/codehost.go266
-rw-r--r--libgo/go/cmd/go/internal/modfetch/codehost/git.go711
-rw-r--r--libgo/go/cmd/go/internal/modfetch/codehost/git_test.go635
-rw-r--r--libgo/go/cmd/go/internal/modfetch/codehost/shell.go140
-rw-r--r--libgo/go/cmd/go/internal/modfetch/codehost/vcs.go528
-rw-r--r--libgo/go/cmd/go/internal/modfetch/coderepo.go605
-rw-r--r--libgo/go/cmd/go/internal/modfetch/coderepo_test.go643
-rw-r--r--libgo/go/cmd/go/internal/modfetch/fetch.go365
-rw-r--r--libgo/go/cmd/go/internal/modfetch/noweb.go24
-rw-r--r--libgo/go/cmd/go/internal/modfetch/proxy.go252
-rw-r--r--libgo/go/cmd/go/internal/modfetch/pseudo.go129
-rw-r--r--libgo/go/cmd/go/internal/modfetch/pseudo_test.go74
-rw-r--r--libgo/go/cmd/go/internal/modfetch/repo.go363
-rw-r--r--libgo/go/cmd/go/internal/modfetch/unzip.go153
-rw-r--r--libgo/go/cmd/go/internal/modfetch/web.go31
-rw-r--r--libgo/go/cmd/go/internal/modfile/gopkgin.go47
-rw-r--r--libgo/go/cmd/go/internal/modfile/print.go164
-rw-r--r--libgo/go/cmd/go/internal/modfile/read.go869
-rw-r--r--libgo/go/cmd/go/internal/modfile/read_test.go365
-rw-r--r--libgo/go/cmd/go/internal/modfile/rule.go724
-rw-r--r--libgo/go/cmd/go/internal/modfile/rule_test.go90
-rw-r--r--libgo/go/cmd/go/internal/modfile/testdata/block.golden29
-rw-r--r--libgo/go/cmd/go/internal/modfile/testdata/block.in29
-rw-r--r--libgo/go/cmd/go/internal/modfile/testdata/comment.golden10
-rw-r--r--libgo/go/cmd/go/internal/modfile/testdata/comment.in8
-rw-r--r--libgo/go/cmd/go/internal/modfile/testdata/empty.golden0
-rw-r--r--libgo/go/cmd/go/internal/modfile/testdata/empty.in0
-rw-r--r--libgo/go/cmd/go/internal/modfile/testdata/gopkg.in.golden6
-rw-r--r--libgo/go/cmd/go/internal/modfile/testdata/module.golden1
-rw-r--r--libgo/go/cmd/go/internal/modfile/testdata/module.in1
-rw-r--r--libgo/go/cmd/go/internal/modfile/testdata/replace.golden5
-rw-r--r--libgo/go/cmd/go/internal/modfile/testdata/replace.in5
-rw-r--r--libgo/go/cmd/go/internal/modfile/testdata/replace2.golden10
-rw-r--r--libgo/go/cmd/go/internal/modfile/testdata/replace2.in10
-rw-r--r--libgo/go/cmd/go/internal/modfile/testdata/rule1.golden7
-rw-r--r--libgo/go/cmd/go/internal/modget/get.go656
-rw-r--r--libgo/go/cmd/go/internal/modinfo/info.go49
-rw-r--r--libgo/go/cmd/go/internal/modload/build.go243
-rw-r--r--libgo/go/cmd/go/internal/modload/help.go462
-rw-r--r--libgo/go/cmd/go/internal/modload/import.go228
-rw-r--r--libgo/go/cmd/go/internal/modload/import_test.go59
-rw-r--r--libgo/go/cmd/go/internal/modload/init.go600
-rw-r--r--libgo/go/cmd/go/internal/modload/list.go109
-rw-r--r--libgo/go/cmd/go/internal/modload/load.go1071
-rw-r--r--libgo/go/cmd/go/internal/modload/query.go249
-rw-r--r--libgo/go/cmd/go/internal/modload/query_test.go151
-rw-r--r--libgo/go/cmd/go/internal/modload/search.go134
-rw-r--r--libgo/go/cmd/go/internal/module/module.go540
-rw-r--r--libgo/go/cmd/go/internal/module/module_test.go318
-rw-r--r--libgo/go/cmd/go/internal/mvs/mvs.go368
-rw-r--r--libgo/go/cmd/go/internal/mvs/mvs_test.go473
-rw-r--r--libgo/go/cmd/go/internal/par/work.go149
-rw-r--r--libgo/go/cmd/go/internal/par/work_test.go77
-rw-r--r--libgo/go/cmd/go/internal/run/run.go46
-rw-r--r--libgo/go/cmd/go/internal/search/search.go505
-rw-r--r--libgo/go/cmd/go/internal/search/search_test.go (renamed from libgo/go/cmd/go/internal/load/match_test.go)10
-rw-r--r--libgo/go/cmd/go/internal/semver/semver.go388
-rw-r--r--libgo/go/cmd/go/internal/semver/semver_test.go182
-rw-r--r--libgo/go/cmd/go/internal/str/path.go25
-rw-r--r--libgo/go/cmd/go/internal/test/cover.go2
-rw-r--r--libgo/go/cmd/go/internal/test/test.go565
-rw-r--r--libgo/go/cmd/go/internal/test/testflag.go2
-rw-r--r--libgo/go/cmd/go/internal/tool/tool.go2
-rw-r--r--libgo/go/cmd/go/internal/txtar/archive.go140
-rw-r--r--libgo/go/cmd/go/internal/txtar/archive_test.go67
-rw-r--r--libgo/go/cmd/go/internal/version/version.go2
-rw-r--r--libgo/go/cmd/go/internal/vet/vet.go7
-rw-r--r--libgo/go/cmd/go/internal/vet/vetflag.go71
-rw-r--r--libgo/go/cmd/go/internal/web2/web.go297
-rw-r--r--libgo/go/cmd/go/internal/web2/web_test.go35
-rw-r--r--libgo/go/cmd/go/internal/webtest/test.go314
-rw-r--r--libgo/go/cmd/go/internal/work/action.go71
-rw-r--r--libgo/go/cmd/go/internal/work/build.go69
-rw-r--r--libgo/go/cmd/go/internal/work/build_test.go51
-rw-r--r--libgo/go/cmd/go/internal/work/buildid.go119
-rw-r--r--libgo/go/cmd/go/internal/work/exec.go757
-rw-r--r--libgo/go/cmd/go/internal/work/gc.go26
-rw-r--r--libgo/go/cmd/go/internal/work/gccgo.go4
-rw-r--r--libgo/go/cmd/go/internal/work/init.go54
-rw-r--r--libgo/go/cmd/go/internal/work/security.go3
-rw-r--r--libgo/go/cmd/go/internal/work/security_test.go2
-rw-r--r--libgo/go/cmd/go/main.go104
-rw-r--r--libgo/go/cmd/go/proxy_test.go272
-rw-r--r--libgo/go/cmd/go/script_test.go905
-rw-r--r--libgo/go/cmd/go/testdata/addmod.go154
-rw-r--r--libgo/go/cmd/go/testdata/badmod/go.mod1
-rw-r--r--libgo/go/cmd/go/testdata/badmod/x.go4
-rw-r--r--libgo/go/cmd/go/testdata/importcycle/src/selfimport/selfimport.go3
-rw-r--r--libgo/go/cmd/go/testdata/mod/README36
-rw-r--r--libgo/go/cmd/go/testdata/mod/example.com_join_subpkg_v1.0.0.txt9
-rw-r--r--libgo/go/cmd/go/testdata/mod/example.com_join_subpkg_v1.1.0.txt9
-rw-r--r--libgo/go/cmd/go/testdata/mod/example.com_join_v1.0.0.txt7
-rw-r--r--libgo/go/cmd/go/testdata/mod/example.com_join_v1.1.0.txt9
-rw-r--r--libgo/go/cmd/go/testdata/mod/example.com_split_subpkg_v1.1.0.txt11
-rw-r--r--libgo/go/cmd/go/testdata/mod/example.com_split_v1.0.0.txt9
-rw-r--r--libgo/go/cmd/go/testdata/mod/example.com_split_v1.1.0.txt9
-rw-r--r--libgo/go/cmd/go/testdata/mod/example.com_v1.0.0.txt9
-rw-r--r--libgo/go/cmd/go/testdata/mod/golang.org_notx_useinternal_v0.1.0.txt13
-rw-r--r--libgo/go/cmd/go/testdata/mod/golang.org_x_internal_v0.1.0.txt43
-rw-r--r--libgo/go/cmd/go/testdata/mod/golang.org_x_text_v0.0.0-20170915032832-14c0d48ead0c.txt47
-rw-r--r--libgo/go/cmd/go/testdata/mod/golang.org_x_text_v0.3.0.txt47
-rw-r--r--libgo/go/cmd/go/testdata/mod/golang.org_x_useinternal_v0.1.0.txt13
-rw-r--r--libgo/go/cmd/go/testdata/mod/gopkg.in_dummy.v2-unstable_v2.0.0.txt9
-rw-r--r--libgo/go/cmd/go/testdata/mod/research.swtch.com_vgo-tour_v1.0.0.txt23
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_!c!g!o_v1.0.0.txt19
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_!q!u!o!t!e_v1.5.2.txt88
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_!q!u!o!t!e_v1.5.3-!p!r!e.txt88
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_badfile1_v1.0.0.txt14
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_badfile2_v1.0.0.txt12
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_badfile3_v1.0.0.txt12
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_badfile4_v1.0.0.txt15
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_badfile5_v1.0.0.txt13
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_badmod_v1.0.0.txt11
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_breaker_v1.0.0.txt11
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_breaker_v2.0.0+incompatible.txt11
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_breaker_v2.0.0.txt11
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_fortune_v1.0.0.txt15
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_fortune_v2_v2.0.0.txt15
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180214005133-e7a685a342c0.txt60
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180214005840-23179ee8a569.txt86
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180628003336-dd9747d19b04.txt100
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709153244-fd906ed3b100.txt86
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709160352-0d003b9c4bfa.txt98
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162749-b44a0b17b2d1.txt104
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162816-fe488b867524.txt104
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162918-a91498bed0a7.txt98
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180710144737-5d9f230bcfba.txt104
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.0.0.txt35
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.1.0.txt48
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.2.0.txt61
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.2.1.txt60
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.3.0.txt73
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.4.0.txt79
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.5.0.txt79
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.5.1.txt86
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.5.2.txt98
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.5.3-pre1.txt100
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_quote_v2.0.0.txt86
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_quote_v2_v2.0.1.txt86
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_quote_v3_v3.0.0.txt45
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_sampler_v1.0.0.txt20
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_sampler_v1.2.0.txt138
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_sampler_v1.2.1.txt134
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_sampler_v1.3.0.txt202
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_sampler_v1.3.1.txt201
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_sampler_v1.99.99.txt140
-rw-r--r--libgo/go/cmd/go/testdata/mod/rsc.io_testonly_v1.0.0.txt9
-rw-r--r--libgo/go/cmd/go/testdata/savedir.go79
-rw-r--r--libgo/go/cmd/go/testdata/script/README261
-rw-r--r--libgo/go/cmd/go/testdata/script/binary_only.txt10
-rw-r--r--libgo/go/cmd/go/testdata/script/build_GOTMPDIR.txt11
-rw-r--r--libgo/go/cmd/go/testdata/script/build_cache_compile.txt18
-rw-r--r--libgo/go/cmd/go/testdata/script/build_cache_link.txt23
-rw-r--r--libgo/go/cmd/go/testdata/script/build_cache_output.txt63
-rw-r--r--libgo/go/cmd/go/testdata/script/cover_atomic_pkgall.txt23
-rw-r--r--libgo/go/cmd/go/testdata/script/cover_pkgall_runtime.txt21
-rw-r--r--libgo/go/cmd/go/testdata/script/cpu_profile_twice.txt20
-rw-r--r--libgo/go/cmd/go/testdata/script/fileline.txt6
-rw-r--r--libgo/go/cmd/go/testdata/script/get_with_git_trace.txt7
-rw-r--r--libgo/go/cmd/go/testdata/script/goflags.txt49
-rw-r--r--libgo/go/cmd/go/testdata/script/help.txt30
-rw-r--r--libgo/go/cmd/go/testdata/script/install_cleans_build.txt22
-rw-r--r--libgo/go/cmd/go/testdata/script/install_cross_gobin.txt25
-rw-r--r--libgo/go/cmd/go/testdata/script/install_rebuild_gopath.txt28
-rw-r--r--libgo/go/cmd/go/testdata/script/install_rebuild_removed.txt42
-rw-r--r--libgo/go/cmd/go/testdata/script/linkname.txt7
-rw-r--r--libgo/go/cmd/go/testdata/script/list_bad_import.txt67
-rw-r--r--libgo/go/cmd/go/testdata/script/list_compiled_imports.txt29
-rw-r--r--libgo/go/cmd/go/testdata/script/list_find.txt10
-rw-r--r--libgo/go/cmd/go/testdata/script/list_std.txt12
-rw-r--r--libgo/go/cmd/go/testdata/script/list_tags.txt8
-rw-r--r--libgo/go/cmd/go/testdata/script/list_test_e.txt9
-rw-r--r--libgo/go/cmd/go/testdata/script/list_test_imports.txt19
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_bad_domain.txt29
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_bad_filenames.txt11
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_build_tags.txt30
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_case.txt20
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_case_cgo.txt9
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_convert_dep.txt9
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_convert_git.txt10
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_convert_glide.txt9
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_convert_glockfile.txt9
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_convert_godeps.txt10
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_convert_tsv.txt9
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_convert_vendor_conf.txt9
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_convert_vendor_json.txt10
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_convert_vendor_manifest.txt10
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_convert_vendor_yml.txt9
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_doc.txt36
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_domain_root.txt12
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_download.txt64
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_edit.txt136
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_enabled.txt82
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_file_proxy.txt25
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_find.txt91
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_fs_patterns.txt66
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_get_commit.txt53
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_get_downgrade.txt39
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_get_incompatible.txt26
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_get_indirect.txt51
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_get_local.txt61
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_get_moved.txt37
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_get_none.txt12
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_get_pseudo.txt80
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_get_upgrade.txt41
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_get_warning.txt10
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_getmode_vendor.txt23
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_go_version.txt61
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_gobuild_import.txt74
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_gofmt_invalid.txt13
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_gopkg_unstable.txt22
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_graph.txt10
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_import.txt18
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_import_mod.txt7
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_init_dep.txt34
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_install_versioned.txt12
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_internal.txt102
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_list.txt60
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_list_bad_import.txt73
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_list_dir.txt32
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_list_upgrade.txt8
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_load_badmod.txt26
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_local_replace.txt23
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_multirepo.txt40
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_nomod.txt43
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_patterns.txt66
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_query.txt24
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_query_exclude.txt26
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_readonly.txt42
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_replace.txt87
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_require_exclude.txt33
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_test.txt119
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_tidy.txt64
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_tidy_quote.txt26
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_tidy_sum.txt33
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_upgrade_patch.txt29
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_vendor.txt230
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_vendor_build.txt27
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_vendor_nodeps.txt9
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_verify.txt85
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_versions.txt14
-rw-r--r--libgo/go/cmd/go/testdata/script/mod_why.txt114
-rw-r--r--libgo/go/cmd/go/testdata/script/pattern_syntax_error.txt10
-rw-r--r--libgo/go/cmd/go/testdata/script/run_hello.txt7
-rw-r--r--libgo/go/cmd/go/testdata/script/test_badtest.txt30
-rw-r--r--libgo/go/cmd/go/testdata/script/test_compile_binary.txt6
-rw-r--r--libgo/go/cmd/go/testdata/script/vendor_complex.txt73
-rw-r--r--libgo/go/cmd/go/testdata/src/badtest/badexec/x_test.go5
-rw-r--r--libgo/go/cmd/go/testdata/src/badtest/badsyntax/x.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/badtest/badsyntax/x_test.go3
-rw-r--r--libgo/go/cmd/go/testdata/src/badtest/badvar/x.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/badtest/badvar/x_test.go5
-rw-r--r--libgo/go/cmd/go/testdata/src/complex/main.go12
-rw-r--r--libgo/go/cmd/go/testdata/src/complex/nest/sub/test12/p.go11
-rw-r--r--libgo/go/cmd/go/testdata/src/complex/nest/sub/test23/p.go11
-rw-r--r--libgo/go/cmd/go/testdata/src/complex/nest/sub/vendor/v2/v2.go3
-rw-r--r--libgo/go/cmd/go/testdata/src/complex/nest/vendor/v1/v1.go3
-rw-r--r--libgo/go/cmd/go/testdata/src/complex/nest/vendor/v2/v2.go3
-rw-r--r--libgo/go/cmd/go/testdata/src/complex/nest/vendor/v3/v3.go3
-rw-r--r--libgo/go/cmd/go/testdata/src/complex/vendor/v/v.go3
-rw-r--r--libgo/go/cmd/go/testdata/src/complex/w/w.go3
-rw-r--r--libgo/go/cmd/go/testdata/src/failfast_test.go8
-rw-r--r--libgo/go/cmd/go/testdata/src/hello/hello.go5
-rw-r--r--libgo/go/cmd/go/testdata/src/testnorun/p.go5
-rw-r--r--libgo/go/cmd/go/testdata/src/vetfail/p1/p1.go2
-rw-r--r--libgo/go/cmd/go/testdata/testcover/pkg1/a.go7
-rw-r--r--libgo/go/cmd/go/testdata/testcover/pkg2/a.go7
-rw-r--r--libgo/go/cmd/go/testdata/testcover/pkg2/a_test.go1
-rw-r--r--libgo/go/cmd/go/testdata/testcover/pkg3/a.go7
-rw-r--r--libgo/go/cmd/go/testdata/testcover/pkg3/a_test.go7
-rw-r--r--libgo/go/cmd/go/testdata/testonly2/t.go6
-rw-r--r--libgo/go/cmd/go/testdata/vendormod.txt160
-rw-r--r--libgo/go/cmd/go/vendor_test.go4
-rw-r--r--libgo/go/cmd/internal/buildid/note.go3
-rw-r--r--libgo/go/cmd/internal/objabi/flag.go61
-rw-r--r--libgo/go/cmd/internal/objabi/funcdata.go2
-rw-r--r--libgo/go/cmd/internal/objabi/funcid.go5
-rw-r--r--libgo/go/cmd/internal/objabi/head.go5
-rw-r--r--libgo/go/cmd/internal/objabi/reloctype.go7
-rw-r--r--libgo/go/cmd/internal/objabi/reloctype_string.go8
-rw-r--r--libgo/go/cmd/internal/objabi/symkind.go4
-rw-r--r--libgo/go/cmd/internal/objabi/symkind_string.go8
-rw-r--r--libgo/go/cmd/internal/objabi/util.go26
-rw-r--r--libgo/go/cmd/internal/test2json/test2json.go41
-rw-r--r--libgo/go/cmd/internal/test2json/testdata/bench.json14
-rw-r--r--libgo/go/cmd/internal/test2json/testdata/bench.test12
-rw-r--r--libgo/go/cmd/internal/test2json/testdata/benchfail.json6
-rw-r--r--libgo/go/cmd/internal/test2json/testdata/benchfail.test4
-rw-r--r--libgo/go/cmd/internal/test2json/testdata/benchshort.json7
-rw-r--r--libgo/go/cmd/internal/test2json/testdata/benchshort.test5
-rw-r--r--libgo/go/cmd/internal/test2json/testdata/issue23036.json12
-rw-r--r--libgo/go/cmd/internal/test2json/testdata/issue23036.test9
-rw-r--r--libgo/go/cmd/internal/test2json/testdata/issue23920.json14
-rw-r--r--libgo/go/cmd/internal/test2json/testdata/issue23920.test7
-rw-r--r--libgo/go/cmd/test2json/main.go14
-rw-r--r--libgo/go/cmd/vet/all/main.go6
-rw-r--r--libgo/go/cmd/vet/all/whitelist/386.txt7
-rw-r--r--libgo/go/cmd/vet/all/whitelist/all.txt12
-rw-r--r--libgo/go/cmd/vet/all/whitelist/amd64.txt18
-rw-r--r--libgo/go/cmd/vet/all/whitelist/arm.txt8
-rw-r--r--libgo/go/cmd/vet/all/whitelist/arm64.txt4
-rw-r--r--libgo/go/cmd/vet/all/whitelist/darwin_386.txt4
-rw-r--r--libgo/go/cmd/vet/all/whitelist/darwin_amd64.txt2
-rw-r--r--libgo/go/cmd/vet/all/whitelist/darwin_arm.txt7
-rw-r--r--libgo/go/cmd/vet/all/whitelist/darwin_arm64.txt5
-rw-r--r--libgo/go/cmd/vet/all/whitelist/linux_ppc64x.txt1
-rw-r--r--libgo/go/cmd/vet/all/whitelist/mips.txt2
-rw-r--r--libgo/go/cmd/vet/all/whitelist/mips64x.txt1
-rw-r--r--libgo/go/cmd/vet/all/whitelist/mipsle.txt2
-rw-r--r--libgo/go/cmd/vet/all/whitelist/mipsx.txt7
-rw-r--r--libgo/go/cmd/vet/all/whitelist/nacl_amd64p32.txt9
-rw-r--r--libgo/go/cmd/vet/all/whitelist/ppc64x.txt5
-rw-r--r--libgo/go/cmd/vet/all/whitelist/s390x.txt21
-rw-r--r--libgo/go/cmd/vet/all/whitelist/wasm.txt28
-rw-r--r--libgo/go/cmd/vet/asmdecl.go10
-rw-r--r--libgo/go/cmd/vet/assign.go2
-rw-r--r--libgo/go/cmd/vet/atomic.go6
-rw-r--r--libgo/go/cmd/vet/bool.go29
-rw-r--r--libgo/go/cmd/vet/buildtag.go61
-rw-r--r--libgo/go/cmd/vet/composite.go36
-rw-r--r--libgo/go/cmd/vet/copylock.go22
-rw-r--r--libgo/go/cmd/vet/dead.go2
-rw-r--r--libgo/go/cmd/vet/doc.go27
-rw-r--r--libgo/go/cmd/vet/main.go141
-rw-r--r--libgo/go/cmd/vet/method.go4
-rw-r--r--libgo/go/cmd/vet/print.go496
-rw-r--r--libgo/go/cmd/vet/testdata/asm/asm.go3
-rw-r--r--libgo/go/cmd/vet/testdata/asm/asm3.s14
-rw-r--r--libgo/go/cmd/vet/testdata/atomic.go12
-rw-r--r--libgo/go/cmd/vet/testdata/bool.go20
-rw-r--r--libgo/go/cmd/vet/testdata/buildtag/buildtag.go6
-rw-r--r--libgo/go/cmd/vet/testdata/composite.go17
-rw-r--r--libgo/go/cmd/vet/testdata/deadcode.go9
-rw-r--r--libgo/go/cmd/vet/testdata/print.go176
-rw-r--r--libgo/go/cmd/vet/testdata/shadow.go8
-rw-r--r--libgo/go/cmd/vet/testdata/structtag.go18
-rw-r--r--libgo/go/cmd/vet/types.go36
-rw-r--r--libgo/go/cmd/vet/vet_test.go299
431 files changed, 37461 insertions, 3110 deletions
diff --git a/libgo/go/cmd/buildid/buildid.go b/libgo/go/cmd/buildid/buildid.go
index 8d810ffdd99..1c7b228c987 100644
--- a/libgo/go/cmd/buildid/buildid.go
+++ b/libgo/go/cmd/buildid/buildid.go
@@ -22,6 +22,21 @@ func usage() {
var wflag = flag.Bool("w", false, "write build ID")
+// taken from cmd/go/internal/work/buildid.go
+func hashToString(h [32]byte) string {
+ const b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
+ const chunks = 5
+ var dst [chunks * 4]byte
+ for i := 0; i < chunks; i++ {
+ v := uint32(h[3*i])<<16 | uint32(h[3*i+1])<<8 | uint32(h[3*i+2])
+ dst[4*i+0] = b64[(v>>18)&0x3F]
+ dst[4*i+1] = b64[(v>>12)&0x3F]
+ dst[4*i+2] = b64[(v>>6)&0x3F]
+ dst[4*i+3] = b64[v&0x3F]
+ }
+ return string(dst[:])
+}
+
func main() {
log.SetPrefix("buildid: ")
log.SetFlags(0)
@@ -41,6 +56,8 @@ func main() {
return
}
+ // Keep in sync with src/cmd/go/internal/work/buildid.go:updateBuildID
+
f, err := os.Open(file)
if err != nil {
log.Fatal(err)
@@ -51,14 +68,14 @@ func main() {
}
f.Close()
- tail := id
- if i := strings.LastIndex(id, "."); i >= 0 {
- tail = tail[i+1:]
+ newID := id[:strings.LastIndex(id, "/")] + "/" + hashToString(hash)
+ if len(newID) != len(id) {
+ log.Fatalf("%s: build ID length mismatch %q vs %q", file, id, newID)
}
- if len(tail) != len(hash)*2 {
- log.Fatalf("%s: cannot find %d-byte hash in id %s", file, len(hash), id)
+
+ if len(matches) == 0 {
+ return
}
- newID := id[:len(id)-len(tail)] + fmt.Sprintf("%x", hash)
f, err = os.OpenFile(file, os.O_WRONLY, 0)
if err != nil {
diff --git a/libgo/go/cmd/cgo/ast.go b/libgo/go/cmd/cgo/ast.go
index 58e0ee78cb7..4462136bf4b 100644
--- a/libgo/go/cmd/cgo/ast.go
+++ b/libgo/go/cmd/cgo/ast.go
@@ -95,7 +95,7 @@ func (f *File) ParseGo(name string, src []byte) {
}
}
if !sawC {
- error_(token.NoPos, `cannot find import "C"`)
+ error_(ast1.Package, `cannot find import "C"`)
}
// In ast2, strip the import "C" line.
@@ -356,6 +356,7 @@ func (f *File) walk(x interface{}, context astContext, visit func(*File, interfa
case *ast.BadExpr:
case *ast.Ident:
case *ast.Ellipsis:
+ f.walk(&n.Elt, ctxType, visit)
case *ast.BasicLit:
case *ast.FuncLit:
f.walk(n.Type, ctxType, visit)
diff --git a/libgo/go/cmd/cgo/doc.go b/libgo/go/cmd/cgo/doc.go
index c16b63a313b..157cd94d653 100644
--- a/libgo/go/cmd/cgo/doc.go
+++ b/libgo/go/cmd/cgo/doc.go
@@ -64,6 +64,11 @@ a full argument: to allow -mfoo=bar, use CGO_CFLAGS_ALLOW='-mfoo.*',
not just CGO_CFLAGS_ALLOW='-mfoo'. Similarly named variables control
the allowed CPPFLAGS, CXXFLAGS, FFLAGS, and LDFLAGS.
+Also for security reasons, only a limited set of characters are
+permitted, notably alphanumeric characters and a few symbols, such as
+'.', that will not be interpreted in unexpected ways. Attempts to use
+forbidden characters will get a "malformed #cgo argument" error.
+
When building, the CGO_CFLAGS, CGO_CPPFLAGS, CGO_CXXFLAGS, CGO_FFLAGS and
CGO_LDFLAGS environment variables are added to the flags derived from
these directives. Package-specific flags should be set using the
@@ -99,17 +104,24 @@ compiled with the C compiler. Any .cc, .cpp, or .cxx files will be
compiled with the C++ compiler. Any .f, .F, .for or .f90 files will be
compiled with the fortran compiler. Any .h, .hh, .hpp, or .hxx files will
not be compiled separately, but, if these header files are changed,
-the C and C++ files will be recompiled. The default C and C++
-compilers may be changed by the CC and CXX environment variables,
-respectively; those environment variables may include command line
-options.
+the package (including its non-Go source files) will be recompiled.
+Note that changes to files in other directories do not cause the package
+to be recompiled, so all non-Go source code for the package should be
+stored in the package directory, not in subdirectories.
+The default C and C++ compilers may be changed by the CC and CXX
+environment variables, respectively; those environment variables
+may include command line options.
The cgo tool is enabled by default for native builds on systems where
it is expected to work. It is disabled by default when
cross-compiling. You can control this by setting the CGO_ENABLED
environment variable when running the go tool: set it to 1 to enable
the use of cgo, and to 0 to disable it. The go tool will set the
-build constraint "cgo" if cgo is enabled.
+build constraint "cgo" if cgo is enabled. The special import "C"
+implies the "cgo" build constraint, as though the file also said
+"// +build cgo". Therefore, if cgo is disabled, files that import
+"C" will not be built by the go tool. (For more about build constraints
+see https://golang.org/pkg/go/build/#hdr-Build_Constraints).
When cross-compiling, you must specify a C cross-compiler for cgo to
use. You can do this by setting the generic CC_FOR_TARGET or the
@@ -219,6 +231,26 @@ C compilers are aware of this calling convention and adjust
the call accordingly, but Go cannot. In Go, you must pass
the pointer to the first element explicitly: C.f(&C.x[0]).
+Calling variadic C functions is not supported. It is possible to
+circumvent this by using a C function wrapper. For example:
+
+ package main
+
+ // #include <stdio.h>
+ // #include <stdlib.h>
+ //
+ // static void myprint(char* s) {
+ // printf("%s\n", s);
+ // }
+ import "C"
+ import "unsafe"
+
+ func main() {
+ cs := C.CString("Hello from stdio")
+ C.myprint(cs)
+ C.free(unsafe.Pointer(cs))
+ }
+
A few special functions convert between Go and C types
by making copies of the data. In pseudo-Go definitions:
@@ -348,6 +380,14 @@ and of course there is nothing stopping the C code from doing anything
it likes. However, programs that break these rules are likely to fail
in unexpected and unpredictable ways.
+Note: the current implementation has a bug. While Go code is permitted
+to write nil or a C pointer (but not a Go pointer) to C memory, the
+current implementation may sometimes cause a runtime error if the
+contents of the C memory appear to be a Go pointer. Therefore, avoid
+passing uninitialized C memory to Go code if the Go code is going to
+store pointer values in it. Zero out the memory in C before passing it
+to Go.
+
Special cases
A few special C types which would normally be represented by a pointer
diff --git a/libgo/go/cmd/cgo/gcc.go b/libgo/go/cmd/cgo/gcc.go
index 534fba17eb4..2a2d0080d5e 100644
--- a/libgo/go/cmd/cgo/gcc.go
+++ b/libgo/go/cmd/cgo/gcc.go
@@ -183,9 +183,29 @@ func (p *Package) Translate(f *File) {
cref.Name.C = cname(cref.Name.Go)
}
p.loadDefines(f)
- needType := p.guessKinds(f)
- if len(needType) > 0 {
- p.loadDWARF(f, needType)
+ p.typedefs = map[string]bool{}
+ p.typedefList = nil
+ numTypedefs := -1
+ for len(p.typedefs) > numTypedefs {
+ numTypedefs = len(p.typedefs)
+ // Also ask about any typedefs we've seen so far.
+ for _, a := range p.typedefList {
+ f.Name[a] = &Name{
+ Go: a,
+ C: a,
+ }
+ }
+ needType := p.guessKinds(f)
+ if len(needType) > 0 {
+ p.loadDWARF(f, needType)
+ }
+
+ // In godefs mode we're OK with the typedefs, which
+ // will presumably also be defined in the file, we
+ // don't want to resolve them to their base types.
+ if *godefs {
+ break
+ }
}
if p.rewriteCalls(f) {
// Add `import _cgo_unsafe "unsafe"` after the package statement.
@@ -570,6 +590,7 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
fatalf("malformed __cgo__ name: %s", name)
}
types[i] = t.Type
+ p.recordTypedefs(t.Type)
}
if e.Tag != dwarf.TagCompileUnit {
r.SkipChildren()
@@ -605,7 +626,25 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
}
}
case "fconst":
- if i < len(floats) {
+ if i >= len(floats) {
+ break
+ }
+ switch base(types[i]).(type) {
+ case *dwarf.IntType, *dwarf.UintType:
+ // This has an integer type so it's
+ // not really a floating point
+ // constant. This can happen when the
+ // C compiler complains about using
+ // the value as an integer constant,
+ // but not as a general constant.
+ // Treat this as a variable of the
+ // appropriate type, not a constant,
+ // to get C-style type handling,
+ // avoiding the problem that C permits
+ // uint64(-1) but Go does not.
+ // See issue 26066.
+ n.Kind = "var"
+ default:
n.Const = fmt.Sprintf("%f", floats[i])
}
case "sconst":
@@ -618,6 +657,47 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
}
}
+// recordTypedefs remembers in p.typedefs all the typedefs used in dtypes and its children.
+func (p *Package) recordTypedefs(dtype dwarf.Type) {
+ p.recordTypedefs1(dtype, map[dwarf.Type]bool{})
+}
+func (p *Package) recordTypedefs1(dtype dwarf.Type, visited map[dwarf.Type]bool) {
+ if dtype == nil {
+ return
+ }
+ if visited[dtype] {
+ return
+ }
+ visited[dtype] = true
+ switch dt := dtype.(type) {
+ case *dwarf.TypedefType:
+ if strings.HasPrefix(dt.Name, "__builtin") {
+ // Don't look inside builtin types. There be dragons.
+ return
+ }
+ if !p.typedefs[dt.Name] {
+ p.typedefs[dt.Name] = true
+ p.typedefList = append(p.typedefList, dt.Name)
+ p.recordTypedefs1(dt.Type, visited)
+ }
+ case *dwarf.PtrType:
+ p.recordTypedefs1(dt.Type, visited)
+ case *dwarf.ArrayType:
+ p.recordTypedefs1(dt.Type, visited)
+ case *dwarf.QualType:
+ p.recordTypedefs1(dt.Type, visited)
+ case *dwarf.FuncType:
+ p.recordTypedefs1(dt.ReturnType, visited)
+ for _, a := range dt.ParamType {
+ p.recordTypedefs1(a, visited)
+ }
+ case *dwarf.StructType:
+ for _, f := range dt.Field {
+ p.recordTypedefs1(f.Type, visited)
+ }
+ }
+}
+
// mangleName does name mangling to translate names
// from the original Go source files to the names
// used in the final Go files generated by cgo.
@@ -1373,7 +1453,7 @@ func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int6
if len(data) <= strlen {
fatalf("invalid string literal")
}
- strs[n] = string(data[:strlen])
+ strs[n] = data[:strlen]
}
}
@@ -1754,6 +1834,7 @@ type typeConv struct {
// Map from types to incomplete pointers to those types.
ptrs map[dwarf.Type][]*Type
// Keys of ptrs in insertion order (deterministic worklist)
+ // ptrKeys contains exactly the keys in ptrs.
ptrKeys []dwarf.Type
// Type names X for which there exists an XGetTypeID function with type func() CFTypeID.
@@ -1896,14 +1977,15 @@ func (c *typeConv) FinishType(pos token.Pos) {
for len(c.ptrKeys) > 0 {
dtype := c.ptrKeys[0]
c.ptrKeys = c.ptrKeys[1:]
+ ptrs := c.ptrs[dtype]
+ delete(c.ptrs, dtype)
// Note Type might invalidate c.ptrs[dtype].
t := c.Type(dtype, pos)
- for _, ptr := range c.ptrs[dtype] {
+ for _, ptr := range ptrs {
ptr.Go.(*ast.StarExpr).X = t.Go
ptr.C.Set("%s*", t.C)
}
- c.ptrs[dtype] = nil // retain the map key
}
}
@@ -2180,6 +2262,10 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
s := *sub
s.Go = c.uintptr
sub = &s
+ // Make sure we update any previously computed type.
+ if oldType := typedef[name.Name]; oldType != nil {
+ oldType.Go = sub.Go
+ }
}
t.Go = name
if unionWithPointer[sub.Go] {
@@ -2341,7 +2427,7 @@ func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
}
// ...or the typedef is one in which we expect bad pointers.
// It will be a uintptr instead of *X.
- if c.badPointerTypedef(dt) {
+ if c.baseBadPointerTypedef(dt) {
break
}
@@ -2693,6 +2779,19 @@ func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
return false
}
+// baseBadPointerTypedef reports whether the base of a chain of typedefs is a bad typedef
+// as badPointerTypedef reports.
+func (c *typeConv) baseBadPointerTypedef(dt *dwarf.TypedefType) bool {
+ for {
+ if t, ok := dt.Type.(*dwarf.TypedefType); ok {
+ dt = t
+ continue
+ }
+ break
+ }
+ return c.badPointerTypedef(dt)
+}
+
func (c *typeConv) badCFType(dt *dwarf.TypedefType) bool {
// The real bad types are CFNumberRef and CFDateRef.
// Sometimes non-pointers are stored in these types.
@@ -2781,13 +2880,31 @@ func (c *typeConv) badJNI(dt *dwarf.TypedefType) bool {
}
}
- // Check that the typedef is:
- // struct _jobject;
- // typedef struct _jobject *jobject;
+ // Check that the typedef is either:
+ // 1:
+ // struct _jobject;
+ // typedef struct _jobject *jobject;
+ // 2: (in NDK16 in C++)
+ // class _jobject {};
+ // typedef _jobject* jobject;
+ // 3: (in NDK16 in C)
+ // typedef void* jobject;
if ptr, ok := w.Type.(*dwarf.PtrType); ok {
- if str, ok := ptr.Type.(*dwarf.StructType); ok {
- if str.StructName == "_jobject" && str.Kind == "struct" && len(str.Field) == 0 && str.Incomplete {
- return true
+ switch v := ptr.Type.(type) {
+ case *dwarf.VoidType:
+ return true
+ case *dwarf.StructType:
+ if v.StructName == "_jobject" && len(v.Field) == 0 {
+ switch v.Kind {
+ case "struct":
+ if v.Incomplete {
+ return true
+ }
+ case "class":
+ if !v.Incomplete {
+ return true
+ }
+ }
}
}
}
@@ -2796,7 +2913,7 @@ func (c *typeConv) badJNI(dt *dwarf.TypedefType) bool {
}
// jniTypes maps from JNI types that we want to be uintptrs, to the underlying type to which
-// they are mapped. The base "jobject" maps to the empty string.
+// they are mapped. The base "jobject" maps to the empty string.
var jniTypes = map[string]string{
"jobject": "",
"jclass": "jobject",
diff --git a/libgo/go/cmd/cgo/godefs.go b/libgo/go/cmd/cgo/godefs.go
index 6d638f06442..6720945cddd 100644
--- a/libgo/go/cmd/cgo/godefs.go
+++ b/libgo/go/cmd/cgo/godefs.go
@@ -19,7 +19,7 @@ import (
func (p *Package) godefs(f *File, srcfile string) string {
var buf bytes.Buffer
- fmt.Fprintf(&buf, "// Created by cgo -godefs - DO NOT EDIT\n")
+ fmt.Fprintf(&buf, "// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n")
fmt.Fprintf(&buf, "// %s %s\n", filepath.Base(os.Args[0]), strings.Join(os.Args[1:], " "))
fmt.Fprintf(&buf, "\n")
diff --git a/libgo/go/cmd/cgo/main.go b/libgo/go/cmd/cgo/main.go
index 890a365ceef..1238016418e 100644
--- a/libgo/go/cmd/cgo/main.go
+++ b/libgo/go/cmd/cgo/main.go
@@ -17,6 +17,7 @@ import (
"go/ast"
"go/printer"
"go/token"
+ "io"
"io/ioutil"
"os"
"path/filepath"
@@ -42,9 +43,11 @@ type Package struct {
Name map[string]*Name // accumulated Name from Files
ExpFunc []*ExpFunc // accumulated ExpFunc from Files
Decl []ast.Decl
- GoFiles []string // list of Go files
- GccFiles []string // list of gcc output files
- Preamble string // collected preamble for _cgo_export.h
+ GoFiles []string // list of Go files
+ GccFiles []string // list of gcc output files
+ Preamble string // collected preamble for _cgo_export.h
+ typedefs map[string]bool // type names that appear in the types of the objects we're interested in
+ typedefList []string
}
// A File collects information about a single Go input file.
@@ -278,6 +281,9 @@ func main() {
if arg == "-fsanitize=thread" {
tsanProlog = yesTsanProlog
}
+ if arg == "-fsanitize=memory" {
+ msanProlog = yesMsanProlog
+ }
}
p := newPackage(args[:i])
@@ -297,6 +303,7 @@ func main() {
// concern is other cgo wrappers for the same functions.
// Use the beginning of the md5 of the input to disambiguate.
h := md5.New()
+ io.WriteString(h, *importPath)
fs := make([]*File, len(goFiles))
for i, input := range goFiles {
if *srcDir != "" {
@@ -410,6 +417,14 @@ func (p *Package) Record(f *File) {
for k, v := range f.Name {
if p.Name[k] == nil {
p.Name[k] = v
+ } else if p.incompleteTypedef(p.Name[k].Type) {
+ p.Name[k] = v
+ } else if p.incompleteTypedef(v.Type) {
+ // Nothing to do.
+ } else if _, ok := nameToC[k]; ok {
+ // Names we predefine may appear inconsistent
+ // if some files typedef them and some don't.
+ // Issue 26743.
} else if !reflect.DeepEqual(p.Name[k], v) {
error_(token.NoPos, "inconsistent definitions for C.%s", fixGo(k))
}
@@ -422,3 +437,9 @@ func (p *Package) Record(f *File) {
}
p.Decl = append(p.Decl, f.AST.Decls...)
}
+
+// incompleteTypedef reports whether t appears to be an incomplete
+// typedef definition.
+func (p *Package) incompleteTypedef(t *Type) bool {
+ return t == nil || (t.Size == 0 && t.Align == -1)
+}
diff --git a/libgo/go/cmd/cgo/out.go b/libgo/go/cmd/cgo/out.go
index 92fad5d31a7..10d4b74b6ee 100644
--- a/libgo/go/cmd/cgo/out.go
+++ b/libgo/go/cmd/cgo/out.go
@@ -17,6 +17,7 @@ import (
"io"
"os"
"path/filepath"
+ "regexp"
"sort"
"strings"
)
@@ -78,7 +79,7 @@ func (p *Package) writeDefs() {
// Write second Go output: definitions of _C_xxx.
// In a separate file so that the import of "unsafe" does not
// pollute the original file.
- fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n\n")
+ fmt.Fprintf(fgo2, "// Code generated by cmd/cgo; DO NOT EDIT.\n\n")
fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName)
fmt.Fprintf(fgo2, "import \"unsafe\"\n\n")
if !*gccgo && *importRuntimeCgo {
@@ -277,10 +278,7 @@ func dynimport(obj string) {
}
}
}
- sym, err := f.ImportedSymbols()
- if err != nil {
- fatalf("cannot load imported symbols from ELF file %s: %v", obj, err)
- }
+ sym, _ := f.ImportedSymbols()
for _, s := range sym {
targ := s.Name
if s.Version != "" {
@@ -288,10 +286,7 @@ func dynimport(obj string) {
}
fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library)
}
- lib, err := f.ImportedLibraries()
- if err != nil {
- fatalf("cannot load imported libraries from ELF file %s: %v", obj, err)
- }
+ lib, _ := f.ImportedLibraries()
for _, l := range lib {
fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l)
}
@@ -299,20 +294,14 @@ func dynimport(obj string) {
}
if f, err := macho.Open(obj); err == nil {
- sym, err := f.ImportedSymbols()
- if err != nil {
- fatalf("cannot load imported symbols from Mach-O file %s: %v", obj, err)
- }
+ sym, _ := f.ImportedSymbols()
for _, s := range sym {
if len(s) > 0 && s[0] == '_' {
s = s[1:]
}
fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s, s, "")
}
- lib, err := f.ImportedLibraries()
- if err != nil {
- fatalf("cannot load imported libraries from Mach-O file %s: %v", obj, err)
- }
+ lib, _ := f.ImportedLibraries()
for _, l := range lib {
fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l)
}
@@ -320,10 +309,7 @@ func dynimport(obj string) {
}
if f, err := pe.Open(obj); err == nil {
- sym, err := f.ImportedSymbols()
- if err != nil {
- fatalf("cannot load imported symbols from PE file %s: %v", obj, err)
- }
+ sym, _ := f.ImportedSymbols()
for _, s := range sym {
ss := strings.Split(s, ":")
name := strings.Split(ss[0], "@")[0]
@@ -559,8 +545,8 @@ func (p *Package) writeOutput(f *File, srcfile string) {
p.GccFiles = append(p.GccFiles, base+".cgo2.c")
// Write Go output: Go input with rewrites of C.xxx to _C_xxx.
- fmt.Fprintf(fgo1, "// Created by cgo - DO NOT EDIT\n\n")
- fmt.Fprintf(fgo1, "//line %s:1\n", srcfile)
+ fmt.Fprintf(fgo1, "// Code generated by cmd/cgo; DO NOT EDIT.\n\n")
+ fmt.Fprintf(fgo1, "//line %s:1:1\n", srcfile)
fgo1.Write(f.Edit.Bytes())
// While we process the vars and funcs, also write gcc output.
@@ -569,6 +555,7 @@ func (p *Package) writeOutput(f *File, srcfile string) {
fmt.Fprintf(fgcc, "%s\n", f.Preamble)
fmt.Fprintf(fgcc, "%s\n", gccProlog)
fmt.Fprintf(fgcc, "%s\n", tsanProlog)
+ fmt.Fprintf(fgcc, "%s\n", msanProlog)
for _, key := range nameKeys(f.Name) {
n := f.Name[key]
@@ -632,14 +619,14 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
// We're trying to write a gcc struct that matches gc's layout.
// Use packed attribute to force no padding in this struct in case
// gcc has different packing requirements.
- fmt.Fprintf(fgcc, "\t%s %v *a = v;\n", ctype, p.packedAttribute())
+ fmt.Fprintf(fgcc, "\t%s %v *_cgo_a = v;\n", ctype, p.packedAttribute())
if n.FuncType.Result != nil {
// Save the stack top for use below.
- fmt.Fprintf(fgcc, "\tchar *stktop = _cgo_topofstack();\n")
+ fmt.Fprintf(fgcc, "\tchar *_cgo_stktop = _cgo_topofstack();\n")
}
tr := n.FuncType.Result
if tr != nil {
- fmt.Fprintf(fgcc, "\t__typeof__(a->r) r;\n")
+ fmt.Fprintf(fgcc, "\t__typeof__(_cgo_a->r) _cgo_r;\n")
}
fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
if n.AddError {
@@ -647,9 +634,9 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
}
fmt.Fprintf(fgcc, "\t")
if tr != nil {
- fmt.Fprintf(fgcc, "r = ")
+ fmt.Fprintf(fgcc, "_cgo_r = ")
if c := tr.C.String(); c[len(c)-1] == '*' {
- fmt.Fprint(fgcc, "(__typeof__(a->r)) ")
+ fmt.Fprint(fgcc, "(__typeof__(_cgo_a->r)) ")
}
}
if n.Kind == "macro" {
@@ -660,7 +647,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
if i > 0 {
fmt.Fprintf(fgcc, ", ")
}
- fmt.Fprintf(fgcc, "a->p%d", i)
+ fmt.Fprintf(fgcc, "_cgo_a->p%d", i)
}
fmt.Fprintf(fgcc, ");\n")
}
@@ -671,9 +658,19 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
if n.FuncType.Result != nil {
// The cgo call may have caused a stack copy (via a callback).
// Adjust the return value pointer appropriately.
- fmt.Fprintf(fgcc, "\ta = (void*)((char*)a + (_cgo_topofstack() - stktop));\n")
+ fmt.Fprintf(fgcc, "\t_cgo_a = (void*)((char*)_cgo_a + (_cgo_topofstack() - _cgo_stktop));\n")
// Save the return value.
- fmt.Fprintf(fgcc, "\ta->r = r;\n")
+ fmt.Fprintf(fgcc, "\t_cgo_a->r = _cgo_r;\n")
+ // The return value is on the Go stack. If we are using msan,
+ // and if the C value is partially or completely uninitialized,
+ // the assignment will mark the Go stack as uninitialized.
+ // The Go compiler does not update msan for changes to the
+ // stack. It is possible that the stack will remain
+ // uninitialized, and then later be used in a way that is
+ // visible to msan, possibly leading to a false positive.
+ // Mark the stack space as written, to avoid this problem.
+ // See issue 26209.
+ fmt.Fprintf(fgcc, "\t_cgo_msan_write(&_cgo_a->r, sizeof(_cgo_a->r));\n")
}
if n.AddError {
fmt.Fprintf(fgcc, "\treturn _cgo_errno;\n")
@@ -708,12 +705,12 @@ func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) {
fmt.Fprintf(fgcc, ")\n")
fmt.Fprintf(fgcc, "{\n")
if t := n.FuncType.Result; t != nil {
- fmt.Fprintf(fgcc, "\t%s r;\n", t.C.String())
+ fmt.Fprintf(fgcc, "\t%s _cgo_r;\n", t.C.String())
}
fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
fmt.Fprintf(fgcc, "\t")
if t := n.FuncType.Result; t != nil {
- fmt.Fprintf(fgcc, "r = ")
+ fmt.Fprintf(fgcc, "_cgo_r = ")
// Cast to void* to avoid warnings due to omitted qualifiers.
if c := t.C.String(); c[len(c)-1] == '*' {
fmt.Fprintf(fgcc, "(void*)")
@@ -739,7 +736,7 @@ func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) {
if c := t.C.String(); c[len(c)-1] == '*' {
fmt.Fprintf(fgcc, "(void*)")
}
- fmt.Fprintf(fgcc, "r;\n")
+ fmt.Fprintf(fgcc, "_cgo_r;\n")
}
fmt.Fprintf(fgcc, "}\n")
fmt.Fprintf(fgcc, "\n")
@@ -748,7 +745,7 @@ func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) {
// packedAttribute returns host compiler struct attribute that will be
// used to match gc's struct layout. For example, on 386 Windows,
// gcc wants to 8-align int64s, but gc does not.
-// Use __gcc_struct__ to work around http://gcc.gnu.org/PR52991 on x86,
+// Use __gcc_struct__ to work around https://gcc.gnu.org/PR52991 on x86,
// and https://golang.org/issue/5603.
func (p *Package) packedAttribute() string {
s := "__attribute__((__packed__"
@@ -763,7 +760,7 @@ func (p *Package) packedAttribute() string {
func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
p.writeExportHeader(fgcch)
- fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
+ fmt.Fprintf(fgcc, "/* Code generated by cmd/cgo; DO NOT EDIT. */\n\n")
fmt.Fprintf(fgcc, "#include <stdlib.h>\n")
fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n\n")
@@ -772,6 +769,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprintf(fgcc, "extern void _cgo_release_context(__SIZE_TYPE__);\n\n")
fmt.Fprintf(fgcc, "extern char* _cgo_topofstack(void);")
fmt.Fprintf(fgcc, "%s\n", tsanProlog)
+ fmt.Fprintf(fgcc, "%s\n", msanProlog)
for _, exp := range p.ExpFunc {
fn := exp.Func
@@ -1004,11 +1002,12 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
p.writeExportHeader(fgcch)
- fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
+ fmt.Fprintf(fgcc, "/* Code generated by cmd/cgo; DO NOT EDIT. */\n\n")
fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n")
fmt.Fprintf(fgcc, "%s\n", gccgoExportFileProlog)
fmt.Fprintf(fgcc, "%s\n", tsanProlog)
+ fmt.Fprintf(fgcc, "%s\n", msanProlog)
for _, exp := range p.ExpFunc {
fn := exp.Func
@@ -1170,7 +1169,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
// writeExportHeader writes out the start of the _cgo_export.h file.
func (p *Package) writeExportHeader(fgcch io.Writer) {
- fmt.Fprintf(fgcch, "/* Created by \"go tool cgo\" - DO NOT EDIT. */\n\n")
+ fmt.Fprintf(fgcch, "/* Code generated by cmd/cgo; DO NOT EDIT. */\n\n")
pkg := *importPath
if pkg == "" {
pkg = p.PackagePath
@@ -1178,8 +1177,15 @@ func (p *Package) writeExportHeader(fgcch io.Writer) {
fmt.Fprintf(fgcch, "/* package %s */\n\n", pkg)
fmt.Fprintf(fgcch, "%s\n", builtinExportProlog)
+ // Remove absolute paths from #line comments in the preamble.
+ // They aren't useful for people using the header file,
+ // and they mean that the header files change based on the
+ // exact location of GOPATH.
+ re := regexp.MustCompile(`(?m)^(#line\s+[0-9]+\s+")[^"]*[/\\]([^"]*")`)
+ preamble := re.ReplaceAllString(p.Preamble, "$1$2")
+
fmt.Fprintf(fgcch, "/* Start of preamble from import \"C\" comments. */\n\n")
- fmt.Fprintf(fgcch, "%s\n", p.Preamble)
+ fmt.Fprintf(fgcch, "%s\n", preamble)
fmt.Fprintf(fgcch, "\n/* End of preamble from import \"C\" comments. */\n\n")
fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
@@ -1414,6 +1420,25 @@ static void _cgo_tsan_release() {
// Set to yesTsanProlog if we see -fsanitize=thread in the flags for gcc.
var tsanProlog = noTsanProlog
+// noMsanProlog is a prologue defining an MSAN function in C.
+// This is used when not compiling with -fsanitize=memory.
+const noMsanProlog = `
+#define _cgo_msan_write(addr, sz)
+`
+
+// yesMsanProlog is a prologue defining an MSAN function in C.
+// This is used when compiling with -fsanitize=memory.
+// See the comment above where _cgo_msan_write is called.
+const yesMsanProlog = `
+extern void __msan_unpoison(const volatile void *, size_t);
+
+#define _cgo_msan_write(addr, sz) __msan_unpoison((addr), (sz))
+`
+
+// msanProlog is set to yesMsanProlog if we see -fsanitize=memory in the flags
+// for the C compiler.
+var msanProlog = noMsanProlog
+
const builtinProlog = `
#line 1 "cgo-builtin-prolog"
#include <stddef.h> /* for ptrdiff_t and size_t below */
diff --git a/libgo/go/cmd/cgo/util.go b/libgo/go/cmd/cgo/util.go
index 4f5c48864e9..921306b7aab 100644
--- a/libgo/go/cmd/cgo/util.go
+++ b/libgo/go/cmd/cgo/util.go
@@ -59,6 +59,8 @@ func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
var bout, berr bytes.Buffer
p.Stdout = &bout
p.Stderr = &berr
+ // Disable escape codes in clang error messages.
+ p.Env = append(os.Environ(), "TERM=dumb")
err := p.Run()
if _, ok := err.(*exec.ExitError); err != nil && !ok {
fatalf("%s", err)
@@ -97,6 +99,8 @@ func error_(pos token.Pos, msg string, args ...interface{}) {
nerrors++
if pos.IsValid() {
fmt.Fprintf(os.Stderr, "%s: ", fset.Position(pos).String())
+ } else {
+ fmt.Fprintf(os.Stderr, "cgo: ")
}
fmt.Fprintf(os.Stderr, msg, args...)
fmt.Fprintf(os.Stderr, "\n")
diff --git a/libgo/go/cmd/go/alldocs.go b/libgo/go/cmd/go/alldocs.go
index aadf97c064f..ebbd154f3e6 100644
--- a/libgo/go/cmd/go/alldocs.go
+++ b/libgo/go/cmd/go/alldocs.go
@@ -2,50 +2,66 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// DO NOT EDIT THIS FILE. GENERATED BY mkalldocs.sh.
+// Code generated by mkalldocs.sh; DO NOT EDIT.
// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.
// Go is a tool for managing Go source code.
//
// Usage:
//
-// go command [arguments]
+// go <command> [arguments]
//
// The commands are:
//
+// bug start a bug report
// build compile packages and dependencies
// clean remove object files and cached files
// doc show documentation for package or symbol
// env print Go environment information
-// bug start a bug report
// fix update packages to use new APIs
// fmt gofmt (reformat) package sources
// generate generate Go files by processing source
// get download and install packages and dependencies
// install compile and install packages and dependencies
-// list list packages
+// list list packages or modules
+// mod module maintenance
// run compile and run Go program
// test test packages
// tool run specified go tool
// version print Go version
// vet report likely mistakes in packages
//
-// Use "go help [command]" for more information about a command.
+// Use "go help <command>" for more information about a command.
//
// Additional help topics:
//
-// c calling between Go and C
// buildmode build modes
+// c calling between Go and C
// cache build and test caching
+// environment environment variables
// filetype file types
+// go.mod the go.mod file
// gopath GOPATH environment variable
-// environment environment variables
+// gopath-get legacy GOPATH go get
+// goproxy module proxy protocol
// importpath import path syntax
-// packages package lists
+// modules modules, module versions, and more
+// module-get module-aware go get
+// packages package lists and patterns
// testflag testing flags
// testfunc testing functions
//
-// Use "go help [topic]" for more information about that topic.
+// Use "go help <topic>" for more information about that topic.
+//
+//
+// Start a bug report
+//
+// Usage:
+//
+// go bug
+//
+// Bug opens the default browser and starts a new bug report.
+// The report includes useful system information.
//
//
// Compile packages and dependencies
@@ -95,7 +111,7 @@
// Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.
// -msan
// enable interoperation with memory sanitizer.
-// Supported only on linux/amd64,
+// Supported only on linux/amd64, linux/arm64
// and only with Clang/LLVM as the host C compiler.
// -v
// print the names of packages as they are compiled.
@@ -127,6 +143,9 @@
// -linkshared
// link against shared libraries previously created with
// -buildmode=shared.
+// -mod mode
+// module download mode to use: readonly, release, or vendor.
+// See 'go help modules' for more.
// -pkgdir dir
// install and load all packages from dir instead of the usual locations.
// For example, when building with a non-standard configuration,
@@ -175,7 +194,7 @@
//
// Usage:
//
-// go clean [-i] [-r] [-n] [-x] [-cache] [-testcache] [build flags] [packages]
+// go clean [clean flags] [build flags] [packages]
//
// Clean removes object files from package source directories.
// The go command builds most objects in a temporary directory,
@@ -218,6 +237,10 @@
// The -testcache flag causes clean to expire all test results in the
// go build cache.
//
+// The -modcache flag causes clean to remove the entire module
+// download cache, including unpacked source code of versioned
+// dependencies.
+//
// For more about build flags, see 'go help build'.
//
// For more about specifying packages, see 'go help packages'.
@@ -349,16 +372,6 @@
// For more about environment variables, see 'go help environment'.
//
//
-// Start a bug report
-//
-// Usage:
-//
-// go bug
-//
-// Bug opens the default browser and starts a new bug report.
-// The report includes useful system information.
-//
-//
// Update packages to use new APIs
//
// Usage:
@@ -419,6 +432,12 @@
// (gofmt), a fully qualified path (/usr/you/bin/mytool), or a
// command alias, described below.
//
+// To convey to humans and machine tools that code is generated,
+// generated source should have a line early in the file that
+// matches the following regular expression (in Go syntax):
+//
+// ^// Code generated .* DO NOT EDIT\.$
+//
// Note that go generate does not parse the file, so lines that look
// like directives in comments or multiline strings will be treated
// as directives.
@@ -506,7 +525,7 @@
//
// Usage:
//
-// go get [-d] [-f] [-fix] [-insecure] [-t] [-u] [-v] [build flags] [packages]
+// go get [-d] [-f] [-t] [-u] [-v] [-fix] [-insecure] [build flags] [packages]
//
// Get downloads the packages named by the import paths, along with their
// dependencies. It then installs the named packages, like 'go install'.
@@ -556,6 +575,12 @@
// For more about how 'go get' finds source code to
// download, see 'go help importpath'.
//
+// This text describes the behavior of get when using GOPATH
+// to manage source code and dependencies.
+// If instead the go command is running in module-aware mode,
+// the details of get's flags and effects change, as does 'go help get'.
+// See 'go help modules' and 'go help module-get'.
+//
// See also: go build, go install, go clean.
//
//
@@ -575,13 +600,16 @@
// See also: go build, go get, go clean.
//
//
-// List packages
+// List packages or modules
//
// Usage:
//
-// go list [-e] [-f format] [-json] [build flags] [packages]
+// go list [-f format] [-json] [-m] [list flags] [build flags] [packages]
//
-// List lists the packages named by the import paths, one per line.
+// List lists the named packages, one per line.
+// The most commonly-used flags are -f and -json, which control the form
+// of the output printed for each package. Other list flags, documented below,
+// control more specific details.
//
// The default output shows the package import path:
//
@@ -591,40 +619,46 @@
// golang.org/x/net/html
//
// The -f flag specifies an alternate format for the list, using the
-// syntax of package template. The default output is equivalent to -f
-// '{{.ImportPath}}'. The struct being passed to the template is:
+// syntax of package template. The default output is equivalent
+// to -f '{{.ImportPath}}'. The struct being passed to the template is:
//
// type Package struct {
-// Dir string // directory containing package sources
-// ImportPath string // import path of package in dir
-// ImportComment string // path in import comment on package statement
-// Name string // package name
-// Doc string // package documentation string
-// Target string // install path
-// Shlib string // the shared library that contains this package (only set when -linkshared)
-// Goroot bool // is this package in the Go root?
-// Standard bool // is this package part of the standard Go library?
-// Stale bool // would 'go install' do anything for this package?
-// StaleReason string // explanation for Stale==true
-// Root string // Go root or Go path dir containing this package
-// ConflictDir string // this directory shadows Dir in $GOPATH
-// BinaryOnly bool // binary-only package: cannot be recompiled from sources
+// Dir string // directory containing package sources
+// ImportPath string // import path of package in dir
+// ImportComment string // path in import comment on package statement
+// Name string // package name
+// Doc string // package documentation string
+// Target string // install path
+// Shlib string // the shared library that contains this package (only set when -linkshared)
+// Goroot bool // is this package in the Go root?
+// Standard bool // is this package part of the standard Go library?
+// Stale bool // would 'go install' do anything for this package?
+// StaleReason string // explanation for Stale==true
+// Root string // Go root or Go path dir containing this package
+// ConflictDir string // this directory shadows Dir in $GOPATH
+// BinaryOnly bool // binary-only package: cannot be recompiled from sources
+// ForTest string // package is only for use in named test
+// Export string // file containing export data (when using -export)
+// Module *Module // info about package's containing module, if any (can be nil)
+// Match []string // command-line patterns matching this package
+// DepOnly bool // package is only a dependency, not explicitly listed
//
// // Source files
-// GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
-// CgoFiles []string // .go sources files that import "C"
-// IgnoredGoFiles []string // .go sources ignored due to build constraints
-// CFiles []string // .c source files
-// CXXFiles []string // .cc, .cxx and .cpp source files
-// MFiles []string // .m source files
-// HFiles []string // .h, .hh, .hpp and .hxx source files
-// FFiles []string // .f, .F, .for and .f90 Fortran source files
-// SFiles []string // .s source files
-// SwigFiles []string // .swig files
-// SwigCXXFiles []string // .swigcxx files
-// SysoFiles []string // .syso object files to add to archive
-// TestGoFiles []string // _test.go files in package
-// XTestGoFiles []string // _test.go files outside package
+// GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
+// CgoFiles []string // .go source files that import "C"
+// CompiledGoFiles []string // .go files presented to compiler (when using -compiled)
+// IgnoredGoFiles []string // .go source files ignored due to build constraints
+// CFiles []string // .c source files
+// CXXFiles []string // .cc, .cxx and .cpp source files
+// MFiles []string // .m source files
+// HFiles []string // .h, .hh, .hpp and .hxx source files
+// FFiles []string // .f, .F, .for and .f90 Fortran source files
+// SFiles []string // .s source files
+// SwigFiles []string // .swig files
+// SwigCXXFiles []string // .swigcxx files
+// SysoFiles []string // .syso object files to add to archive
+// TestGoFiles []string // _test.go files in package
+// XTestGoFiles []string // _test.go files outside package
//
// // Cgo directives
// CgoCFLAGS []string // cgo: flags for C compiler
@@ -635,10 +669,11 @@
// CgoPkgConfig []string // cgo: pkg-config names
//
// // Dependency information
-// Imports []string // import paths used by this package
-// Deps []string // all (recursively) imported dependencies
-// TestImports []string // imports from TestGoFiles
-// XTestImports []string // imports from XTestGoFiles
+// Imports []string // import paths used by this package
+// ImportMap map[string]string // map from source import to ImportPath (identity entries omitted)
+// Deps []string // all (recursively) imported dependencies
+// TestImports []string // imports from TestGoFiles
+// XTestImports []string // imports from XTestGoFiles
//
// // Error information
// Incomplete bool // this package or a dependency has an error
@@ -650,7 +685,7 @@
// path to the vendor directory (for example, "d/vendor/p" instead of "p"),
// so that the ImportPath uniquely identifies a given copy of a package.
// The Imports, Deps, TestImports, and XTestImports lists also contain these
-// expanded imports paths. See golang.org/s/go15vendor for more about vendoring.
+// expanded import paths. See golang.org/s/go15vendor for more about vendoring.
//
// The error information, if any, is
//
@@ -660,22 +695,25 @@
// Err string // the error itself
// }
//
+// The module information is a Module struct, defined in the discussion
+// of list -m below.
+//
// The template function "join" calls strings.Join.
//
// The template function "context" returns the build context, defined as:
//
-// type Context struct {
-// GOARCH string // target architecture
-// GOOS string // target operating system
-// GOROOT string // Go root
-// GOPATH string // Go path
-// CgoEnabled bool // whether cgo can be used
-// UseAllFiles bool // use files regardless of +build lines, file names
-// Compiler string // compiler to assume when computing target paths
-// BuildTags []string // build constraints to match in +build lines
-// ReleaseTags []string // releases the current release is compatible with
-// InstallSuffix string // suffix to use in the name of the install dir
-// }
+// type Context struct {
+// GOARCH string // target architecture
+// GOOS string // target operating system
+// GOROOT string // Go root
+// GOPATH string // Go path
+// CgoEnabled bool // whether cgo can be used
+// UseAllFiles bool // use files regardless of +build lines, file names
+// Compiler string // compiler to assume when computing target paths
+// BuildTags []string // build constraints to match in +build lines
+// ReleaseTags []string // releases the current release is compatible with
+// InstallSuffix string // suffix to use in the name of the install dir
+// }
//
// For more information about the meaning of these fields see the documentation
// for the go/build package's Context type.
@@ -683,6 +721,18 @@
// The -json flag causes the package data to be printed in JSON format
// instead of using the template format.
//
+// The -compiled flag causes list to set CompiledGoFiles to the Go source
+// files presented to the compiler. Typically this means that it repeats
+// the files listed in GoFiles and then also adds the Go code generated
+// by processing CgoFiles and SwigFiles. The Imports list contains the
+// union of all imports from both GoFiles and CompiledGoFiles.
+//
+// The -deps flag causes list to iterate over not just the named packages
+// but also all their dependencies. It visits them in a depth-first post-order
+// traversal, so that a package is listed only after all its dependencies.
+// Packages not explicitly listed on the command line will have the DepOnly
+// field set to true.
+//
// The -e flag changes the handling of erroneous packages, those that
// cannot be found or are malformed. By default, the list command
// prints an error to standard error for each erroneous package and
@@ -693,19 +743,380 @@
// a non-nil Error field; other information may or may not be missing
// (zeroed).
//
+// The -export flag causes list to set the Export field to the name of a
+// file containing up-to-date export information for the given package.
+//
+// The -find flag causes list to identify the named packages but not
+// resolve their dependencies: the Imports and Deps lists will be empty.
+//
+// The -test flag causes list to report not only the named packages
+// but also their test binaries (for packages with tests), to convey to
+// source code analysis tools exactly how test binaries are constructed.
+// The reported import path for a test binary is the import path of
+// the package followed by a ".test" suffix, as in "math/rand.test".
+// When building a test, it is sometimes necessary to rebuild certain
+// dependencies specially for that test (most commonly the tested
+// package itself). The reported import path of a package recompiled
+// for a particular test binary is followed by a space and the name of
+// the test binary in brackets, as in "math/rand [math/rand.test]"
+// or "regexp [sort.test]". The ForTest field is also set to the name
+// of the package being tested ("math/rand" or "sort" in the previous
+// examples).
+//
+// The Dir, Target, Shlib, Root, ConflictDir, and Export file paths
+// are all absolute paths.
+//
+// By default, the lists GoFiles, CgoFiles, and so on hold names of files in Dir
+// (that is, paths relative to Dir, not absolute paths).
+// The generated files added when using the -compiled and -test flags
+// are absolute paths referring to cached copies of generated Go source files.
+// Although they are Go source files, the paths may not end in ".go".
+//
+// The -m flag causes list to list modules instead of packages.
+//
+// When listing modules, the -f flag still specifies a format template
+// applied to a Go struct, but now a Module struct:
+//
+// type Module struct {
+// Path string // module path
+// Version string // module version
+// Versions []string // available module versions (with -versions)
+// Replace *Module // replaced by this module
+// Time *time.Time // time version was created
+// Update *Module // available update, if any (with -u)
+// Main bool // is this the main module?
+// Indirect bool // is this module only an indirect dependency of main module?
+// Dir string // directory holding files for this module, if any
+// GoMod string // path to go.mod file for this module, if any
+// Error *ModuleError // error loading module
+// }
+//
+// type ModuleError struct {
+// Err string // the error itself
+// }
+//
+// The default output is to print the module path and then
+// information about the version and replacement if any.
+// For example, 'go list -m all' might print:
+//
+// my/main/module
+// golang.org/x/text v0.3.0 => /tmp/text
+// rsc.io/pdf v0.1.1
+//
+// The Module struct has a String method that formats this
+// line of output, so that the default format is equivalent
+// to -f '{{.String}}'.
+//
+// Note that when a module has been replaced, its Replace field
+// describes the replacement module, and its Dir field is set to
+// the replacement's source code, if present. (That is, if Replace
+// is non-nil, then Dir is set to Replace.Dir, with no access to
+// the replaced source code.)
+//
+// The -u flag adds information about available upgrades.
+// When the latest version of a given module is newer than
+// the current one, list -u sets the Module's Update field
+// to information about the newer module.
+// The Module's String method indicates an available upgrade by
+// formatting the newer version in brackets after the current version.
+// For example, 'go list -m -u all' might print:
+//
+// my/main/module
+// golang.org/x/text v0.3.0 [v0.4.0] => /tmp/text
+// rsc.io/pdf v0.1.1 [v0.1.2]
+//
+// (For tools, 'go list -m -u -json all' may be more convenient to parse.)
+//
+// The -versions flag causes list to set the Module's Versions field
+// to a list of all known versions of that module, ordered according
+// to semantic versioning, earliest to latest. The flag also changes
+// the default output format to display the module path followed by the
+// space-separated version list.
+//
+// The arguments to list -m are interpreted as a list of modules, not packages.
+// The main module is the module containing the current directory.
+// The active modules are the main module and its dependencies.
+// With no arguments, list -m shows the main module.
+// With arguments, list -m shows the modules specified by the arguments.
+// Any of the active modules can be specified by its module path.
+// The special pattern "all" specifies all the active modules, first the main
+// module and then dependencies sorted by module path.
+// A pattern containing "..." specifies the active modules whose
+// module paths match the pattern.
+// A query of the form path@version specifies the result of that query,
+// which is not limited to active modules.
+// See 'go help modules' for more about module queries.
+//
+// The template function "module" takes a single string argument
+// that must be a module path or query and returns the specified
+// module as a Module struct. If an error occurs, the result will
+// be a Module struct with a non-nil Error field.
+//
// For more about build flags, see 'go help build'.
//
// For more about specifying packages, see 'go help packages'.
//
+// For more about modules, see 'go help modules'.
+//
+//
+// Module maintenance
+//
+// Go mod provides access to operations on modules.
+//
+// Note that support for modules is built into all the go commands,
+// not just 'go mod'. For example, day-to-day adding, removing, upgrading,
+// and downgrading of dependencies should be done using 'go get'.
+// See 'go help modules' for an overview of module functionality.
+//
+// Usage:
+//
+// go mod <command> [arguments]
+//
+// The commands are:
+//
+// download download modules to local cache
+// edit edit go.mod from tools or scripts
+// graph print module requirement graph
+// init initialize new module in current directory
+// tidy add missing and remove unused modules
+// vendor make vendored copy of dependencies
+// verify verify dependencies have expected content
+// why explain why packages or modules are needed
+//
+// Use "go help mod <command>" for more information about a command.
+//
+// Download modules to local cache
+//
+// Usage:
+//
+// go mod download [-dir] [-json] [modules]
+//
+// Download downloads the named modules, which can be module patterns selecting
+// dependencies of the main module or module queries of the form path@version.
+// With no arguments, download applies to all dependencies of the main module.
+//
+// The go command will automatically download modules as needed during ordinary
+// execution. The "go mod download" command is useful mainly for pre-filling
+// the local cache or to compute the answers for a Go module proxy.
+//
+// By default, download reports errors to standard error but is otherwise silent.
+// The -json flag causes download to print a sequence of JSON objects
+// to standard output, describing each downloaded module (or failure),
+// corresponding to this Go struct:
+//
+// type Module struct {
+// Path string // module path
+// Version string // module version
+// Error string // error loading module
+// Info string // absolute path to cached .info file
+// GoMod string // absolute path to cached .mod file
+// Zip string // absolute path to cached .zip file
+// Dir string // absolute path to cached source root directory
+// Sum string // checksum for path, version (as in go.sum)
+// GoModSum string // checksum for go.mod (as in go.sum)
+// }
+//
+// See 'go help modules' for more about module queries.
+//
+//
+// Edit go.mod from tools or scripts
+//
+// Usage:
+//
+// go mod edit [editing flags] [go.mod]
+//
+// Edit provides a command-line interface for editing go.mod,
+// for use primarily by tools or scripts. It reads only go.mod;
+// it does not look up information about the modules involved.
+// By default, edit reads and writes the go.mod file of the main module,
+// but a different target file can be specified after the editing flags.
+//
+// The editing flags specify a sequence of editing operations.
+//
+// The -fmt flag reformats the go.mod file without making other changes.
+// This reformatting is also implied by any other modifications that use or
+// rewrite the go.mod file. The only time this flag is needed is if no other
+// flags are specified, as in 'go mod edit -fmt'.
+//
+// The -module flag changes the module's path (the go.mod file's module line).
+//
+// The -require=path@version and -droprequire=path flags
+// add and drop a requirement on the given module path and version.
+// Note that -require overrides any existing requirements on path.
+// These flags are mainly for tools that understand the module graph.
+// Users should prefer 'go get path@version' or 'go get path@none',
+// which make other go.mod adjustments as needed to satisfy
+// constraints imposed by other modules.
+//
+// The -exclude=path@version and -dropexclude=path@version flags
+// add and drop an exclusion for the given module path and version.
+// Note that -exclude=path@version is a no-op if that exclusion already exists.
+//
+// The -replace=old[@v]=new[@v] and -dropreplace=old[@v] flags
+// add and drop a replacement of the given module path and version pair.
+// If the @v in old@v is omitted, the replacement applies to all versions
+// with the old module path. If the @v in new@v is omitted, the new path
+// should be a local module root directory, not a module path.
+// Note that -replace overrides any existing replacements for old[@v].
+//
+// The -require, -droprequire, -exclude, -dropexclude, -replace,
+// and -dropreplace editing flags may be repeated, and the changes
+// are applied in the order given.
+//
+// The -print flag prints the final go.mod in its text format instead of
+// writing it back to go.mod.
+//
+// The -json flag prints the final go.mod file in JSON format instead of
+// writing it back to go.mod. The JSON output corresponds to these Go types:
+//
+// type Module struct {
+// Path string
+// Version string
+// }
+//
+// type GoMod struct {
+// Module Module
+// Require []Require
+// Exclude []Module
+// Replace []Replace
+// }
+//
+// type Require struct {
+// Path string
+// Version string
+// Indirect bool
+// }
+//
+// type Replace struct {
+// Old Module
+// New Module
+// }
+//
+// Note that this only describes the go.mod file itself, not other modules
+// referred to indirectly. For the full set of modules available to a build,
+// use 'go list -m -json all'.
+//
+// For example, a tool can obtain the go.mod as a data structure by
+// parsing the output of 'go mod edit -json' and can then make changes
+// by invoking 'go mod edit' with -require, -exclude, and so on.
+//
+//
+// Print module requirement graph
+//
+// Usage:
+//
+// go mod graph
+//
+// Graph prints the module requirement graph (with replacements applied)
+// in text form. Each line in the output has two space-separated fields: a module
+// and one of its requirements. Each module is identified as a string of the form
+// path@version, except for the main module, which has no @version suffix.
+//
+//
+// Initialize new module in current directory
+//
+// Usage:
+//
+// go mod init [module]
+//
+// Init initializes and writes a new go.mod to the current directory,
+// in effect creating a new module rooted at the current directory.
+// The file go.mod must not already exist.
+// If possible, init will guess the module path from import comments
+// (see 'go help importpath') or from version control configuration.
+// To override this guess, supply the module path as an argument.
+//
+//
+// Add missing and remove unused modules
+//
+// Usage:
+//
+// go mod tidy [-v]
+//
+// Tidy makes sure go.mod matches the source code in the module.
+// It adds any missing modules necessary to build the current module's
+// packages and dependencies, and it removes unused modules that
+// don't provide any relevant packages. It also adds any missing entries
+// to go.sum and removes any unnecessary ones.
+//
+// The -v flag causes tidy to print information about removed modules
+// to standard error.
+//
+//
+// Make vendored copy of dependencies
+//
+// Usage:
+//
+// go mod vendor [-v]
+//
+// Vendor resets the main module's vendor directory to include all packages
+// needed to build and test all the main module's packages.
+// It does not include test code for vendored packages.
+//
+// The -v flag causes vendor to print the names of vendored
+// modules and packages to standard error.
+//
+//
+// Verify dependencies have expected content
+//
+// Usage:
+//
+// go mod verify
+//
+// Verify checks that the dependencies of the current module,
+// which are stored in a local downloaded source cache, have not been
+// modified since being downloaded. If all the modules are unmodified,
+// verify prints "all modules verified." Otherwise it reports which
+// modules have been changed and causes 'go mod' to exit with a
+// non-zero status.
+//
+//
+// Explain why packages or modules are needed
+//
+// Usage:
+//
+// go mod why [-m] [-vendor] packages...
+//
+// Why shows a shortest path in the import graph from the main module to
+// each of the listed packages. If the -m flag is given, why treats the
+// arguments as a list of modules and finds a path to any package in each
+// of the modules.
+//
+// By default, why queries the graph of packages matched by "go list all",
+// which includes tests for reachable packages. The -vendor flag causes why
+// to exclude tests of dependencies.
+//
+// The output is a sequence of stanzas, one for each package or module
+// name on the command line, separated by blank lines. Each stanza begins
+// with a comment line "# package" or "# module" giving the target
+// package or module. Subsequent lines give a path through the import
+// graph, one package per line. If the package or module is not
+// referenced from the main module, the stanza will display a single
+// parenthesized note indicating that fact.
+//
+// For example:
+//
+// $ go mod why golang.org/x/text/language golang.org/x/text/encoding
+// # golang.org/x/text/language
+// rsc.io/quote
+// rsc.io/sampler
+// golang.org/x/text/language
+//
+// # golang.org/x/text/encoding
+// (main module does not need package golang.org/x/text/encoding)
+// $
+//
//
// Compile and run Go program
//
// Usage:
//
-// go run [build flags] [-exec xprog] gofiles... [arguments...]
+// go run [build flags] [-exec xprog] package [arguments...]
//
-// Run compiles and runs the main package comprising the named Go source files.
-// A Go source file is defined to be a file ending in a literal ".go" suffix.
+// Run compiles and runs the named main Go package.
+// Typically the package is specified as a list of .go source files,
+// but it may also be an import path, file system path, or pattern
+// matching a single known package, as in 'go run .' or 'go run my/cmd'.
//
// By default, 'go run' runs the compiled binary directly: 'a.out arguments...'.
// If the -exec flag is given, 'go run' invokes the binary using xprog:
@@ -717,7 +1128,10 @@
// cross-compiled programs when a simulator or other execution method is
// available.
//
+// The exit status of Run is not the exit status of the compiled binary.
+//
// For more about build flags, see 'go help build'.
+// For more about specifying packages, see 'go help packages'.
//
// See also: go build.
//
@@ -753,9 +1167,12 @@
//
// As part of building a test binary, go test runs go vet on the package
// and its test source files to identify significant problems. If go vet
-// finds any problems, go test reports those and does not run the test binary.
-// Only a high-confidence subset of the default go vet checks are used.
-// To disable the running of go vet, use the -vet=off flag.
+// finds any problems, go test reports those and does not run the test
+// binary. Only a high-confidence subset of the default go vet checks are
+// used. That subset is: 'atomic', 'bool', 'buildtags', 'nilfunc', and
+// 'printf'. You can see the documentation for these and other vet tests
+// via "go doc cmd/vet". To disable the running of go vet, use the
+// -vet=off flag.
//
// All test output and summary lines are printed to the go command's
// standard output, even if the test printed them to its own standard
@@ -887,25 +1304,6 @@
// See also: go fmt, go fix.
//
//
-// Calling between Go and C
-//
-// There are two different ways to call between Go and C/C++ code.
-//
-// The first is the cgo tool, which is part of the Go distribution. For
-// information on how to use it see the cgo documentation (go doc cmd/cgo).
-//
-// The second is the SWIG program, which is a general tool for
-// interfacing between languages. For information on SWIG see
-// http://swig.org/. When running go build, any file with a .swig
-// extension will be passed to SWIG. Any file with a .swigcxx extension
-// will be passed to SWIG with the -c++ option.
-//
-// When either cgo or SWIG is used, go build will pass any .c, .m, .s,
-// or .S files to the C compiler, and any .cc, .cpp, .cxx files to the C++
-// compiler. The CC or CXX environment variables may be set to determine
-// the C or C++ compiler, respectively, to use.
-//
-//
// Build modes
//
// The 'go build' and 'go install' commands take a -buildmode argument which
@@ -952,6 +1350,25 @@
// import, into a Go plugin. Packages not named main are ignored.
//
//
+// Calling between Go and C
+//
+// There are two different ways to call between Go and C/C++ code.
+//
+// The first is the cgo tool, which is part of the Go distribution. For
+// information on how to use it see the cgo documentation (go doc cmd/cgo).
+//
+// The second is the SWIG program, which is a general tool for
+// interfacing between languages. For information on SWIG see
+// http://swig.org/. When running go build, any file with a .swig
+// extension will be passed to SWIG. Any file with a .swigcxx extension
+// will be passed to SWIG with the -c++ option.
+//
+// When either cgo or SWIG is used, go build will pass any .c, .m, .s,
+// or .S files to the C compiler, and any .cc, .cpp, .cxx files to the C++
+// compiler. The CC or CXX environment variables may be set to determine
+// the C or C++ compiler, respectively, to use.
+//
+//
// Build and test caching
//
// The go command caches build outputs for reuse in future builds.
@@ -959,6 +1376,7 @@
// in the standard user cache directory for the current operating system.
// Setting the GOCACHE environment variable overrides this default,
// and running 'go env GOCACHE' prints the current cache directory.
+// You can set the variable to 'off' to disable the cache.
//
// The go command periodically deletes cached data that has not been
// used recently. Running 'go clean -cache' deletes all cached data.
@@ -991,6 +1409,129 @@
// decisions about whether to reuse a cached test result.
//
//
+// Environment variables
+//
+// The go command, and the tools it invokes, examine a few different
+// environment variables. For many of these, you can see the default
+// value of on your system by running 'go env NAME', where NAME is the
+// name of the variable.
+//
+// General-purpose environment variables:
+//
+// GCCGO
+// The gccgo command to run for 'go build -compiler=gccgo'.
+// GOARCH
+// The architecture, or processor, for which to compile code.
+// Examples are amd64, 386, arm, ppc64.
+// GOBIN
+// The directory where 'go install' will install a command.
+// GOCACHE
+// The directory where the go command will store cached
+// information for reuse in future builds.
+// GOFLAGS
+// A space-separated list of -flag=value settings to apply
+// to go commands by default, when the given flag is known by
+// the current command. Flags listed on the command-line
+// are applied after this list and therefore override it.
+// GOOS
+// The operating system for which to compile code.
+// Examples are linux, darwin, windows, netbsd.
+// GOPATH
+// For more details see: 'go help gopath'.
+// GOPROXY
+// URL of Go module proxy. See 'go help goproxy'.
+// GORACE
+// Options for the race detector.
+// See https://golang.org/doc/articles/race_detector.html.
+// GOROOT
+// The root of the go tree.
+// GOTMPDIR
+// The directory where the go command will write
+// temporary source files, packages, and binaries.
+//
+// Environment variables for use with cgo:
+//
+// CC
+// The command to use to compile C code.
+// CGO_ENABLED
+// Whether the cgo command is supported. Either 0 or 1.
+// CGO_CFLAGS
+// Flags that cgo will pass to the compiler when compiling
+// C code.
+// CGO_CFLAGS_ALLOW
+// A regular expression specifying additional flags to allow
+// to appear in #cgo CFLAGS source code directives.
+// Does not apply to the CGO_CFLAGS environment variable.
+// CGO_CFLAGS_DISALLOW
+// A regular expression specifying flags that must be disallowed
+// from appearing in #cgo CFLAGS source code directives.
+// Does not apply to the CGO_CFLAGS environment variable.
+// CGO_CPPFLAGS, CGO_CPPFLAGS_ALLOW, CGO_CPPFLAGS_DISALLOW
+// Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW,
+// but for the C preprocessor.
+// CGO_CXXFLAGS, CGO_CXXFLAGS_ALLOW, CGO_CXXFLAGS_DISALLOW
+// Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW,
+// but for the C++ compiler.
+// CGO_FFLAGS, CGO_FFLAGS_ALLOW, CGO_FFLAGS_DISALLOW
+// Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW,
+// but for the Fortran compiler.
+// CGO_LDFLAGS, CGO_LDFLAGS_ALLOW, CGO_LDFLAGS_DISALLOW
+// Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW,
+// but for the linker.
+// CXX
+// The command to use to compile C++ code.
+// PKG_CONFIG
+// Path to pkg-config tool.
+//
+// Architecture-specific environment variables:
+//
+// GOARM
+// For GOARCH=arm, the ARM architecture for which to compile.
+// Valid values are 5, 6, 7.
+// GO386
+// For GOARCH=386, the floating point instruction set.
+// Valid values are 387, sse2.
+// GOMIPS
+// For GOARCH=mips{,le}, whether to use floating point instructions.
+// Valid values are hardfloat (default), softfloat.
+// GOMIPS64
+// For GOARCH=mips64{,le}, whether to use floating point instructions.
+// Valid values are hardfloat (default), softfloat.
+//
+// Special-purpose environment variables:
+//
+// GCCGOTOOLDIR
+// If set, where to find gccgo tools, such as cgo.
+// The default is based on how gccgo was configured.
+// GOROOT_FINAL
+// The root of the installed Go tree, when it is
+// installed in a location other than where it is built.
+// File names in stack traces are rewritten from GOROOT to
+// GOROOT_FINAL.
+// GO_EXTLINK_ENABLED
+// Whether the linker should use external linking mode
+// when using -linkmode=auto with code that uses cgo.
+// Set to 0 to disable external linking mode, 1 to enable it.
+// GIT_ALLOW_PROTOCOL
+// Defined by Git. A colon-separated list of schemes that are allowed to be used
+// with git fetch/clone. If set, any scheme not explicitly mentioned will be
+// considered insecure by 'go get'.
+//
+// Additional information available from 'go env' but not read from the environment:
+//
+// GOEXE
+// The executable file name suffix (".exe" on Windows, "" on other systems).
+// GOHOSTARCH
+// The architecture (GOARCH) of the Go toolchain binaries.
+// GOHOSTOS
+// The operating system (GOOS) of the Go toolchain binaries.
+// GOMOD
+// The absolute path to the go.mod of the main module,
+// or the empty string if not using modules.
+// GOTOOLDIR
+// The directory where the go tools (compile, cover, doc, etc...) are installed.
+//
+//
// File types
//
// The go command examines the contents of a restricted set of files
@@ -1036,6 +1577,85 @@
// command.
//
//
+// The go.mod file
+//
+// A module version is defined by a tree of source files, with a go.mod
+// file in its root. When the go command is run, it looks in the current
+// directory and then successive parent directories to find the go.mod
+// marking the root of the main (current) module.
+//
+// The go.mod file itself is line-oriented, with // comments but
+// no /* */ comments. Each line holds a single directive, made up of a
+// verb followed by arguments. For example:
+//
+// module my/thing
+// require other/thing v1.0.2
+// require new/thing v2.3.4
+// exclude old/thing v1.2.3
+// replace bad/thing v1.4.5 => good/thing v1.4.5
+//
+// The verbs are module, to define the module path; require, to require
+// a particular module at a given version or later; exclude, to exclude
+// a particular module version from use; and replace, to replace a module
+// version with a different module version. Exclude and replace apply only
+// in the main module's go.mod and are ignored in dependencies.
+// See https://research.swtch.com/vgo-mvs for details.
+//
+// The leading verb can be factored out of adjacent lines to create a block,
+// like in Go imports:
+//
+// require (
+// new/thing v2.3.4
+// old/thing v1.2.3
+// )
+//
+// The go.mod file is designed both to be edited directly and to be
+// easily updated by tools. The 'go mod edit' command can be used to
+// parse and edit the go.mod file from programs and tools.
+// See 'go help mod edit'.
+//
+// The go command automatically updates go.mod each time it uses the
+// module graph, to make sure go.mod always accurately reflects reality
+// and is properly formatted. For example, consider this go.mod file:
+//
+// module M
+//
+// require (
+// A v1
+// B v1.0.0
+// C v1.0.0
+// D v1.2.3
+// E dev
+// )
+//
+// exclude D v1.2.3
+//
+// The update rewrites non-canonical version identifiers to semver form,
+// so A's v1 becomes v1.0.0 and E's dev becomes the pseudo-version for the
+// latest commit on the dev branch, perhaps v0.0.0-20180523231146-b3f5c0f6e5f1.
+//
+// The update modifies requirements to respect exclusions, so the
+// requirement on the excluded D v1.2.3 is updated to use the next
+// available version of D, perhaps D v1.2.4 or D v1.3.0.
+//
+// The update removes redundant or misleading requirements.
+// For example, if A v1.0.0 itself requires B v1.2.0 and C v1.0.0,
+// then go.mod's requirement of B v1.0.0 is misleading (superseded by
+// A's need for v1.2.0), and its requirement of C v1.0.0 is redundant
+// (implied by A's need for the same version), so both will be removed.
+// If module M contains packages that directly import packages from B or
+// C, then the requirements will be kept but updated to the actual
+// versions being used.
+//
+// Finally, the update reformats the go.mod in a canonical formatting, so
+// that future mechanical changes will result in minimal diffs.
+//
+// Because the module graph defines the meaning of import statements, any
+// commands that load packages also use and therefore update go.mod,
+// including go build, go get, go install, go list, go test, go mod graph,
+// go mod tidy, and go mod why.
+//
+//
// GOPATH environment variable
//
// The Go path is used to resolve import statements.
@@ -1102,6 +1722,12 @@
//
// See https://golang.org/doc/code.html for an example.
//
+// GOPATH and Modules
+//
+// When using modules, GOPATH is no longer used for resolving imports.
+// However, it is still used to store downloaded source code (in GOPATH/pkg/mod)
+// and compiled commands (in GOPATH/bin).
+//
// Internal Directories
//
// Code in or below a directory named "internal" is importable only
@@ -1185,103 +1811,67 @@
// See https://golang.org/s/go15vendor for details.
//
//
-// Environment variables
+// Module proxy protocol
//
-// The go command, and the tools it invokes, examine a few different
-// environment variables. For many of these, you can see the default
-// value of on your system by running 'go env NAME', where NAME is the
-// name of the variable.
+// The go command by default downloads modules from version control systems
+// directly, just as 'go get' always has. The GOPROXY environment variable allows
+// further control over the download source. If GOPROXY is unset, is the empty string,
+// or is the string "direct", downloads use the default direct connection to version
+// control systems. Setting GOPROXY to "off" disallows downloading modules from
+// any source. Otherwise, GOPROXY is expected to be the URL of a module proxy,
+// in which case the go command will fetch all modules from that proxy.
+// No matter the source of the modules, downloaded modules must match existing
+// entries in go.sum (see 'go help modules' for discussion of verification).
//
-// General-purpose environment variables:
+// A Go module proxy is any web server that can respond to GET requests for
+// URLs of a specified form. The requests have no query parameters, so even
+// a site serving from a fixed file system (including a file:/// URL)
+// can be a module proxy.
//
-// GCCGO
-// The gccgo command to run for 'go build -compiler=gccgo'.
-// GOARCH
-// The architecture, or processor, for which to compile code.
-// Examples are amd64, 386, arm, ppc64.
-// GOBIN
-// The directory where 'go install' will install a command.
-// GOOS
-// The operating system for which to compile code.
-// Examples are linux, darwin, windows, netbsd.
-// GOPATH
-// For more details see: 'go help gopath'.
-// GORACE
-// Options for the race detector.
-// See https://golang.org/doc/articles/race_detector.html.
-// GOROOT
-// The root of the go tree.
-// GOTMPDIR
-// The directory where the go command will write
-// temporary source files, packages, and binaries.
-// GOCACHE
-// The directory where the go command will store
-// cached information for reuse in future builds.
+// The GET requests sent to a Go module proxy are:
//
-// Environment variables for use with cgo:
+// GET $GOPROXY/<module>/@v/list returns a list of all known versions of the
+// given module, one per line.
//
-// CC
-// The command to use to compile C code.
-// CGO_ENABLED
-// Whether the cgo command is supported. Either 0 or 1.
-// CGO_CFLAGS
-// Flags that cgo will pass to the compiler when compiling
-// C code.
-// CGO_CFLAGS_ALLOW
-// A regular expression specifying additional flags to allow
-// to appear in #cgo CFLAGS source code directives.
-// Does not apply to the CGO_CFLAGS environment variable.
-// CGO_CFLAGS_DISALLOW
-// A regular expression specifying flags that must be disallowed
-// from appearing in #cgo CFLAGS source code directives.
-// Does not apply to the CGO_CFLAGS environment variable.
-// CGO_CPPFLAGS, CGO_CPPFLAGS_ALLOW, CGO_CPPFLAGS_DISALLOW
-// Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW,
-// but for the C preprocessor.
-// CGO_CXXFLAGS, CGO_CXXFLAGS_ALLOW, CGO_CXXFLAGS_DISALLOW
-// Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW,
-// but for the C++ compiler.
-// CGO_FFLAGS, CGO_FFLAGS_ALLOW, CGO_FFLAGS_DISALLOW
-// Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW,
-// but for the Fortran compiler.
-// CGO_LDFLAGS, CGO_LDFLAGS_ALLOW, CGO_LDFLAGS_DISALLOW
-// Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW,
-// but for the linker.
-// CXX
-// The command to use to compile C++ code.
-// PKG_CONFIG
-// Path to pkg-config tool.
+// GET $GOPROXY/<module>/@v/<version>.info returns JSON-formatted metadata
+// about that version of the given module.
//
-// Architecture-specific environment variables:
+// GET $GOPROXY/<module>/@v/<version>.mod returns the go.mod file
+// for that version of the given module.
//
-// GOARM
-// For GOARCH=arm, the ARM architecture for which to compile.
-// Valid values are 5, 6, 7.
-// GO386
-// For GOARCH=386, the floating point instruction set.
-// Valid values are 387, sse2.
-// GOMIPS
-// For GOARCH=mips{,le}, whether to use floating point instructions.
-// Valid values are hardfloat (default), softfloat.
+// GET $GOPROXY/<module>/@v/<version>.zip returns the zip archive
+// for that version of the given module.
//
-// Special-purpose environment variables:
+// To avoid problems when serving from case-sensitive file systems,
+// the <module> and <version> elements are case-encoded, replacing every
+// uppercase letter with an exclamation mark followed by the corresponding
+// lower-case letter: github.com/Azure encodes as github.com/!azure.
//
-// GCCGOTOOLDIR
-// If set, where to find gccgo tools, such as cgo.
-// The default is based on how gccgo was configured.
-// GOROOT_FINAL
-// The root of the installed Go tree, when it is
-// installed in a location other than where it is built.
-// File names in stack traces are rewritten from GOROOT to
-// GOROOT_FINAL.
-// GO_EXTLINK_ENABLED
-// Whether the linker should use external linking mode
-// when using -linkmode=auto with code that uses cgo.
-// Set to 0 to disable external linking mode, 1 to enable it.
-// GIT_ALLOW_PROTOCOL
-// Defined by Git. A colon-separated list of schemes that are allowed to be used
-// with git fetch/clone. If set, any scheme not explicitly mentioned will be
-// considered insecure by 'go get'.
+// The JSON-formatted metadata about a given module corresponds to
+// this Go data structure, which may be expanded in the future:
+//
+// type Info struct {
+// Version string // version string
+// Time time.Time // commit time
+// }
+//
+// The zip archive for a specific version of a given module is a
+// standard zip file that contains the file tree corresponding
+// to the module's source code and related files. The archive uses
+// slash-separated paths, and every file path in the archive must
+// begin with <module>@<version>/, where the module and version are
+// substituted directly, not case-encoded. The root of the module
+// file tree corresponds to the <module>@<version>/ prefix in the
+// archive.
+//
+// Even when downloading directly from version control systems,
+// the go command synthesizes explicit info, mod, and zip files
+// and stores them in its local cache, $GOPATH/pkg/mod/cache/download,
+// the same as if it had downloaded them directly from a proxy.
+// The cache layout is the same as the proxy URL space, so
+// serving $GOPATH/pkg/mod/cache/download at (or copying it to)
+// https://example.com/proxy would let other users access those
+// cached module versions with GOPROXY=https://example.com/proxy.
//
//
// Import path syntax
@@ -1361,6 +1951,7 @@
// that repository. The supported version control systems are:
//
// Bazaar .bzr
+// Fossil .fossil
// Git .git
// Mercurial .hg
// Subversion .svn
@@ -1404,7 +1995,7 @@
// In particular, it should appear before any raw JavaScript or CSS,
// to avoid confusing the go command's restricted parser.
//
-// The vcs is one of "git", "hg", "svn", etc,
+// The vcs is one of "bzr", "fossil", "git", "hg", "svn".
//
// The repo-root is the root of the version control system
// containing a scheme and not containing a .vcs qualifier.
@@ -1426,12 +2017,22 @@
// same meta tag and then git clone https://code.org/r/p/exproj into
// GOPATH/src/example.org.
//
-// New downloaded packages are written to the first directory listed in the GOPATH
-// environment variable (For more details see: 'go help gopath').
+// When using GOPATH, downloaded packages are written to the first directory
+// listed in the GOPATH environment variable.
+// (See 'go help gopath-get' and 'go help gopath'.)
+//
+// When using modules, downloaded packages are stored in the module cache.
+// (See 'go help modules-get' and 'go help goproxy'.)
//
-// The go command attempts to download the version of the
-// package appropriate for the Go release being used.
-// Run 'go help get' for more.
+// When using modules, an additional variant of the go-import meta tag is
+// recognized and is preferred over those listing version control systems.
+// That variant uses "mod" as the vcs in the content value, as in:
+//
+// <meta name="go-import" content="example.org mod https://code.org/moduleproxy">
+//
+// This tag means to fetch modules with paths beginning with example.org
+// from the module proxy available at the URL https://code.org/moduleproxy.
+// See 'go help goproxy' for details about the proxy protocol.
//
// Import path checking
//
@@ -1454,10 +2055,484 @@
// This makes it possible to copy code into alternate locations in vendor trees
// without needing to update import comments.
//
+// Import path checking is also disabled when using modules.
+// Import path comments are obsoleted by the go.mod file's module statement.
+//
// See https://golang.org/s/go14customimport for details.
//
//
-// Package lists
+// Modules, module versions, and more
+//
+// A module is a collection of related Go packages.
+// Modules are the unit of source code interchange and versioning.
+// The go command has direct support for working with modules,
+// including recording and resolving dependencies on other modules.
+// Modules replace the old GOPATH-based approach to specifying
+// which source files are used in a given build.
+//
+// Preliminary module support
+//
+// Go 1.11 includes preliminary support for Go modules,
+// including a new module-aware 'go get' command.
+// We intend to keep revising this support, while preserving compatibility,
+// until it can be declared official (no longer preliminary),
+// and then at a later point we may remove support for work
+// in GOPATH and the old 'go get' command.
+//
+// The quickest way to take advantage of the new Go 1.11 module support
+// is to check out your repository into a directory outside GOPATH/src,
+// create a go.mod file (described in the next section) there, and run
+// go commands from within that file tree.
+//
+// For more fine-grained control, the module support in Go 1.11 respects
+// a temporary environment variable, GO111MODULE, which can be set to one
+// of three string values: off, on, or auto (the default).
+// If GO111MODULE=off, then the go command never uses the
+// new module support. Instead it looks in vendor directories and GOPATH
+// to find dependencies; we now refer to this as "GOPATH mode."
+// If GO111MODULE=on, then the go command requires the use of modules,
+// never consulting GOPATH. We refer to this as the command being
+// module-aware or running in "module-aware mode".
+// If GO111MODULE=auto or is unset, then the go command enables or
+// disables module support based on the current directory.
+// Module support is enabled only when the current directory is outside
+// GOPATH/src and itself contains a go.mod file or is below a directory
+// containing a go.mod file.
+//
+// In module-aware mode, GOPATH no longer defines the meaning of imports
+// during a build, but it still stores downloaded dependencies (in GOPATH/pkg/mod)
+// and installed commands (in GOPATH/bin, unless GOBIN is set).
+//
+// Defining a module
+//
+// A module is defined by a tree of Go source files with a go.mod file
+// in the tree's root directory. The directory containing the go.mod file
+// is called the module root. Typically the module root will also correspond
+// to a source code repository root (but in general it need not).
+// The module is the set of all Go packages in the module root and its
+// subdirectories, but excluding subtrees with their own go.mod files.
+//
+// The "module path" is the import path prefix corresponding to the module root.
+// The go.mod file defines the module path and lists the specific versions
+// of other modules that should be used when resolving imports during a build,
+// by giving their module paths and versions.
+//
+// For example, this go.mod declares that the directory containing it is the root
+// of the module with path example.com/m, and it also declares that the module
+// depends on specific versions of golang.org/x/text and gopkg.in/yaml.v2:
+//
+// module example.com/m
+//
+// require (
+// golang.org/x/text v0.3.0
+// gopkg.in/yaml.v2 v2.1.0
+// )
+//
+// The go.mod file can also specify replacements and excluded versions
+// that only apply when building the module directly; they are ignored
+// when the module is incorporated into a larger build.
+// For more about the go.mod file, see 'go help go.mod'.
+//
+// To start a new module, simply create a go.mod file in the root of the
+// module's directory tree, containing only a module statement.
+// The 'go mod init' command can be used to do this:
+//
+// go mod init example.com/m
+//
+// In a project already using an existing dependency management tool like
+// godep, glide, or dep, 'go mod init' will also add require statements
+// matching the existing configuration.
+//
+// Once the go.mod file exists, no additional steps are required:
+// go commands like 'go build', 'go test', or even 'go list' will automatically
+// add new dependencies as needed to satisfy imports.
+//
+// The main module and the build list
+//
+// The "main module" is the module containing the directory where the go command
+// is run. The go command finds the module root by looking for a go.mod in the
+// current directory, or else the current directory's parent directory,
+// or else the parent's parent directory, and so on.
+//
+// The main module's go.mod file defines the precise set of packages available
+// for use by the go command, through require, replace, and exclude statements.
+// Dependency modules, found by following require statements, also contribute
+// to the definition of that set of packages, but only through their go.mod
+// files' require statements: any replace and exclude statements in dependency
+// modules are ignored. The replace and exclude statements therefore allow the
+// main module complete control over its own build, without also being subject
+// to complete control by dependencies.
+//
+// The set of modules providing packages to builds is called the "build list".
+// The build list initially contains only the main module. Then the go command
+// adds to the list the exact module versions required by modules already
+// on the list, recursively, until there is nothing left to add to the list.
+// If multiple versions of a particular module are added to the list,
+// then at the end only the latest version (according to semantic version
+// ordering) is kept for use in the build.
+//
+// The 'go list' command provides information about the main module
+// and the build list. For example:
+//
+// go list -m # print path of main module
+// go list -m -f={{.Dir}} # print root directory of main module
+// go list -m all # print build list
+//
+// Maintaining module requirements
+//
+// The go.mod file is meant to be readable and editable by both
+// programmers and tools. The go command itself automatically updates the go.mod file
+// to maintain a standard formatting and the accuracy of require statements.
+//
+// Any go command that finds an unfamiliar import will look up the module
+// containing that import and add the latest version of that module
+// to go.mod automatically. In most cases, therefore, it suffices to
+// add an import to source code and run 'go build', 'go test', or even 'go list':
+// as part of analyzing the package, the go command will discover
+// and resolve the import and update the go.mod file.
+//
+// Any go command can determine that a module requirement is
+// missing and must be added, even when considering only a single
+// package from the module. On the other hand, determining that a module requirement
+// is no longer necessary and can be deleted requires a full view of
+// all packages in the module, across all possible build configurations
+// (architectures, operating systems, build tags, and so on).
+// The 'go mod tidy' command builds that view and then
+// adds any missing module requirements and removes unnecessary ones.
+//
+// As part of maintaining the require statements in go.mod, the go command
+// tracks which ones provide packages imported directly by the current module
+// and which ones provide packages only used indirectly by other module
+// dependencies. Requirements needed only for indirect uses are marked with a
+// "// indirect" comment in the go.mod file. Indirect requirements are
+// automatically removed from the go.mod file once they are implied by other
+// direct requirements. Indirect requirements only arise when using modules
+// that fail to state some of their own dependencies or when explicitly
+// upgrading a module's dependencies ahead of its own stated requirements.
+//
+// Because of this automatic maintenance, the information in go.mod is an
+// up-to-date, readable description of the build.
+//
+// The 'go get' command updates go.mod to change the module versions used in a
+// build. An upgrade of one module may imply upgrading others, and similarly a
+// downgrade of one module may imply downgrading others. The 'go get' command
+// makes these implied changes as well. If go.mod is edited directly, commands
+// like 'go build' or 'go list' will assume that an upgrade is intended and
+// automatically make any implied upgrades and update go.mod to reflect them.
+//
+// The 'go mod' command provides other functionality for use in maintaining
+// and understanding modules and go.mod files. See 'go help mod'.
+//
+// The -mod build flag provides additional control over updating and use of go.mod.
+//
+// If invoked with -mod=readonly, the go command is disallowed from the implicit
+// automatic updating of go.mod described above. Instead, it fails when any changes
+// to go.mod are needed. This setting is most useful to check that go.mod does
+// not need updates, such as in a continuous integration and testing system.
+// The "go get" command remains permitted to update go.mod even with -mod=readonly,
+// and the "go mod" commands do not take the -mod flag (or any other build flags).
+//
+// If invoked with -mod=vendor, the go command assumes that the vendor
+// directory holds the correct copies of dependencies and ignores
+// the dependency descriptions in go.mod.
+//
+// Pseudo-versions
+//
+// The go.mod file and the go command more generally use semantic versions as
+// the standard form for describing module versions, so that versions can be
+// compared to determine which should be considered earlier or later than another.
+// 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. The time portion ensures that two pseudo-versions can
+// be compared to determine which happened later, the commit hash identifes
+// the underlying commit, and the prefix (v0.0.0- in this example) is derived from
+// the most recent tagged version in the commit graph before this commit.
+//
+// There are three pseudo-version forms:
+//
+// vX.0.0-yyyymmddhhmmss-abcdefabcdef is used when there is no earlier
+// versioned commit with an appropriate major version before the target commit.
+// (This was originally the only form, so some older go.mod files use this form
+// even for commits that do follow tags.)
+//
+// vX.Y.Z-pre.0.yyyymmddhhmmss-abcdefabcdef is used when the most
+// recent versioned commit before the target commit is vX.Y.Z-pre.
+//
+// vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdefabcdef is used when the most
+// recent versioned commit before the target commit is vX.Y.Z.
+//
+// Pseudo-versions never need to be typed by hand: the go command will accept
+// the plain commit hash and translate it into a pseudo-version (or a tagged
+// version if available) automatically. This conversion is an example of a
+// module query.
+//
+// Module queries
+//
+// The go command accepts a "module query" in place of a module version
+// both on the command line and in the main module's go.mod file.
+// (After evaluating a query found in the main module's go.mod file,
+// the go command updates the file to replace the query with its result.)
+//
+// A fully-specified semantic version, such as "v1.2.3",
+// evaluates to that specific version.
+//
+// A semantic version prefix, such as "v1" or "v1.2",
+// evaluates to the latest available tagged version with that prefix.
+//
+// A semantic version comparison, such as "<v1.2.3" or ">=v1.5.6",
+// evaluates to the available tagged version nearest to the comparison target
+// (the latest version for < and <=, the earliest version for > and >=).
+//
+// The string "latest" matches the latest available tagged version,
+// or else the underlying source repository's latest untagged revision.
+//
+// A revision identifier for the underlying source repository,
+// such as a commit hash prefix, revision tag, or branch name,
+// selects that specific code revision. If the revision is
+// also tagged with a semantic version, the query evaluates to
+// that semantic version. Otherwise the query evaluates to a
+// pseudo-version for the commit.
+//
+// All queries prefer release versions to pre-release versions.
+// For example, "<v1.2.3" will prefer to return "v1.2.2"
+// instead of "v1.2.3-pre1", even though "v1.2.3-pre1" is nearer
+// to the comparison target.
+//
+// Module versions disallowed by exclude statements in the
+// main module's go.mod are considered unavailable and cannot
+// be returned by queries.
+//
+// For example, these commands are all valid:
+//
+// go get github.com/gorilla/mux@latest # same (@latest is default for 'go get')
+// go get github.com/gorilla/mux@v1.6.2 # records v1.6.2
+// go get github.com/gorilla/mux@e3702bed2 # records v1.6.2
+// go get github.com/gorilla/mux@c856192 # records v0.0.0-20180517173623-c85619274f5d
+// go get github.com/gorilla/mux@master # records current meaning of master
+//
+// Module compatibility and semantic versioning
+//
+// The go command requires that modules use semantic versions and expects that
+// the versions accurately describe compatibility: it assumes that v1.5.4 is a
+// backwards-compatible replacement for v1.5.3, v1.4.0, and even v1.0.0.
+// More generally the go command expects that packages follow the
+// "import compatibility rule", which says:
+//
+// "If an old package and a new package have the same import path,
+// the new package must be backwards compatible with the old package."
+//
+// Because the go command assumes the import compatibility rule,
+// a module definition can only set the minimum required version of one
+// of its dependencies: it cannot set a maximum or exclude selected versions.
+// Still, the import compatibility rule is not a guarantee: it may be that
+// v1.5.4 is buggy and not a backwards-compatible replacement for v1.5.3.
+// Because of this, the go command never updates from an older version
+// to a newer version of a module unasked.
+//
+// In semantic versioning, changing the major version number indicates a lack
+// of backwards compatibility with earlier versions. To preserve import
+// compatibility, the go command requires that modules with major version v2
+// or later use a module path with that major version as the final element.
+// For example, version v2.0.0 of example.com/m must instead use module path
+// example.com/m/v2, and packages in that module would use that path as
+// their import path prefix, as in example.com/m/v2/sub/pkg. Including the
+// major version number in the module path and import paths in this way is
+// called "semantic import versioning". Pseudo-versions for modules with major
+// version v2 and later begin with that major version instead of v0, as in
+// v2.0.0-20180326061214-4fc5987536ef.
+//
+// As a special case, module paths beginning with gopkg.in/ continue to use the
+// conventions established on that system: the major version is always present,
+// and it is preceded by a dot instead of a slash: gopkg.in/yaml.v1
+// and gopkg.in/yaml.v2, not gopkg.in/yaml and gopkg.in/yaml/v2.
+//
+// The go command treats modules with different module paths as unrelated:
+// it makes no connection between example.com/m and example.com/m/v2.
+// Modules with different major versions can be used together in a build
+// and are kept separate by the fact that their packages use different
+// import paths.
+//
+// In semantic versioning, major version v0 is for initial development,
+// indicating no expectations of stability or backwards compatibility.
+// Major version v0 does not appear in the module path, because those
+// versions are preparation for v1.0.0, and v1 does not appear in the
+// module path either.
+//
+// Code written before the semantic import versioning convention
+// was introduced may use major versions v2 and later to describe
+// the same set of unversioned import paths as used in v0 and v1.
+// To accommodate such code, 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 when converted to a module
+// version, as in v2.0.0+incompatible. The +incompatible tag is also
+// applied to pseudo-versions derived from such versions, as in
+// v2.0.1-0.yyyymmddhhmmss-abcdefabcdef+incompatible.
+//
+// In general, having a dependency in the build list (as reported by 'go list -m all')
+// on a v0 version, pre-release version, pseudo-version, or +incompatible version
+// is an indication that problems are more likely when upgrading that
+// dependency, since there is no expectation of compatibility for those.
+//
+// See https://research.swtch.com/vgo-import for more information about
+// semantic import versioning, and see https://semver.org/ for more about
+// semantic versioning.
+//
+// Module code layout
+//
+// For now, see https://research.swtch.com/vgo-module for information
+// about how source code in version control systems is mapped to
+// module file trees.
+//
+// Module downloading and verification
+//
+// The go command maintains, in the main module's root directory alongside
+// go.mod, a file named go.sum containing the expected cryptographic checksums
+// of the content of specific module versions. Each time a dependency is
+// used, its checksum is added to go.sum if missing or else required to match
+// the existing entry in go.sum.
+//
+// The go command maintains a cache of downloaded packages and computes
+// and records the cryptographic checksum of each package at download time.
+// In normal operation, the go command checks these pre-computed checksums
+// against the main module's go.sum file, instead of recomputing them on
+// each command invocation. The 'go mod verify' command checks that
+// the cached copies of module downloads still match both their recorded
+// checksums and the entries in go.sum.
+//
+// The go command can fetch modules from a proxy instead of connecting
+// to source control systems directly, according to the setting of the GOPROXY
+// environment variable.
+//
+// See 'go help goproxy' for details about the proxy and also the format of
+// the cached downloaded packages.
+//
+// Modules and vendoring
+//
+// When using modules, the go command completely ignores vendor directories.
+//
+// By default, the go command satisfies dependencies by downloading modules
+// from their sources and using those downloaded copies (after verification,
+// as described in the previous section). To allow interoperation with older
+// versions of Go, or to ensure that all files used for a build are stored
+// together in a single file tree, 'go mod vendor' creates a directory named
+// vendor in the root directory of the main module and stores there all the
+// packages from dependency modules that are needed to support builds and
+// tests of packages in the main module.
+//
+// To build using the main module's top-level vendor directory to satisfy
+// dependencies (disabling use of the usual network sources and local
+// caches), use 'go build -mod=vendor'. Note that only the main module's
+// top-level vendor directory is used; vendor directories in other locations
+// are still ignored.
+//
+//
+// Module-aware go get
+//
+// The 'go get' command changes behavior depending on whether the
+// go command is running in module-aware mode or legacy GOPATH mode.
+// This help text, accessible as 'go help module-get' even in legacy GOPATH mode,
+// describes 'go get' as it operates in module-aware mode.
+//
+// Usage: go get [-d] [-m] [-u] [-v] [-insecure] [build flags] [packages]
+//
+// Get resolves and adds dependencies to the current development module
+// and then builds and installs them.
+//
+// The first step is to resolve which dependencies to add.
+//
+// For each named package or package pattern, get must decide which version of
+// the corresponding module to use. By default, get chooses the latest tagged
+// release version, such as v0.4.5 or v1.2.3. If there are no tagged release
+// versions, get chooses the latest tagged prerelease version, such as
+// v0.0.1-pre1. If there are no tagged versions at all, get chooses the latest
+// known commit.
+//
+// This default version selection can be overridden by adding an @version
+// suffix to the package argument, as in 'go get golang.org/x/text@v0.3.0'.
+// For modules stored in source control repositories, the version suffix can
+// also be a commit hash, branch identifier, or other syntax known to the
+// source control system, as in 'go get golang.org/x/text@master'.
+// The version suffix @latest explicitly requests the default behavior
+// described above.
+//
+// If a module under consideration is already a dependency of the current
+// development module, then get will update the required version.
+// Specifying a version earlier than the current required version is valid and
+// downgrades the dependency. The version suffix @none indicates that the
+// dependency should be removed entirely.
+//
+// Although get defaults to using the latest version of the module containing
+// a named package, it does not use the latest version of that module's
+// dependencies. Instead it prefers to use the specific dependency versions
+// requested by that module. For example, if the latest A requires module
+// B v1.2.3, while B v1.2.4 and v1.3.1 are also available, then 'go get A'
+// will use the latest A but then use B v1.2.3, as requested by A. (If there
+// are competing requirements for a particular module, then 'go get' resolves
+// those requirements by taking the maximum requested version.)
+//
+// The -u flag instructs get to update dependencies to use newer minor or
+// patch releases when available. Continuing the previous example,
+// 'go get -u A' will use the latest A with B v1.3.1 (not B v1.2.3).
+//
+// The -u=patch flag (not -u patch) instructs get to update dependencies
+// to use newer patch releases when available. Continuing the previous example,
+// 'go get -u=patch A' will use the latest A with B v1.2.4 (not B v1.2.3).
+//
+// In general, adding a new dependency may require upgrading
+// existing dependencies to keep a working build, and 'go get' does
+// this automatically. Similarly, downgrading one dependency may
+// require downgrading other dependenceis, and 'go get' does
+// this automatically as well.
+//
+// The -m flag instructs get to stop here, after resolving, upgrading,
+// and downgrading modules and updating go.mod. When using -m,
+// each specified package path must be a module path as well,
+// not the import path of a package below the module root.
+//
+// The -insecure flag permits fetching from repositories and resolving
+// custom domains using insecure schemes such as HTTP. Use with caution.
+//
+// The second step is to download (if needed), build, and install
+// the named packages.
+//
+// If an argument names a module but not a package (because there is no
+// Go source code in the module's root directory), then the install step
+// is skipped for that argument, instead of causing a build failure.
+// For example 'go get golang.org/x/perf' succeeds even though there
+// is no code corresponding to that import path.
+//
+// Note that package patterns are allowed and are expanded after resolving
+// the module versions. For example, 'go get golang.org/x/perf/cmd/...'
+// adds the latest golang.org/x/perf and then installs the commands in that
+// latest version.
+//
+// The -d flag instructs get to download the source code needed to build
+// the named packages, including downloading necessary dependencies,
+// but not to build and install them.
+//
+// With no package arguments, 'go get' applies to the main module,
+// and to the Go package in the current directory, if any. In particular,
+// 'go get -u' and 'go get -u=patch' update all the dependencies of the
+// main module. With no package arguments and also without -u,
+// 'go get' is not much more than 'go install', and 'go get -d' not much
+// more than 'go list'.
+//
+// For more about modules, see 'go help modules'.
+//
+// For more about specifying packages, see 'go help packages'.
+//
+// This text describes the behavior of get using modules to manage source
+// code and dependencies. If instead the go command is running in GOPATH
+// mode, the details of get's flags and effects change, as does 'go help get'.
+// See 'go help modules' and 'go help gopath-get'.
+//
+// See also: go build, go install, go clean, go mod.
+//
+//
+// Package lists and patterns
//
// Many commands apply to a set of packages:
//
@@ -1481,9 +2556,11 @@
//
// - "main" denotes the top-level package in a stand-alone executable.
//
-// - "all" expands to all package directories found in all the GOPATH
+// - "all" expands to all packages found in all the GOPATH
// trees. For example, 'go list all' lists all the packages on the local
-// system.
+// system. When using modules, "all" expands to all packages in
+// the main module and their dependencies, including dependencies
+// needed by tests of any of those.
//
// - "std" is like all but expands to just the packages in the standard
// Go library.
@@ -1682,14 +2759,13 @@
// Writes test binary as -c would.
//
// -memprofile mem.out
-// Write a memory profile to the file after all tests have passed.
+// Write an allocation profile to the file after all tests have passed.
// Writes test binary as -c would.
//
// -memprofilerate n
-// Enable more precise (and expensive) memory profiles by setting
-// runtime.MemProfileRate. See 'go doc runtime.MemProfileRate'.
-// To profile all memory allocations, use -test.memprofilerate=1
-// and pass --alloc_space flag to the pprof tool.
+// Enable more precise (and expensive) memory allocation profiles by
+// setting runtime.MemProfileRate. See 'go doc runtime.MemProfileRate'.
+// To profile all memory allocations, use -test.memprofilerate=1.
//
// -mutexprofile mutex.out
// Write a mutex contention profile to the specified file
@@ -1739,6 +2815,12 @@
// the package list would have to appear before -myflag, but could appear
// on either side of -v.
//
+// When 'go test' runs in package list mode, 'go test' caches successful
+// package test results to avoid unnecessary repeated running of tests. To
+// disable test caching, use any test flag or argument other than the
+// cacheable flags. The idiomatic way to disable test caching explicitly
+// is to use -count=1.
+//
// To keep an argument for a test binary from being interpreted as a
// known flag or a package name, use -args (see 'go help test') which
// passes the remainder of the command line through to the test binary
diff --git a/libgo/go/cmd/go/go_test.go b/libgo/go/cmd/go/go_test.go
index 20606d813e6..e88338815c3 100644
--- a/libgo/go/cmd/go/go_test.go
+++ b/libgo/go/cmd/go/go_test.go
@@ -8,12 +8,14 @@ import (
"bytes"
"debug/elf"
"debug/macho"
+ "flag"
"fmt"
"go/format"
"internal/race"
"internal/testenv"
"io"
"io/ioutil"
+ "log"
"os"
"os/exec"
"path/filepath"
@@ -48,7 +50,7 @@ func tooSlow(t *testing.T) {
func init() {
switch runtime.GOOS {
- case "android", "nacl":
+ case "android", "js", "nacl":
canRun = false
case "darwin":
switch runtime.GOARCH {
@@ -99,6 +101,11 @@ func init() {
var testGOROOT string
var testCC string
+var testGOCACHE string
+
+var testGo string
+var testTmpDir string
+var testBin string
// The TestMain function creates a go command for testing purposes and
// deletes it after the tests have been run.
@@ -111,8 +118,28 @@ func TestMain(m *testing.M) {
}
os.Unsetenv("GOROOT_FINAL")
+ flag.Parse()
+ if *proxyAddr != "" {
+ StartProxy()
+ select {}
+ }
+
+ dir, err := ioutil.TempDir(os.Getenv("GOTMPDIR"), "cmd-go-test-")
+ if err != nil {
+ log.Fatal(err)
+ }
+ testTmpDir = dir
+ if !*testWork {
+ defer removeAll(testTmpDir)
+ }
+
if canRun {
- args := []string{"build", "-tags", "testgo", "-o", "testgo" + exeSuffix}
+ testBin = filepath.Join(testTmpDir, "testbin")
+ if err := os.Mkdir(testBin, 0777); err != nil {
+ log.Fatal(err)
+ }
+ testGo = filepath.Join(testBin, "go"+exeSuffix)
+ args := []string{"build", "-tags", "testgo", "-o", testGo}
if race.Enabled {
args = append(args, "-race")
}
@@ -165,7 +192,7 @@ func TestMain(m *testing.M) {
}
testCC = strings.TrimSpace(string(out))
- if out, err := exec.Command("./testgo"+exeSuffix, "env", "CGO_ENABLED").Output(); err != nil {
+ if out, err := exec.Command(testGo, "env", "CGO_ENABLED").Output(); err != nil {
fmt.Fprintf(os.Stderr, "running testgo failed: %v\n", err)
canRun = false
} else {
@@ -175,6 +202,13 @@ func TestMain(m *testing.M) {
}
}
+ out, err = exec.Command(gotool, "env", "GOCACHE").CombinedOutput()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "could not find testing GOCACHE: %v\n%s", err, out)
+ os.Exit(2)
+ }
+ testGOCACHE = strings.TrimSpace(string(out))
+
// As of Sept 2017, MSan is only supported on linux/amd64.
// https://github.com/google/sanitizers/wiki/MemorySanitizer#getting-memorysanitizer
canMSan = canCgo && runtime.GOOS == "linux" && runtime.GOARCH == "amd64"
@@ -190,21 +224,18 @@ func TestMain(m *testing.M) {
os.Unsetenv("GOBIN")
os.Unsetenv("GOPATH")
os.Unsetenv("GIT_ALLOW_PROTOCOL")
- if home, ccacheDir := os.Getenv("HOME"), os.Getenv("CCACHE_DIR"); home != "" && ccacheDir == "" {
- // On some systems the default C compiler is ccache.
- // Setting HOME to a non-existent directory will break
- // those systems. Set CCACHE_DIR to cope. Issue 17668.
- os.Setenv("CCACHE_DIR", filepath.Join(home, ".ccache"))
- }
os.Setenv("HOME", "/test-go-home-does-not-exist")
+ // On some systems the default C compiler is ccache.
+ // Setting HOME to a non-existent directory will break
+ // those systems. Disable ccache and use real compiler. Issue 17668.
+ os.Setenv("CCACHE_DISABLE", "1")
if os.Getenv("GOCACHE") == "" {
- os.Setenv("GOCACHE", "off") // because $HOME is gone
+ os.Setenv("GOCACHE", testGOCACHE) // because $HOME is gone
}
r := m.Run()
-
- if canRun {
- os.Remove("testgo" + exeSuffix)
+ if !*testWork {
+ removeAll(testTmpDir) // os.Exit won't run defer
}
os.Exit(r)
@@ -234,6 +265,7 @@ type testgoData struct {
ran bool
inParallel bool
stdout, stderr bytes.Buffer
+ execDir string // dir for tg.run
}
// skipIfGccgo skips the test if using gccgo.
@@ -352,10 +384,7 @@ func (tg *testgoData) unsetenv(name string) {
}
func (tg *testgoData) goTool() string {
- if tg.wd == "" {
- return "./testgo" + exeSuffix
- }
- return filepath.Join(tg.wd, "testgo"+exeSuffix)
+ return testGo
}
// doRun runs the test go command, recording stdout and stderr and
@@ -389,6 +418,7 @@ func (tg *testgoData) doRun(args []string) error {
cmd := exec.Command(prog, args...)
tg.stdout.Reset()
tg.stderr.Reset()
+ cmd.Dir = tg.execDir
cmd.Stdout = &tg.stdout
cmd.Stderr = &tg.stderr
cmd.Env = tg.env
@@ -409,7 +439,8 @@ func (tg *testgoData) doRun(args []string) error {
func (tg *testgoData) run(args ...string) {
tg.t.Helper()
if status := tg.doRun(args); status != nil {
- tg.t.Logf("go %v failed unexpectedly: %v", args, status)
+ wd, _ := os.Getwd()
+ tg.t.Logf("go %v failed unexpectedly in %s: %v", args, wd, status)
tg.t.FailNow()
}
}
@@ -735,7 +766,11 @@ func (tg *testgoData) wantStale(pkg, reason, msg string) {
if !stale {
tg.t.Fatal(msg)
}
- if reason == "" && why != "" || !strings.Contains(why, reason) {
+ // We always accept the reason as being "not installed but
+ // available in build cache", because when that is the case go
+ // list doesn't try to sort out the underlying reason why the
+ // package is not installed.
+ if reason == "" && why != "" || !strings.Contains(why, reason) && !strings.Contains(why, "not installed but available in build cache") {
tg.t.Errorf("wrong reason for Stale=true: %q, want %q", why, reason)
}
}
@@ -752,24 +787,51 @@ func (tg *testgoData) wantNotStale(pkg, reason, msg string) {
}
}
+// If -testwork is specified, the test prints the name of the temp directory
+// and does not remove it when done, so that a programmer can
+// poke at the test file tree afterward.
+var testWork = flag.Bool("testwork", false, "")
+
// cleanup cleans up a test that runs testgo.
func (tg *testgoData) cleanup() {
tg.t.Helper()
if tg.wd != "" {
+ wd, _ := os.Getwd()
+ tg.t.Logf("ended in %s", wd)
+
if err := os.Chdir(tg.wd); err != nil {
// We are unlikely to be able to continue.
fmt.Fprintln(os.Stderr, "could not restore working directory, crashing:", err)
os.Exit(2)
}
}
+ if *testWork {
+ tg.t.Logf("TESTWORK=%s\n", tg.path("."))
+ return
+ }
for _, path := range tg.temps {
- tg.check(os.RemoveAll(path))
+ tg.check(removeAll(path))
}
if tg.tempdir != "" {
- tg.check(os.RemoveAll(tg.tempdir))
+ tg.check(removeAll(tg.tempdir))
}
}
+func removeAll(dir string) error {
+ // module cache has 0444 directories;
+ // make them writable in order to remove content.
+ filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return nil // ignore errors walking in file system
+ }
+ if info.IsDir() {
+ os.Chmod(path, 0777)
+ }
+ return nil
+ })
+ return os.RemoveAll(dir)
+}
+
// failSSH puts an ssh executable in the PATH that always fails.
// This is to stub out uses of ssh by go get.
func (tg *testgoData) failSSH() {
@@ -782,92 +844,6 @@ func (tg *testgoData) failSSH() {
tg.setenv("PATH", fmt.Sprintf("%v%c%v", fail, filepath.ListSeparator, os.Getenv("PATH")))
}
-func TestBuildComplex(t *testing.T) {
- // Simple smoke test for build configuration.
- tg := testgo(t)
- defer tg.cleanup()
- tg.parallel()
- tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
- tg.run("build", "-x", "-o", os.DevNull, "complex")
-
- if _, err := exec.LookPath("gccgo"); err == nil {
- tg.run("build", "-x", "-o", os.DevNull, "-compiler=gccgo", "complex")
- }
-}
-
-func TestFileLineInErrorMessages(t *testing.T) {
- tg := testgo(t)
- defer tg.cleanup()
- tg.parallel()
- tg.tempFile("err.go", `package main; import "bar"`)
- path := tg.path("err.go")
- tg.runFail("run", path)
- shortPath := path
- if rel, err := filepath.Rel(tg.pwd(), path); err == nil && len(rel) < len(path) {
- shortPath = rel
- }
- tg.grepStderr("^"+regexp.QuoteMeta(shortPath)+":", "missing file:line in error message")
-}
-
-func TestProgramNameInCrashMessages(t *testing.T) {
- skipIfGccgo(t, "gccgo does not use cmd/link")
- tg := testgo(t)
- defer tg.cleanup()
- tg.parallel()
- tg.tempFile("triv.go", `package main; func main() {}`)
- tg.runFail("build", "-ldflags", "-crash_for_testing", tg.path("triv.go"))
- tg.grepStderr(`[/\\]tool[/\\].*[/\\]link`, "missing linker name in error message")
-}
-
-func TestBrokenTestsWithoutTestFunctionsAllFail(t *testing.T) {
- tg := testgo(t)
- defer tg.cleanup()
- // TODO: tg.parallel()
- tg.runFail("test", "./testdata/src/badtest/...")
- tg.grepBothNot("^ok", "test passed unexpectedly")
- tg.grepBoth("FAIL.*badtest/badexec", "test did not run everything")
- tg.grepBoth("FAIL.*badtest/badsyntax", "test did not run everything")
- tg.grepBoth("FAIL.*badtest/badvar", "test did not run everything")
-}
-
-func TestGoBuildDashAInDevBranch(t *testing.T) {
- if testing.Short() {
- t.Skip("don't rebuild the standard library in short mode")
- }
-
- tg := testgo(t)
- defer tg.cleanup()
- tg.run("install", "math") // should be up to date already but just in case
- tg.setenv("TESTGO_IS_GO_RELEASE", "0")
- tg.run("build", "-v", "-a", "math")
- tg.grepStderr("runtime", "testgo build -a math in dev branch DID NOT build runtime, but should have")
-
- // Everything is out of date. Rebuild to leave things in a better state.
- tg.run("install", "std")
-}
-
-func TestGoBuildDashAInReleaseBranch(t *testing.T) {
- if testing.Short() {
- t.Skip("don't rebuild the standard library in short mode")
- }
-
- tg := testgo(t)
- defer tg.cleanup()
- tg.run("install", "math", "net/http") // should be up to date already but just in case
- tg.setenv("TESTGO_IS_GO_RELEASE", "1")
- tg.run("install", "-v", "-a", "math")
- tg.grepStderr("runtime", "testgo build -a math in release branch DID NOT build runtime, but should have")
-
- // Now runtime.a is updated (newer mtime), so everything would look stale if not for being a release.
- tg.run("build", "-v", "net/http")
- tg.grepStderrNot("strconv", "testgo build -v net/http in release branch with newer runtime.a DID build strconv but should not have")
- tg.grepStderrNot("golang.org/x/net/http2/hpack", "testgo build -v net/http in release branch with newer runtime.a DID build .../golang.org/x/net/http2/hpack but should not have")
- tg.grepStderrNot("net/http", "testgo build -v net/http in release branch with newer runtime.a DID build net/http but should not have")
-
- // Everything is out of date. Rebuild to leave things in a better state.
- tg.run("install", "std")
-}
-
func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
if testing.Short() {
t.Skip("don't rebuild the standard library in short mode")
@@ -876,13 +852,13 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
- addNL := func(name string) (restore func()) {
+ addVar := func(name string, idx int) (restore func()) {
data, err := ioutil.ReadFile(name)
if err != nil {
t.Fatal(err)
}
old := data
- data = append(data, '\n')
+ data = append(data, fmt.Sprintf("var DummyUnusedVar%d bool\n", idx)...)
if err := ioutil.WriteFile(name, append(data, '\n'), 0666); err != nil {
t.Fatal(err)
}
@@ -894,9 +870,11 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
}
}
- tg.tempFile("d1/src/p1/p1.go", `package p1`)
+ // Every main package depends on the "runtime".
+ tg.tempFile("d1/src/p1/p1.go", `package main; func main(){}`)
tg.setenv("GOPATH", tg.path("d1"))
- tg.run("install", "-a", "p1")
+ // Pass -i flag to rebuild everything outdated.
+ tg.run("install", "-i", "p1")
tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly, before any changes")
// Changing mtime of runtime/internal/sys/sys.go
@@ -904,225 +882,33 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
// In fact this should be true even outside a release branch.
sys := runtime.GOROOT() + "/src/runtime/internal/sys/sys.go"
tg.sleep()
- restore := addNL(sys)
+ restore := addVar(sys, 0)
restore()
tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly, after updating mtime of runtime/internal/sys/sys.go")
// But changing content of any file should have an effect.
// Previously zversion.go was the only one that mattered;
// now they all matter, so keep using sys.go.
- restore = addNL(sys)
+ restore = addVar(sys, 1)
defer restore()
tg.wantStale("p1", "stale dependency: runtime/internal/sys", "./testgo list claims p1 is NOT stale, incorrectly, after changing sys.go")
restore()
tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly, after changing back to old release")
- addNL(sys)
+ addVar(sys, 2)
tg.wantStale("p1", "stale dependency: runtime/internal/sys", "./testgo list claims p1 is NOT stale, incorrectly, after changing sys.go again")
- tg.run("install", "p1")
+ tg.run("install", "-i", "p1")
tg.wantNotStale("p1", "", "./testgo list claims p1 is stale after building with new release")
// Restore to "old" release.
restore()
tg.wantStale("p1", "stale dependency: runtime/internal/sys", "./testgo list claims p1 is NOT stale, incorrectly, after restoring sys.go")
- tg.run("install", "p1")
+ tg.run("install", "-i", "p1")
tg.wantNotStale("p1", "", "./testgo list claims p1 is stale after building with old release")
// Everything is out of date. Rebuild to leave things in a better state.
tg.run("install", "std")
}
-func TestGoListStandard(t *testing.T) {
- skipIfGccgo(t, "gccgo does not GOROOT")
- tooSlow(t)
- tg := testgo(t)
- defer tg.cleanup()
- // TODO: tg.parallel()
- tg.cd(runtime.GOROOT() + "/src")
- tg.run("list", "-f", "{{if not .Standard}}{{.ImportPath}}{{end}}", "./...")
- stdout := tg.getStdout()
- for _, line := range strings.Split(stdout, "\n") {
- if strings.HasPrefix(line, "_/") && strings.HasSuffix(line, "/src") {
- // $GOROOT/src shows up if there are any .go files there.
- // We don't care.
- continue
- }
- if line == "" {
- continue
- }
- t.Errorf("package in GOROOT not listed as standard: %v", line)
- }
-
- // Similarly, expanding std should include some of our vendored code.
- tg.run("list", "std", "cmd")
- tg.grepStdout("golang.org/x/net/http2/hpack", "list std cmd did not mention vendored hpack")
- tg.grepStdout("golang.org/x/arch/x86/x86asm", "list std cmd did not mention vendored x86asm")
-}
-
-func TestGoInstallCleansUpAfterGoBuild(t *testing.T) {
- tooSlow(t)
- tg := testgo(t)
- defer tg.cleanup()
- // TODO: tg.parallel()
- tg.tempFile("src/mycmd/main.go", `package main; func main(){}`)
- tg.setenv("GOPATH", tg.path("."))
- tg.cd(tg.path("src/mycmd"))
-
- doesNotExist := func(file, msg string) {
- if _, err := os.Stat(file); err == nil {
- t.Fatal(msg)
- } else if !os.IsNotExist(err) {
- t.Fatal(msg, "error:", err)
- }
- }
-
- tg.run("build")
- tg.wantExecutable("mycmd"+exeSuffix, "testgo build did not write command binary")
- tg.run("install")
- doesNotExist("mycmd"+exeSuffix, "testgo install did not remove command binary")
- tg.run("build")
- tg.wantExecutable("mycmd"+exeSuffix, "testgo build did not write command binary (second time)")
- // Running install with arguments does not remove the target,
- // even in the same directory.
- tg.run("install", "mycmd")
- tg.wantExecutable("mycmd"+exeSuffix, "testgo install mycmd removed command binary when run in mycmd")
- tg.run("build")
- tg.wantExecutable("mycmd"+exeSuffix, "testgo build did not write command binary (third time)")
- // And especially not outside the directory.
- tg.cd(tg.path("."))
- if data, err := ioutil.ReadFile("src/mycmd/mycmd" + exeSuffix); err != nil {
- t.Fatal("could not read file:", err)
- } else {
- if err := ioutil.WriteFile("mycmd"+exeSuffix, data, 0555); err != nil {
- t.Fatal("could not write file:", err)
- }
- }
- tg.run("install", "mycmd")
- tg.wantExecutable("src/mycmd/mycmd"+exeSuffix, "testgo install mycmd removed command binary from its source dir when run outside mycmd")
- tg.wantExecutable("mycmd"+exeSuffix, "testgo install mycmd removed command binary from current dir when run outside mycmd")
-}
-
-func TestGoInstallRebuildsStalePackagesInOtherGOPATH(t *testing.T) {
- tooSlow(t)
- tg := testgo(t)
- defer tg.cleanup()
- tg.parallel()
- tg.tempFile("d1/src/p1/p1.go", `package p1
- import "p2"
- func F() { p2.F() }`)
- tg.tempFile("d2/src/p2/p2.go", `package p2
- func F() {}`)
- sep := string(filepath.ListSeparator)
- tg.setenv("GOPATH", tg.path("d1")+sep+tg.path("d2"))
- tg.run("install", "-i", "p1")
- tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly")
- tg.wantNotStale("p2", "", "./testgo list claims p2 is stale, incorrectly")
- tg.sleep()
- if f, err := os.OpenFile(tg.path("d2/src/p2/p2.go"), os.O_WRONLY|os.O_APPEND, 0); err != nil {
- t.Fatal(err)
- } else if _, err = f.WriteString(`func G() {}`); err != nil {
- t.Fatal(err)
- } else {
- tg.must(f.Close())
- }
- tg.wantStale("p2", "build ID mismatch", "./testgo list claims p2 is NOT stale, incorrectly")
- tg.wantStale("p1", "stale dependency: p2", "./testgo list claims p1 is NOT stale, incorrectly")
-
- tg.run("install", "-i", "p1")
- tg.wantNotStale("p2", "", "./testgo list claims p2 is stale after reinstall, incorrectly")
- tg.wantNotStale("p1", "", "./testgo list claims p1 is stale after reinstall, incorrectly")
-}
-
-func TestGoInstallDetectsRemovedFiles(t *testing.T) {
- tg := testgo(t)
- defer tg.cleanup()
- tg.parallel()
- tg.tempFile("src/mypkg/x.go", `package mypkg`)
- tg.tempFile("src/mypkg/y.go", `package mypkg`)
- tg.tempFile("src/mypkg/z.go", `// +build missingtag
-
- package mypkg`)
- tg.setenv("GOPATH", tg.path("."))
- tg.run("install", "mypkg")
- tg.wantNotStale("mypkg", "", "./testgo list mypkg claims mypkg is stale, incorrectly")
- // z.go was not part of the build; removing it is okay.
- tg.must(os.Remove(tg.path("src/mypkg/z.go")))
- tg.wantNotStale("mypkg", "", "./testgo list mypkg claims mypkg is stale after removing z.go; should not be stale")
- // y.go was part of the package; removing it should be detected.
- tg.must(os.Remove(tg.path("src/mypkg/y.go")))
- tg.wantStale("mypkg", "build ID mismatch", "./testgo list mypkg claims mypkg is NOT stale after removing y.go; should be stale")
-}
-
-func TestWildcardMatchesSyntaxErrorDirs(t *testing.T) {
- tg := testgo(t)
- defer tg.cleanup()
- // TODO: tg.parallel()
- tg.tempFile("src/mypkg/x.go", `package mypkg`)
- tg.tempFile("src/mypkg/y.go", `pkg mypackage`)
- tg.setenv("GOPATH", tg.path("."))
- tg.cd(tg.path("src/mypkg"))
- tg.runFail("list", "./...")
- tg.runFail("build", "./...")
- tg.runFail("install", "./...")
-}
-
-func TestGoListWithTags(t *testing.T) {
- tg := testgo(t)
- defer tg.cleanup()
- tg.tempFile("src/mypkg/x.go", "// +build thetag\n\npackage mypkg\n")
- tg.setenv("GOPATH", tg.path("."))
- tg.cd(tg.path("./src"))
- tg.run("list", "-tags=thetag", "./my...")
- tg.grepStdout("mypkg", "did not find mypkg")
-}
-
-func TestGoInstallErrorOnCrossCompileToBin(t *testing.T) {
- if testing.Short() {
- t.Skip("don't install into GOROOT in short mode")
- }
-
- tg := testgo(t)
- defer tg.cleanup()
- tg.tempFile("src/mycmd/x.go", `package main
- func main() {}`)
- tg.setenv("GOPATH", tg.path("."))
- tg.cd(tg.path("src/mycmd"))
-
- tg.run("build", "mycmd")
-
- goarch := "386"
- if runtime.GOARCH == "386" {
- goarch = "amd64"
- }
- tg.setenv("GOOS", "linux")
- tg.setenv("GOARCH", goarch)
- tg.run("install", "mycmd")
- tg.setenv("GOBIN", tg.path("."))
- tg.runFail("install", "mycmd")
- tg.run("install", "cmd/pack")
-}
-
-func TestGoInstallDetectsRemovedFilesInPackageMain(t *testing.T) {
- tooSlow(t)
- tg := testgo(t)
- defer tg.cleanup()
- tg.parallel()
- tg.tempFile("src/mycmd/x.go", `package main
- func main() {}`)
- tg.tempFile("src/mycmd/y.go", `package main`)
- tg.tempFile("src/mycmd/z.go", `// +build missingtag
-
- package main`)
- tg.setenv("GOPATH", tg.path("."))
- tg.run("install", "mycmd")
- tg.wantNotStale("mycmd", "", "./testgo list mypkg claims mycmd is stale, incorrectly")
- // z.go was not part of the build; removing it is okay.
- tg.must(os.Remove(tg.path("src/mycmd/z.go")))
- tg.wantNotStale("mycmd", "", "./testgo list mycmd claims mycmd is stale after removing z.go; should not be stale")
- // y.go was part of the package; removing it should be detected.
- tg.must(os.Remove(tg.path("src/mycmd/y.go")))
- tg.wantStale("mycmd", "build ID mismatch", "./testgo list mycmd claims mycmd is NOT stale after removing y.go; should be stale")
-}
-
func testLocalRun(tg *testgoData, exepath, local, match string) {
tg.t.Helper()
out, err := exec.Command(exepath).Output()
@@ -1250,14 +1036,14 @@ func TestInternalPackagesInGOROOTAreRespected(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.runFail("build", "-v", "./testdata/testinternal")
- tg.grepBoth(`testinternal(\/|\\)p\.go\:3\:8\: use of internal package not allowed`, "wrong error message for testdata/testinternal")
+ tg.grepBoth(`testinternal(\/|\\)p\.go\:3\:8\: use of internal package net/http/internal not allowed`, "wrong error message for testdata/testinternal")
}
func TestInternalPackagesOutsideGOROOTAreRespected(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.runFail("build", "-v", "./testdata/testinternal2")
- tg.grepBoth(`testinternal2(\/|\\)p\.go\:3\:8\: use of internal package not allowed`, "wrote error message for testdata/testinternal2")
+ tg.grepBoth(`testinternal2(\/|\\)p\.go\:3\:8\: use of internal package .*internal/w not allowed`, "wrote error message for testdata/testinternal2")
}
func TestRunInternal(t *testing.T) {
@@ -1267,7 +1053,19 @@ func TestRunInternal(t *testing.T) {
tg.setenv("GOPATH", dir)
tg.run("run", filepath.Join(dir, "src/run/good.go"))
tg.runFail("run", filepath.Join(dir, "src/run/bad.go"))
- tg.grepStderr(`testdata(\/|\\)src(\/|\\)run(\/|\\)bad\.go\:3\:8\: use of internal package not allowed`, "unexpected error for run/bad.go")
+ tg.grepStderr(`testdata(\/|\\)src(\/|\\)run(\/|\\)bad\.go\:3\:8\: use of internal package run/subdir/internal/private not allowed`, "unexpected error for run/bad.go")
+}
+
+func TestRunPkg(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ dir := filepath.Join(tg.pwd(), "testdata")
+ tg.setenv("GOPATH", dir)
+ tg.run("run", "hello")
+ tg.grepStderr("hello, world", "did not find hello, world")
+ tg.cd(filepath.Join(dir, "src/hello"))
+ tg.run("run", ".")
+ tg.grepStderr("hello, world", "did not find hello, world")
}
func testMove(t *testing.T, vcs, url, base, config string) {
@@ -1368,6 +1166,41 @@ func TestImportCommentConflict(t *testing.T) {
tg.grepStderr("found import comments", "go build did not mention comment conflict")
}
+func TestImportCycle(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/importcycle"))
+ tg.runFail("build", "selfimport")
+
+ count := tg.grepCountBoth("import cycle not allowed")
+ if count == 0 {
+ t.Fatal("go build did not mention cyclical import")
+ }
+ if count > 1 {
+ t.Fatal("go build mentioned import cycle more than once")
+ }
+
+ // Don't hang forever.
+ tg.run("list", "-e", "-json", "selfimport")
+}
+
+func TestListImportMap(t *testing.T) {
+ skipIfGccgo(t, "gccgo does not have standard packages")
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.run("list", "-f", "{{.ImportPath}}: {{.ImportMap}}", "net", "fmt")
+ tg.grepStdout(`^net: map\[(.* )?golang_org/x/net/dns/dnsmessage:vendor/golang_org/x/net/dns/dnsmessage.*\]`, "net/http should have rewritten dnsmessage import")
+ tg.grepStdout(`^fmt: map\[\]`, "fmt should have no rewritten imports")
+ tg.run("list", "-deps", "-test", "-f", "{{.ImportPath}} MAP: {{.ImportMap}}\n{{.ImportPath}} IMPORT: {{.Imports}}", "fmt")
+ tg.grepStdout(`^flag \[fmt\.test\] MAP: map\[fmt:fmt \[fmt\.test\]\]`, "flag [fmt.test] should import fmt [fmt.test] as fmt")
+ tg.grepStdout(`^fmt\.test MAP: map\[(.* )?testing:testing \[fmt\.test\]`, "fmt.test should import testing [fmt.test] as testing")
+ tg.grepStdout(`^fmt\.test MAP: map\[(.* )?testing:testing \[fmt\.test\]`, "fmt.test should import testing [fmt.test] as testing")
+ tg.grepStdoutNot(`^fmt\.test MAP: map\[(.* )?os:`, "fmt.test should not import a modified os")
+ tg.grepStdout(`^fmt\.test IMPORT: \[fmt \[fmt\.test\] fmt_test \[fmt\.test\] os testing \[fmt\.test\] testing/internal/testdeps \[fmt\.test\]\]`, "wrong imports for fmt.test")
+}
+
// cmd/go: custom import path checking should not apply to Go packages without import comment.
func TestIssue10952(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
@@ -1459,6 +1292,7 @@ func TestGetGitDefaultBranch(t *testing.T) {
tg.grepStdout(`\* another-branch`, "not on correct default branch")
}
+// Security issue. Don't disable. See golang.org/issue/22125.
func TestAccidentalGitCheckout(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
if _, err := exec.LookPath("git"); err != nil {
@@ -1469,13 +1303,17 @@ func TestAccidentalGitCheckout(t *testing.T) {
defer tg.cleanup()
tg.parallel()
tg.tempDir("src")
+
tg.setenv("GOPATH", tg.path("."))
tg.runFail("get", "-u", "vcs-test.golang.org/go/test1-svn-git")
tg.grepStderr("src[\\\\/]vcs-test.* uses git, but parent .*src[\\\\/]vcs-test.* uses svn", "get did not fail for right reason")
- tg.runFail("get", "-u", "vcs-test.golang.org/go/test2-svn-git/test2main")
- tg.grepStderr("src[\\\\/]vcs-test.* uses git, but parent .*src[\\\\/]vcs-test.* uses svn", "get did not fail for right reason")
+ if _, err := os.Stat(tg.path("SrC")); err == nil {
+ // This case only triggers on a case-insensitive file system.
+ tg.runFail("get", "-u", "vcs-test.golang.org/go/test2-svn-git/test2main")
+ tg.grepStderr("src[\\\\/]vcs-test.* uses git, but parent .*src[\\\\/]vcs-test.* uses svn", "get did not fail for right reason")
+ }
}
func TestErrorMessageForSyntaxErrorInTestGoFileSaysFAIL(t *testing.T) {
@@ -1483,7 +1321,8 @@ func TestErrorMessageForSyntaxErrorInTestGoFileSaysFAIL(t *testing.T) {
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.runFail("test", "syntaxerror")
- tg.grepStderr("FAIL", "go test did not say FAIL")
+ tg.grepStderr("x_test.go:", "did not diagnose error")
+ tg.grepStdout("FAIL", "go test did not say FAIL")
}
func TestWildcardsDoNotLookInUselessDirectories(t *testing.T) {
@@ -1580,6 +1419,7 @@ func TestRelativeGOBINFail(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.tempFile("triv.go", `package main; func main() {}`)
+ tg.cd(tg.path("."))
tg.setenv("GOBIN", ".")
tg.runFail("install")
tg.grepStderr("cannot install, GOBIN must be an absolute path", "go install must fail if $GOBIN is a relative path")
@@ -1634,12 +1474,6 @@ func TestPackageMainTestCompilerFlags(t *testing.T) {
tg.grepStderr(`([\\/]compile|gccgo).* (-p p1|-fgo-pkgpath=p1).*p1\.go`, "should have run compile -p p1 p1.go")
}
-// The runtime version string takes one of two forms:
-// "go1.X[.Y]" for Go releases, and "devel +hash" at tip.
-// Determine whether we are in a released copy by
-// inspecting the version.
-var isGoRelease = strings.HasPrefix(runtime.Version(), "go1")
-
// Issue 12690
func TestPackageNotStaleWithTrailingSlash(t *testing.T) {
skipIfGccgo(t, "gccgo does not have GOROOT")
@@ -1727,8 +1561,8 @@ func TestGoGetTestOnlyPkg(t *testing.T) {
defer tg.cleanup()
tg.tempDir("gopath")
tg.setenv("GOPATH", tg.path("gopath"))
- tg.run("get", "golang.org/x/tour/content")
- tg.run("get", "-t", "golang.org/x/tour/content")
+ tg.run("get", "golang.org/x/tour/content...")
+ tg.run("get", "-t", "golang.org/x/tour/content...")
}
func TestInstalls(t *testing.T) {
@@ -1854,7 +1688,7 @@ func TestGoListStdDoesNotIncludeCommands(t *testing.T) {
}
func TestGoListCmdOnlyShowsCommands(t *testing.T) {
- skipIfGccgo(t, "gccgo has no GOROOT")
+ skipIfGccgo(t, "gccgo does not have GOROOT")
tooSlow(t)
tg := testgo(t)
defer tg.cleanup()
@@ -1894,6 +1728,118 @@ func TestGoListDeps(t *testing.T) {
tg.tempFile("src/p1/p2/p3/p4/p.go", "package p4\n")
tg.run("list", "-f", "{{.Deps}}", "p1")
tg.grepStdout("p1/p2/p3/p4", "Deps(p1) does not mention p4")
+
+ tg.run("list", "-deps", "p1")
+ tg.grepStdout("p1/p2/p3/p4", "-deps p1 does not mention p4")
+
+ if runtime.Compiler != "gccgo" {
+ // Check the list is in dependency order.
+ tg.run("list", "-deps", "math")
+ want := "internal/cpu\nunsafe\nmath\n"
+ out := tg.stdout.String()
+ if !strings.Contains(out, "internal/cpu") {
+ // Some systems don't use internal/cpu.
+ want = "unsafe\nmath\n"
+ }
+ if tg.stdout.String() != want {
+ t.Fatalf("list -deps math: wrong order\nhave %q\nwant %q", tg.stdout.String(), want)
+ }
+ }
+}
+
+func TestGoListTest(t *testing.T) {
+ skipIfGccgo(t, "gccgo does not have standard packages")
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.makeTempdir()
+ tg.setenv("GOCACHE", tg.tempdir)
+
+ tg.run("list", "-test", "-deps", "sort")
+ tg.grepStdout(`^sort.test$`, "missing test main")
+ tg.grepStdout(`^sort$`, "missing real sort")
+ tg.grepStdout(`^sort \[sort.test\]$`, "missing test copy of sort")
+ tg.grepStdout(`^testing \[sort.test\]$`, "missing test copy of testing")
+ tg.grepStdoutNot(`^testing$`, "unexpected real copy of testing")
+
+ tg.run("list", "-test", "sort")
+ tg.grepStdout(`^sort.test$`, "missing test main")
+ tg.grepStdout(`^sort$`, "missing real sort")
+ tg.grepStdout(`^sort \[sort.test\]$`, "unexpected test copy of sort")
+ tg.grepStdoutNot(`^testing \[sort.test\]$`, "unexpected test copy of testing")
+ tg.grepStdoutNot(`^testing$`, "unexpected real copy of testing")
+
+ tg.run("list", "-test", "cmd/dist", "cmd/doc")
+ tg.grepStdout(`^cmd/dist$`, "missing cmd/dist")
+ tg.grepStdout(`^cmd/doc$`, "missing cmd/doc")
+ tg.grepStdout(`^cmd/doc\.test$`, "missing cmd/doc test")
+ tg.grepStdoutNot(`^cmd/dist\.test$`, "unexpected cmd/dist test")
+ tg.grepStdoutNot(`^testing`, "unexpected testing")
+
+ tg.run("list", "-test", "runtime/cgo")
+ tg.grepStdout(`^runtime/cgo$`, "missing runtime/cgo")
+
+ tg.run("list", "-deps", "-f", "{{if .DepOnly}}{{.ImportPath}}{{end}}", "sort")
+ tg.grepStdout(`^reflect$`, "missing reflect")
+ tg.grepStdoutNot(`^sort`, "unexpected sort")
+}
+
+func TestGoListCompiledCgo(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.makeTempdir()
+ tg.setenv("GOCACHE", tg.tempdir)
+
+ tg.run("list", "-f", `{{join .CgoFiles "\n"}}`, "net")
+ if tg.stdout.String() == "" {
+ t.Skip("net does not use cgo")
+ }
+ if strings.Contains(tg.stdout.String(), tg.tempdir) {
+ t.Fatalf(".CgoFiles unexpectedly mentioned cache %s", tg.tempdir)
+ }
+ tg.run("list", "-compiled", "-f", `{{.Dir}}{{"\n"}}{{join .CompiledGoFiles "\n"}}`, "net")
+ if !strings.Contains(tg.stdout.String(), tg.tempdir) {
+ t.Fatalf(".CompiledGoFiles with -compiled did not mention cache %s", tg.tempdir)
+ }
+ dir := ""
+ for _, file := range strings.Split(tg.stdout.String(), "\n") {
+ if file == "" {
+ continue
+ }
+ if dir == "" {
+ dir = file
+ continue
+ }
+ if !strings.Contains(file, "/") && !strings.Contains(file, `\`) {
+ file = filepath.Join(dir, file)
+ }
+ if _, err := os.Stat(file); err != nil {
+ t.Fatalf("cannot find .CompiledGoFiles result %s: %v", file, err)
+ }
+ }
+}
+
+func TestGoListExport(t *testing.T) {
+ skipIfGccgo(t, "gccgo does not have standard packages")
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.makeTempdir()
+ tg.setenv("GOCACHE", tg.tempdir)
+
+ tg.run("list", "-f", "{{.Export}}", "strings")
+ if tg.stdout.String() != "" {
+ t.Fatalf(".Export without -export unexpectedly set")
+ }
+ tg.run("list", "-export", "-f", "{{.Export}}", "strings")
+ file := strings.TrimSpace(tg.stdout.String())
+ if file == "" {
+ t.Fatalf(".Export with -export was empty")
+ }
+ if _, err := os.Stat(file); err != nil {
+ t.Fatalf("cannot find .Export result %s: %v", file, err)
+ }
}
// Issue 4096. Validate the output of unsuccessful go install foo/quxx.
@@ -1966,6 +1912,17 @@ func homeEnvName() string {
}
}
+func tempEnvName() string {
+ switch runtime.GOOS {
+ case "windows":
+ return "TMP"
+ case "plan9":
+ return "TMPDIR" // actually plan 9 doesn't have one at all but this is fine
+ default:
+ return "TMPDIR"
+ }
+}
+
func TestDefaultGOPATH(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
@@ -2635,6 +2592,18 @@ func TestCoverageFunc(t *testing.T) {
tg.grepStdoutNot(`\tf\t*[0-9]`, "reported coverage for assembly function f")
}
+// Issue 24588.
+func TestCoverageDashC(t *testing.T) {
+ skipIfGccgo(t, "gccgo has no cover tool")
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.makeTempdir()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ tg.run("test", "-c", "-o", tg.path("coverdep"), "-coverprofile="+tg.path("no/such/dir/cover.out"), "coverdep")
+ tg.wantExecutable(tg.path("coverdep"), "go -test -c -coverprofile did not create executable")
+}
+
func TestPluginNonMain(t *testing.T) {
wd, err := os.Getwd()
if err != nil {
@@ -2845,7 +2814,7 @@ func TestCgoPkgConfig(t *testing.T) {
// OpenBSD's pkg-config is strict about whitespace and only
// supports backslash-escaped whitespace. It does not support
// quotes, which the normal freedesktop.org pkg-config does
- // support. See http://man.openbsd.org/pkg-config.1
+ // support. See https://man.openbsd.org/pkg-config.1
tg.tempFile("foo.pc", `
Name: foo
Description: The foo library
@@ -3048,11 +3017,25 @@ func TestBuildDashIInstallsDependencies(t *testing.T) {
checkbar("cmd")
}
-func TestGoBuildInTestOnlyDirectoryFailsWithAGoodError(t *testing.T) {
+func TestGoBuildTestOnly(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
- tg.runFail("build", "./testdata/testonly")
- tg.grepStderr("no non-test Go files in", "go build ./testdata/testonly produced unexpected error")
+ tg.makeTempdir()
+ tg.setenv("GOPATH", tg.path("."))
+ tg.tempFile("src/testonly/t_test.go", `package testonly`)
+ tg.tempFile("src/testonly2/t.go", `package testonly2`)
+ tg.cd(tg.path("src"))
+
+ // Named explicitly, test-only packages should be reported as unbuildable/uninstallable,
+ // even if there is a wildcard also matching.
+ tg.runFail("build", "testonly", "testonly...")
+ tg.grepStderr("no non-test Go files in", "go build ./xtestonly produced unexpected error")
+ tg.runFail("install", "./testonly")
+ tg.grepStderr("no non-test Go files in", "go install ./testonly produced unexpected error")
+
+ // Named through a wildcards, the test-only packages should be silently ignored.
+ tg.run("build", "testonly...")
+ tg.run("install", "./testonly...")
}
func TestGoTestDetectsTestOnlyImportCycles(t *testing.T) {
@@ -3088,6 +3071,9 @@ func TestGoTestMainAsNormalTest(t *testing.T) {
}
func TestGoTestMainTwice(t *testing.T) {
+ if testing.Short() {
+ t.Skip("Skipping in short mode")
+ }
tg := testgo(t)
defer tg.cleanup()
tg.makeTempdir()
@@ -3182,6 +3168,22 @@ func TestGoGenerateEnv(t *testing.T) {
}
}
+func TestGoGenerateXTestPkgName(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ t.Skip("skipping because windows has no echo command")
+ }
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.tempFile("env_test.go", "package main_test\n\n//go:generate echo $GOPACKAGE")
+ tg.run("generate", tg.path("env_test.go"))
+ want := "main_test"
+ if got := strings.TrimSpace(tg.getStdout()); got != want {
+ t.Errorf("go generate in XTest file got package name %q; want %q", got, want)
+ }
+}
+
func TestGoGenerateBadImports(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("skipping because windows has no echo command")
@@ -3549,24 +3551,43 @@ func TestImportLocal(t *testing.T) {
}
func TestGoGetInsecure(t *testing.T) {
- testenv.MustHaveExternalNetwork(t)
+ test := func(t *testing.T, modules bool) {
+ testenv.MustHaveExternalNetwork(t)
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.makeTempdir()
+ tg.failSSH()
+
+ if modules {
+ tg.setenv("GOPATH", tg.path("gp"))
+ tg.tempFile("go.mod", "module m")
+ tg.cd(tg.path("."))
+ tg.setenv("GO111MODULE", "on")
+ } else {
+ tg.setenv("GOPATH", tg.path("."))
+ tg.setenv("GO111MODULE", "off")
+ }
- tg := testgo(t)
- defer tg.cleanup()
- tg.makeTempdir()
- tg.setenv("GOPATH", tg.path("."))
- tg.failSSH()
+ const repo = "insecure.go-get-issue-15410.appspot.com/pkg/p"
- const repo = "insecure.go-get-issue-15410.appspot.com/pkg/p"
+ // Try go get -d of HTTP-only repo (should fail).
+ tg.runFail("get", "-d", repo)
- // Try go get -d of HTTP-only repo (should fail).
- tg.runFail("get", "-d", repo)
+ // Try again with -insecure (should succeed).
+ tg.run("get", "-d", "-insecure", repo)
- // Try again with -insecure (should succeed).
- tg.run("get", "-d", "-insecure", repo)
+ // Try updating without -insecure (should fail).
+ tg.runFail("get", "-d", "-u", "-f", repo)
+
+ if modules {
+ tg.run("list", "-m", "...")
+ tg.grepStdout("insecure.go-get-issue", "should find insecure module")
+ }
+ }
- // Try updating without -insecure (should fail).
- tg.runFail("get", "-d", "-u", "-f", repo)
+ t.Run("gopath", func(t *testing.T) { test(t, false) })
+ t.Run("modules", func(t *testing.T) { test(t, true) })
}
func TestGoGetUpdateInsecure(t *testing.T) {
@@ -3593,6 +3614,40 @@ func TestGoGetUpdateInsecure(t *testing.T) {
tg.run("get", "-d", "-u", "-f", "-insecure", pkg)
}
+func TestGoGetUpdateUnknownProtocol(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.makeTempdir()
+ tg.setenv("GOPATH", tg.path("."))
+
+ const repo = "github.com/golang/example"
+
+ // Clone the repo via HTTPS manually.
+ repoDir := tg.path("src/" + repo)
+ cmd := exec.Command("git", "clone", "-q", "https://"+repo, repoDir)
+ if out, err := cmd.CombinedOutput(); err != nil {
+ t.Fatalf("cloning %v repo: %v\n%s", repo, err, out)
+ }
+
+ // Configure the repo to use a protocol unknown to cmd/go
+ // that still actually works.
+ cmd = exec.Command("git", "remote", "set-url", "origin", "xyz://"+repo)
+ cmd.Dir = repoDir
+ if out, err := cmd.CombinedOutput(); err != nil {
+ t.Fatalf("git remote set-url: %v\n%s", err, out)
+ }
+ cmd = exec.Command("git", "config", "--local", "url.https://github.com/.insteadOf", "xyz://github.com/")
+ cmd.Dir = repoDir
+ if out, err := cmd.CombinedOutput(); err != nil {
+ t.Fatalf("git config: %v\n%s", err, out)
+ }
+
+ // We need -f to ignore import comments.
+ tg.run("get", "-d", "-u", "-f", repo+"/hello")
+}
+
func TestGoGetInsecureCustomDomain(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
@@ -4175,9 +4230,10 @@ func TestGoGetUpdateWithWildcard(t *testing.T) {
tg.setenv("GOPATH", tg.path("."))
const aPkgImportPath = "github.com/tmwh/go-get-issue-14450/a"
tg.run("get", aPkgImportPath)
- tg.run("get", "-u", ".../")
- tg.grepStderrNot("cannot find package", "did not update packages given wildcard path")
+ tg.runFail("get", "-u", ".../")
+ tg.grepStderr("cannot find package.*d-dependency/e", "should have detected e missing")
+ // Even though get -u failed, the source for others should be downloaded.
var expectedPkgPaths = []string{
"src/github.com/tmwh/go-get-issue-14450/b",
"src/github.com/tmwh/go-get-issue-14450-b-dependency/c",
@@ -4754,7 +4810,7 @@ func main() {}`)
before()
tg.run("install", "mycmd")
after()
- tg.wantStale("mycmd", "stale dependency: runtime/internal/sys", "should be stale after environment variable change")
+ tg.wantStale("mycmd", "stale dependency", "should be stale after environment variable change")
}
}
@@ -4795,34 +4851,34 @@ func TestTestRegexps(t *testing.T) {
// BenchmarkX/Y is run in full, twice
want := `=== RUN TestX
=== RUN TestX/Y
- x_test.go:6: LOG: X running
- x_test.go:8: LOG: Y running
+ x_test.go:6: LOG: X running
+ x_test.go:8: LOG: Y running
=== RUN TestXX
- z_test.go:10: LOG: XX running
+ z_test.go:10: LOG: XX running
=== RUN TestX
=== RUN TestX/Y
- x_test.go:6: LOG: X running
- x_test.go:8: LOG: Y running
+ x_test.go:6: LOG: X running
+ x_test.go:8: LOG: Y running
=== RUN TestXX
- z_test.go:10: LOG: XX running
+ z_test.go:10: LOG: XX running
--- BENCH: BenchmarkX/Y
- x_test.go:15: LOG: Y running N=1
- x_test.go:15: LOG: Y running N=100
- x_test.go:15: LOG: Y running N=10000
- x_test.go:15: LOG: Y running N=1000000
- x_test.go:15: LOG: Y running N=100000000
- x_test.go:15: LOG: Y running N=2000000000
+ x_test.go:15: LOG: Y running N=1
+ x_test.go:15: LOG: Y running N=100
+ x_test.go:15: LOG: Y running N=10000
+ x_test.go:15: LOG: Y running N=1000000
+ x_test.go:15: LOG: Y running N=100000000
+ x_test.go:15: LOG: Y running N=2000000000
--- BENCH: BenchmarkX/Y
- x_test.go:15: LOG: Y running N=1
- x_test.go:15: LOG: Y running N=100
- x_test.go:15: LOG: Y running N=10000
- x_test.go:15: LOG: Y running N=1000000
- x_test.go:15: LOG: Y running N=100000000
- x_test.go:15: LOG: Y running N=2000000000
+ x_test.go:15: LOG: Y running N=1
+ x_test.go:15: LOG: Y running N=100
+ x_test.go:15: LOG: Y running N=10000
+ x_test.go:15: LOG: Y running N=1000000
+ x_test.go:15: LOG: Y running N=100000000
+ x_test.go:15: LOG: Y running N=2000000000
--- BENCH: BenchmarkX
- x_test.go:13: LOG: X running N=1
+ x_test.go:13: LOG: X running N=1
--- BENCH: BenchmarkXX
- z_test.go:18: LOG: XX running N=1
+ z_test.go:18: LOG: XX running N=1
`
have := strings.Join(lines, "")
@@ -4857,7 +4913,8 @@ func TestBuildmodePIE(t *testing.T) {
platform := fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH)
switch platform {
case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x",
- "android/amd64", "android/arm", "android/arm64", "android/386":
+ "android/amd64", "android/arm", "android/arm64", "android/386",
+ "freebsd/amd64":
case "darwin/amd64":
default:
t.Skipf("skipping test because buildmode=pie is not supported on %s", platform)
@@ -4872,7 +4929,7 @@ func TestBuildmodePIE(t *testing.T) {
tg.run("build", "-buildmode=pie", "-o", obj, src)
switch runtime.GOOS {
- case "linux", "android":
+ case "linux", "android", "freebsd":
f, err := elf.Open(obj)
if err != nil {
t.Fatal(err)
@@ -4983,7 +5040,8 @@ func TestWrongGOOSErrorBeforeLoadError(t *testing.T) {
}
func TestUpxCompression(t *testing.T) {
- if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
+ if runtime.GOOS != "linux" ||
+ (runtime.GOARCH != "amd64" && runtime.GOARCH != "386") {
t.Skipf("skipping upx test on %s/%s", runtime.GOOS, runtime.GOARCH)
}
@@ -5036,79 +5094,47 @@ func TestUpxCompression(t *testing.T) {
}
}
-func TestGOTMPDIR(t *testing.T) {
- tg := testgo(t)
- defer tg.cleanup()
- tg.parallel()
- tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
- tg.makeTempdir()
- tg.setenv("GOTMPDIR", tg.tempdir)
- tg.setenv("GOCACHE", "off")
-
- // complex/x is a trivial non-main package.
- tg.run("build", "-work", "-x", "complex/w")
- tg.grepStderr("WORK="+regexp.QuoteMeta(tg.tempdir), "did not work in $GOTMPDIR")
-}
-
-func TestBuildCache(t *testing.T) {
- tooSlow(t)
- if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
- t.Skip("GODEBUG gocacheverify")
+// Test that Go binaries can be run under QEMU in user-emulation mode
+// (See issue #13024).
+func TestQEMUUserMode(t *testing.T) {
+ if testing.Short() && testenv.Builder() == "" {
+ t.Skipf("skipping in -short mode on non-builder")
}
- tg := testgo(t)
- defer tg.cleanup()
- tg.parallel()
- tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
- tg.makeTempdir()
- tg.setenv("GOCACHE", tg.tempdir)
-
- // complex/w is a trivial non-main package.
- // It imports nothing, so there should be no Deps.
- tg.run("list", "-f={{join .Deps \" \"}}", "complex/w")
- tg.grepStdoutNot(".+", "complex/w depends on unexpected packages")
-
- tg.run("build", "-x", "complex/w")
- tg.grepStderr(`[\\/]compile|gccgo`, "did not run compiler")
-
- tg.run("build", "-x", "complex/w")
- tg.grepStderrNot(`[\\/]compile|gccgo`, "ran compiler incorrectly")
-
- tg.run("build", "-a", "-x", "complex/w")
- tg.grepStderr(`[\\/]compile|gccgo`, "did not run compiler with -a")
-
- // complex is a non-trivial main package.
- // the link step should not be cached.
- tg.run("build", "-o", os.DevNull, "-x", "complex")
- tg.grepStderr(`[\\/]link|gccgo`, "did not run linker")
- tg.run("build", "-o", os.DevNull, "-x", "complex")
- tg.grepStderr(`[\\/]link|gccgo`, "did not run linker")
-}
-
-func TestCacheOutput(t *testing.T) {
- // Test that command output is cached and replayed too.
- if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
- t.Skip("GODEBUG gocacheverify")
+ testArchs := []struct {
+ g, qemu string
+ }{
+ {"arm", "arm"},
+ {"arm64", "aarch64"},
}
+
tg := testgo(t)
defer tg.cleanup()
+ tg.tempFile("main.go", `package main; import "fmt"; func main() { fmt.Print("hello qemu-user") }`)
tg.parallel()
- tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
- tg.makeTempdir()
- tg.setenv("GOCACHE", tg.tempdir)
+ src, obj := tg.path("main.go"), tg.path("main")
- tg.run("build", "-gcflags=-m", "errors")
- stdout1 := tg.getStdout()
- stderr1 := tg.getStderr()
+ for _, arch := range testArchs {
+ out, err := exec.Command("qemu-"+arch.qemu, "--version").CombinedOutput()
+ if err != nil {
+ t.Logf("Skipping %s test (qemu-%s not available)", arch.g, arch.qemu)
+ continue
+ }
- tg.run("build", "-gcflags=-m", "errors")
- stdout2 := tg.getStdout()
- stderr2 := tg.getStderr()
+ tg.setenv("GOARCH", arch.g)
+ tg.run("build", "-o", obj, src)
- if stdout2 != stdout1 || stderr2 != stderr1 {
- t.Errorf("cache did not reproduce output:\n\nstdout1:\n%s\n\nstdout2:\n%s\n\nstderr1:\n%s\n\nstderr2:\n%s",
- stdout1, stdout2, stderr1, stderr2)
+ out, err = exec.Command("qemu-"+arch.qemu, obj).CombinedOutput()
+ if err != nil {
+ t.Logf("qemu-%s output:\n%s\n", arch.qemu, out)
+ t.Errorf("qemu-%s failed with %v", arch.qemu, err)
+ continue
+ }
+ if want := "hello qemu-user"; string(out) != want {
+ t.Errorf("bad output from qemu-%s:\ngot %s; want %s", arch.qemu, out, want)
+ }
}
+
}
func TestCacheListStale(t *testing.T) {
@@ -5151,6 +5177,32 @@ func TestCacheCoverage(t *testing.T) {
tg.run("test", "-cover", "-short", "math", "strings")
}
+func TestCacheVet(t *testing.T) {
+ skipIfGccgo(t, "gccgo has no standard packages")
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+
+ if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
+ t.Skip("GODEBUG gocacheverify")
+ }
+ if os.Getenv("GOCACHE") == "off" {
+ tooSlow(t)
+ tg.makeTempdir()
+ tg.setenv("GOCACHE", tg.path("cache"))
+ }
+
+ // Check that second vet reuses cgo-derived inputs.
+ // The first command could be build instead of vet,
+ // except that if the cache is empty and there's a net.a
+ // in GOROOT/pkg, the build will not bother to regenerate
+ // and cache the cgo outputs, whereas vet always will.
+ tg.run("vet", "os/user")
+ tg.run("vet", "-x", "os/user")
+ tg.grepStderrNot(`^(clang|gcc)`, "should not have run compiler")
+ tg.grepStderrNot(`[\\/]cgo `, "should not have run cgo")
+}
+
func TestIssue22588(t *testing.T) {
// Don't get confused by stderr coming from tools.
tg := testgo(t)
@@ -5241,14 +5293,14 @@ func TestTestCache(t *testing.T) {
// timeout here should not affect result being cached
// or being retrieved later.
tg.run("test", "-x", "-timeout=10s", "errors")
- tg.grepStderr(`[\\/](compile|gccgo) `, "did not run compiler")
- tg.grepStderr(`[\\/](link|gccgo) `, "did not run linker")
+ tg.grepStderr(`[\\/]compile|gccgo`, "did not run compiler")
+ tg.grepStderr(`[\\/]link|gccgo`, "did not run linker")
tg.grepStderr(`errors\.test`, "did not run test")
tg.run("test", "-x", "errors")
tg.grepStdout(`ok \terrors\t\(cached\)`, "did not report cached result")
- tg.grepStderrNot(`[\\/](compile|gccgo) `, "incorrectly ran compiler")
- tg.grepStderrNot(`[\\/](link|gccgo) `, "incorrectly ran linker")
+ tg.grepStderrNot(`[\\/]compile|gccgo`, "incorrectly ran compiler")
+ tg.grepStderrNot(`[\\/]link|gccgo`, "incorrectly ran linker")
tg.grepStderrNot(`errors\.test`, "incorrectly ran test")
tg.grepStderrNot("DO NOT USE", "poisoned action status leaked")
@@ -5520,9 +5572,29 @@ func TestTestVet(t *testing.T) {
tg.runFail("test", "vetfail/...")
tg.grepStderr(`Printf format %d`, "did not diagnose bad Printf")
tg.grepStdout(`ok\s+vetfail/p2`, "did not run vetfail/p2")
+
+ // Use -a so that we need to recompute the vet-specific export data for
+ // vetfail/p1.
+ tg.run("test", "-a", "vetfail/p2")
+ tg.grepStderrNot(`invalid.*constraint`, "did diagnose bad build constraint in vetxonly mode")
+}
+
+func TestTestSkipVetAfterFailedBuild(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+
+ tg.tempFile("x_test.go", `package x
+ func f() {
+ return 1
+ }
+ `)
+
+ tg.runFail("test", tg.path("x_test.go"))
+ tg.grepStderrNot(`vet`, "vet should be skipped after the failed build")
}
-func TestTestRebuild(t *testing.T) {
+func TestTestVetRebuild(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.parallel()
@@ -5558,6 +5630,7 @@ func TestTestRebuild(t *testing.T) {
tg.setenv("GOPATH", tg.path("."))
tg.run("test", "b")
+ tg.run("vet", "b")
}
func TestInstallDeps(t *testing.T) {
@@ -5619,37 +5692,6 @@ func TestRelativePkgdir(t *testing.T) {
tg.run("build", "-i", "-pkgdir=.", "runtime")
}
-func TestGcflagsPatterns(t *testing.T) {
- skipIfGccgo(t, "gccgo has no standard packages")
- tg := testgo(t)
- defer tg.cleanup()
- tg.setenv("GOPATH", "")
- tg.setenv("GOCACHE", "off")
-
- tg.run("build", "-n", "-v", "-gcflags= \t\r\n -e", "fmt")
- tg.grepStderr("^# fmt", "did not rebuild fmt")
- tg.grepStderrNot("^# reflect", "incorrectly rebuilt reflect")
-
- tg.run("build", "-n", "-v", "-gcflags=-e", "fmt", "reflect")
- tg.grepStderr("^# fmt", "did not rebuild fmt")
- tg.grepStderr("^# reflect", "did not rebuild reflect")
- tg.grepStderrNot("^# runtime", "incorrectly rebuilt runtime")
-
- tg.run("build", "-n", "-x", "-v", "-gcflags= \t\r\n reflect \t\r\n = \t\r\n -N", "fmt")
- tg.grepStderr("^# fmt", "did not rebuild fmt")
- tg.grepStderr("^# reflect", "did not rebuild reflect")
- tg.grepStderr("compile.* -N .*-p reflect", "did not build reflect with -N flag")
- tg.grepStderrNot("compile.* -N .*-p fmt", "incorrectly built fmt with -N flag")
-
- tg.run("test", "-c", "-n", "-gcflags=-N", "-ldflags=-X=x.y=z", "strings")
- tg.grepStderr("compile.* -N .*compare_test.go", "did not compile strings_test package with -N flag")
- tg.grepStderr("link.* -X=x.y=z", "did not link strings.test binary with -X flag")
-
- tg.run("test", "-c", "-n", "-gcflags=strings=-N", "-ldflags=strings=-X=x.y=z", "strings")
- tg.grepStderr("compile.* -N .*compare_test.go", "did not compile strings_test package with -N flag")
- tg.grepStderr("link.* -X=x.y=z", "did not link strings.test binary with -X flag")
-}
-
func TestGoTestMinusN(t *testing.T) {
// Intent here is to verify that 'go test -n' works without crashing.
// This reuses flag_test.go, but really any test would do.
@@ -5726,6 +5768,9 @@ func TestFailFast(t *testing.T) {
// non-parallel subtests:
{"TestFailingSubtestsA", true, 1},
{"TestFailingSubtestsA", false, 2},
+ // fatal test
+ {"TestFatal[CD]", true, 1},
+ {"TestFatal[CD]", false, 2},
}
for _, tt := range tests {
@@ -5789,59 +5834,6 @@ func init() {}
tg.run("test", "a")
}
-// Issue 23150.
-func TestCpuprofileTwice(t *testing.T) {
- tg := testgo(t)
- defer tg.cleanup()
- tg.parallel()
- tg.tempFile("prof/src/x/x_test.go", `
- package x_test
- import (
- "testing"
- "time"
- )
- func TestSleep(t *testing.T) { time.Sleep(10 * time.Millisecond) }`)
- tg.setenv("GOPATH", tg.path("prof"))
- bin := tg.path("x.test")
- out := tg.path("cpu.out")
- tg.run("test", "-o="+bin, "-cpuprofile="+out, "x")
- tg.must(os.Remove(out))
- tg.run("test", "-o="+bin, "-cpuprofile="+out, "x")
- tg.mustExist(out)
-}
-
-// Issue 23694.
-func TestAtomicCoverpkgAll(t *testing.T) {
- skipIfGccgo(t, "gccgo has no cover tool")
- tg := testgo(t)
- defer tg.cleanup()
- tg.parallel()
-
- tg.tempFile("src/x/x.go", `package x; import _ "sync/atomic"; func F() {}`)
- tg.tempFile("src/x/x_test.go", `package x; import "testing"; func TestF(t *testing.T) { F() }`)
- tg.setenv("GOPATH", tg.path("."))
- tg.run("test", "-coverpkg=all", "-covermode=atomic", "x")
- if canRace {
- tg.run("test", "-coverpkg=all", "-race", "x")
- }
-}
-
-// Issue 23882.
-func TestCoverpkgAllRuntime(t *testing.T) {
- skipIfGccgo(t, "gccgo has no cover tool")
- tg := testgo(t)
- defer tg.cleanup()
- tg.parallel()
-
- tg.tempFile("src/x/x.go", `package x; import _ "runtime"; func F() {}`)
- tg.tempFile("src/x/x_test.go", `package x; import "testing"; func TestF(t *testing.T) { F() }`)
- tg.setenv("GOPATH", tg.path("."))
- tg.run("test", "-coverpkg=all", "x")
- if canRace {
- tg.run("test", "-coverpkg=all", "-race", "x")
- }
-}
-
func TestBadCommandLines(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
@@ -5871,12 +5863,12 @@ func TestBadCommandLines(t *testing.T) {
tg.tempFile("src/@x/x.go", "package x\n")
tg.setenv("GOPATH", tg.path("."))
tg.runFail("build", "@x")
- tg.grepStderr("invalid input directory name \"@x\"", "did not reject @x directory")
+ tg.grepStderr("invalid input directory name \"@x\"|cannot use path@version syntax", "did not reject @x directory")
tg.tempFile("src/@x/y/y.go", "package y\n")
tg.setenv("GOPATH", tg.path("."))
tg.runFail("build", "@x/y")
- tg.grepStderr("invalid import path \"@x/y\"", "did not reject @x/y import path")
+ tg.grepStderr("invalid import path \"@x/y\"|cannot use path@version syntax", "did not reject @x/y import path")
tg.tempFile("src/-x/x.go", "package x\n")
tg.setenv("GOPATH", tg.path("."))
@@ -6032,3 +6024,198 @@ echo $* >>`+tg.path("pkg-config.out"))
t.Errorf("got %q want %q", out, want)
}
}
+
+func TestCgoCache(t *testing.T) {
+ if !canCgo {
+ t.Skip("no cgo")
+ }
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.tempFile("src/x/a.go", `package main
+ // #ifndef VAL
+ // #define VAL 0
+ // #endif
+ // int val = VAL;
+ import "C"
+ import "fmt"
+ func main() { fmt.Println(C.val) }
+ `)
+ tg.setenv("GOPATH", tg.path("."))
+ exe := tg.path("x.exe")
+ tg.run("build", "-o", exe, "x")
+ tg.setenv("CGO_LDFLAGS", "-lnosuchlibraryexists")
+ tg.runFail("build", "-o", exe, "x")
+ tg.grepStderr(`nosuchlibraryexists`, "did not run linker with changed CGO_LDFLAGS")
+}
+
+// Issue 23982
+func TestFilepathUnderCwdFormat(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.run("test", "-x", "-cover", "log")
+ tg.grepStderrNot(`\.log\.cover\.go`, "-x output should contain correctly formatted filepath under cwd")
+}
+
+// Issue 24396.
+func TestDontReportRemoveOfEmptyDir(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.tempFile("src/a/a.go", `package a`)
+ tg.setenv("GOPATH", tg.path("."))
+ tg.run("install", "-x", "a")
+ tg.run("install", "-x", "a")
+ // The second install should have printed only a WORK= line,
+ // nothing else.
+ if bytes.Count(tg.stdout.Bytes(), []byte{'\n'})+bytes.Count(tg.stderr.Bytes(), []byte{'\n'}) > 1 {
+ t.Error("unnecessary output when installing installed package")
+ }
+}
+
+// Issue 23264.
+func TestNoRelativeTmpdir(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+
+ tg.tempFile("src/a/a.go", `package a`)
+ tg.cd(tg.path("."))
+ tg.must(os.Mkdir("tmp", 0777))
+
+ tg.setenv("GOCACHE", "off")
+ tg.setenv("GOPATH", tg.path("."))
+ tg.setenv("GOTMPDIR", "tmp")
+ tg.run("build", "-work", "a")
+ tg.grepStderr("WORK=[^t]", "work should be absolute path")
+
+ tg.unsetenv("GOTMPDIR")
+ tg.setenv("TMP", "tmp") // windows
+ tg.setenv("TMPDIR", "tmp") // unix
+ tg.run("build", "-work", "a")
+ tg.grepStderr("WORK=[^t]", "work should be absolute path")
+}
+
+// Issue 24704.
+func TestLinkerTmpDirIsDeleted(t *testing.T) {
+ skipIfGccgo(t, "gccgo does not use cmd/link")
+ if !canCgo {
+ t.Skip("skipping because cgo not enabled")
+ }
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.tempFile("a.go", `package main; import "C"; func main() {}`)
+ tg.run("build", "-ldflags", "-v", "-o", os.DevNull, tg.path("a.go"))
+ // Find line that has "host link:" in linker output.
+ stderr := tg.getStderr()
+ var hostLinkLine string
+ for _, line := range strings.Split(stderr, "\n") {
+ if !strings.Contains(line, "host link:") {
+ continue
+ }
+ hostLinkLine = line
+ break
+ }
+ if hostLinkLine == "" {
+ t.Fatal(`fail to find with "host link:" string in linker output`)
+ }
+ // Find parameter, like "/tmp/go-link-408556474/go.o" inside of
+ // "host link:" line, and extract temp directory /tmp/go-link-408556474
+ // out of it.
+ tmpdir := hostLinkLine
+ i := strings.Index(tmpdir, `go.o"`)
+ if i == -1 {
+ t.Fatalf(`fail to find "go.o" in "host link:" line %q`, hostLinkLine)
+ }
+ tmpdir = tmpdir[:i-1]
+ i = strings.LastIndex(tmpdir, `"`)
+ if i == -1 {
+ t.Fatalf(`fail to find " in "host link:" line %q`, hostLinkLine)
+ }
+ tmpdir = tmpdir[i+1:]
+ // Verify that temp directory has been removed.
+ _, err := os.Stat(tmpdir)
+ if err == nil {
+ t.Fatalf("temp directory %q has not been removed", tmpdir)
+ }
+ if !os.IsNotExist(err) {
+ t.Fatalf("Stat(%q) returns unexpected error: %v", tmpdir, err)
+ }
+}
+
+func testCDAndGOPATHAreDifferent(tg *testgoData, cd, gopath string) {
+ skipIfGccgo(tg.t, "gccgo does not support -ldflags -X")
+ tg.setenv("GOPATH", gopath)
+
+ tg.tempDir("dir")
+ exe := tg.path("dir/a.exe")
+
+ tg.cd(cd)
+
+ tg.run("build", "-o", exe, "-ldflags", "-X=my.pkg.Text=linkXworked")
+ out, err := exec.Command(exe).CombinedOutput()
+ if err != nil {
+ tg.t.Fatal(err)
+ }
+ if string(out) != "linkXworked\n" {
+ tg.t.Errorf(`incorrect output with GOPATH=%q and CD=%q: expected "linkXworked\n", but have %q`, gopath, cd, string(out))
+ }
+}
+
+func TestCDAndGOPATHAreDifferent(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+
+ gopath := filepath.Join(tg.pwd(), "testdata")
+ cd := filepath.Join(gopath, "src/my.pkg/main")
+
+ testCDAndGOPATHAreDifferent(tg, cd, gopath)
+ if runtime.GOOS == "windows" {
+ testCDAndGOPATHAreDifferent(tg, cd, strings.Replace(gopath, `\`, `/`, -1))
+ testCDAndGOPATHAreDifferent(tg, cd, strings.ToUpper(gopath))
+ testCDAndGOPATHAreDifferent(tg, cd, strings.ToLower(gopath))
+ }
+}
+
+// Issue 26242.
+func TestGoTestWithoutTests(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ tg.run("test", "testnorun")
+ tg.grepStdout(`testnorun\t\[no test files\]`, "do not want test to run")
+}
+
+// Issue 25579.
+func TestGoBuildDashODevNull(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ tg.run("build", "-o", os.DevNull, filepath.Join(tg.pwd(), "testdata", "src", "hello", "hello.go"))
+ tg.mustNotExist("hello")
+ tg.mustNotExist("hello.exe")
+}
+
+// Issue 25093.
+func TestCoverpkgTestOnly(t *testing.T) {
+ skipIfGccgo(t, "gccgo has no cover tool")
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.tempFile("src/a/a.go", `package a
+ func F(i int) int {
+ return i*i
+ }`)
+ tg.tempFile("src/atest/a_test.go", `
+ package a_test
+ import ( "a"; "testing" )
+ func TestF(t *testing.T) { a.F(2) }
+ `)
+ tg.setenv("GOPATH", tg.path("."))
+ tg.run("test", "-coverpkg=a", "atest")
+ tg.grepStderrNot("no packages being tested depend on matches", "bad match message")
+ tg.grepStdout("coverage: 100", "no coverage")
+}
diff --git a/libgo/go/cmd/go/go_windows_test.go b/libgo/go/cmd/go/go_windows_test.go
index aa68a195802..99af3d43dcc 100644
--- a/libgo/go/cmd/go/go_windows_test.go
+++ b/libgo/go/cmd/go/go_windows_test.go
@@ -12,7 +12,6 @@ import (
"os/exec"
"path/filepath"
"strings"
- "syscall"
"testing"
)
@@ -57,15 +56,6 @@ func TestAbsolutePath(t *testing.T) {
}
}
-func isWindowsXP(t *testing.T) bool {
- v, err := syscall.GetVersion()
- if err != nil {
- t.Fatalf("GetVersion failed: %v", err)
- }
- major := byte(v)
- return major < 6
-}
-
func runIcacls(t *testing.T, args ...string) string {
t.Helper()
out, err := exec.Command("icacls", args...).CombinedOutput()
@@ -89,10 +79,6 @@ func runGetACL(t *testing.T, path string) string {
// has discretionary access control list (DACL) set as if the file
// was created in the destination directory.
func TestACL(t *testing.T) {
- if isWindowsXP(t) {
- t.Skip("Windows XP does not have powershell command")
- }
-
tmpdir, err := ioutil.TempDir("", "TestACL")
if err != nil {
t.Fatal(err)
@@ -111,7 +97,7 @@ func TestACL(t *testing.T) {
// will make all files created in TestACL/tmp have different
// security attributes to the files created in TestACL.
runIcacls(t, newtmpdir,
- "/grant", "guest:(oi)(ci)f", // add Guest user to have full access
+ "/grant", "*S-1-5-32-546:(oi)(ci)f", // add Guests group to have full access
)
src := filepath.Join(tmpdir, "main.go")
diff --git a/libgo/go/cmd/go/internal/base/base.go b/libgo/go/cmd/go/internal/base/base.go
index 286efbc0410..e7f54c9a365 100644
--- a/libgo/go/cmd/go/internal/base/base.go
+++ b/libgo/go/cmd/go/internal/base/base.go
@@ -45,25 +45,43 @@ type Command struct {
// CustomFlags indicates that the command will do its own
// flag parsing.
CustomFlags bool
+
+ // Commands lists the available commands and help topics.
+ // The order here is the order in which they are printed by 'go help'.
+ // Note that subcommands are in general best avoided.
+ Commands []*Command
}
-// Commands lists the available commands and help topics.
-// The order here is the order in which they are printed by 'go help'.
-var Commands []*Command
+var Go = &Command{
+ UsageLine: "go",
+ Long: `Go is a tool for managing Go source code.`,
+ // Commands initialized in package main
+}
-// Name returns the command's name: the first word in the usage line.
-func (c *Command) Name() string {
+// LongName returns the command's long name: all the words in the usage line between "go" and a flag or argument,
+func (c *Command) LongName() string {
name := c.UsageLine
- i := strings.Index(name, " ")
- if i >= 0 {
+ if i := strings.Index(name, " ["); i >= 0 {
name = name[:i]
}
+ if name == "go" {
+ return ""
+ }
+ return strings.TrimPrefix(name, "go ")
+}
+
+// Name returns the command's short name: the last word in the usage line before a flag or argument.
+func (c *Command) Name() string {
+ name := c.LongName()
+ if i := strings.LastIndex(name, " "); i >= 0 {
+ name = name[i+1:]
+ }
return name
}
func (c *Command) Usage() {
fmt.Fprintf(os.Stderr, "usage: %s\n", c.UsageLine)
- fmt.Fprintf(os.Stderr, "Run 'go help %s' for details.\n", c.Name())
+ fmt.Fprintf(os.Stderr, "Run 'go help %s' for details.\n", c.LongName())
os.Exit(2)
}
diff --git a/libgo/go/cmd/go/internal/base/goflags.go b/libgo/go/cmd/go/internal/base/goflags.go
new file mode 100644
index 00000000000..2f50b50bfcf
--- /dev/null
+++ b/libgo/go/cmd/go/internal/base/goflags.go
@@ -0,0 +1,152 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package base
+
+import (
+ "flag"
+ "fmt"
+ "os"
+ "runtime"
+ "strings"
+
+ "cmd/go/internal/cfg"
+)
+
+var (
+ goflags []string // cached $GOFLAGS list; can be -x or --x form
+ knownFlag = make(map[string]bool) // flags allowed to appear in $GOFLAGS; no leading dashes
+)
+
+// AddKnownFlag adds name to the list of known flags for use in $GOFLAGS.
+func AddKnownFlag(name string) {
+ knownFlag[name] = true
+}
+
+// GOFLAGS returns the flags from $GOFLAGS.
+// The list can be assumed to contain one string per flag,
+// with each string either beginning with -name or --name.
+func GOFLAGS() []string {
+ InitGOFLAGS()
+ return goflags
+}
+
+// InitGOFLAGS initializes the goflags list from $GOFLAGS.
+// If goflags is already initialized, it does nothing.
+func InitGOFLAGS() {
+ if goflags != nil { // already initialized
+ return
+ }
+
+ // Build list of all flags for all commands.
+ // If no command has that flag, then we report the problem.
+ // This catches typos while still letting users record flags in GOFLAGS
+ // that only apply to a subset of go commands.
+ // Commands using CustomFlags can report their flag names
+ // by calling AddKnownFlag instead.
+ var walkFlags func(*Command)
+ walkFlags = func(cmd *Command) {
+ for _, sub := range cmd.Commands {
+ walkFlags(sub)
+ }
+ cmd.Flag.VisitAll(func(f *flag.Flag) {
+ knownFlag[f.Name] = true
+ })
+ }
+ walkFlags(Go)
+
+ // Ignore bad flag in go env and go bug, because
+ // they are what people reach for when debugging
+ // a problem, and maybe they're debugging GOFLAGS.
+ // (Both will show the GOFLAGS setting if let succeed.)
+ hideErrors := cfg.CmdName == "env" || cfg.CmdName == "bug"
+
+ goflags = strings.Fields(os.Getenv("GOFLAGS"))
+ if goflags == nil {
+ goflags = []string{} // avoid work on later InitGOFLAGS call
+ }
+
+ // Each of the words returned by strings.Fields must be its own flag.
+ // To set flag arguments use -x=value instead of -x value.
+ // For boolean flags, -x is fine instead of -x=true.
+ for _, f := range goflags {
+ // Check that every flag looks like -x --x -x=value or --x=value.
+ if !strings.HasPrefix(f, "-") || f == "-" || f == "--" || strings.HasPrefix(f, "---") || strings.HasPrefix(f, "-=") || strings.HasPrefix(f, "--=") {
+ if hideErrors {
+ continue
+ }
+ Fatalf("go: parsing $GOFLAGS: non-flag %q", f)
+ }
+
+ name := f[1:]
+ if name[0] == '-' {
+ name = name[1:]
+ }
+ if i := strings.Index(name, "="); i >= 0 {
+ name = name[:i]
+ }
+ if !knownFlag[name] {
+ if hideErrors {
+ continue
+ }
+ Fatalf("go: parsing $GOFLAGS: unknown flag -%s", name)
+ }
+ }
+}
+
+// boolFlag is the optional interface for flag.Value known to the flag package.
+// (It is not clear why package flag does not export this interface.)
+type boolFlag interface {
+ flag.Value
+ IsBoolFlag() bool
+}
+
+// SetFromGOFLAGS sets the flags in the given flag set using settings in $GOFLAGS.
+func SetFromGOFLAGS(flags flag.FlagSet) {
+ InitGOFLAGS()
+
+ // This loop is similar to flag.Parse except that it ignores
+ // unknown flags found in goflags, so that setting, say, GOFLAGS=-ldflags=-w
+ // does not break commands that don't have a -ldflags.
+ // It also adjusts the output to be clear that the reported problem is from $GOFLAGS.
+ where := "$GOFLAGS"
+ if runtime.GOOS == "windows" {
+ where = "%GOFLAGS%"
+ }
+ for _, goflag := range goflags {
+ name, value, hasValue := goflag, "", false
+ if i := strings.Index(goflag, "="); i >= 0 {
+ name, value, hasValue = goflag[:i], goflag[i+1:], true
+ }
+ if strings.HasPrefix(name, "--") {
+ name = name[1:]
+ }
+ f := flags.Lookup(name[1:])
+ if f == nil {
+ continue
+ }
+ if fb, ok := f.Value.(boolFlag); ok && fb.IsBoolFlag() {
+ if hasValue {
+ if err := fb.Set(value); err != nil {
+ fmt.Fprintf(flags.Output(), "go: invalid boolean value %q for flag %s (from %s): %v\n", value, name, where, err)
+ flags.Usage()
+ }
+ } else {
+ if err := fb.Set("true"); err != nil {
+ fmt.Fprintf(flags.Output(), "go: invalid boolean flag %s (from %s): %v\n", name, where, err)
+ flags.Usage()
+ }
+ }
+ } else {
+ if !hasValue {
+ fmt.Fprintf(flags.Output(), "go: flag needs an argument: %s (from %s)\n", name, where)
+ flags.Usage()
+ }
+ if err := f.Value.Set(value); err != nil {
+ fmt.Fprintf(flags.Output(), "go: invalid value %q for flag %s (from %s): %v\n", value, name, where, err)
+ flags.Usage()
+ }
+ }
+ }
+}
diff --git a/libgo/go/cmd/go/internal/base/signal_unix.go b/libgo/go/cmd/go/internal/base/signal_unix.go
index b90f3a2f191..c109eecadb3 100644
--- a/libgo/go/cmd/go/internal/base/signal_unix.go
+++ b/libgo/go/cmd/go/internal/base/signal_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build aix darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd js linux nacl netbsd openbsd solaris
package base
diff --git a/libgo/go/cmd/go/internal/bug/bug.go b/libgo/go/cmd/go/internal/bug/bug.go
index 963da94c493..e701f6eac9c 100644
--- a/libgo/go/cmd/go/internal/bug/bug.go
+++ b/libgo/go/cmd/go/internal/bug/bug.go
@@ -25,7 +25,7 @@ import (
var CmdBug = &base.Command{
Run: runBug,
- UsageLine: "bug",
+ UsageLine: "go bug",
Short: "start a bug report",
Long: `
Bug opens the default browser and starts a new bug report.
@@ -38,6 +38,9 @@ func init() {
}
func runBug(cmd *base.Command, args []string) {
+ if len(args) > 0 {
+ base.Fatalf("go bug: bug takes no arguments")
+ }
var buf bytes.Buffer
buf.WriteString(bugHeader)
inspectGoVersion(&buf)
diff --git a/libgo/go/cmd/go/internal/cache/cache.go b/libgo/go/cmd/go/internal/cache/cache.go
index edb58826f17..0cf01550ff9 100644
--- a/libgo/go/cmd/go/internal/cache/cache.go
+++ b/libgo/go/cmd/go/internal/cache/cache.go
@@ -189,6 +189,21 @@ func (c *Cache) get(id ActionID) (Entry, error) {
return Entry{buf, size, time.Unix(0, tm)}, nil
}
+// GetFile looks up the action ID in the cache and returns
+// the name of the corresponding data file.
+func (c *Cache) GetFile(id ActionID) (file string, entry Entry, err error) {
+ entry, err = c.Get(id)
+ if err != nil {
+ return "", Entry{}, err
+ }
+ file = c.OutputFile(entry.OutputID)
+ info, err := os.Stat(file)
+ if err != nil || info.Size() != entry.Size {
+ return "", Entry{}, errMissing
+ }
+ return file, entry, nil
+}
+
// GetBytes looks up the action ID in the cache and returns
// the corresponding output bytes.
// GetBytes should only be used for data that can be expected to fit in memory.
diff --git a/libgo/go/cmd/go/internal/cache/default.go b/libgo/go/cmd/go/internal/cache/default.go
index 97283762258..02fc1e896f7 100644
--- a/libgo/go/cmd/go/internal/cache/default.go
+++ b/libgo/go/cmd/go/internal/cache/default.go
@@ -35,12 +35,14 @@ See golang.org to learn more about Go.
// initDefaultCache does the work of finding the default cache
// the first time Default is called.
func initDefaultCache() {
- dir := DefaultDir()
+ dir, showWarnings := defaultDir()
if dir == "off" {
return
}
if err := os.MkdirAll(dir, 0777); err != nil {
- fmt.Fprintf(os.Stderr, "go: disabling cache (%s) due to initialization failure: %s\n", dir, err)
+ if showWarnings {
+ fmt.Fprintf(os.Stderr, "go: disabling cache (%s) due to initialization failure: %s\n", dir, err)
+ }
return
}
if _, err := os.Stat(filepath.Join(dir, "README")); err != nil {
@@ -50,7 +52,9 @@ func initDefaultCache() {
c, err := Open(dir)
if err != nil {
- fmt.Fprintf(os.Stderr, "go: disabling cache (%s) due to initialization failure: %s\n", dir, err)
+ if showWarnings {
+ fmt.Fprintf(os.Stderr, "go: disabling cache (%s) due to initialization failure: %s\n", dir, err)
+ }
return
}
defaultCache = c
@@ -59,14 +63,24 @@ func initDefaultCache() {
// DefaultDir returns the effective GOCACHE setting.
// It returns "off" if the cache is disabled.
func DefaultDir() string {
+ dir, _ := defaultDir()
+ return dir
+}
+
+// defaultDir returns the effective GOCACHE setting.
+// It returns "off" if the cache is disabled.
+// The second return value reports whether warnings should
+// be shown if the cache fails to initialize.
+func defaultDir() (string, bool) {
dir := os.Getenv("GOCACHE")
if dir != "" {
- return dir
+ return dir, true
}
// Compute default location.
// TODO(rsc): This code belongs somewhere else,
// like maybe ioutil.CacheDir or os.CacheDir.
+ showWarnings := true
switch runtime.GOOS {
case "windows":
dir = os.Getenv("LocalAppData")
@@ -76,20 +90,20 @@ func DefaultDir() string {
dir = os.Getenv("AppData")
}
if dir == "" {
- return "off"
+ return "off", true
}
case "darwin":
dir = os.Getenv("HOME")
if dir == "" {
- return "off"
+ return "off", true
}
dir += "/Library/Caches"
case "plan9":
dir = os.Getenv("home")
if dir == "" {
- return "off"
+ return "off", true
}
// Plan 9 has no established per-user cache directory,
// but $home/lib/xyz is the usual equivalent of $HOME/.xyz on Unix.
@@ -101,10 +115,15 @@ func DefaultDir() string {
if dir == "" {
dir = os.Getenv("HOME")
if dir == "" {
- return "off"
+ return "off", true
+ }
+ if dir == "/" {
+ // probably docker run with -u flag
+ // https://golang.org/issue/26280
+ showWarnings = false
}
dir += "/.cache"
}
}
- return filepath.Join(dir, "go-build")
+ return filepath.Join(dir, "go-build"), showWarnings
}
diff --git a/libgo/go/cmd/go/internal/cache/default_unix_test.go b/libgo/go/cmd/go/internal/cache/default_unix_test.go
new file mode 100644
index 00000000000..a207497a42c
--- /dev/null
+++ b/libgo/go/cmd/go/internal/cache/default_unix_test.go
@@ -0,0 +1,67 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !windows,!darwin,!plan9
+
+package cache
+
+import (
+ "os"
+ "strings"
+ "testing"
+)
+
+func TestDefaultDir(t *testing.T) {
+ goCacheDir := "/tmp/test-go-cache"
+ xdgCacheDir := "/tmp/test-xdg-cache"
+ homeDir := "/tmp/test-home"
+
+ // undo env changes when finished
+ defer func(GOCACHE, XDG_CACHE_HOME, HOME string) {
+ os.Setenv("GOCACHE", GOCACHE)
+ os.Setenv("XDG_CACHE_HOME", XDG_CACHE_HOME)
+ os.Setenv("HOME", HOME)
+ }(os.Getenv("GOCACHE"), os.Getenv("XDG_CACHE_HOME"), os.Getenv("HOME"))
+
+ os.Setenv("GOCACHE", goCacheDir)
+ os.Setenv("XDG_CACHE_HOME", xdgCacheDir)
+ os.Setenv("HOME", homeDir)
+
+ dir, showWarnings := defaultDir()
+ if dir != goCacheDir {
+ t.Errorf("Cache DefaultDir %q should be $GOCACHE %q", dir, goCacheDir)
+ }
+ if !showWarnings {
+ t.Error("Warnings should be shown when $GOCACHE is set")
+ }
+
+ os.Unsetenv("GOCACHE")
+ dir, showWarnings = defaultDir()
+ if !strings.HasPrefix(dir, xdgCacheDir+"/") {
+ t.Errorf("Cache DefaultDir %q should be under $XDG_CACHE_HOME %q when $GOCACHE is unset", dir, xdgCacheDir)
+ }
+ if !showWarnings {
+ t.Error("Warnings should be shown when $XDG_CACHE_HOME is set")
+ }
+
+ os.Unsetenv("XDG_CACHE_HOME")
+ dir, showWarnings = defaultDir()
+ if !strings.HasPrefix(dir, homeDir+"/.cache/") {
+ t.Errorf("Cache DefaultDir %q should be under $HOME/.cache %q when $GOCACHE and $XDG_CACHE_HOME are unset", dir, homeDir+"/.cache")
+ }
+ if !showWarnings {
+ t.Error("Warnings should be shown when $HOME is not /")
+ }
+
+ os.Unsetenv("HOME")
+ if dir, _ := defaultDir(); dir != "off" {
+ t.Error("Cache not disabled when $GOCACHE, $XDG_CACHE_HOME, and $HOME are unset")
+ }
+
+ os.Setenv("HOME", "/")
+ if _, showWarnings := defaultDir(); showWarnings {
+ // https://golang.org/issue/26280
+ t.Error("Cache initalization warnings should be squelched when $GOCACHE and $XDG_CACHE_HOME are unset and $HOME is /")
+ }
+}
diff --git a/libgo/go/cmd/go/internal/cfg/cfg.go b/libgo/go/cmd/go/internal/cfg/cfg.go
index f0a2277d1b2..8dc4d1fbd29 100644
--- a/libgo/go/cmd/go/internal/cfg/cfg.go
+++ b/libgo/go/cmd/go/internal/cfg/cfg.go
@@ -20,7 +20,8 @@ import (
var (
BuildA bool // -a flag
BuildBuildmode string // -buildmode flag
- BuildContext = build.Default
+ BuildContext = defaultContext()
+ BuildMod string // -mod flag
BuildI bool // -i flag
BuildLinkshared bool // -linkshared flag
BuildMSan bool // -msan flag
@@ -42,6 +43,12 @@ var (
DebugActiongraph string // -debug-actiongraph flag (undocumented, unstable)
)
+func defaultContext() build.Context {
+ ctxt := build.Default
+ ctxt.JoinPath = filepath.Join // back door to say "do not use go command"
+ return ctxt
+}
+
func init() {
BuildToolchainCompiler = func() string { return "missing-compiler" }
BuildToolchainLinker = func() string { return "missing-linker" }
@@ -67,6 +74,16 @@ var (
Goos = BuildContext.GOOS
ExeSuffix string
Gopath = filepath.SplitList(BuildContext.GOPATH)
+
+ // ModulesEnabled specifies whether the go command is running
+ // in module-aware mode (as opposed to GOPATH mode).
+ // It is equal to modload.Enabled, but not all packages can import modload.
+ ModulesEnabled bool
+
+ // GoModInGOPATH records whether we've found a go.mod in GOPATH/src
+ // in GO111MODULE=auto mode. In that case, we don't use modules
+ // but people might expect us to, so 'go get' warns.
+ GoModInGOPATH string
)
func init() {
@@ -84,9 +101,10 @@ var (
GOROOT_FINAL = findGOROOT_FINAL()
// Used in envcmd.MkEnv and build ID computations.
- GOARM = fmt.Sprint(objabi.GOARM)
- GO386 = objabi.GO386
- GOMIPS = objabi.GOMIPS
+ GOARM = fmt.Sprint(objabi.GOARM)
+ GO386 = objabi.GO386
+ GOMIPS = objabi.GOMIPS
+ GOMIPS64 = objabi.GOMIPS64
)
// Update build context to use our computed GOROOT.
@@ -102,6 +120,16 @@ func init() {
}
}
+// There is a copy of findGOROOT, isSameDir, and isGOROOT in
+// x/tools/cmd/godoc/goroot.go.
+// Try to keep them in sync for now.
+
+// findGOROOT returns the GOROOT value, using either an explicitly
+// provided environment variable, a GOROOT that contains the current
+// os.Executable value, or else the GOROOT that the binary was built
+// with from runtime.GOROOT().
+//
+// There is a copy of this code in x/tools/cmd/godoc/goroot.go.
func findGOROOT() string {
if env := os.Getenv("GOROOT"); env != "" {
return filepath.Clean(env)
@@ -161,6 +189,8 @@ func isSameDir(dir1, dir2 string) bool {
// It does this by looking for the path/pkg/tool directory,
// which is necessary for useful operation of the cmd/go tool,
// and is not typically present in a GOPATH.
+//
+// There is a copy of this code in x/tools/cmd/godoc/goroot.go.
func isGOROOT(path string) bool {
stat, err := os.Stat(filepath.Join(path, "pkg", "tool"))
if err != nil {
diff --git a/libgo/go/cmd/go/internal/clean/clean.go b/libgo/go/cmd/go/internal/clean/clean.go
index fa5af944af6..d023592eedc 100644
--- a/libgo/go/cmd/go/internal/clean/clean.go
+++ b/libgo/go/cmd/go/internal/clean/clean.go
@@ -17,11 +17,13 @@ import (
"cmd/go/internal/cache"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
+ "cmd/go/internal/modfetch"
+ "cmd/go/internal/modload"
"cmd/go/internal/work"
)
var CmdClean = &base.Command{
- UsageLine: "clean [-i] [-r] [-n] [-x] [-cache] [-testcache] [build flags] [packages]",
+ UsageLine: "go clean [clean flags] [build flags] [packages]",
Short: "remove object files and cached files",
Long: `
Clean removes object files from package source directories.
@@ -65,6 +67,10 @@ The -cache flag causes clean to remove the entire go build cache.
The -testcache flag causes clean to expire all test results in the
go build cache.
+The -modcache flag causes clean to remove the entire module
+download cache, including unpacked source code of versioned
+dependencies.
+
For more about build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.
@@ -75,6 +81,7 @@ var (
cleanI bool // clean -i flag
cleanR bool // clean -r flag
cleanCache bool // clean -cache flag
+ cleanModcache bool // clean -modcache flag
cleanTestcache bool // clean -testcache flag
)
@@ -85,6 +92,7 @@ func init() {
CmdClean.Flag.BoolVar(&cleanI, "i", false, "")
CmdClean.Flag.BoolVar(&cleanR, "r", false, "")
CmdClean.Flag.BoolVar(&cleanCache, "cache", false, "")
+ CmdClean.Flag.BoolVar(&cleanModcache, "modcache", false, "")
CmdClean.Flag.BoolVar(&cleanTestcache, "testcache", false, "")
// -n and -x are important enough to be
@@ -95,8 +103,13 @@ func init() {
}
func runClean(cmd *base.Command, args []string) {
- for _, pkg := range load.PackagesAndErrors(args) {
- clean(pkg)
+ if len(args) == 0 && modload.Failed() {
+ // Don't try to clean current directory,
+ // which will cause modload to base.Fatalf.
+ } else {
+ for _, pkg := range load.PackagesAndErrors(args) {
+ clean(pkg)
+ }
}
if cleanCache {
@@ -138,6 +151,29 @@ func runClean(cmd *base.Command, args []string) {
}
}
}
+
+ if cleanModcache {
+ if modfetch.PkgMod == "" {
+ base.Fatalf("go clean -modcache: no module cache")
+ }
+ if err := removeAll(modfetch.PkgMod); err != nil {
+ base.Errorf("go clean -modcache: %v", err)
+ }
+ }
+}
+
+func removeAll(dir string) error {
+ // Module cache has 0555 directories; make them writable in order to remove content.
+ filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return nil // ignore errors walking in file system
+ }
+ if info.IsDir() {
+ os.Chmod(path, 0777)
+ }
+ return nil
+ })
+ return os.RemoveAll(dir)
}
var cleaned = map[*load.Package]bool{}
diff --git a/libgo/go/cmd/go/internal/cmdflag/flag.go b/libgo/go/cmd/go/internal/cmdflag/flag.go
index 7ab30221279..b2a67e6f74a 100644
--- a/libgo/go/cmd/go/internal/cmdflag/flag.go
+++ b/libgo/go/cmd/go/internal/cmdflag/flag.go
@@ -69,6 +69,14 @@ func SyntaxError(cmd, msg string) {
os.Exit(2)
}
+// AddKnownFlags registers the flags in defns with base.AddKnownFlag.
+func AddKnownFlags(cmd string, defns []*Defn) {
+ for _, f := range defns {
+ base.AddKnownFlag(f.Name)
+ base.AddKnownFlag(cmd + "." + f.Name)
+ }
+}
+
// Parse sees if argument i is present in the definitions and if so,
// returns its definition, value, and whether it consumed an extra word.
// If the flag begins (cmd+".") it is ignored for the purpose of this function.
@@ -121,3 +129,31 @@ func Parse(cmd string, defns []*Defn, args []string, i int) (f *Defn, value stri
f = nil
return
}
+
+// FindGOFLAGS extracts and returns the flags matching defns from GOFLAGS.
+// Ideally the caller would mention that the flags were from GOFLAGS
+// when reporting errors, but that's too hard for now.
+func FindGOFLAGS(defns []*Defn) []string {
+ var flags []string
+ for _, flag := range base.GOFLAGS() {
+ // Flags returned by base.GOFLAGS are well-formed, one of:
+ // -x
+ // --x
+ // -x=value
+ // --x=value
+ if strings.HasPrefix(flag, "--") {
+ flag = flag[1:]
+ }
+ name := flag[1:]
+ if i := strings.Index(name, "="); i >= 0 {
+ name = name[:i]
+ }
+ for _, f := range defns {
+ if name == f.Name {
+ flags = append(flags, flag)
+ break
+ }
+ }
+ }
+ return flags
+}
diff --git a/libgo/go/cmd/go/internal/dirhash/hash.go b/libgo/go/cmd/go/internal/dirhash/hash.go
new file mode 100644
index 00000000000..61d8face567
--- /dev/null
+++ b/libgo/go/cmd/go/internal/dirhash/hash.go
@@ -0,0 +1,103 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package dirhash defines hashes over directory trees.
+package dirhash
+
+import (
+ "archive/zip"
+ "crypto/sha256"
+ "encoding/base64"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+)
+
+var DefaultHash = Hash1
+
+type Hash func(files []string, open func(string) (io.ReadCloser, error)) (string, error)
+
+func Hash1(files []string, open func(string) (io.ReadCloser, error)) (string, error) {
+ h := sha256.New()
+ files = append([]string(nil), files...)
+ sort.Strings(files)
+ for _, file := range files {
+ if strings.Contains(file, "\n") {
+ return "", errors.New("filenames with newlines are not supported")
+ }
+ r, err := open(file)
+ if err != nil {
+ return "", err
+ }
+ hf := sha256.New()
+ _, err = io.Copy(hf, r)
+ r.Close()
+ if err != nil {
+ return "", err
+ }
+ fmt.Fprintf(h, "%x %s\n", hf.Sum(nil), file)
+ }
+ return "h1:" + base64.StdEncoding.EncodeToString(h.Sum(nil)), nil
+}
+
+func HashDir(dir, prefix string, hash Hash) (string, error) {
+ files, err := DirFiles(dir, prefix)
+ if err != nil {
+ return "", err
+ }
+ osOpen := func(name string) (io.ReadCloser, error) {
+ return os.Open(filepath.Join(dir, strings.TrimPrefix(name, prefix)))
+ }
+ return hash(files, osOpen)
+}
+
+func DirFiles(dir, prefix string) ([]string, error) {
+ var files []string
+ dir = filepath.Clean(dir)
+ err := filepath.Walk(dir, func(file string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+ if info.IsDir() {
+ return nil
+ }
+ rel := file
+ if dir != "." {
+ rel = file[len(dir)+1:]
+ }
+ f := filepath.Join(prefix, rel)
+ files = append(files, filepath.ToSlash(f))
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+ return files, nil
+}
+
+func HashZip(zipfile string, hash Hash) (string, error) {
+ z, err := zip.OpenReader(zipfile)
+ if err != nil {
+ return "", err
+ }
+ defer z.Close()
+ var files []string
+ zfiles := make(map[string]*zip.File)
+ for _, file := range z.File {
+ files = append(files, file.Name)
+ zfiles[file.Name] = file
+ }
+ zipOpen := func(name string) (io.ReadCloser, error) {
+ f := zfiles[name]
+ if f == nil {
+ return nil, fmt.Errorf("file %q not found in zip", name) // should never happen
+ }
+ return f.Open()
+ }
+ return hash(files, zipOpen)
+}
diff --git a/libgo/go/cmd/go/internal/dirhash/hash_test.go b/libgo/go/cmd/go/internal/dirhash/hash_test.go
new file mode 100644
index 00000000000..ed463c1949c
--- /dev/null
+++ b/libgo/go/cmd/go/internal/dirhash/hash_test.go
@@ -0,0 +1,135 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package dirhash
+
+import (
+ "archive/zip"
+ "crypto/sha256"
+ "encoding/base64"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+)
+
+func h(s string) string {
+ return fmt.Sprintf("%x", sha256.Sum256([]byte(s)))
+}
+
+func htop(k string, s string) string {
+ sum := sha256.Sum256([]byte(s))
+ return k + ":" + base64.StdEncoding.EncodeToString(sum[:])
+}
+
+func TestHash1(t *testing.T) {
+ files := []string{"xyz", "abc"}
+ open := func(name string) (io.ReadCloser, error) {
+ return ioutil.NopCloser(strings.NewReader("data for " + name)), nil
+ }
+ want := htop("h1", fmt.Sprintf("%s %s\n%s %s\n", h("data for abc"), "abc", h("data for xyz"), "xyz"))
+ out, err := Hash1(files, open)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if out != want {
+ t.Errorf("Hash1(...) = %s, want %s", out, want)
+ }
+
+ _, err = Hash1([]string{"xyz", "a\nbc"}, open)
+ if err == nil {
+ t.Error("Hash1: expected error on newline in filenames")
+ }
+}
+
+func TestHashDir(t *testing.T) {
+ dir, err := ioutil.TempDir("", "dirhash-test-")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+ if err := ioutil.WriteFile(filepath.Join(dir, "xyz"), []byte("data for xyz"), 0666); err != nil {
+ t.Fatal(err)
+ }
+ if err := ioutil.WriteFile(filepath.Join(dir, "abc"), []byte("data for abc"), 0666); err != nil {
+ t.Fatal(err)
+ }
+ want := htop("h1", fmt.Sprintf("%s %s\n%s %s\n", h("data for abc"), "prefix/abc", h("data for xyz"), "prefix/xyz"))
+ out, err := HashDir(dir, "prefix", Hash1)
+ if err != nil {
+ t.Fatalf("HashDir: %v", err)
+ }
+ if out != want {
+ t.Errorf("HashDir(...) = %s, want %s", out, want)
+ }
+}
+
+func TestHashZip(t *testing.T) {
+ f, err := ioutil.TempFile("", "dirhash-test-")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.Remove(f.Name())
+ defer f.Close()
+
+ z := zip.NewWriter(f)
+ w, err := z.Create("prefix/xyz")
+ if err != nil {
+ t.Fatal(err)
+ }
+ w.Write([]byte("data for xyz"))
+ w, err = z.Create("prefix/abc")
+ if err != nil {
+ t.Fatal(err)
+ }
+ w.Write([]byte("data for abc"))
+ if err := z.Close(); err != nil {
+ t.Fatal(err)
+ }
+ if err := f.Close(); err != nil {
+ t.Fatal(err)
+ }
+
+ want := htop("h1", fmt.Sprintf("%s %s\n%s %s\n", h("data for abc"), "prefix/abc", h("data for xyz"), "prefix/xyz"))
+ out, err := HashZip(f.Name(), Hash1)
+ if err != nil {
+ t.Fatalf("HashDir: %v", err)
+ }
+ if out != want {
+ t.Errorf("HashDir(...) = %s, want %s", out, want)
+ }
+}
+
+func TestDirFiles(t *testing.T) {
+ dir, err := ioutil.TempDir("", "dirfiles-test-")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+ if err := ioutil.WriteFile(filepath.Join(dir, "xyz"), []byte("data for xyz"), 0666); err != nil {
+ t.Fatal(err)
+ }
+ if err := ioutil.WriteFile(filepath.Join(dir, "abc"), []byte("data for abc"), 0666); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.Mkdir(filepath.Join(dir, "subdir"), 0777); err != nil {
+ t.Fatal(err)
+ }
+ if err := ioutil.WriteFile(filepath.Join(dir, "subdir", "xyz"), []byte("data for subdir xyz"), 0666); err != nil {
+ t.Fatal(err)
+ }
+ prefix := "foo/bar@v2.3.4"
+ out, err := DirFiles(dir, prefix)
+ if err != nil {
+ t.Fatalf("DirFiles: %v", err)
+ }
+ for _, file := range out {
+ if !strings.HasPrefix(file, prefix) {
+ t.Errorf("Dir file = %s, want prefix %s", file, prefix)
+ }
+ }
+}
diff --git a/libgo/go/cmd/go/internal/doc/doc.go b/libgo/go/cmd/go/internal/doc/doc.go
index d73dd9ad914..4e7dca082d7 100644
--- a/libgo/go/cmd/go/internal/doc/doc.go
+++ b/libgo/go/cmd/go/internal/doc/doc.go
@@ -12,7 +12,7 @@ import (
var CmdDoc = &base.Command{
Run: runDoc,
- UsageLine: "doc [-u] [-c] [package|[package.]symbol[.methodOrField]]",
+ UsageLine: "go doc [-u] [-c] [package|[package.]symbol[.methodOrField]]",
CustomFlags: true,
Short: "show documentation for package or symbol",
Long: `
diff --git a/libgo/go/cmd/go/internal/envcmd/env.go b/libgo/go/cmd/go/internal/envcmd/env.go
index 603f7b5060c..afadbade38e 100644
--- a/libgo/go/cmd/go/internal/envcmd/env.go
+++ b/libgo/go/cmd/go/internal/envcmd/env.go
@@ -9,6 +9,7 @@ import (
"encoding/json"
"fmt"
"os"
+ "path/filepath"
"runtime"
"strings"
@@ -16,11 +17,12 @@ import (
"cmd/go/internal/cache"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
+ "cmd/go/internal/modload"
"cmd/go/internal/work"
)
var CmdEnv = &base.Command{
- UsageLine: "env [-json] [var ...]",
+ UsageLine: "go env [-json] [var ...]",
Short: "print Go environment information",
Long: `
Env prints Go environment information.
@@ -52,17 +54,16 @@ func MkEnv() []cfg.EnvVar {
{Name: "GOBIN", Value: cfg.GOBIN},
{Name: "GOCACHE", Value: cache.DefaultDir()},
{Name: "GOEXE", Value: cfg.ExeSuffix},
+ {Name: "GOFLAGS", Value: os.Getenv("GOFLAGS")},
{Name: "GOHOSTARCH", Value: runtime.GOARCH},
{Name: "GOHOSTOS", Value: runtime.GOOS},
{Name: "GOOS", Value: cfg.Goos},
{Name: "GOPATH", Value: cfg.BuildContext.GOPATH},
+ {Name: "GOPROXY", Value: os.Getenv("GOPROXY")},
{Name: "GORACE", Value: os.Getenv("GORACE")},
{Name: "GOROOT", Value: cfg.GOROOT},
{Name: "GOTMPDIR", Value: os.Getenv("GOTMPDIR")},
{Name: "GOTOOLDIR", Value: base.ToolDir},
-
- // disable escape codes in clang errors
- {Name: "TERM", Value: "dumb"},
}
if work.GccgoBin != "" {
@@ -78,6 +79,8 @@ func MkEnv() []cfg.EnvVar {
env = append(env, cfg.EnvVar{Name: "GO386", Value: cfg.GO386})
case "mips", "mipsle":
env = append(env, cfg.EnvVar{Name: "GOMIPS", Value: cfg.GOMIPS})
+ case "mips64", "mips64le":
+ env = append(env, cfg.EnvVar{Name: "GOMIPS64", Value: cfg.GOMIPS64})
}
cc := cfg.DefaultCC(cfg.Goos, cfg.Goarch)
@@ -111,6 +114,18 @@ func findEnv(env []cfg.EnvVar, name string) string {
// ExtraEnvVars returns environment variables that should not leak into child processes.
func ExtraEnvVars() []cfg.EnvVar {
+ gomod := ""
+ if modload.Init(); modload.ModRoot != "" {
+ gomod = filepath.Join(modload.ModRoot, "go.mod")
+ }
+ return []cfg.EnvVar{
+ {Name: "GOMOD", Value: gomod},
+ }
+}
+
+// ExtraEnvVarsCostly returns environment variables that should not leak into child processes
+// but are costly to evaluate.
+func ExtraEnvVarsCostly() []cfg.EnvVar {
var b work.Builder
b.Init()
cppflags, cflags, cxxflags, fflags, ldflags, err := b.CFlags(&load.Package{})
@@ -120,6 +135,7 @@ func ExtraEnvVars() []cfg.EnvVar {
return nil
}
cmd := b.GccCmd(".", "")
+
return []cfg.EnvVar{
// Note: Update the switch in runEnv below when adding to this list.
{Name: "CGO_CFLAGS", Value: strings.Join(cflags, " ")},
@@ -134,13 +150,14 @@ func ExtraEnvVars() []cfg.EnvVar {
func runEnv(cmd *base.Command, args []string) {
env := cfg.CmdEnv
+ env = append(env, ExtraEnvVars()...)
- // Do we need to call ExtraEnvVars, which is a bit expensive?
+ // Do we need to call ExtraEnvVarsCostly, which is a bit expensive?
// Only if we're listing all environment variables ("go env")
// or the variables being requested are in the extra list.
- needExtra := true
+ needCostly := true
if len(args) > 0 {
- needExtra = false
+ needCostly = false
for _, arg := range args {
switch arg {
case "CGO_CFLAGS",
@@ -150,12 +167,12 @@ func runEnv(cmd *base.Command, args []string) {
"CGO_LDFLAGS",
"PKG_CONFIG",
"GOGCCFLAGS":
- needExtra = true
+ needCostly = true
}
}
}
- if needExtra {
- env = append(env, ExtraEnvVars()...)
+ if needCostly {
+ env = append(env, ExtraEnvVarsCostly()...)
}
if len(args) > 0 {
diff --git a/libgo/go/cmd/go/internal/fix/fix.go b/libgo/go/cmd/go/internal/fix/fix.go
index 99c7ca51acf..aab164148ff 100644
--- a/libgo/go/cmd/go/internal/fix/fix.go
+++ b/libgo/go/cmd/go/internal/fix/fix.go
@@ -9,12 +9,15 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
+ "cmd/go/internal/modload"
"cmd/go/internal/str"
+ "fmt"
+ "os"
)
var CmdFix = &base.Command{
Run: runFix,
- UsageLine: "fix [packages]",
+ UsageLine: "go fix [packages]",
Short: "update packages to use new APIs",
Long: `
Fix runs the Go fix command on the packages named by the import paths.
@@ -29,7 +32,15 @@ See also: go fmt, go vet.
}
func runFix(cmd *base.Command, args []string) {
+ printed := false
for _, pkg := range load.Packages(args) {
+ if modload.Enabled() && !pkg.Module.Main {
+ if !printed {
+ fmt.Fprintf(os.Stderr, "go: not fixing packages in dependency modules\n")
+ printed = true
+ }
+ continue
+ }
// Use pkg.gofiles instead of pkg.Dir so that
// the command only applies to this package,
// not to packages in subdirectories.
diff --git a/libgo/go/cmd/go/internal/fmtcmd/fmt.go b/libgo/go/cmd/go/internal/fmtcmd/fmt.go
index eb96823fa6a..8e4ef372816 100644
--- a/libgo/go/cmd/go/internal/fmtcmd/fmt.go
+++ b/libgo/go/cmd/go/internal/fmtcmd/fmt.go
@@ -6,6 +6,7 @@
package fmtcmd
import (
+ "fmt"
"os"
"path/filepath"
"runtime"
@@ -15,6 +16,7 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
+ "cmd/go/internal/modload"
"cmd/go/internal/str"
)
@@ -24,7 +26,7 @@ func init() {
var CmdFmt = &base.Command{
Run: runFmt,
- UsageLine: "fmt [-n] [-x] [packages]",
+ UsageLine: "go fmt [-n] [-x] [packages]",
Short: "gofmt (reformat) package sources",
Long: `
Fmt runs the command 'gofmt -l -w' on the packages named
@@ -43,6 +45,7 @@ See also: go fix, go vet.
}
func runFmt(cmd *base.Command, args []string) {
+ printed := false
gofmt := gofmtPath()
procs := runtime.GOMAXPROCS(0)
var wg sync.WaitGroup
@@ -57,6 +60,13 @@ func runFmt(cmd *base.Command, args []string) {
}()
}
for _, pkg := range load.PackagesAndErrors(args) {
+ if modload.Enabled() && pkg.Module != nil && !pkg.Module.Main {
+ if !printed {
+ fmt.Fprintf(os.Stderr, "go: not formatting packages in dependency modules\n")
+ printed = true
+ }
+ continue
+ }
if pkg.Error != nil {
if strings.HasPrefix(pkg.Error.Err, "build constraints exclude all Go files") {
// Skip this error, as we will format
diff --git a/libgo/go/cmd/go/internal/generate/generate.go b/libgo/go/cmd/go/internal/generate/generate.go
index 75c0d3b09d6..9482be98aef 100644
--- a/libgo/go/cmd/go/internal/generate/generate.go
+++ b/libgo/go/cmd/go/internal/generate/generate.go
@@ -21,12 +21,13 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
+ "cmd/go/internal/modload"
"cmd/go/internal/work"
)
var CmdGenerate = &base.Command{
Run: runGenerate,
- UsageLine: "generate [-run regexp] [-n] [-v] [-x] [build flags] [file.go... | packages]",
+ UsageLine: "go generate [-run regexp] [-n] [-v] [-x] [build flags] [file.go... | packages]",
Short: "generate Go files by processing source",
Long: `
Generate runs commands described by directives within existing
@@ -47,6 +48,12 @@ that can be run locally. It must either be in the shell path
(gofmt), a fully qualified path (/usr/you/bin/mytool), or a
command alias, described below.
+To convey to humans and machine tools that code is generated,
+generated source should have a line early in the file that
+matches the following regular expression (in Go syntax):
+
+ ^// Code generated .* DO NOT EDIT\.$
+
Note that go generate does not parse the file, so lines that look
like directives in comments or multiline strings will be treated
as directives.
@@ -152,9 +159,28 @@ func runGenerate(cmd *base.Command, args []string) {
}
}
// Even if the arguments are .go files, this loop suffices.
+ printed := false
for _, pkg := range load.Packages(args) {
+ if modload.Enabled() && !pkg.Module.Main {
+ if !printed {
+ fmt.Fprintf(os.Stderr, "go: not generating in packages in dependency modules\n")
+ printed = true
+ }
+ continue
+ }
+
+ pkgName := pkg.Name
+
for _, file := range pkg.InternalGoFiles() {
- if !generate(pkg.Name, file) {
+ if !generate(pkgName, file) {
+ break
+ }
+ }
+
+ pkgName += "_test"
+
+ for _, file := range pkg.InternalXGoFiles() {
+ if !generate(pkgName, file) {
break
}
}
diff --git a/libgo/go/cmd/go/internal/get/discovery.go b/libgo/go/cmd/go/internal/get/discovery.go
index 97aa1d7e8d6..6ba5c091e39 100644
--- a/libgo/go/cmd/go/internal/get/discovery.go
+++ b/libgo/go/cmd/go/internal/get/discovery.go
@@ -28,7 +28,7 @@ func charsetReader(charset string, input io.Reader) (io.Reader, error) {
// parseMetaGoImports returns meta imports from the HTML in r.
// Parsing ends at the end of the <head> section or the beginning of the <body>.
-func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) {
+func parseMetaGoImports(r io.Reader, mod ModuleMode) (imports []metaImport, err error) {
d := xml.NewDecoder(r)
d.CharsetReader = charsetReader
d.Strict = false
@@ -39,13 +39,13 @@ func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) {
if err == io.EOF || len(imports) > 0 {
err = nil
}
- return
+ break
}
if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") {
- return
+ break
}
if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") {
- return
+ break
}
e, ok := t.(xml.StartElement)
if !ok || !strings.EqualFold(e.Name.Local, "meta") {
@@ -55,13 +55,6 @@ func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) {
continue
}
if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 {
- // Ignore VCS type "mod", which is new Go modules.
- // This code is for old go get and must ignore the new mod lines.
- // Otherwise matchGoImport will complain about two
- // different metaImport lines for the same Prefix.
- if f[1] == "mod" {
- continue
- }
imports = append(imports, metaImport{
Prefix: f[0],
VCS: f[1],
@@ -69,6 +62,27 @@ func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) {
})
}
}
+
+ // Extract mod entries if we are paying attention to them.
+ var list []metaImport
+ var have map[string]bool
+ if mod == PreferMod {
+ have = make(map[string]bool)
+ for _, m := range imports {
+ if m.VCS == "mod" {
+ have[m.Prefix] = true
+ list = append(list, m)
+ }
+ }
+ }
+
+ // Append non-mod entries, ignoring those superseded by a mod entry.
+ for _, m := range imports {
+ if m.VCS != "mod" && !have[m.Prefix] {
+ list = append(list, m)
+ }
+ }
+ return list, nil
}
// attrValue returns the attribute value for the case-insensitive key
diff --git a/libgo/go/cmd/go/internal/get/get.go b/libgo/go/cmd/go/internal/get/get.go
index 5bfeac387cc..e4148bceb04 100644
--- a/libgo/go/cmd/go/internal/get/get.go
+++ b/libgo/go/cmd/go/internal/get/get.go
@@ -16,13 +16,14 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
+ "cmd/go/internal/search"
"cmd/go/internal/str"
"cmd/go/internal/web"
"cmd/go/internal/work"
)
var CmdGet = &base.Command{
- UsageLine: "get [-d] [-f] [-fix] [-insecure] [-t] [-u] [-v] [build flags] [packages]",
+ UsageLine: "go get [-d] [-f] [-t] [-u] [-v] [-fix] [-insecure] [build flags] [packages]",
Short: "download and install packages and dependencies",
Long: `
Get downloads the packages named by the import paths, along with their
@@ -73,23 +74,56 @@ For more about specifying packages, see 'go help packages'.
For more about how 'go get' finds source code to
download, see 'go help importpath'.
+This text describes the behavior of get when using GOPATH
+to manage source code and dependencies.
+If instead the go command is running in module-aware mode,
+the details of get's flags and effects change, as does 'go help get'.
+See 'go help modules' and 'go help module-get'.
+
See also: go build, go install, go clean.
`,
}
-var getD = CmdGet.Flag.Bool("d", false, "")
-var getF = CmdGet.Flag.Bool("f", false, "")
-var getT = CmdGet.Flag.Bool("t", false, "")
-var getU = CmdGet.Flag.Bool("u", false, "")
-var getFix = CmdGet.Flag.Bool("fix", false, "")
-var getInsecure = CmdGet.Flag.Bool("insecure", false, "")
+var HelpGopathGet = &base.Command{
+ UsageLine: "gopath-get",
+ Short: "legacy GOPATH go get",
+ Long: `
+The 'go get' command changes behavior depending on whether the
+go command is running in module-aware mode or legacy GOPATH mode.
+This help text, accessible as 'go help gopath-get' even in module-aware mode,
+describes 'go get' as it operates in legacy GOPATH mode.
+
+Usage: ` + CmdGet.UsageLine + `
+` + CmdGet.Long,
+}
+
+var (
+ getD = CmdGet.Flag.Bool("d", false, "")
+ getF = CmdGet.Flag.Bool("f", false, "")
+ getT = CmdGet.Flag.Bool("t", false, "")
+ getU = CmdGet.Flag.Bool("u", false, "")
+ getFix = CmdGet.Flag.Bool("fix", false, "")
+
+ Insecure bool
+)
func init() {
work.AddBuildFlags(CmdGet)
CmdGet.Run = runGet // break init loop
+ CmdGet.Flag.BoolVar(&Insecure, "insecure", Insecure, "")
}
func runGet(cmd *base.Command, args []string) {
+ if cfg.ModulesEnabled {
+ // Should not happen: main.go should install the separate module-enabled get code.
+ base.Fatalf("go get: modules not implemented")
+ }
+ if cfg.GoModInGOPATH != "" {
+ // Warn about not using modules with GO111MODULE=auto when go.mod exists.
+ // To silence the warning, users can set GO111MODULE=off.
+ fmt.Fprintf(os.Stderr, "go get: warning: modules disabled by GO111MODULE=auto in GOPATH/src;\n\tignoring %s;\n\tsee 'go help modules'\n", base.ShortPath(cfg.GoModInGOPATH))
+ }
+
work.BuildInit()
if *getF && !*getU {
@@ -129,9 +163,8 @@ func runGet(cmd *base.Command, args []string) {
if *getT {
mode |= load.GetTestDeps
}
- args = downloadPaths(args)
- for _, arg := range args {
- download(arg, nil, &stk, mode)
+ for _, pkg := range downloadPaths(args) {
+ download(pkg, nil, &stk, mode)
}
base.ExitIfErrors()
@@ -150,8 +183,7 @@ func runGet(cmd *base.Command, args []string) {
// This leads to duplicated loads of the standard packages.
load.ClearCmdCache()
- args = load.ImportPaths(args)
- load.PackagesForBuild(args)
+ pkgs := load.PackagesForBuild(args)
// Phase 3. Install.
if *getD {
@@ -161,7 +193,7 @@ func runGet(cmd *base.Command, args []string) {
return
}
- work.InstallPackages(args, true)
+ work.InstallPackages(args, pkgs)
}
// downloadPaths prepares the list of paths to pass to download.
@@ -169,28 +201,21 @@ func runGet(cmd *base.Command, args []string) {
// for a particular pattern, downloadPaths leaves it in the result list,
// in the hope that we can figure out the repository from the
// initial ...-free prefix.
-func downloadPaths(args []string) []string {
- args = load.ImportPathsNoDotExpansion(args)
- var out []string
- for _, a := range args {
- if strings.Contains(a, "...") {
- var expand []string
- // Use matchPackagesInFS to avoid printing
- // warnings. They will be printed by the
- // eventual call to importPaths instead.
- if build.IsLocalImport(a) {
- expand = load.MatchPackagesInFS(a)
- } else {
- expand = load.MatchPackages(a)
- }
- if len(expand) > 0 {
- out = append(out, expand...)
- continue
- }
+func downloadPaths(patterns []string) []string {
+ for _, arg := range patterns {
+ if strings.Contains(arg, "@") {
+ base.Fatalf("go: cannot use path@version syntax in GOPATH mode")
+ }
+ }
+ var pkgs []string
+ for _, m := range search.ImportPathsQuiet(patterns) {
+ if len(m.Pkgs) == 0 && strings.Contains(m.Pattern, "...") {
+ pkgs = append(pkgs, m.Pattern)
+ } else {
+ pkgs = append(pkgs, m.Pkgs...)
}
- out = append(out, a)
}
- return out
+ return pkgs
}
// downloadCache records the import paths we have already
@@ -215,7 +240,7 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int)
}
load1 := func(path string, mode int) *load.Package {
if parent == nil {
- return load.LoadPackage(path, stk)
+ return load.LoadPackageNoFlags(path, stk)
}
return load.LoadImport(path, parent.Dir, parent, stk, nil, mode|load.ResolveModule)
}
@@ -271,9 +296,9 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int)
// for p has been replaced in the package cache.
if wildcardOkay && strings.Contains(arg, "...") {
if build.IsLocalImport(arg) {
- args = load.MatchPackagesInFS(arg)
+ args = search.MatchPackagesInFS(arg).Pkgs
} else {
- args = load.MatchPackages(arg)
+ args = search.MatchPackages(arg).Pkgs
}
isWildcard = true
}
@@ -304,7 +329,7 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int)
base.Run(cfg.BuildToolexec, str.StringList(base.Tool("fix"), files))
// The imports might have changed, so reload again.
- p = load.ReloadPackage(arg, stk)
+ p = load.ReloadPackageNoFlags(arg, stk)
if p.Error != nil {
base.Errorf("%s", p.Error)
return
@@ -369,10 +394,11 @@ func downloadPackage(p *load.Package) error {
vcs *vcsCmd
repo, rootPath string
err error
+ blindRepo bool // set if the repo has unusual configuration
)
security := web.Secure
- if *getInsecure {
+ if Insecure {
security = web.Insecure
}
@@ -389,20 +415,22 @@ func downloadPackage(p *load.Package) error {
dir := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath))
remote, err := vcs.remoteRepo(vcs, dir)
if err != nil {
- return err
+ // Proceed anyway. The package is present; we likely just don't understand
+ // the repo configuration (e.g. unusual remote protocol).
+ blindRepo = true
}
repo = remote
- if !*getF {
- if rr, err := repoRootForImportPath(p.ImportPath, security); err == nil {
- repo := rr.repo
+ if !*getF && err == nil {
+ if rr, err := RepoRootForImportPath(p.ImportPath, IgnoreMod, security); err == nil {
+ repo := rr.Repo
if rr.vcs.resolveRepo != nil {
resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo)
if err == nil {
repo = resolved
}
}
- if remote != repo && rr.isCustom {
- return fmt.Errorf("%s is a custom import path for %s, but %s is checked out from %s", rr.root, repo, dir, remote)
+ if remote != repo && rr.IsCustom {
+ return fmt.Errorf("%s is a custom import path for %s, but %s is checked out from %s", rr.Root, repo, dir, remote)
}
}
}
@@ -410,13 +438,13 @@ func downloadPackage(p *load.Package) error {
} else {
// Analyze the import path to determine the version control system,
// repository, and the import path for the root of the repository.
- rr, err := repoRootForImportPath(p.ImportPath, security)
+ rr, err := RepoRootForImportPath(p.ImportPath, IgnoreMod, security)
if err != nil {
return err
}
- vcs, repo, rootPath = rr.vcs, rr.repo, rr.root
+ vcs, repo, rootPath = rr.vcs, rr.Repo, rr.Root
}
- if !vcs.isSecure(repo) && !*getInsecure {
+ if !blindRepo && !vcs.isSecure(repo) && !Insecure {
return fmt.Errorf("cannot download, %v uses insecure protocol", repo)
}
diff --git a/libgo/go/cmd/go/internal/get/pkg_test.go b/libgo/go/cmd/go/internal/get/pkg_test.go
index 1179d86693a..fc6a179c2e1 100644
--- a/libgo/go/cmd/go/internal/get/pkg_test.go
+++ b/libgo/go/cmd/go/internal/get/pkg_test.go
@@ -33,15 +33,18 @@ func TestFoldDup(t *testing.T) {
var parseMetaGoImportsTests = []struct {
in string
+ mod ModuleMode
out []metaImport
}{
{
`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
+ IgnoreMod,
[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
},
{
`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
<meta name="go-import" content="baz/quux git http://github.com/rsc/baz/quux">`,
+ IgnoreMod,
[]metaImport{
{"foo/bar", "git", "https://github.com/rsc/foo/bar"},
{"baz/quux", "git", "http://github.com/rsc/baz/quux"},
@@ -50,6 +53,7 @@ var parseMetaGoImportsTests = []struct {
{
`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
<meta name="go-import" content="foo/bar mod http://github.com/rsc/baz/quux">`,
+ IgnoreMod,
[]metaImport{
{"foo/bar", "git", "https://github.com/rsc/foo/bar"},
},
@@ -57,35 +61,65 @@ var parseMetaGoImportsTests = []struct {
{
`<meta name="go-import" content="foo/bar mod http://github.com/rsc/baz/quux">
<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
+ IgnoreMod,
[]metaImport{
{"foo/bar", "git", "https://github.com/rsc/foo/bar"},
},
},
{
+ `<meta name="go-import" content="foo/bar mod http://github.com/rsc/baz/quux">
+ <meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
+ PreferMod,
+ []metaImport{
+ {"foo/bar", "mod", "http://github.com/rsc/baz/quux"},
+ },
+ },
+ {
`<head>
<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
</head>`,
+ IgnoreMod,
[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
},
{
`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
<body>`,
+ IgnoreMod,
[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
},
{
`<!doctype html><meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
+ IgnoreMod,
[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
},
{
// XML doesn't like <div style=position:relative>.
`<!doctype html><title>Page Not Found</title><meta name=go-import content="chitin.io/chitin git https://github.com/chitin-io/chitin"><div style=position:relative>DRAFT</div>`,
+ IgnoreMod,
[]metaImport{{"chitin.io/chitin", "git", "https://github.com/chitin-io/chitin"}},
},
+ {
+ `<meta name="go-import" content="myitcv.io git https://github.com/myitcv/x">
+ <meta name="go-import" content="myitcv.io/blah2 mod https://raw.githubusercontent.com/myitcv/pubx/master">
+ `,
+ IgnoreMod,
+ []metaImport{{"myitcv.io", "git", "https://github.com/myitcv/x"}},
+ },
+ {
+ `<meta name="go-import" content="myitcv.io git https://github.com/myitcv/x">
+ <meta name="go-import" content="myitcv.io/blah2 mod https://raw.githubusercontent.com/myitcv/pubx/master">
+ `,
+ PreferMod,
+ []metaImport{
+ {"myitcv.io/blah2", "mod", "https://raw.githubusercontent.com/myitcv/pubx/master"},
+ {"myitcv.io", "git", "https://github.com/myitcv/x"},
+ },
+ },
}
func TestParseMetaGoImports(t *testing.T) {
for i, tt := range parseMetaGoImportsTests {
- out, err := parseMetaGoImports(strings.NewReader(tt.in))
+ out, err := parseMetaGoImports(strings.NewReader(tt.in), tt.mod)
if err != nil {
t.Errorf("test#%d: %v", i, err)
continue
diff --git a/libgo/go/cmd/go/internal/get/vcs.go b/libgo/go/cmd/go/internal/get/vcs.go
index 0b2a04e04f8..5cd164f2ff3 100644
--- a/libgo/go/cmd/go/internal/get/vcs.go
+++ b/libgo/go/cmd/go/internal/get/vcs.go
@@ -5,7 +5,6 @@
package get
import (
- "bytes"
"encoding/json"
"errors"
"fmt"
@@ -428,19 +427,18 @@ func (v *vcsCmd) run1(dir string, cmdline string, keyval []string, verbose bool)
fmt.Printf("cd %s\n", dir)
fmt.Printf("%s %s\n", v.cmd, strings.Join(args, " "))
}
- var buf bytes.Buffer
- cmd.Stdout = &buf
- cmd.Stderr = &buf
- err = cmd.Run()
- out := buf.Bytes()
+ out, err := cmd.Output()
if err != nil {
if verbose || cfg.BuildV {
fmt.Fprintf(os.Stderr, "# cd %s; %s %s\n", dir, v.cmd, strings.Join(args, " "))
- os.Stderr.Write(out)
+ if ee, ok := err.(*exec.ExitError); ok && len(ee.Stderr) > 0 {
+ os.Stderr.Write(ee.Stderr)
+ } else {
+ fmt.Fprintf(os.Stderr, err.Error())
+ }
}
- return out, err
}
- return out, nil
+ return out, err
}
// ping pings to determine scheme to use.
@@ -624,27 +622,29 @@ func checkNestedVCS(vcs *vcsCmd, dir, srcRoot string) error {
return nil
}
-// repoRoot represents a version control system, a repo, and a root of
-// where to put it on disk.
-type repoRoot struct {
- vcs *vcsCmd
-
- // repo is the repository URL, including scheme
- repo string
+// RepoRoot describes the repository root for a tree of source code.
+type RepoRoot struct {
+ Repo string // repository URL, including scheme
+ Root string // import path corresponding to root of repo
+ IsCustom bool // defined by served <meta> tags (as opposed to hard-coded pattern)
+ VCS string // vcs type ("mod", "git", ...)
- // root is the import path corresponding to the root of the
- // repository
- root string
-
- // isCustom is true for custom import paths (those defined by HTML meta tags)
- isCustom bool
+ vcs *vcsCmd // internal: vcs command access
}
var httpPrefixRE = regexp.MustCompile(`^https?:`)
-// repoRootForImportPath analyzes importPath to determine the
+// ModuleMode specifies whether to prefer modules when looking up code sources.
+type ModuleMode int
+
+const (
+ IgnoreMod ModuleMode = iota
+ PreferMod
+)
+
+// RepoRootForImportPath analyzes importPath to determine the
// version control system, and code repository to use.
-func repoRootForImportPath(importPath string, security web.SecurityMode) (*repoRoot, error) {
+func RepoRootForImportPath(importPath string, mod ModuleMode, security web.SecurityMode) (*RepoRoot, error) {
rr, err := repoRootFromVCSPaths(importPath, "", security, vcsPaths)
if err == errUnknownSite {
// If there are wildcards, look up the thing before the wildcard,
@@ -654,7 +654,7 @@ func repoRootForImportPath(importPath string, security web.SecurityMode) (*repoR
if i := strings.Index(lookup, "/.../"); i >= 0 {
lookup = lookup[:i]
}
- rr, err = repoRootForImportDynamic(lookup, security)
+ rr, err = repoRootForImportDynamic(lookup, mod, security)
if err != nil {
err = fmt.Errorf("unrecognized import path %q (%v)", importPath, err)
}
@@ -667,7 +667,7 @@ func repoRootForImportPath(importPath string, security web.SecurityMode) (*repoR
}
}
- if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.root, "...") {
+ if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.Root, "...") {
// Do not allow wildcards in the repo root.
rr = nil
err = fmt.Errorf("cannot expand ... in %q", importPath)
@@ -680,7 +680,7 @@ var errUnknownSite = errors.New("dynamic lookup required to find mapping")
// repoRootFromVCSPaths attempts to map importPath to a repoRoot
// using the mappings defined in vcsPaths.
// If scheme is non-empty, that scheme is forced.
-func repoRootFromVCSPaths(importPath, scheme string, security web.SecurityMode, vcsPaths []*vcsPath) (*repoRoot, error) {
+func repoRootFromVCSPaths(importPath, scheme string, security web.SecurityMode, vcsPaths []*vcsPath) (*RepoRoot, error) {
// A common error is to use https://packagepath because that's what
// hg and git require. Diagnose this helpfully.
if loc := httpPrefixRE.FindStringIndex(importPath); loc != nil {
@@ -733,28 +733,32 @@ func repoRootFromVCSPaths(importPath, scheme string, security web.SecurityMode,
if security == web.Secure && !vcs.isSecureScheme(scheme) {
continue
}
- if vcs.ping(scheme, match["repo"]) == nil {
+ if vcs.pingCmd != "" && vcs.ping(scheme, match["repo"]) == nil {
match["repo"] = scheme + "://" + match["repo"]
- break
+ goto Found
}
}
+ // No scheme found. Fall back to the first one.
+ match["repo"] = vcs.scheme[0] + "://" + match["repo"]
+ Found:
}
}
- rr := &repoRoot{
+ rr := &RepoRoot{
+ Repo: match["repo"],
+ Root: match["root"],
+ VCS: vcs.cmd,
vcs: vcs,
- repo: match["repo"],
- root: match["root"],
}
return rr, nil
}
return nil, errUnknownSite
}
-// repoRootForImportDynamic finds a *repoRoot for a custom domain that's not
+// repoRootForImportDynamic finds a *RepoRoot for a custom domain that's not
// statically known by repoRootForImportPathStatic.
//
// This handles custom import paths like "name.tld/pkg/foo" or just "name.tld".
-func repoRootForImportDynamic(importPath string, security web.SecurityMode) (*repoRoot, error) {
+func repoRootForImportDynamic(importPath string, mod ModuleMode, security web.SecurityMode) (*RepoRoot, error) {
slash := strings.Index(importPath, "/")
if slash < 0 {
slash = len(importPath)
@@ -772,7 +776,7 @@ func repoRootForImportDynamic(importPath string, security web.SecurityMode) (*re
return nil, fmt.Errorf(msg, err)
}
defer body.Close()
- imports, err := parseMetaGoImports(body)
+ imports, err := parseMetaGoImports(body, mod)
if err != nil {
return nil, fmt.Errorf("parsing %s: %v", importPath, err)
}
@@ -799,7 +803,7 @@ func repoRootForImportDynamic(importPath string, security web.SecurityMode) (*re
}
urlStr0 := urlStr
var imports []metaImport
- urlStr, imports, err = metaImportsForPrefix(mmi.Prefix, security)
+ urlStr, imports, err = metaImportsForPrefix(mmi.Prefix, mod, security)
if err != nil {
return nil, err
}
@@ -809,48 +813,34 @@ func repoRootForImportDynamic(importPath string, security web.SecurityMode) (*re
}
}
- if err := validateRepoRootScheme(mmi.RepoRoot); err != nil {
+ if err := validateRepoRoot(mmi.RepoRoot); err != nil {
return nil, fmt.Errorf("%s: invalid repo root %q: %v", urlStr, mmi.RepoRoot, err)
}
- rr := &repoRoot{
- vcs: vcsByCmd(mmi.VCS),
- repo: mmi.RepoRoot,
- root: mmi.Prefix,
- isCustom: true,
- }
- if rr.vcs == nil {
+ vcs := vcsByCmd(mmi.VCS)
+ if vcs == nil && mmi.VCS != "mod" {
return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, mmi.VCS)
}
+
+ rr := &RepoRoot{
+ Repo: mmi.RepoRoot,
+ Root: mmi.Prefix,
+ IsCustom: true,
+ VCS: mmi.VCS,
+ vcs: vcs,
+ }
return rr, nil
}
-// validateRepoRootScheme returns an error if repoRoot does not seem
-// to have a valid URL scheme. At this point we permit things that
-// aren't valid URLs, although later, if not using -insecure, we will
-// restrict repoRoots to be valid URLs. This is only because we've
-// historically permitted them, and people may depend on that.
-func validateRepoRootScheme(repoRoot string) error {
- end := strings.Index(repoRoot, "://")
- if end <= 0 {
- return errors.New("no scheme")
+// validateRepoRoot returns an error if repoRoot does not seem to be
+// a valid URL with scheme.
+func validateRepoRoot(repoRoot string) error {
+ url, err := url.Parse(repoRoot)
+ if err != nil {
+ return err
}
-
- // RFC 3986 section 3.1.
- for i := 0; i < end; i++ {
- c := repoRoot[i]
- switch {
- case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z':
- // OK.
- case '0' <= c && c <= '9' || c == '+' || c == '-' || c == '.':
- // OK except at start.
- if i == 0 {
- return errors.New("invalid scheme")
- }
- default:
- return errors.New("invalid scheme")
- }
+ if url.Scheme == "" {
+ return errors.New("no scheme")
}
-
return nil
}
@@ -868,7 +858,7 @@ var (
// It is an error if no imports are found.
// urlStr will still be valid if err != nil.
// The returned urlStr will be of the form "https://golang.org/x/tools?go-get=1"
-func metaImportsForPrefix(importPrefix string, security web.SecurityMode) (urlStr string, imports []metaImport, err error) {
+func metaImportsForPrefix(importPrefix string, mod ModuleMode, security web.SecurityMode) (urlStr string, imports []metaImport, err error) {
setCache := func(res fetchResult) (fetchResult, error) {
fetchCacheMu.Lock()
defer fetchCacheMu.Unlock()
@@ -888,7 +878,7 @@ func metaImportsForPrefix(importPrefix string, security web.SecurityMode) (urlSt
if err != nil {
return setCache(fetchResult{urlStr: urlStr, err: fmt.Errorf("fetch %s: %v", urlStr, err)})
}
- imports, err := parseMetaGoImports(body)
+ imports, err := parseMetaGoImports(body, mod)
if err != nil {
return setCache(fetchResult{urlStr: urlStr, err: fmt.Errorf("parsing %s: %v", urlStr, err)})
}
@@ -956,7 +946,13 @@ func matchGoImport(imports []metaImport, importPath string) (metaImport, error)
continue
}
- if match != -1 {
+ if match >= 0 {
+ if imports[match].VCS == "mod" && im.VCS != "mod" {
+ // All the mod entries precede all the non-mod entries.
+ // We have a mod entry and don't care about the rest,
+ // matching or not.
+ break
+ }
return metaImport{}, fmt.Errorf("multiple meta tags match import path %q", importPath)
}
match = i
@@ -1001,7 +997,7 @@ var vcsPaths = []*vcsPath{
// IBM DevOps Services (JazzHub)
{
prefix: "hub.jazz.net/git/",
- re: `^(?P<root>hub.jazz.net/git/[a-z0-9]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`,
+ re: `^(?P<root>hub\.jazz\.net/git/[a-z0-9]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`,
vcs: "git",
repo: "https://{root}",
check: noVCSSuffix,
@@ -1010,7 +1006,7 @@ var vcsPaths = []*vcsPath{
// Git at Apache
{
prefix: "git.apache.org/",
- re: `^(?P<root>git.apache.org/[a-z0-9_.\-]+\.git)(/[A-Za-z0-9_.\-]+)*$`,
+ re: `^(?P<root>git\.apache\.org/[a-z0-9_.\-]+\.git)(/[A-Za-z0-9_.\-]+)*$`,
vcs: "git",
repo: "https://{root}",
},
diff --git a/libgo/go/cmd/go/internal/get/vcs_test.go b/libgo/go/cmd/go/internal/get/vcs_test.go
index a6f8642026c..d13721bed1a 100644
--- a/libgo/go/cmd/go/internal/get/vcs_test.go
+++ b/libgo/go/cmd/go/internal/get/vcs_test.go
@@ -16,43 +16,43 @@ import (
"cmd/go/internal/web"
)
-// Test that RepoRootForImportPath creates the correct RepoRoot for a given importPath.
+// Test that RepoRootForImportPath determines the correct RepoRoot for a given importPath.
// TODO(cmang): Add tests for SVN and BZR.
func TestRepoRootForImportPath(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
tests := []struct {
path string
- want *repoRoot
+ want *RepoRoot
}{
{
"github.com/golang/groupcache",
- &repoRoot{
+ &RepoRoot{
vcs: vcsGit,
- repo: "https://github.com/golang/groupcache",
+ Repo: "https://github.com/golang/groupcache",
},
},
// Unicode letters in directories (issue 18660).
{
"github.com/user/unicode/испытание",
- &repoRoot{
+ &RepoRoot{
vcs: vcsGit,
- repo: "https://github.com/user/unicode",
+ Repo: "https://github.com/user/unicode",
},
},
// IBM DevOps Services tests
{
"hub.jazz.net/git/user1/pkgname",
- &repoRoot{
+ &RepoRoot{
vcs: vcsGit,
- repo: "https://hub.jazz.net/git/user1/pkgname",
+ Repo: "https://hub.jazz.net/git/user1/pkgname",
},
},
{
"hub.jazz.net/git/user1/pkgname/submodule/submodule/submodule",
- &repoRoot{
+ &RepoRoot{
vcs: vcsGit,
- repo: "https://hub.jazz.net/git/user1/pkgname",
+ Repo: "https://hub.jazz.net/git/user1/pkgname",
},
},
{
@@ -60,6 +60,10 @@ func TestRepoRootForImportPath(t *testing.T) {
nil,
},
{
+ "hubajazz.net",
+ nil,
+ },
+ {
"hub2.jazz.net",
nil,
},
@@ -87,9 +91,9 @@ func TestRepoRootForImportPath(t *testing.T) {
},
{
"hub.jazz.net/git/user/pkg.name",
- &repoRoot{
+ &RepoRoot{
vcs: vcsGit,
- repo: "https://hub.jazz.net/git/user/pkg.name",
+ Repo: "https://hub.jazz.net/git/user/pkg.name",
},
},
// User names cannot have uppercase letters
@@ -100,9 +104,9 @@ func TestRepoRootForImportPath(t *testing.T) {
// OpenStack tests
{
"git.openstack.org/openstack/swift",
- &repoRoot{
+ &RepoRoot{
vcs: vcsGit,
- repo: "https://git.openstack.org/openstack/swift",
+ Repo: "https://git.openstack.org/openstack/swift",
},
},
// Trailing .git is less preferred but included for
@@ -110,16 +114,16 @@ func TestRepoRootForImportPath(t *testing.T) {
// be compilable on both old and new go
{
"git.openstack.org/openstack/swift.git",
- &repoRoot{
+ &RepoRoot{
vcs: vcsGit,
- repo: "https://git.openstack.org/openstack/swift.git",
+ Repo: "https://git.openstack.org/openstack/swift.git",
},
},
{
"git.openstack.org/openstack/swift/go/hummingbird",
- &repoRoot{
+ &RepoRoot{
vcs: vcsGit,
- repo: "https://git.openstack.org/openstack/swift",
+ Repo: "https://git.openstack.org/openstack/swift",
},
},
{
@@ -141,24 +145,28 @@ func TestRepoRootForImportPath(t *testing.T) {
nil,
},
{
+ "gitbapache.org",
+ nil,
+ },
+ {
"git.apache.org/package-name.git",
- &repoRoot{
+ &RepoRoot{
vcs: vcsGit,
- repo: "https://git.apache.org/package-name.git",
+ Repo: "https://git.apache.org/package-name.git",
},
},
{
"git.apache.org/package-name_2.x.git/path/to/lib",
- &repoRoot{
+ &RepoRoot{
vcs: vcsGit,
- repo: "https://git.apache.org/package-name_2.x.git",
+ Repo: "https://git.apache.org/package-name_2.x.git",
},
},
{
"chiselapp.com/user/kyle/repository/fossilgg",
- &repoRoot{
+ &RepoRoot{
vcs: vcsFossil,
- repo: "https://chiselapp.com/user/kyle/repository/fossilgg",
+ Repo: "https://chiselapp.com/user/kyle/repository/fossilgg",
},
},
{
@@ -173,21 +181,21 @@ func TestRepoRootForImportPath(t *testing.T) {
}
for _, test := range tests {
- got, err := repoRootForImportPath(test.path, web.Secure)
+ got, err := RepoRootForImportPath(test.path, IgnoreMod, web.Secure)
want := test.want
if want == nil {
if err == nil {
- t.Errorf("repoRootForImportPath(%q): Error expected but not received", test.path)
+ t.Errorf("RepoRootForImportPath(%q): Error expected but not received", test.path)
}
continue
}
if err != nil {
- t.Errorf("repoRootForImportPath(%q): %v", test.path, err)
+ t.Errorf("RepoRootForImportPath(%q): %v", test.path, err)
continue
}
- if got.vcs.name != want.vcs.name || got.repo != want.repo {
- t.Errorf("repoRootForImportPath(%q) = VCS(%s) Repo(%s), want VCS(%s) Repo(%s)", test.path, got.vcs, got.repo, want.vcs, want.repo)
+ if got.vcs.name != want.vcs.name || got.Repo != want.Repo {
+ t.Errorf("RepoRootForImportPath(%q) = VCS(%s) Repo(%s), want VCS(%s) Repo(%s)", test.path, got.vcs, got.Repo, want.vcs, want.Repo)
}
}
}
@@ -219,18 +227,18 @@ func TestFromDir(t *testing.T) {
f.Close()
}
- want := repoRoot{
+ want := RepoRoot{
vcs: vcs,
- root: path.Join("example.com", vcs.name),
+ Root: path.Join("example.com", vcs.name),
}
- var got repoRoot
- got.vcs, got.root, err = vcsFromDir(dir, tempDir)
+ var got RepoRoot
+ got.vcs, got.Root, err = vcsFromDir(dir, tempDir)
if err != nil {
t.Errorf("FromDir(%q, %q): %v", dir, tempDir, err)
continue
}
- if got.vcs.name != want.vcs.name || got.root != want.root {
- t.Errorf("FromDir(%q, %q) = VCS(%s) Root(%s), want VCS(%s) Root(%s)", dir, tempDir, got.vcs, got.root, want.vcs, want.root)
+ if got.vcs.name != want.vcs.name || got.Root != want.Root {
+ t.Errorf("FromDir(%q, %q) = VCS(%s) Root(%s), want VCS(%s) Root(%s)", dir, tempDir, got.vcs, got.Root, want.vcs, want.Root)
}
}
}
@@ -393,6 +401,22 @@ func TestMatchGoImport(t *testing.T) {
path: "different.example.com/user/foo",
err: errors.New("meta tags do not match import path"),
},
+ {
+ imports: []metaImport{
+ {Prefix: "myitcv.io/blah2", VCS: "mod", RepoRoot: "https://raw.githubusercontent.com/myitcv/pubx/master"},
+ {Prefix: "myitcv.io", VCS: "git", RepoRoot: "https://github.com/myitcv/x"},
+ },
+ path: "myitcv.io/blah2/foo",
+ mi: metaImport{Prefix: "myitcv.io/blah2", VCS: "mod", RepoRoot: "https://raw.githubusercontent.com/myitcv/pubx/master"},
+ },
+ {
+ imports: []metaImport{
+ {Prefix: "myitcv.io/blah2", VCS: "mod", RepoRoot: "https://raw.githubusercontent.com/myitcv/pubx/master"},
+ {Prefix: "myitcv.io", VCS: "git", RepoRoot: "https://github.com/myitcv/x"},
+ },
+ path: "myitcv.io/other",
+ mi: metaImport{Prefix: "myitcv.io", VCS: "git", RepoRoot: "https://github.com/myitcv/x"},
+ },
}
for _, test := range tests {
@@ -409,45 +433,46 @@ func TestMatchGoImport(t *testing.T) {
}
}
-func TestValidateRepoRootScheme(t *testing.T) {
+func TestValidateRepoRoot(t *testing.T) {
tests := []struct {
root string
- err string
+ ok bool
}{
{
root: "",
- err: "no scheme",
+ ok: false,
},
{
root: "http://",
- err: "",
+ ok: true,
},
{
- root: "a://",
- err: "",
+ root: "git+ssh://",
+ ok: true,
},
{
- root: "a#://",
- err: "invalid scheme",
+ root: "http#://",
+ ok: false,
+ },
+ {
+ root: "-config",
+ ok: false,
},
{
root: "-config://",
- err: "invalid scheme",
+ ok: false,
},
}
for _, test := range tests {
- err := validateRepoRootScheme(test.root)
- if err == nil {
- if test.err != "" {
- t.Errorf("validateRepoRootScheme(%q) = nil, want %q", test.root, test.err)
- }
- } else if test.err == "" {
- if err != nil {
- t.Errorf("validateRepoRootScheme(%q) = %q, want nil", test.root, test.err)
+ err := validateRepoRoot(test.root)
+ ok := err == nil
+ if ok != test.ok {
+ want := "error"
+ if test.ok {
+ want = "nil"
}
- } else if err.Error() != test.err {
- t.Errorf("validateRepoRootScheme(%q) = %q, want %q", test.root, err, test.err)
+ t.Errorf("validateRepoRoot(%q) = %q, want %s", test.root, err, want)
}
}
}
diff --git a/libgo/go/cmd/go/internal/help/help.go b/libgo/go/cmd/go/internal/help/help.go
index b4c5217f836..a80afe36c41 100644
--- a/libgo/go/cmd/go/internal/help/help.go
+++ b/libgo/go/cmd/go/internal/help/help.go
@@ -21,82 +21,95 @@ import (
// Help implements the 'help' command.
func Help(args []string) {
- if len(args) == 0 {
- PrintUsage(os.Stdout)
- // not exit 2: succeeded at 'go help'.
- return
- }
- if len(args) != 1 {
- fmt.Fprintf(os.Stderr, "usage: go help command\n\nToo many arguments given.\n")
- os.Exit(2) // failed at 'go help'
- }
-
- arg := args[0]
-
// 'go help documentation' generates doc.go.
- if arg == "documentation" {
+ if len(args) == 1 && args[0] == "documentation" {
fmt.Println("// Copyright 2011 The Go Authors. All rights reserved.")
fmt.Println("// Use of this source code is governed by a BSD-style")
fmt.Println("// license that can be found in the LICENSE file.")
fmt.Println()
- fmt.Println("// DO NOT EDIT THIS FILE. GENERATED BY mkalldocs.sh.")
+ fmt.Println("// Code generated by mkalldocs.sh; DO NOT EDIT.")
fmt.Println("// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.")
fmt.Println()
buf := new(bytes.Buffer)
- PrintUsage(buf)
+ PrintUsage(buf, base.Go)
usage := &base.Command{Long: buf.String()}
- tmpl(&commentWriter{W: os.Stdout}, documentationTemplate, append([]*base.Command{usage}, base.Commands...))
+ cmds := []*base.Command{usage}
+ for _, cmd := range base.Go.Commands {
+ if cmd.UsageLine == "gopath-get" {
+ // Avoid duplication of the "get" documentation.
+ continue
+ }
+ cmds = append(cmds, cmd)
+ cmds = append(cmds, cmd.Commands...)
+ }
+ tmpl(&commentWriter{W: os.Stdout}, documentationTemplate, cmds)
fmt.Println("package main")
return
}
- for _, cmd := range base.Commands {
- if cmd.Name() == arg {
- tmpl(os.Stdout, helpTemplate, cmd)
- // not exit 2: succeeded at 'go help cmd'.
- return
+ cmd := base.Go
+Args:
+ for i, arg := range args {
+ for _, sub := range cmd.Commands {
+ if sub.Name() == arg {
+ cmd = sub
+ continue Args
+ }
+ }
+
+ // helpSuccess is the help command using as many args as possible that would succeed.
+ helpSuccess := "go help"
+ if i > 0 {
+ helpSuccess = " " + strings.Join(args[:i], " ")
}
+ fmt.Fprintf(os.Stderr, "go help %s: unknown help topic. Run '%s'.\n", strings.Join(args, " "), helpSuccess)
+ os.Exit(2) // failed at 'go help cmd'
}
- fmt.Fprintf(os.Stderr, "Unknown help topic %#q. Run 'go help'.\n", arg)
- os.Exit(2) // failed at 'go help cmd'
+ if len(cmd.Commands) > 0 {
+ PrintUsage(os.Stdout, cmd)
+ } else {
+ tmpl(os.Stdout, helpTemplate, cmd)
+ }
+ // not exit 2: succeeded at 'go help cmd'.
+ return
}
-var usageTemplate = `Go is a tool for managing Go source code.
+var usageTemplate = `{{.Long | trim}}
Usage:
- go command [arguments]
+ {{.UsageLine}} <command> [arguments]
The commands are:
-{{range .}}{{if .Runnable}}
+{{range .Commands}}{{if or (.Runnable) .Commands}}
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
-Use "go help [command]" for more information about a command.
-
+Use "go help{{with .LongName}} {{.}}{{end}} <command>" for more information about a command.
+{{if eq (.UsageLine) "go"}}
Additional help topics:
-{{range .}}{{if not .Runnable}}
+{{range .Commands}}{{if and (not .Runnable) (not .Commands)}}
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
-Use "go help [topic]" for more information about that topic.
-
+Use "go help{{with .LongName}} {{.}}{{end}} <topic>" for more information about that topic.
+{{end}}
`
-var helpTemplate = `{{if .Runnable}}usage: go {{.UsageLine}}
+var helpTemplate = `{{if .Runnable}}usage: {{.UsageLine}}
{{end}}{{.Long | trim}}
`
var documentationTemplate = `{{range .}}{{if .Short}}{{.Short | capitalize}}
-{{end}}{{if .Runnable}}Usage:
+{{end}}{{if .Commands}}` + usageTemplate + `{{else}}{{if .Runnable}}Usage:
- go {{.UsageLine}}
+ {{.UsageLine}}
{{end}}{{.Long | trim}}
-{{end}}`
+{{end}}{{end}}`
// commentWriter writes a Go comment to the underlying io.Writer,
// using line comment form (//).
@@ -171,8 +184,8 @@ func capitalize(s string) string {
return string(unicode.ToTitle(r)) + s[n:]
}
-func PrintUsage(w io.Writer) {
+func PrintUsage(w io.Writer, cmd *base.Command) {
bw := bufio.NewWriter(w)
- tmpl(bw, usageTemplate, base.Commands)
+ tmpl(bw, usageTemplate, cmd)
bw.Flush()
}
diff --git a/libgo/go/cmd/go/internal/help/helpdoc.go b/libgo/go/cmd/go/internal/help/helpdoc.go
index 6aa449a8e29..aff4ce12f6c 100644
--- a/libgo/go/cmd/go/internal/help/helpdoc.go
+++ b/libgo/go/cmd/go/internal/help/helpdoc.go
@@ -30,7 +30,7 @@ the C or C++ compiler, respectively, to use.
var HelpPackages = &base.Command{
UsageLine: "packages",
- Short: "package lists",
+ Short: "package lists and patterns",
Long: `
Many commands apply to a set of packages:
@@ -54,9 +54,11 @@ for packages to be built with the go tool:
- "main" denotes the top-level package in a stand-alone executable.
-- "all" expands to all package directories found in all the GOPATH
+- "all" expands to all packages found in all the GOPATH
trees. For example, 'go list all' lists all the packages on the local
-system.
+system. When using modules, "all" expands to all packages in
+the main module and their dependencies, including dependencies
+needed by tests of any of those.
- "std" is like all but expands to just the packages in the standard
Go library.
@@ -193,6 +195,7 @@ using the named version control system, and then the path inside
that repository. The supported version control systems are:
Bazaar .bzr
+ Fossil .fossil
Git .git
Mercurial .hg
Subversion .svn
@@ -236,7 +239,7 @@ The meta tag should appear as early in the file as possible.
In particular, it should appear before any raw JavaScript or CSS,
to avoid confusing the go command's restricted parser.
-The vcs is one of "git", "hg", "svn", etc,
+The vcs is one of "bzr", "fossil", "git", "hg", "svn".
The repo-root is the root of the version control system
containing a scheme and not containing a .vcs qualifier.
@@ -258,12 +261,22 @@ the go tool will verify that https://example.org/?go-get=1 contains the
same meta tag and then git clone https://code.org/r/p/exproj into
GOPATH/src/example.org.
-New downloaded packages are written to the first directory listed in the GOPATH
-environment variable (For more details see: 'go help gopath').
+When using GOPATH, downloaded packages are written to the first directory
+listed in the GOPATH environment variable.
+(See 'go help gopath-get' and 'go help gopath'.)
+
+When using modules, downloaded packages are stored in the module cache.
+(See 'go help modules-get' and 'go help goproxy'.)
+
+When using modules, an additional variant of the go-import meta tag is
+recognized and is preferred over those listing version control systems.
+That variant uses "mod" as the vcs in the content value, as in:
-The go command attempts to download the version of the
-package appropriate for the Go release being used.
-Run 'go help get' for more.
+ <meta name="go-import" content="example.org mod https://code.org/moduleproxy">
+
+This tag means to fetch modules with paths beginning with example.org
+from the module proxy available at the URL https://code.org/moduleproxy.
+See 'go help goproxy' for details about the proxy protocol.
Import path checking
@@ -286,6 +299,9 @@ Import path checking is disabled for code found within vendor trees.
This makes it possible to copy code into alternate locations in vendor trees
without needing to update import comments.
+Import path checking is also disabled when using modules.
+Import path comments are obsoleted by the go.mod file's module statement.
+
See https://golang.org/s/go14customimport for details.
`,
}
@@ -358,6 +374,12 @@ in the list.
See https://golang.org/doc/code.html for an example.
+GOPATH and Modules
+
+When using modules, GOPATH is no longer used for resolving imports.
+However, it is still used to store downloaded source code (in GOPATH/pkg/mod)
+and compiled commands (in GOPATH/bin).
+
Internal Directories
Code in or below a directory named "internal" is importable only
@@ -461,11 +483,21 @@ General-purpose environment variables:
Examples are amd64, 386, arm, ppc64.
GOBIN
The directory where 'go install' will install a command.
+ GOCACHE
+ The directory where the go command will store cached
+ information for reuse in future builds.
+ GOFLAGS
+ A space-separated list of -flag=value settings to apply
+ to go commands by default, when the given flag is known by
+ the current command. Flags listed on the command-line
+ are applied after this list and therefore override it.
GOOS
The operating system for which to compile code.
Examples are linux, darwin, windows, netbsd.
GOPATH
For more details see: 'go help gopath'.
+ GOPROXY
+ URL of Go module proxy. See 'go help goproxy'.
GORACE
Options for the race detector.
See https://golang.org/doc/articles/race_detector.html.
@@ -474,9 +506,6 @@ General-purpose environment variables:
GOTMPDIR
The directory where the go command will write
temporary source files, packages, and binaries.
- GOCACHE
- The directory where the go command will store
- cached information for reuse in future builds.
Environment variables for use with cgo:
@@ -523,6 +552,9 @@ Architecture-specific environment variables:
GOMIPS
For GOARCH=mips{,le}, whether to use floating point instructions.
Valid values are hardfloat (default), softfloat.
+ GOMIPS64
+ For GOARCH=mips64{,le}, whether to use floating point instructions.
+ Valid values are hardfloat (default), softfloat.
Special-purpose environment variables:
@@ -542,6 +574,20 @@ Special-purpose environment variables:
Defined by Git. A colon-separated list of schemes that are allowed to be used
with git fetch/clone. If set, any scheme not explicitly mentioned will be
considered insecure by 'go get'.
+
+Additional information available from 'go env' but not read from the environment:
+
+ GOEXE
+ The executable file name suffix (".exe" on Windows, "" on other systems).
+ GOHOSTARCH
+ The architecture (GOARCH) of the Go toolchain binaries.
+ GOHOSTOS
+ The operating system (GOOS) of the Go toolchain binaries.
+ GOMOD
+ The absolute path to the go.mod of the main module,
+ or the empty string if not using modules.
+ GOTOOLDIR
+ The directory where the go tools (compile, cover, doc, etc...) are installed.
`,
}
@@ -651,6 +697,7 @@ The default location for cache data is a subdirectory named go-build
in the standard user cache directory for the current operating system.
Setting the GOCACHE environment variable overrides this default,
and running 'go env GOCACHE' prints the current cache directory.
+You can set the variable to 'off' to disable the cache.
The go command periodically deletes cached data that has not been
used recently. Running 'go clean -cache' deletes all cached data.
diff --git a/libgo/go/cmd/go/internal/imports/build.go b/libgo/go/cmd/go/internal/imports/build.go
new file mode 100644
index 00000000000..d1adf9440cb
--- /dev/null
+++ b/libgo/go/cmd/go/internal/imports/build.go
@@ -0,0 +1,211 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Copied from Go distribution src/go/build/build.go, syslist.go
+
+package imports
+
+import (
+ "bytes"
+ "strings"
+ "unicode"
+)
+
+var slashslash = []byte("//")
+
+// ShouldBuild reports whether it is okay to use this file,
+// The rule is that in the file's leading run of // comments
+// and blank lines, which must be followed by a blank line
+// (to avoid including a Go package clause doc comment),
+// lines beginning with '// +build' are taken as build directives.
+//
+// The file is accepted only if each such line lists something
+// matching the file. For example:
+//
+// // +build windows linux
+//
+// marks the file as applicable only on Windows and Linux.
+//
+// If tags["*"] is true, then ShouldBuild will consider every
+// build tag except "ignore" to be both true and false for
+// the purpose of satisfying build tags, in order to estimate
+// (conservatively) whether a file could ever possibly be used
+// in any build.
+//
+func ShouldBuild(content []byte, tags map[string]bool) bool {
+ // Pass 1. Identify leading run of // comments and blank lines,
+ // which must be followed by a blank line.
+ end := 0
+ p := content
+ for len(p) > 0 {
+ line := p
+ if i := bytes.IndexByte(line, '\n'); i >= 0 {
+ line, p = line[:i], p[i+1:]
+ } else {
+ p = p[len(p):]
+ }
+ line = bytes.TrimSpace(line)
+ if len(line) == 0 { // Blank line
+ end = len(content) - len(p)
+ continue
+ }
+ if !bytes.HasPrefix(line, slashslash) { // Not comment line
+ break
+ }
+ }
+ content = content[:end]
+
+ // Pass 2. Process each line in the run.
+ p = content
+ allok := true
+ for len(p) > 0 {
+ line := p
+ if i := bytes.IndexByte(line, '\n'); i >= 0 {
+ line, p = line[:i], p[i+1:]
+ } else {
+ p = p[len(p):]
+ }
+ line = bytes.TrimSpace(line)
+ if !bytes.HasPrefix(line, slashslash) {
+ continue
+ }
+ line = bytes.TrimSpace(line[len(slashslash):])
+ if len(line) > 0 && line[0] == '+' {
+ // Looks like a comment +line.
+ f := strings.Fields(string(line))
+ if f[0] == "+build" {
+ ok := false
+ for _, tok := range f[1:] {
+ if matchTags(tok, tags) {
+ ok = true
+ }
+ }
+ if !ok {
+ allok = false
+ }
+ }
+ }
+ }
+
+ return allok
+}
+
+// matchTags reports whether the name is one of:
+//
+// tag (if tags[tag] is true)
+// !tag (if tags[tag] is false)
+// a comma-separated list of any of these
+//
+func matchTags(name string, tags map[string]bool) bool {
+ if name == "" {
+ return false
+ }
+ if i := strings.Index(name, ","); i >= 0 {
+ // comma-separated list
+ ok1 := matchTags(name[:i], tags)
+ ok2 := matchTags(name[i+1:], tags)
+ return ok1 && ok2
+ }
+ if strings.HasPrefix(name, "!!") { // bad syntax, reject always
+ return false
+ }
+ if strings.HasPrefix(name, "!") { // negation
+ return len(name) > 1 && matchTag(name[1:], tags, false)
+ }
+ return matchTag(name, tags, true)
+}
+
+// matchTag reports whether the tag name is valid and satisfied by tags[name]==want.
+func matchTag(name string, tags map[string]bool, want bool) bool {
+ // Tags must be letters, digits, underscores or dots.
+ // Unlike in Go identifiers, all digits are fine (e.g., "386").
+ for _, c := range name {
+ if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' {
+ return false
+ }
+ }
+
+ if tags["*"] && name != "" && name != "ignore" {
+ // Special case for gathering all possible imports:
+ // if we put * in the tags map then all tags
+ // except "ignore" are considered both present and not
+ // (so we return true no matter how 'want' is set).
+ return true
+ }
+
+ have := tags[name]
+ if name == "linux" {
+ have = have || tags["android"]
+ }
+ return have == want
+}
+
+// MatchFile returns false if the name contains a $GOOS or $GOARCH
+// suffix which does not match the current system.
+// The recognized name formats are:
+//
+// name_$(GOOS).*
+// name_$(GOARCH).*
+// name_$(GOOS)_$(GOARCH).*
+// name_$(GOOS)_test.*
+// name_$(GOARCH)_test.*
+// name_$(GOOS)_$(GOARCH)_test.*
+//
+// An exception: if GOOS=android, then files with GOOS=linux are also matched.
+//
+// If tags["*"] is true, then MatchFile will consider all possible
+// GOOS and GOARCH to be available and will consequently
+// always return true.
+func MatchFile(name string, tags map[string]bool) bool {
+ if tags["*"] {
+ return true
+ }
+ if dot := strings.Index(name, "."); dot != -1 {
+ name = name[:dot]
+ }
+
+ // Before Go 1.4, a file called "linux.go" would be equivalent to having a
+ // build tag "linux" in that file. For Go 1.4 and beyond, we require this
+ // auto-tagging to apply only to files with a non-empty prefix, so
+ // "foo_linux.go" is tagged but "linux.go" is not. This allows new operating
+ // systems, such as android, to arrive without breaking existing code with
+ // innocuous source code in "android.go". The easiest fix: cut everything
+ // in the name before the initial _.
+ i := strings.Index(name, "_")
+ if i < 0 {
+ return true
+ }
+ name = name[i:] // ignore everything before first _
+
+ l := strings.Split(name, "_")
+ if n := len(l); n > 0 && l[n-1] == "test" {
+ l = l[:n-1]
+ }
+ n := len(l)
+ if n >= 2 && KnownOS[l[n-2]] && KnownArch[l[n-1]] {
+ return tags[l[n-2]] && tags[l[n-1]]
+ }
+ if n >= 1 && KnownOS[l[n-1]] {
+ return tags[l[n-1]]
+ }
+ if n >= 1 && KnownArch[l[n-1]] {
+ return tags[l[n-1]]
+ }
+ return true
+}
+
+var KnownOS = make(map[string]bool)
+var KnownArch = make(map[string]bool)
+
+func init() {
+ for _, v := range strings.Fields(goosList) {
+ KnownOS[v] = true
+ }
+ for _, v := range strings.Fields(goarchList) {
+ KnownArch[v] = true
+ }
+}
+
+const goosList = "android darwin dragonfly freebsd js linux nacl netbsd openbsd plan9 solaris windows zos "
+const goarchList = "386 amd64 amd64p32 arm armbe arm64 arm64be ppc64 ppc64le mips mipsle mips64 mips64le mips64p32 mips64p32le ppc riscv riscv64 s390 s390x sparc sparc64 wasm "
diff --git a/libgo/go/cmd/go/internal/imports/read.go b/libgo/go/cmd/go/internal/imports/read.go
new file mode 100644
index 00000000000..58c2abdc29a
--- /dev/null
+++ b/libgo/go/cmd/go/internal/imports/read.go
@@ -0,0 +1,249 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Copied from Go distribution src/go/build/read.go.
+
+package imports
+
+import (
+ "bufio"
+ "errors"
+ "io"
+ "unicode/utf8"
+)
+
+type importReader struct {
+ b *bufio.Reader
+ buf []byte
+ peek byte
+ err error
+ eof bool
+ nerr int
+}
+
+func isIdent(c byte) bool {
+ return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '_' || c >= utf8.RuneSelf
+}
+
+var (
+ errSyntax = errors.New("syntax error")
+ errNUL = errors.New("unexpected NUL in input")
+)
+
+// syntaxError records a syntax error, but only if an I/O error has not already been recorded.
+func (r *importReader) syntaxError() {
+ if r.err == nil {
+ r.err = errSyntax
+ }
+}
+
+// readByte reads the next byte from the input, saves it in buf, and returns it.
+// If an error occurs, readByte records the error in r.err and returns 0.
+func (r *importReader) readByte() byte {
+ c, err := r.b.ReadByte()
+ if err == nil {
+ r.buf = append(r.buf, c)
+ if c == 0 {
+ err = errNUL
+ }
+ }
+ if err != nil {
+ if err == io.EOF {
+ r.eof = true
+ } else if r.err == nil {
+ r.err = err
+ }
+ c = 0
+ }
+ return c
+}
+
+// peekByte returns the next byte from the input reader but does not advance beyond it.
+// If skipSpace is set, peekByte skips leading spaces and comments.
+func (r *importReader) peekByte(skipSpace bool) byte {
+ if r.err != nil {
+ if r.nerr++; r.nerr > 10000 {
+ panic("go/build: import reader looping")
+ }
+ return 0
+ }
+
+ // Use r.peek as first input byte.
+ // Don't just return r.peek here: it might have been left by peekByte(false)
+ // and this might be peekByte(true).
+ c := r.peek
+ if c == 0 {
+ c = r.readByte()
+ }
+ for r.err == nil && !r.eof {
+ if skipSpace {
+ // For the purposes of this reader, semicolons are never necessary to
+ // understand the input and are treated as spaces.
+ switch c {
+ case ' ', '\f', '\t', '\r', '\n', ';':
+ c = r.readByte()
+ continue
+
+ case '/':
+ c = r.readByte()
+ if c == '/' {
+ for c != '\n' && r.err == nil && !r.eof {
+ c = r.readByte()
+ }
+ } else if c == '*' {
+ var c1 byte
+ for (c != '*' || c1 != '/') && r.err == nil {
+ if r.eof {
+ r.syntaxError()
+ }
+ c, c1 = c1, r.readByte()
+ }
+ } else {
+ r.syntaxError()
+ }
+ c = r.readByte()
+ continue
+ }
+ }
+ break
+ }
+ r.peek = c
+ return r.peek
+}
+
+// nextByte is like peekByte but advances beyond the returned byte.
+func (r *importReader) nextByte(skipSpace bool) byte {
+ c := r.peekByte(skipSpace)
+ r.peek = 0
+ return c
+}
+
+// readKeyword reads the given keyword from the input.
+// If the keyword is not present, readKeyword records a syntax error.
+func (r *importReader) readKeyword(kw string) {
+ r.peekByte(true)
+ for i := 0; i < len(kw); i++ {
+ if r.nextByte(false) != kw[i] {
+ r.syntaxError()
+ return
+ }
+ }
+ if isIdent(r.peekByte(false)) {
+ r.syntaxError()
+ }
+}
+
+// readIdent reads an identifier from the input.
+// If an identifier is not present, readIdent records a syntax error.
+func (r *importReader) readIdent() {
+ c := r.peekByte(true)
+ if !isIdent(c) {
+ r.syntaxError()
+ return
+ }
+ for isIdent(r.peekByte(false)) {
+ r.peek = 0
+ }
+}
+
+// readString reads a quoted string literal from the input.
+// If an identifier is not present, readString records a syntax error.
+func (r *importReader) readString(save *[]string) {
+ switch r.nextByte(true) {
+ case '`':
+ start := len(r.buf) - 1
+ for r.err == nil {
+ if r.nextByte(false) == '`' {
+ if save != nil {
+ *save = append(*save, string(r.buf[start:]))
+ }
+ break
+ }
+ if r.eof {
+ r.syntaxError()
+ }
+ }
+ case '"':
+ start := len(r.buf) - 1
+ for r.err == nil {
+ c := r.nextByte(false)
+ if c == '"' {
+ if save != nil {
+ *save = append(*save, string(r.buf[start:]))
+ }
+ break
+ }
+ if r.eof || c == '\n' {
+ r.syntaxError()
+ }
+ if c == '\\' {
+ r.nextByte(false)
+ }
+ }
+ default:
+ r.syntaxError()
+ }
+}
+
+// readImport reads an import clause - optional identifier followed by quoted string -
+// from the input.
+func (r *importReader) readImport(imports *[]string) {
+ c := r.peekByte(true)
+ if c == '.' {
+ r.peek = 0
+ } else if isIdent(c) {
+ r.readIdent()
+ }
+ r.readString(imports)
+}
+
+// ReadComments is like ioutil.ReadAll, except that it only reads the leading
+// block of comments in the file.
+func ReadComments(f io.Reader) ([]byte, error) {
+ r := &importReader{b: bufio.NewReader(f)}
+ r.peekByte(true)
+ if r.err == nil && !r.eof {
+ // Didn't reach EOF, so must have found a non-space byte. Remove it.
+ r.buf = r.buf[:len(r.buf)-1]
+ }
+ return r.buf, r.err
+}
+
+// ReadImports is like ioutil.ReadAll, except that it expects a Go file as input
+// and stops reading the input once the imports have completed.
+func ReadImports(f io.Reader, reportSyntaxError bool, imports *[]string) ([]byte, error) {
+ r := &importReader{b: bufio.NewReader(f)}
+
+ r.readKeyword("package")
+ r.readIdent()
+ for r.peekByte(true) == 'i' {
+ r.readKeyword("import")
+ if r.peekByte(true) == '(' {
+ r.nextByte(false)
+ for r.peekByte(true) != ')' && r.err == nil {
+ r.readImport(imports)
+ }
+ r.nextByte(false)
+ } else {
+ r.readImport(imports)
+ }
+ }
+
+ // If we stopped successfully before EOF, we read a byte that told us we were done.
+ // Return all but that last byte, which would cause a syntax error if we let it through.
+ if r.err == nil && !r.eof {
+ return r.buf[:len(r.buf)-1], nil
+ }
+
+ // If we stopped for a syntax error, consume the whole file so that
+ // we are sure we don't change the errors that go/parser returns.
+ if r.err == errSyntax && !reportSyntaxError {
+ r.err = nil
+ for r.err == nil && !r.eof {
+ r.readByte()
+ }
+ }
+
+ return r.buf, r.err
+}
diff --git a/libgo/go/cmd/go/internal/imports/read_test.go b/libgo/go/cmd/go/internal/imports/read_test.go
new file mode 100644
index 00000000000..6ea356f1ff0
--- /dev/null
+++ b/libgo/go/cmd/go/internal/imports/read_test.go
@@ -0,0 +1,228 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Copied from Go distribution src/go/build/read.go.
+
+package imports
+
+import (
+ "io"
+ "strings"
+ "testing"
+)
+
+const quote = "`"
+
+type readTest struct {
+ // Test input contains ℙ where readImports should stop.
+ in string
+ err string
+}
+
+var readImportsTests = []readTest{
+ {
+ `package p`,
+ "",
+ },
+ {
+ `package p; import "x"`,
+ "",
+ },
+ {
+ `package p; import . "x"`,
+ "",
+ },
+ {
+ `package p; import "x";ℙvar x = 1`,
+ "",
+ },
+ {
+ `package p
+
+ // comment
+
+ import "x"
+ import _ "x"
+ import a "x"
+
+ /* comment */
+
+ import (
+ "x" /* comment */
+ _ "x"
+ a "x" // comment
+ ` + quote + `x` + quote + `
+ _ /*comment*/ ` + quote + `x` + quote + `
+ a ` + quote + `x` + quote + `
+ )
+ import (
+ )
+ import ()
+ import()import()import()
+ import();import();import()
+
+ ℙvar x = 1
+ `,
+ "",
+ },
+}
+
+var readCommentsTests = []readTest{
+ {
+ `ℙpackage p`,
+ "",
+ },
+ {
+ `ℙpackage p; import "x"`,
+ "",
+ },
+ {
+ `ℙpackage p; import . "x"`,
+ "",
+ },
+ {
+ `// foo
+
+ /* bar */
+
+ /* quux */ // baz
+
+ /*/ zot */
+
+ // asdf
+ ℙHello, world`,
+ "",
+ },
+}
+
+func testRead(t *testing.T, tests []readTest, read func(io.Reader) ([]byte, error)) {
+ for i, tt := range tests {
+ var in, testOut string
+ j := strings.Index(tt.in, "ℙ")
+ if j < 0 {
+ in = tt.in
+ testOut = tt.in
+ } else {
+ in = tt.in[:j] + tt.in[j+len("ℙ"):]
+ testOut = tt.in[:j]
+ }
+ r := strings.NewReader(in)
+ buf, err := read(r)
+ if err != nil {
+ if tt.err == "" {
+ t.Errorf("#%d: err=%q, expected success (%q)", i, err, string(buf))
+ continue
+ }
+ if !strings.Contains(err.Error(), tt.err) {
+ t.Errorf("#%d: err=%q, expected %q", i, err, tt.err)
+ continue
+ }
+ continue
+ }
+ if err == nil && tt.err != "" {
+ t.Errorf("#%d: success, expected %q", i, tt.err)
+ continue
+ }
+
+ out := string(buf)
+ if out != testOut {
+ t.Errorf("#%d: wrong output:\nhave %q\nwant %q\n", i, out, testOut)
+ }
+ }
+}
+
+func TestReadImports(t *testing.T) {
+ testRead(t, readImportsTests, func(r io.Reader) ([]byte, error) { return ReadImports(r, true, nil) })
+}
+
+func TestReadComments(t *testing.T) {
+ testRead(t, readCommentsTests, ReadComments)
+}
+
+var readFailuresTests = []readTest{
+ {
+ `package`,
+ "syntax error",
+ },
+ {
+ "package p\n\x00\nimport `math`\n",
+ "unexpected NUL in input",
+ },
+ {
+ `package p; import`,
+ "syntax error",
+ },
+ {
+ `package p; import "`,
+ "syntax error",
+ },
+ {
+ "package p; import ` \n\n",
+ "syntax error",
+ },
+ {
+ `package p; import "x`,
+ "syntax error",
+ },
+ {
+ `package p; import _`,
+ "syntax error",
+ },
+ {
+ `package p; import _ "`,
+ "syntax error",
+ },
+ {
+ `package p; import _ "x`,
+ "syntax error",
+ },
+ {
+ `package p; import .`,
+ "syntax error",
+ },
+ {
+ `package p; import . "`,
+ "syntax error",
+ },
+ {
+ `package p; import . "x`,
+ "syntax error",
+ },
+ {
+ `package p; import (`,
+ "syntax error",
+ },
+ {
+ `package p; import ("`,
+ "syntax error",
+ },
+ {
+ `package p; import ("x`,
+ "syntax error",
+ },
+ {
+ `package p; import ("x"`,
+ "syntax error",
+ },
+}
+
+func TestReadFailures(t *testing.T) {
+ // Errors should be reported (true arg to readImports).
+ testRead(t, readFailuresTests, func(r io.Reader) ([]byte, error) { return ReadImports(r, true, nil) })
+}
+
+func TestReadFailuresIgnored(t *testing.T) {
+ // Syntax errors should not be reported (false arg to readImports).
+ // Instead, entire file should be the output and no error.
+ // Convert tests not to return syntax errors.
+ tests := make([]readTest, len(readFailuresTests))
+ copy(tests, readFailuresTests)
+ for i := range tests {
+ tt := &tests[i]
+ if !strings.Contains(tt.err, "NUL") {
+ tt.err = ""
+ }
+ }
+ testRead(t, tests, func(r io.Reader) ([]byte, error) { return ReadImports(r, false, nil) })
+}
diff --git a/libgo/go/cmd/go/internal/imports/scan.go b/libgo/go/cmd/go/internal/imports/scan.go
new file mode 100644
index 00000000000..d944e95724e
--- /dev/null
+++ b/libgo/go/cmd/go/internal/imports/scan.go
@@ -0,0 +1,96 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package imports
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "sort"
+ "strconv"
+ "strings"
+)
+
+func ScanDir(dir string, tags map[string]bool) ([]string, []string, error) {
+ infos, err := ioutil.ReadDir(dir)
+ if err != nil {
+ return nil, nil, err
+ }
+ var files []string
+ for _, info := range infos {
+ name := info.Name()
+ if info.Mode().IsRegular() && !strings.HasPrefix(name, "_") && strings.HasSuffix(name, ".go") && MatchFile(name, tags) {
+ files = append(files, filepath.Join(dir, name))
+ }
+ }
+ return scanFiles(files, tags, false)
+}
+
+func ScanFiles(files []string, tags map[string]bool) ([]string, []string, error) {
+ return scanFiles(files, tags, true)
+}
+
+func scanFiles(files []string, tags map[string]bool, explicitFiles bool) ([]string, []string, error) {
+ imports := make(map[string]bool)
+ testImports := make(map[string]bool)
+ numFiles := 0
+Files:
+ for _, name := range files {
+ r, err := os.Open(name)
+ if err != nil {
+ return nil, nil, err
+ }
+ var list []string
+ data, err := ReadImports(r, false, &list)
+ r.Close()
+ if err != nil {
+ return nil, nil, fmt.Errorf("reading %s: %v", name, err)
+ }
+
+ // import "C" is implicit requirement of cgo tag.
+ // When listing files on the command line (explicitFiles=true)
+ // we do not apply build tag filtering but we still do apply
+ // cgo filtering, so no explicitFiles check here.
+ // Why? Because we always have, and it's not worth breaking
+ // that behavior now.
+ for _, path := range list {
+ if path == `"C"` && !tags["cgo"] && !tags["*"] {
+ continue Files
+ }
+ }
+
+ if !explicitFiles && !ShouldBuild(data, tags) {
+ continue
+ }
+ numFiles++
+ m := imports
+ if strings.HasSuffix(name, "_test.go") {
+ m = testImports
+ }
+ for _, p := range list {
+ q, err := strconv.Unquote(p)
+ if err != nil {
+ continue
+ }
+ m[q] = true
+ }
+ }
+ if numFiles == 0 {
+ return nil, nil, ErrNoGo
+ }
+ return keys(imports), keys(testImports), nil
+}
+
+var ErrNoGo = fmt.Errorf("no Go source files")
+
+func keys(m map[string]bool) []string {
+ var list []string
+ for k := range m {
+ list = append(list, k)
+ }
+ sort.Strings(list)
+ return list
+}
diff --git a/libgo/go/cmd/go/internal/imports/scan_test.go b/libgo/go/cmd/go/internal/imports/scan_test.go
new file mode 100644
index 00000000000..6a2ff62ba75
--- /dev/null
+++ b/libgo/go/cmd/go/internal/imports/scan_test.go
@@ -0,0 +1,67 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package imports
+
+import (
+ "internal/testenv"
+ "path/filepath"
+ "reflect"
+ "runtime"
+ "testing"
+)
+
+func TestScan(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+
+ imports, testImports, err := ScanDir(filepath.Join(runtime.GOROOT(), "src/encoding/json"), Tags())
+ if err != nil {
+ t.Fatal(err)
+ }
+ foundBase64 := false
+ for _, p := range imports {
+ if p == "encoding/base64" {
+ foundBase64 = true
+ }
+ if p == "encoding/binary" {
+ // A dependency but not an import
+ t.Errorf("json reported as importing encoding/binary but does not")
+ }
+ if p == "net/http" {
+ // A test import but not an import
+ t.Errorf("json reported as importing encoding/binary but does not")
+ }
+ }
+ if !foundBase64 {
+ t.Errorf("json missing import encoding/base64 (%q)", imports)
+ }
+
+ foundHTTP := false
+ for _, p := range testImports {
+ if p == "net/http" {
+ foundHTTP = true
+ }
+ if p == "unicode/utf16" {
+ // A package import but not a test import
+ t.Errorf("json reported as test-importing unicode/utf16 but does not")
+ }
+ }
+ if !foundHTTP {
+ t.Errorf("json missing test import net/http (%q)", testImports)
+ }
+}
+
+func TestScanStar(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+
+ imports, _, err := ScanDir("testdata/import1", map[string]bool{"*": true})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ want := []string{"import1", "import2", "import3", "import4"}
+ if !reflect.DeepEqual(imports, want) {
+ t.Errorf("ScanDir testdata/import1:\nhave %v\nwant %v", imports, want)
+ }
+}
diff --git a/libgo/go/cmd/go/internal/imports/tags.go b/libgo/go/cmd/go/internal/imports/tags.go
new file mode 100644
index 00000000000..1c22a472b80
--- /dev/null
+++ b/libgo/go/cmd/go/internal/imports/tags.go
@@ -0,0 +1,34 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package imports
+
+import "cmd/go/internal/cfg"
+
+var tags map[string]bool
+
+func Tags() map[string]bool {
+ if tags == nil {
+ tags = loadTags()
+ }
+ return tags
+}
+
+func loadTags() map[string]bool {
+ tags := map[string]bool{
+ cfg.BuildContext.GOOS: true,
+ cfg.BuildContext.GOARCH: true,
+ cfg.BuildContext.Compiler: true,
+ }
+ if cfg.BuildContext.CgoEnabled {
+ tags["cgo"] = true
+ }
+ for _, tag := range cfg.BuildContext.BuildTags {
+ tags[tag] = true
+ }
+ for _, tag := range cfg.BuildContext.ReleaseTags {
+ tags[tag] = true
+ }
+ return tags
+}
diff --git a/libgo/go/cmd/go/internal/imports/testdata/import1/x.go b/libgo/go/cmd/go/internal/imports/testdata/import1/x.go
new file mode 100644
index 00000000000..98f9191053b
--- /dev/null
+++ b/libgo/go/cmd/go/internal/imports/testdata/import1/x.go
@@ -0,0 +1,3 @@
+package x
+
+import "import1"
diff --git a/libgo/go/cmd/go/internal/imports/testdata/import1/x1.go b/libgo/go/cmd/go/internal/imports/testdata/import1/x1.go
new file mode 100644
index 00000000000..6a9594aed03
--- /dev/null
+++ b/libgo/go/cmd/go/internal/imports/testdata/import1/x1.go
@@ -0,0 +1,9 @@
+// +build blahblh
+// +build linux
+// +build !linux
+// +build windows
+// +build darwin
+
+package x
+
+import "import4"
diff --git a/libgo/go/cmd/go/internal/imports/testdata/import1/x_darwin.go b/libgo/go/cmd/go/internal/imports/testdata/import1/x_darwin.go
new file mode 100644
index 00000000000..a0c3fdd21b5
--- /dev/null
+++ b/libgo/go/cmd/go/internal/imports/testdata/import1/x_darwin.go
@@ -0,0 +1,3 @@
+package xxxx
+
+import "import3"
diff --git a/libgo/go/cmd/go/internal/imports/testdata/import1/x_windows.go b/libgo/go/cmd/go/internal/imports/testdata/import1/x_windows.go
new file mode 100644
index 00000000000..63c508248fb
--- /dev/null
+++ b/libgo/go/cmd/go/internal/imports/testdata/import1/x_windows.go
@@ -0,0 +1,3 @@
+package x
+
+import "import2"
diff --git a/libgo/go/cmd/go/internal/list/list.go b/libgo/go/cmd/go/internal/list/list.go
index 16e7f70d731..b3ba4edc650 100644
--- a/libgo/go/cmd/go/internal/list/list.go
+++ b/libgo/go/cmd/go/internal/list/list.go
@@ -7,23 +7,33 @@ package list
import (
"bufio"
+ "bytes"
"encoding/json"
"io"
"os"
+ "sort"
"strings"
"text/template"
"cmd/go/internal/base"
+ "cmd/go/internal/cache"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
+ "cmd/go/internal/modload"
+ "cmd/go/internal/str"
"cmd/go/internal/work"
)
var CmdList = &base.Command{
- UsageLine: "list [-e] [-f format] [-json] [build flags] [packages]",
- Short: "list packages",
+ // Note: -f -json -m are listed explicitly because they are the most common list flags.
+ // Do not send CLs removing them because they're covered by [list flags].
+ UsageLine: "go list [-f format] [-json] [-m] [list flags] [build flags] [packages]",
+ Short: "list packages or modules",
Long: `
-List lists the packages named by the import paths, one per line.
+List lists the named packages, one per line.
+The most commonly-used flags are -f and -json, which control the form
+of the output printed for each package. Other list flags, documented below,
+control more specific details.
The default output shows the package import path:
@@ -33,40 +43,46 @@ The default output shows the package import path:
golang.org/x/net/html
The -f flag specifies an alternate format for the list, using the
-syntax of package template. The default output is equivalent to -f
-'{{.ImportPath}}'. The struct being passed to the template is:
+syntax of package template. The default output is equivalent
+to -f '{{.ImportPath}}'. The struct being passed to the template is:
type Package struct {
- Dir string // directory containing package sources
- ImportPath string // import path of package in dir
- ImportComment string // path in import comment on package statement
- Name string // package name
- Doc string // package documentation string
- Target string // install path
- Shlib string // the shared library that contains this package (only set when -linkshared)
- Goroot bool // is this package in the Go root?
- Standard bool // is this package part of the standard Go library?
- Stale bool // would 'go install' do anything for this package?
- StaleReason string // explanation for Stale==true
- Root string // Go root or Go path dir containing this package
- ConflictDir string // this directory shadows Dir in $GOPATH
- BinaryOnly bool // binary-only package: cannot be recompiled from sources
+ Dir string // directory containing package sources
+ ImportPath string // import path of package in dir
+ ImportComment string // path in import comment on package statement
+ Name string // package name
+ Doc string // package documentation string
+ Target string // install path
+ Shlib string // the shared library that contains this package (only set when -linkshared)
+ Goroot bool // is this package in the Go root?
+ Standard bool // is this package part of the standard Go library?
+ Stale bool // would 'go install' do anything for this package?
+ StaleReason string // explanation for Stale==true
+ Root string // Go root or Go path dir containing this package
+ ConflictDir string // this directory shadows Dir in $GOPATH
+ BinaryOnly bool // binary-only package: cannot be recompiled from sources
+ ForTest string // package is only for use in named test
+ Export string // file containing export data (when using -export)
+ Module *Module // info about package's containing module, if any (can be nil)
+ Match []string // command-line patterns matching this package
+ DepOnly bool // package is only a dependency, not explicitly listed
// Source files
- GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
- CgoFiles []string // .go sources files that import "C"
- IgnoredGoFiles []string // .go sources ignored due to build constraints
- CFiles []string // .c source files
- CXXFiles []string // .cc, .cxx and .cpp source files
- MFiles []string // .m source files
- HFiles []string // .h, .hh, .hpp and .hxx source files
- FFiles []string // .f, .F, .for and .f90 Fortran source files
- SFiles []string // .s source files
- SwigFiles []string // .swig files
- SwigCXXFiles []string // .swigcxx files
- SysoFiles []string // .syso object files to add to archive
- TestGoFiles []string // _test.go files in package
- XTestGoFiles []string // _test.go files outside package
+ GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
+ CgoFiles []string // .go source files that import "C"
+ CompiledGoFiles []string // .go files presented to compiler (when using -compiled)
+ IgnoredGoFiles []string // .go source files ignored due to build constraints
+ CFiles []string // .c source files
+ CXXFiles []string // .cc, .cxx and .cpp source files
+ MFiles []string // .m source files
+ HFiles []string // .h, .hh, .hpp and .hxx source files
+ FFiles []string // .f, .F, .for and .f90 Fortran source files
+ SFiles []string // .s source files
+ SwigFiles []string // .swig files
+ SwigCXXFiles []string // .swigcxx files
+ SysoFiles []string // .syso object files to add to archive
+ TestGoFiles []string // _test.go files in package
+ XTestGoFiles []string // _test.go files outside package
// Cgo directives
CgoCFLAGS []string // cgo: flags for C compiler
@@ -77,10 +93,11 @@ syntax of package template. The default output is equivalent to -f
CgoPkgConfig []string // cgo: pkg-config names
// Dependency information
- Imports []string // import paths used by this package
- Deps []string // all (recursively) imported dependencies
- TestImports []string // imports from TestGoFiles
- XTestImports []string // imports from XTestGoFiles
+ Imports []string // import paths used by this package
+ ImportMap map[string]string // map from source import to ImportPath (identity entries omitted)
+ Deps []string // all (recursively) imported dependencies
+ TestImports []string // imports from TestGoFiles
+ XTestImports []string // imports from XTestGoFiles
// Error information
Incomplete bool // this package or a dependency has an error
@@ -92,7 +109,7 @@ Packages stored in vendor directories report an ImportPath that includes the
path to the vendor directory (for example, "d/vendor/p" instead of "p"),
so that the ImportPath uniquely identifies a given copy of a package.
The Imports, Deps, TestImports, and XTestImports lists also contain these
-expanded imports paths. See golang.org/s/go15vendor for more about vendoring.
+expanded import paths. See golang.org/s/go15vendor for more about vendoring.
The error information, if any, is
@@ -102,22 +119,25 @@ The error information, if any, is
Err string // the error itself
}
+The module information is a Module struct, defined in the discussion
+of list -m below.
+
The template function "join" calls strings.Join.
The template function "context" returns the build context, defined as:
- type Context struct {
- GOARCH string // target architecture
- GOOS string // target operating system
- GOROOT string // Go root
- GOPATH string // Go path
- CgoEnabled bool // whether cgo can be used
- UseAllFiles bool // use files regardless of +build lines, file names
- Compiler string // compiler to assume when computing target paths
- BuildTags []string // build constraints to match in +build lines
- ReleaseTags []string // releases the current release is compatible with
- InstallSuffix string // suffix to use in the name of the install dir
- }
+ type Context struct {
+ GOARCH string // target architecture
+ GOOS string // target operating system
+ GOROOT string // Go root
+ GOPATH string // Go path
+ CgoEnabled bool // whether cgo can be used
+ UseAllFiles bool // use files regardless of +build lines, file names
+ Compiler string // compiler to assume when computing target paths
+ BuildTags []string // build constraints to match in +build lines
+ ReleaseTags []string // releases the current release is compatible with
+ InstallSuffix string // suffix to use in the name of the install dir
+ }
For more information about the meaning of these fields see the documentation
for the go/build package's Context type.
@@ -125,6 +145,18 @@ for the go/build package's Context type.
The -json flag causes the package data to be printed in JSON format
instead of using the template format.
+The -compiled flag causes list to set CompiledGoFiles to the Go source
+files presented to the compiler. Typically this means that it repeats
+the files listed in GoFiles and then also adds the Go code generated
+by processing CgoFiles and SwigFiles. The Imports list contains the
+union of all imports from both GoFiles and CompiledGoFiles.
+
+The -deps flag causes list to iterate over not just the named packages
+but also all their dependencies. It visits them in a depth-first post-order
+traversal, so that a package is listed only after all its dependencies.
+Packages not explicitly listed on the command line will have the DepOnly
+field set to true.
+
The -e flag changes the handling of erroneous packages, those that
cannot be found or are malformed. By default, the list command
prints an error to standard error for each erroneous package and
@@ -135,9 +167,120 @@ printing. Erroneous packages will have a non-empty ImportPath and
a non-nil Error field; other information may or may not be missing
(zeroed).
+The -export flag causes list to set the Export field to the name of a
+file containing up-to-date export information for the given package.
+
+The -find flag causes list to identify the named packages but not
+resolve their dependencies: the Imports and Deps lists will be empty.
+
+The -test flag causes list to report not only the named packages
+but also their test binaries (for packages with tests), to convey to
+source code analysis tools exactly how test binaries are constructed.
+The reported import path for a test binary is the import path of
+the package followed by a ".test" suffix, as in "math/rand.test".
+When building a test, it is sometimes necessary to rebuild certain
+dependencies specially for that test (most commonly the tested
+package itself). The reported import path of a package recompiled
+for a particular test binary is followed by a space and the name of
+the test binary in brackets, as in "math/rand [math/rand.test]"
+or "regexp [sort.test]". The ForTest field is also set to the name
+of the package being tested ("math/rand" or "sort" in the previous
+examples).
+
+The Dir, Target, Shlib, Root, ConflictDir, and Export file paths
+are all absolute paths.
+
+By default, the lists GoFiles, CgoFiles, and so on hold names of files in Dir
+(that is, paths relative to Dir, not absolute paths).
+The generated files added when using the -compiled and -test flags
+are absolute paths referring to cached copies of generated Go source files.
+Although they are Go source files, the paths may not end in ".go".
+
+The -m flag causes list to list modules instead of packages.
+
+When listing modules, the -f flag still specifies a format template
+applied to a Go struct, but now a Module struct:
+
+ type Module struct {
+ Path string // module path
+ Version string // module version
+ Versions []string // available module versions (with -versions)
+ Replace *Module // replaced by this module
+ Time *time.Time // time version was created
+ Update *Module // available update, if any (with -u)
+ Main bool // is this the main module?
+ Indirect bool // is this module only an indirect dependency of main module?
+ Dir string // directory holding files for this module, if any
+ GoMod string // path to go.mod file for this module, if any
+ Error *ModuleError // error loading module
+ }
+
+ type ModuleError struct {
+ Err string // the error itself
+ }
+
+The default output is to print the module path and then
+information about the version and replacement if any.
+For example, 'go list -m all' might print:
+
+ my/main/module
+ golang.org/x/text v0.3.0 => /tmp/text
+ rsc.io/pdf v0.1.1
+
+The Module struct has a String method that formats this
+line of output, so that the default format is equivalent
+to -f '{{.String}}'.
+
+Note that when a module has been replaced, its Replace field
+describes the replacement module, and its Dir field is set to
+the replacement's source code, if present. (That is, if Replace
+is non-nil, then Dir is set to Replace.Dir, with no access to
+the replaced source code.)
+
+The -u flag adds information about available upgrades.
+When the latest version of a given module is newer than
+the current one, list -u sets the Module's Update field
+to information about the newer module.
+The Module's String method indicates an available upgrade by
+formatting the newer version in brackets after the current version.
+For example, 'go list -m -u all' might print:
+
+ my/main/module
+ golang.org/x/text v0.3.0 [v0.4.0] => /tmp/text
+ rsc.io/pdf v0.1.1 [v0.1.2]
+
+(For tools, 'go list -m -u -json all' may be more convenient to parse.)
+
+The -versions flag causes list to set the Module's Versions field
+to a list of all known versions of that module, ordered according
+to semantic versioning, earliest to latest. The flag also changes
+the default output format to display the module path followed by the
+space-separated version list.
+
+The arguments to list -m are interpreted as a list of modules, not packages.
+The main module is the module containing the current directory.
+The active modules are the main module and its dependencies.
+With no arguments, list -m shows the main module.
+With arguments, list -m shows the modules specified by the arguments.
+Any of the active modules can be specified by its module path.
+The special pattern "all" specifies all the active modules, first the main
+module and then dependencies sorted by module path.
+A pattern containing "..." specifies the active modules whose
+module paths match the pattern.
+A query of the form path@version specifies the result of that query,
+which is not limited to active modules.
+See 'go help modules' for more about module queries.
+
+The template function "module" takes a single string argument
+that must be a module path or query and returns the specified
+module as a Module struct. If an error occurs, the result will
+be a Module struct with a non-nil Error field.
+
For more about build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.
+
+For more about modules, see 'go help modules'.
`,
}
@@ -146,20 +289,43 @@ func init() {
work.AddBuildFlags(CmdList)
}
-var listE = CmdList.Flag.Bool("e", false, "")
-var listFmt = CmdList.Flag.String("f", "{{.ImportPath}}", "")
-var listJson = CmdList.Flag.Bool("json", false, "")
+var (
+ listCompiled = CmdList.Flag.Bool("compiled", false, "")
+ listDeps = CmdList.Flag.Bool("deps", false, "")
+ listE = CmdList.Flag.Bool("e", false, "")
+ listExport = CmdList.Flag.Bool("export", false, "")
+ listFmt = CmdList.Flag.String("f", "", "")
+ listFind = CmdList.Flag.Bool("find", false, "")
+ listJson = CmdList.Flag.Bool("json", false, "")
+ listM = CmdList.Flag.Bool("m", false, "")
+ listU = CmdList.Flag.Bool("u", false, "")
+ listTest = CmdList.Flag.Bool("test", false, "")
+ listVersions = CmdList.Flag.Bool("versions", false, "")
+)
+
var nl = []byte{'\n'}
func runList(cmd *base.Command, args []string) {
+ modload.LoadTests = *listTest
work.BuildInit()
out := newTrackingWriter(os.Stdout)
defer out.w.Flush()
- var do func(*load.PackagePublic)
+ if *listFmt == "" {
+ if *listM {
+ *listFmt = "{{.String}}"
+ if *listVersions {
+ *listFmt = `{{.Path}}{{range .Versions}} {{.}}{{end}}`
+ }
+ } else {
+ *listFmt = "{{.ImportPath}}"
+ }
+ }
+
+ var do func(interface{})
if *listJson {
- do = func(p *load.PackagePublic) {
- b, err := json.MarshalIndent(p, "", "\t")
+ do = func(x interface{}) {
+ b, err := json.MarshalIndent(x, "", "\t")
if err != nil {
out.Flush()
base.Fatalf("%s", err)
@@ -178,13 +344,14 @@ func runList(cmd *base.Command, args []string) {
fm := template.FuncMap{
"join": strings.Join,
"context": context,
+ "module": modload.ModuleInfo,
}
tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt)
if err != nil {
base.Fatalf("%s", err)
}
- do = func(p *load.PackagePublic) {
- if err := tmpl.Execute(out, p); err != nil {
+ do = func(x interface{}) {
+ if err := tmpl.Execute(out, x); err != nil {
out.Flush()
base.Fatalf("%s", err)
}
@@ -194,6 +361,62 @@ func runList(cmd *base.Command, args []string) {
}
}
+ if *listM {
+ // Module mode.
+ if *listCompiled {
+ base.Fatalf("go list -compiled cannot be used with -m")
+ }
+ if *listDeps {
+ // TODO(rsc): Could make this mean something with -m.
+ base.Fatalf("go list -deps cannot be used with -m")
+ }
+ if *listExport {
+ base.Fatalf("go list -export cannot be used with -m")
+ }
+ if *listFind {
+ base.Fatalf("go list -find cannot be used with -m")
+ }
+ if *listTest {
+ base.Fatalf("go list -test cannot be used with -m")
+ }
+
+ if modload.Init(); !modload.Enabled() {
+ base.Fatalf("go list -m: not using modules")
+ }
+ modload.LoadBuildList()
+
+ mods := modload.ListModules(args, *listU, *listVersions)
+ if !*listE {
+ for _, m := range mods {
+ if m.Error != nil {
+ base.Errorf("go list -m %s: %v", m.Path, m.Error.Err)
+ }
+ }
+ base.ExitIfErrors()
+ }
+ for _, m := range mods {
+ do(m)
+ }
+ return
+ }
+
+ // Package mode (not -m).
+ if *listU {
+ base.Fatalf("go list -u can only be used with -m")
+ }
+ if *listVersions {
+ base.Fatalf("go list -versions can only be used with -m")
+ }
+
+ // These pairings make no sense.
+ if *listFind && *listDeps {
+ base.Fatalf("go list -deps cannot be used with -find")
+ }
+ if *listFind && *listTest {
+ base.Fatalf("go list -test cannot be used with -find")
+ }
+
+ load.IgnoreImports = *listFind
var pkgs []*load.Package
if *listE {
pkgs = load.PackagesAndErrors(args)
@@ -201,27 +424,178 @@ func runList(cmd *base.Command, args []string) {
pkgs = load.Packages(args)
}
- // Estimate whether staleness information is needed,
- // since it's a little bit of work to compute.
+ if cache.Default() == nil {
+ // These flags return file names pointing into the build cache,
+ // so the build cache must exist.
+ if *listCompiled {
+ base.Fatalf("go list -compiled requires build cache")
+ }
+ if *listExport {
+ base.Fatalf("go list -export requires build cache")
+ }
+ if *listTest {
+ base.Fatalf("go list -test requires build cache")
+ }
+ }
+
+ if *listTest {
+ c := cache.Default()
+ // Add test binaries to packages to be listed.
+ for _, p := range pkgs {
+ if p.Error != nil {
+ continue
+ }
+ if len(p.TestGoFiles)+len(p.XTestGoFiles) > 0 {
+ pmain, ptest, pxtest, err := load.GetTestPackagesFor(p, nil)
+ if err != nil {
+ if *listE {
+ pkgs = append(pkgs, &load.Package{
+ PackagePublic: load.PackagePublic{
+ ImportPath: p.ImportPath + ".test",
+ Error: &load.PackageError{Err: err.Error()},
+ },
+ })
+ continue
+ }
+ base.Errorf("can't load test package: %s", err)
+ continue
+ }
+ pkgs = append(pkgs, pmain)
+ if ptest != nil {
+ pkgs = append(pkgs, ptest)
+ }
+ if pxtest != nil {
+ pkgs = append(pkgs, pxtest)
+ }
+
+ data := *pmain.Internal.TestmainGo
+ h := cache.NewHash("testmain")
+ h.Write([]byte("testmain\n"))
+ h.Write(data)
+ out, _, err := c.Put(h.Sum(), bytes.NewReader(data))
+ if err != nil {
+ base.Fatalf("%s", err)
+ }
+ pmain.GoFiles[0] = c.OutputFile(out)
+ }
+ }
+ }
+
+ // Remember which packages are named on the command line.
+ cmdline := make(map[*load.Package]bool)
+ for _, p := range pkgs {
+ cmdline[p] = true
+ }
+
+ if *listDeps {
+ // Note: This changes the order of the listed packages
+ // from "as written on the command line" to
+ // "a depth-first post-order traversal".
+ // (The dependency exploration order for a given node
+ // is alphabetical, same as listed in .Deps.)
+ // Note that -deps is applied after -test,
+ // so that you only get descriptions of tests for the things named
+ // explicitly on the command line, not for all dependencies.
+ pkgs = load.PackageList(pkgs)
+ }
+
+ // Do we need to run a build to gather information?
needStale := *listJson || strings.Contains(*listFmt, ".Stale")
- if needStale {
+ if needStale || *listExport || *listCompiled {
var b work.Builder
b.Init()
- b.ComputeStaleOnly = true
+ b.IsCmdList = true
+ b.NeedExport = *listExport
+ b.NeedCompiledGoFiles = *listCompiled
a := &work.Action{}
// TODO: Use pkgsFilter?
for _, p := range pkgs {
- a.Deps = append(a.Deps, b.AutoAction(work.ModeInstall, work.ModeInstall, p))
+ if len(p.GoFiles)+len(p.CgoFiles) > 0 {
+ a.Deps = append(a.Deps, b.AutoAction(work.ModeInstall, work.ModeInstall, p))
+ }
}
b.Do(a)
}
- for _, pkg := range pkgs {
+ for _, p := range pkgs {
// Show vendor-expanded paths in listing
- pkg.TestImports = pkg.Resolve(pkg.TestImports)
- pkg.XTestImports = pkg.Resolve(pkg.XTestImports)
+ p.TestImports = p.Resolve(p.TestImports)
+ p.XTestImports = p.Resolve(p.XTestImports)
+ p.DepOnly = !cmdline[p]
+
+ if *listCompiled {
+ p.Imports = str.StringList(p.Imports, p.Internal.CompiledImports)
+ }
+ }
+
+ if *listTest {
+ all := pkgs
+ if !*listDeps {
+ all = load.PackageList(pkgs)
+ }
+ // Update import paths to distinguish the real package p
+ // from p recompiled for q.test.
+ // This must happen only once the build code is done
+ // looking at import paths, because it will get very confused
+ // if it sees these.
+ old := make(map[string]string)
+ for _, p := range all {
+ if p.ForTest != "" {
+ new := p.ImportPath + " [" + p.ForTest + ".test]"
+ old[new] = p.ImportPath
+ p.ImportPath = new
+ }
+ p.DepOnly = !cmdline[p]
+ }
+ // Update import path lists to use new strings.
+ m := make(map[string]string)
+ for _, p := range all {
+ for _, p1 := range p.Internal.Imports {
+ if p1.ForTest != "" {
+ m[old[p1.ImportPath]] = p1.ImportPath
+ }
+ }
+ for i, old := range p.Imports {
+ if new := m[old]; new != "" {
+ p.Imports[i] = new
+ }
+ }
+ for old := range m {
+ delete(m, old)
+ }
+ }
+ // Recompute deps lists using new strings, from the leaves up.
+ for _, p := range all {
+ deps := make(map[string]bool)
+ for _, p1 := range p.Internal.Imports {
+ deps[p1.ImportPath] = true
+ for _, d := range p1.Deps {
+ deps[d] = true
+ }
+ }
+ p.Deps = make([]string, 0, len(deps))
+ for d := range deps {
+ p.Deps = append(p.Deps, d)
+ }
+ sort.Strings(p.Deps)
+ }
+ }
+
+ // Record non-identity import mappings in p.ImportMap.
+ for _, p := range pkgs {
+ for i, srcPath := range p.Internal.RawImports {
+ path := p.Imports[i]
+ if path != srcPath {
+ if p.ImportMap == nil {
+ p.ImportMap = make(map[string]string)
+ }
+ p.ImportMap[srcPath] = path
+ }
+ }
+ }
- do(&pkg.PackagePublic)
+ for _, p := range pkgs {
+ do(&p.PackagePublic)
}
}
diff --git a/libgo/go/cmd/go/internal/load/flag.go b/libgo/go/cmd/go/internal/load/flag.go
index 7ad4208ccc0..7534e65f54c 100644
--- a/libgo/go/cmd/go/internal/load/flag.go
+++ b/libgo/go/cmd/go/internal/load/flag.go
@@ -91,31 +91,3 @@ func (f *PerPackageFlag) For(p *Package) []string {
}
return flags
}
-
-var cmdlineMatchers []func(*Package) bool
-
-// SetCmdlinePatterns records the set of patterns given on the command line,
-// for use by the PerPackageFlags.
-func SetCmdlinePatterns(args []string) {
- setCmdlinePatterns(args, base.Cwd)
-}
-
-func setCmdlinePatterns(args []string, cwd string) {
- if len(args) == 0 {
- args = []string{"."}
- }
- cmdlineMatchers = nil // allow reset for testing
- for _, arg := range args {
- cmdlineMatchers = append(cmdlineMatchers, MatchPackage(arg, cwd))
- }
-}
-
-// isCmdlinePkg reports whether p is a package listed on the command line.
-func isCmdlinePkg(p *Package) bool {
- for _, m := range cmdlineMatchers {
- if m(p) {
- return true
- }
- }
- return false
-}
diff --git a/libgo/go/cmd/go/internal/load/path.go b/libgo/go/cmd/go/internal/load/path.go
index 45a9e7b242b..0211b284a40 100644
--- a/libgo/go/cmd/go/internal/load/path.go
+++ b/libgo/go/cmd/go/internal/load/path.go
@@ -32,22 +32,6 @@ func hasSubdir(root, dir string) (rel string, ok bool) {
return filepath.ToSlash(dir[len(root):]), true
}
-// hasPathPrefix reports whether the path s begins with the
-// elements in prefix.
-func hasPathPrefix(s, prefix string) bool {
- switch {
- default:
- return false
- case len(s) == len(prefix):
- return s == prefix
- case len(s) > len(prefix):
- if prefix != "" && prefix[len(prefix)-1] == '/' {
- return strings.HasPrefix(s, prefix)
- }
- return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
- }
-}
-
// expandPath returns the symlink-expanded form of path.
func expandPath(p string) string {
x, err := filepath.EvalSymlinks(p)
diff --git a/libgo/go/cmd/go/internal/load/pkg.go b/libgo/go/cmd/go/internal/load/pkg.go
index dfb1ff63afe..0579fd5ca53 100644
--- a/libgo/go/cmd/go/internal/load/pkg.go
+++ b/libgo/go/cmd/go/internal/load/pkg.go
@@ -22,9 +22,26 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
+ "cmd/go/internal/modinfo"
+ "cmd/go/internal/search"
"cmd/go/internal/str"
)
+var (
+ // module initialization hook; never nil, no-op if module use is disabled
+ ModInit func()
+
+ // module hooks; nil if module use is disabled
+ ModBinDir func() string // return effective bin directory
+ ModLookup func(path string) (dir, realPath string, err error) // lookup effective meaning of import
+ ModPackageModuleInfo func(path string) *modinfo.ModulePublic // return module info for Package struct
+ ModImportPaths func(args []string) []*search.Match // expand import paths
+ ModPackageBuildInfo func(main string, deps []string) string // return module info to embed in binary
+ ModInfoProg func(info string) []byte // wrap module info in .go code for binary
+ ModImportFromFiles func([]string) // update go.mod to add modules for imports in these files
+ ModDirImportPath func(string) string // return effective import path for directory
+)
+
var IgnoreImports bool // control whether we ignore imports in packages
// A Package describes a single package found in a directory.
@@ -37,18 +54,24 @@ type PackagePublic struct {
// Note: These fields are part of the go command's public API.
// See list.go. It is okay to add fields, but not to change or
// remove existing ones. Keep in sync with list.go
- Dir string `json:",omitempty"` // directory containing package sources
- ImportPath string `json:",omitempty"` // import path of package in dir
- ImportComment string `json:",omitempty"` // path in import comment on package statement
- Name string `json:",omitempty"` // package name
- Doc string `json:",omitempty"` // package documentation string
- Target string `json:",omitempty"` // installed target for this package (may be executable)
- Shlib string `json:",omitempty"` // the shared library that contains this package (only set when -linkshared)
- Goroot bool `json:",omitempty"` // is this package found in the Go root?
- Standard bool `json:",omitempty"` // is this package part of the standard Go library?
- Root string `json:",omitempty"` // Go root or Go path dir containing this package
- ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory
- BinaryOnly bool `json:",omitempty"` // package cannot be recompiled
+ Dir string `json:",omitempty"` // directory containing package sources
+ ImportPath string `json:",omitempty"` // import path of package in dir
+ ImportComment string `json:",omitempty"` // path in import comment on package statement
+ Name string `json:",omitempty"` // package name
+ Doc string `json:",omitempty"` // package documentation string
+ Target string `json:",omitempty"` // installed target for this package (may be executable)
+ Shlib string `json:",omitempty"` // the shared library that contains this package (only set when -linkshared)
+ Root string `json:",omitempty"` // Go root or Go path dir containing this package
+ ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory
+ ForTest string `json:",omitempty"` // package is only for use in named test
+ Export string `json:",omitempty"` // file containing export data (set by go list -export)
+ Module *modinfo.ModulePublic `json:",omitempty"` // info about package's module, if any
+ Match []string `json:",omitempty"` // command-line patterns matching this package
+ Goroot bool `json:",omitempty"` // is this package found in the Go root?
+ Standard bool `json:",omitempty"` // is this package part of the standard Go library?
+ DepOnly bool `json:",omitempty"` // package is only as a dependency, not explicitly listed
+ BinaryOnly bool `json:",omitempty"` // package cannot be recompiled
+ Incomplete bool `json:",omitempty"` // was there an error loading this package or dependencies?
// Stale and StaleReason remain here *only* for the list command.
// They are only initialized in preparation for list execution.
@@ -59,18 +82,19 @@ type PackagePublic struct {
// Source files
// If you add to this list you MUST add to p.AllFiles (below) too.
// Otherwise file name security lists will not apply to any new additions.
- GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
- CgoFiles []string `json:",omitempty"` // .go sources files that import "C"
- IgnoredGoFiles []string `json:",omitempty"` // .go sources ignored due to build constraints
- CFiles []string `json:",omitempty"` // .c source files
- CXXFiles []string `json:",omitempty"` // .cc, .cpp and .cxx source files
- MFiles []string `json:",omitempty"` // .m source files
- HFiles []string `json:",omitempty"` // .h, .hh, .hpp and .hxx source files
- FFiles []string `json:",omitempty"` // .f, .F, .for and .f90 Fortran source files
- SFiles []string `json:",omitempty"` // .s source files
- SwigFiles []string `json:",omitempty"` // .swig files
- SwigCXXFiles []string `json:",omitempty"` // .swigcxx files
- SysoFiles []string `json:",omitempty"` // .syso system object files added to package
+ GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
+ CgoFiles []string `json:",omitempty"` // .go source files that import "C"
+ CompiledGoFiles []string `json:",omitempty"` // .go output from running cgo on CgoFiles
+ IgnoredGoFiles []string `json:",omitempty"` // .go source files ignored due to build constraints
+ CFiles []string `json:",omitempty"` // .c source files
+ CXXFiles []string `json:",omitempty"` // .cc, .cpp and .cxx source files
+ MFiles []string `json:",omitempty"` // .m source files
+ HFiles []string `json:",omitempty"` // .h, .hh, .hpp and .hxx source files
+ FFiles []string `json:",omitempty"` // .f, .F, .for and .f90 Fortran source files
+ SFiles []string `json:",omitempty"` // .s source files
+ SwigFiles []string `json:",omitempty"` // .swig files
+ SwigCXXFiles []string `json:",omitempty"` // .swigcxx files
+ SysoFiles []string `json:",omitempty"` // .syso system object files added to package
// Cgo directives
CgoCFLAGS []string `json:",omitempty"` // cgo: flags for C compiler
@@ -81,11 +105,12 @@ type PackagePublic struct {
CgoPkgConfig []string `json:",omitempty"` // cgo: pkg-config names
// Dependency information
- Imports []string `json:",omitempty"` // import paths used by this package
- Deps []string `json:",omitempty"` // all (recursively) imported dependencies
+ Imports []string `json:",omitempty"` // import paths used by this package
+ ImportMap map[string]string `json:",omitempty"` // map from source import to ImportPath (identity entries omitted)
+ Deps []string `json:",omitempty"` // all (recursively) imported dependencies
// Error information
- Incomplete bool `json:",omitempty"` // was there an error loading this package or dependencies?
+ // Incomplete is above, packed into the other bools
Error *PackageError `json:",omitempty"` // error loading this package (not dependencies)
DepsErrors []*PackageError `json:",omitempty"` // errors loading dependencies
@@ -107,6 +132,7 @@ func (p *Package) AllFiles() []string {
return str.StringList(
p.GoFiles,
p.CgoFiles,
+ // no p.CompiledGoFiles, because they are from GoFiles or generated by us
p.IgnoredGoFiles,
p.CFiles,
p.CXXFiles,
@@ -122,21 +148,33 @@ func (p *Package) AllFiles() []string {
)
}
+// Desc returns the package "description", for use in b.showOutput.
+func (p *Package) Desc() string {
+ if p.ForTest != "" {
+ return p.ImportPath + " [" + p.ForTest + ".test]"
+ }
+ return p.ImportPath
+}
+
type PackageInternal struct {
// Unexported fields are not part of the public API.
- Build *build.Package
- Imports []*Package // this package's direct imports
- RawImports []string // this package's original imports as they appear in the text of the program
- ForceLibrary bool // this package is a library (even if named "main")
- CmdlineFiles bool // package built from files listed on command line
- CmdlinePkg bool // package listed on command line
- Local bool // imported via local path (./ or ../)
- LocalPrefix string // interpret ./ and ../ imports relative to this prefix
- ExeName string // desired name for temporary executable
- CoverMode string // preprocess Go source files with the coverage tool in this mode
- CoverVars map[string]*CoverVar // variables created by coverage analysis
- OmitDebug bool // tell linker not to write debug information
- GobinSubdir bool // install target would be subdir of GOBIN
+ Build *build.Package
+ Imports []*Package // this package's direct imports
+ CompiledImports []string // additional Imports necessary when using CompiledGoFiles (all from standard library)
+ RawImports []string // this package's original imports as they appear in the text of the program
+ ForceLibrary bool // this package is a library (even if named "main")
+ CmdlineFiles bool // package built from files listed on command line
+ CmdlinePkg bool // package listed on command line
+ CmdlinePkgLiteral bool // package listed as literal on command line (not via wildcard)
+ Local bool // imported via local path (./ or ../)
+ LocalPrefix string // interpret ./ and ../ imports relative to this prefix
+ ExeName string // desired name for temporary executable
+ CoverMode string // preprocess Go source files with the coverage tool in this mode
+ CoverVars map[string]*CoverVar // variables created by coverage analysis
+ OmitDebug bool // tell linker not to write debug information
+ GobinSubdir bool // install target would be subdir of GOBIN
+ BuildInfo string // add this info to package main
+ TestmainGo *[]byte // content for _testmain.go
Asmflags []string // -asmflags for this package
Gcflags []string // -gcflags for this package
@@ -224,7 +262,7 @@ func (p *Package) copyBuild(pp *build.Package) {
// TODO? Target
p.Goroot = pp.Goroot
- p.Standard = p.Goroot && p.ImportPath != "" && isStandardImportPath(p.ImportPath)
+ p.Standard = p.Goroot && p.ImportPath != "" && search.IsStandardImportPath(p.ImportPath)
p.GoFiles = pp.GoFiles
p.CgoFiles = pp.CgoFiles
p.IgnoredGoFiles = pp.IgnoredGoFiles
@@ -253,24 +291,12 @@ func (p *Package) copyBuild(pp *build.Package) {
p.XTestImports = pp.XTestImports
if IgnoreImports {
p.Imports = nil
+ p.Internal.RawImports = nil
p.TestImports = nil
p.XTestImports = nil
}
}
-// isStandardImportPath reports whether $GOROOT/src/path should be considered
-// part of the standard distribution. For historical reasons we allow people to add
-// their own code to $GOROOT instead of using $GOPATH, but we assume that
-// code will start with a domain name (dot in the first element).
-func isStandardImportPath(path string) bool {
- i := strings.Index(path, "/")
- if i < 0 {
- i = len(path)
- }
- elem := path[:i]
- return !strings.Contains(elem, ".")
-}
-
// A PackageError describes an error loading information about a package.
type PackageError struct {
ImportStack []string // shortest path from package named on command line to this one
@@ -296,7 +322,9 @@ func (p *PackageError) Error() string {
return "package " + strings.Join(p.ImportStack, "\n\timports ") + ": " + p.Err
}
-// An ImportStack is a stack of import paths.
+// An ImportStack is a stack of import paths, possibly with the suffix " (test)" appended.
+// The import path of a test package is the import path of the corresponding
+// non-test package with the suffix "_test" added.
type ImportStack []string
func (s *ImportStack) Push(p string) {
@@ -349,15 +377,17 @@ func ClearPackageCachePartial(args []string) {
}
}
-// reloadPackage is like loadPackage but makes sure
+// ReloadPackageNoFlags is like LoadPackageNoFlags but makes sure
// not to use the package cache.
-func ReloadPackage(arg string, stk *ImportStack) *Package {
+// It is only for use by GOPATH-based "go get".
+// TODO(rsc): When GOPATH-based "go get" is removed, delete this function.
+func ReloadPackageNoFlags(arg string, stk *ImportStack) *Package {
p := packageCache[arg]
if p != nil {
delete(packageCache, p.Dir)
delete(packageCache, p.ImportPath)
}
- return LoadPackage(arg, stk)
+ return LoadPackageNoFlags(arg, stk)
}
// dirToImportPath returns the pseudo-import path we use for a package
@@ -406,10 +436,53 @@ const (
// but possibly a local import path (an absolute file system path or one beginning
// with ./ or ../). A local relative path is interpreted relative to srcDir.
// It returns a *Package describing the package found in that directory.
+// LoadImport does not set tool flags and should only be used by
+// this package, as part of a bigger load operation, and by GOPATH-based "go get".
+// TODO(rsc): When GOPATH-based "go get" is removed, unexport this function.
func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) *Package {
stk.Push(path)
defer stk.Pop()
+ if strings.HasPrefix(path, "mod/") {
+ // Paths beginning with "mod/" might accidentally
+ // look in the module cache directory tree in $GOPATH/pkg/mod/.
+ // This prefix is owned by the Go core for possible use in the
+ // standard library (since it does not begin with a domain name),
+ // so it's OK to disallow entirely.
+ return &Package{
+ PackagePublic: PackagePublic{
+ ImportPath: path,
+ Error: &PackageError{
+ ImportStack: stk.Copy(),
+ Err: fmt.Sprintf("disallowed import path %q", path),
+ },
+ },
+ }
+ }
+
+ if strings.Contains(path, "@") {
+ var text string
+ if cfg.ModulesEnabled {
+ text = "can only use path@version syntax with 'go get'"
+ } else {
+ text = "cannot use path@version syntax in GOPATH mode"
+ }
+ return &Package{
+ PackagePublic: PackagePublic{
+ ImportPath: path,
+ Error: &PackageError{
+ ImportStack: stk.Copy(),
+ Err: text,
+ },
+ },
+ }
+ }
+
+ parentPath := ""
+ if parent != nil {
+ parentPath = parent.ImportPath
+ }
+
// Determine canonical identifier for this package.
// For a local import the identifier is the pseudo-import path
// we create from the full directory to the package.
@@ -418,8 +491,16 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo
importPath := path
origPath := path
isLocal := build.IsLocalImport(path)
+ var modDir string
+ var modErr error
if isLocal {
importPath = dirToImportPath(filepath.Join(srcDir, path))
+ } else if cfg.ModulesEnabled {
+ var p string
+ modDir, p, modErr = ModLookup(path)
+ if modErr == nil {
+ importPath = p
+ }
} else if mode&ResolveImport != 0 {
// We do our own path resolution, because we want to
// find out the key to use in packageCache without the
@@ -444,17 +525,31 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo
// Load package.
// Import always returns bp != nil, even if an error occurs,
// in order to return partial information.
- buildMode := build.ImportComment
- if mode&ResolveImport == 0 || path != origPath {
- // Not vendoring, or we already found the vendored path.
- buildMode |= build.IgnoreVendor
+ var bp *build.Package
+ var err error
+ if modDir != "" {
+ bp, err = cfg.BuildContext.ImportDir(modDir, 0)
+ } else if modErr != nil {
+ bp = new(build.Package)
+ err = fmt.Errorf("unknown import path %q: %v", importPath, modErr)
+ } else if cfg.ModulesEnabled && path != "unsafe" {
+ bp = new(build.Package)
+ err = fmt.Errorf("unknown import path %q: internal error: module loader did not resolve import", importPath)
+ } else {
+ buildMode := build.ImportComment
+ if mode&ResolveImport == 0 || path != origPath {
+ // Not vendoring, or we already found the vendored path.
+ buildMode |= build.IgnoreVendor
+ }
+ bp, err = cfg.BuildContext.Import(path, srcDir, buildMode)
}
- bp, err := cfg.BuildContext.Import(path, srcDir, buildMode)
bp.ImportPath = importPath
if cfg.GOBIN != "" {
bp.BinDir = cfg.GOBIN
+ } else if cfg.ModulesEnabled {
+ bp.BinDir = ModBinDir()
}
- if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path &&
+ if modDir == "" && err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path &&
!strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/") {
err = fmt.Errorf("code in directory %s expects import %q", bp.Dir, bp.ImportComment)
}
@@ -463,7 +558,7 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo
p = setErrorPos(p, importPos)
}
- if origPath != cleanImport(origPath) {
+ if modDir == "" && origPath != cleanImport(origPath) {
p.Error = &PackageError{
ImportStack: stk.Copy(),
Err: fmt.Sprintf("non-canonical import path: %q should be %q", origPath, pathpkg.Clean(origPath)),
@@ -473,11 +568,11 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo
}
// Checked on every import because the rules depend on the code doing the importing.
- if perr := disallowInternal(srcDir, p, stk); perr != p {
+ if perr := disallowInternal(srcDir, parent, parentPath, p, stk); perr != p {
return setErrorPos(perr, importPos)
}
if mode&ResolveImport != 0 {
- if perr := disallowVendor(srcDir, origPath, p, stk); perr != p {
+ if perr := disallowVendor(srcDir, parent, parentPath, origPath, p, stk); perr != p {
return setErrorPos(perr, importPos)
}
}
@@ -539,8 +634,14 @@ func isDir(path string) bool {
// There are two different resolutions applied.
// First, there is Go 1.5 vendoring (golang.org/s/go15vendor).
// If vendor expansion doesn't trigger, then the path is also subject to
-// Go 1.11 vgo legacy conversion (golang.org/issue/25069).
+// Go 1.11 module legacy conversion (golang.org/issue/25069).
func ResolveImportPath(parent *Package, path string) (found string) {
+ if cfg.ModulesEnabled {
+ if _, p, e := ModLookup(path); e == nil {
+ return p
+ }
+ return path
+ }
found = VendoredImportPath(parent, path)
if found != path {
return found
@@ -828,10 +929,11 @@ func reusePackage(p *Package, stk *ImportStack) *Package {
return p
}
-// disallowInternal checks that srcDir is allowed to import p.
+// disallowInternal checks that srcDir (containing package importerPath, if non-empty)
+// is allowed to import p.
// If the import is allowed, disallowInternal returns the original package p.
// If not, it returns a new package containing just an appropriate error.
-func disallowInternal(srcDir string, p *Package, stk *ImportStack) *Package {
+func disallowInternal(srcDir string, importer *Package, importerPath string, p *Package, stk *ImportStack) *Package {
// golang.org/s/go14internal:
// An import of a path containing the element “internal”
// is disallowed if the importing code is outside the tree
@@ -874,23 +976,40 @@ func disallowInternal(srcDir string, p *Package, stk *ImportStack) *Package {
if i > 0 {
i-- // rewind over slash in ".../internal"
}
- parent := p.Dir[:i+len(p.Dir)-len(p.ImportPath)]
- if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
- return p
- }
- // Look for symlinks before reporting error.
- srcDir = expandPath(srcDir)
- parent = expandPath(parent)
- if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
- return p
+ if p.Module == nil {
+ parent := p.Dir[:i+len(p.Dir)-len(p.ImportPath)]
+
+ if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
+ return p
+ }
+
+ // Look for symlinks before reporting error.
+ srcDir = expandPath(srcDir)
+ parent = expandPath(parent)
+ if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
+ return p
+ }
+ } else {
+ // p is in a module, so make it available based on the importer's import path instead
+ // of the file path (https://golang.org/issue/23970).
+ if importerPath == "." {
+ // The importer is a list of command-line files.
+ // Pretend that the import path is the import path of the
+ // directory containing them.
+ importerPath = ModDirImportPath(importer.Dir)
+ }
+ parentOfInternal := p.ImportPath[:i]
+ if str.HasPathPrefix(importerPath, parentOfInternal) {
+ return p
+ }
}
// Internal is present, and srcDir is outside parent's tree. Not allowed.
perr := *p
perr.Error = &PackageError{
ImportStack: stk.Copy(),
- Err: "use of internal package not allowed",
+ Err: "use of internal package " + p.ImportPath + " not allowed",
}
perr.Incomplete = true
return &perr
@@ -915,10 +1034,11 @@ func findInternal(path string) (index int, ok bool) {
return 0, false
}
-// disallowVendor checks that srcDir is allowed to import p as path.
+// disallowVendor checks that srcDir (containing package importerPath, if non-empty)
+// is allowed to import p as path.
// If the import is allowed, disallowVendor returns the original package p.
// If not, it returns a new package containing just an appropriate error.
-func disallowVendor(srcDir, path string, p *Package, stk *ImportStack) *Package {
+func disallowVendor(srcDir string, importer *Package, importerPath, path string, p *Package, stk *ImportStack) *Package {
// The stack includes p.ImportPath.
// If that's the only thing on the stack, we started
// with a name given on the command line, not an
@@ -927,6 +1047,20 @@ func disallowVendor(srcDir, path string, p *Package, stk *ImportStack) *Package
return p
}
+ // Modules must not import vendor packages in the standard library,
+ // but the usual vendor visibility check will not catch them
+ // because the module loader presents them with an ImportPath starting
+ // with "golang_org/" instead of "vendor/".
+ if p.Standard && !importer.Standard && strings.HasPrefix(p.ImportPath, "golang_org") {
+ perr := *p
+ perr.Error = &PackageError{
+ ImportStack: stk.Copy(),
+ Err: "use of vendored package " + path + " not allowed",
+ }
+ perr.Incomplete = true
+ return &perr
+ }
+
if perr := disallowVendorVisibility(srcDir, p, stk); perr != p {
return perr
}
@@ -1057,26 +1191,6 @@ var foldPath = make(map[string]string)
func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
p.copyBuild(bp)
- // Decide whether p was listed on the command line.
- // Given that load is called while processing the command line,
- // you might think we could simply pass a flag down into load
- // saying whether we are loading something named on the command
- // line or something to satisfy an import. But the first load of a
- // package named on the command line may be as a dependency
- // of an earlier package named on the command line, not when we
- // get to that package during command line processing.
- // For example "go test fmt reflect" will load reflect as a dependency
- // of fmt before it attempts to load as a command-line argument.
- // Because loads are cached, the later load will be a no-op,
- // so it is important that the first load can fill in CmdlinePkg correctly.
- // Hence the call to an explicit matching check here.
- p.Internal.CmdlinePkg = isCmdlinePkg(p)
-
- p.Internal.Asmflags = BuildAsmflags.For(p)
- p.Internal.Gcflags = BuildGcflags.For(p)
- p.Internal.Ldflags = BuildLdflags.For(p)
- p.Internal.Gccgoflags = BuildGccgoflags.For(p)
-
// The localPrefix is the path we interpret ./ imports relative to.
// Synthesized main packages sometimes override this.
if p.Internal.Local {
@@ -1113,11 +1227,45 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
return
}
_, elem := filepath.Split(p.Dir)
+ if cfg.ModulesEnabled {
+ // NOTE(rsc): Using p.ImportPath instead of p.Dir
+ // makes sure we install a package in the root of a
+ // cached module directory as that package name
+ // not name@v1.2.3.
+ // Using p.ImportPath instead of p.Dir
+ // is probably correct all the time,
+ // even for non-module-enabled code,
+ // but I'm not brave enough to change the
+ // non-module behavior this late in the
+ // release cycle. Maybe for Go 1.12.
+ // See golang.org/issue/26869.
+ _, elem = pathpkg.Split(p.ImportPath)
+
+ // If this is example.com/mycmd/v2, it's more useful to install it as mycmd than as v2.
+ // See golang.org/issue/24667.
+ isVersion := func(v string) bool {
+ if len(v) < 2 || v[0] != 'v' || v[1] < '1' || '9' < v[1] {
+ return false
+ }
+ for i := 2; i < len(v); i++ {
+ if c := v[i]; c < '0' || '9' < c {
+ return false
+ }
+ }
+ return true
+ }
+ if isVersion(elem) {
+ _, elem = pathpkg.Split(pathpkg.Dir(p.ImportPath))
+ }
+ }
full := cfg.BuildContext.GOOS + "_" + cfg.BuildContext.GOARCH + "/" + elem
if cfg.BuildContext.GOOS != base.ToolGOOS || cfg.BuildContext.GOARCH != base.ToolGOARCH {
// Install cross-compiled binaries to subdirectories of bin.
elem = full
}
+ if p.Internal.Build.BinDir == "" && cfg.ModulesEnabled {
+ p.Internal.Build.BinDir = ModBinDir()
+ }
if p.Internal.Build.BinDir != "" {
// Install to GOBIN or bin of GOPATH entry.
p.Target = filepath.Join(p.Internal.Build.BinDir, elem)
@@ -1165,31 +1313,37 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
// Build augmented import list to add implicit dependencies.
// Be careful not to add imports twice, just to avoid confusion.
importPaths := p.Imports
- addImport := func(path string) {
+ addImport := func(path string, forCompiler bool) {
for _, p := range importPaths {
if path == p {
return
}
}
importPaths = append(importPaths, path)
+ if forCompiler {
+ p.Internal.CompiledImports = append(p.Internal.CompiledImports, path)
+ }
}
- // Cgo translation adds imports of "runtime/cgo" and "syscall",
+ // Cgo translation adds imports of "unsafe", "runtime/cgo" and "syscall",
// except for certain packages, to avoid circular dependencies.
+ if p.UsesCgo() {
+ addImport("unsafe", true)
+ }
if p.UsesCgo() && (!p.Standard || !cgoExclude[p.ImportPath]) && cfg.BuildContext.Compiler != "gccgo" {
- addImport("runtime/cgo")
+ addImport("runtime/cgo", true)
}
if p.UsesCgo() && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) {
- addImport("syscall")
+ addImport("syscall", true)
}
// SWIG adds imports of some standard packages.
if p.UsesSwig() {
if cfg.BuildContext.Compiler != "gccgo" {
- addImport("runtime/cgo")
+ addImport("runtime/cgo", true)
}
- addImport("syscall")
- addImport("sync")
+ addImport("syscall", true)
+ addImport("sync", true)
// TODO: The .swig and .swigcxx files can use
// %go_import directives to import other packages.
@@ -1198,7 +1352,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
// The linker loads implicit dependencies.
if p.Name == "main" && !p.Internal.ForceLibrary {
for _, dep := range LinkerDeps(p) {
- addImport(dep)
+ addImport(dep, false)
}
}
@@ -1368,6 +1522,13 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
setError(fmt.Sprintf("case-insensitive import collision: %q and %q", p.ImportPath, other))
return
}
+
+ if cfg.ModulesEnabled {
+ p.Module = ModPackageModuleInfo(p.ImportPath)
+ if p.Name == "main" {
+ p.Internal.BuildInfo = ModPackageBuildInfo(p.ImportPath, p.Deps)
+ }
+ }
}
// SafeArg reports whether arg is a "safe" command-line argument,
@@ -1466,7 +1627,13 @@ func (p *Package) mkAbs(list []string) []string {
// InternalGoFiles returns the list of Go files being built for the package,
// using absolute paths.
func (p *Package) InternalGoFiles() []string {
- return p.mkAbs(str.StringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles))
+ return p.mkAbs(str.StringList(p.GoFiles, p.CgoFiles, p.TestGoFiles))
+}
+
+// InternalXGoFiles returns the list of Go files being built for the XTest package,
+// using absolute paths.
+func (p *Package) InternalXGoFiles() []string {
+ return p.mkAbs(p.XTestGoFiles)
}
// InternalGoFiles returns the list of all Go files possibly relevant for the package,
@@ -1492,7 +1659,7 @@ func (p *Package) UsesCgo() bool {
return len(p.CgoFiles) > 0
}
-// packageList returns the list of packages in the dag rooted at roots
+// PackageList returns the list of packages in the dag rooted at roots
// as visited in a depth-first post-order traversal.
func PackageList(roots []*Package) []*Package {
seen := map[*Package]bool{}
@@ -1514,6 +1681,42 @@ func PackageList(roots []*Package) []*Package {
return all
}
+// TestPackageList returns the list of packages in the dag rooted at roots
+// as visited in a depth-first post-order traversal, including the test
+// imports of the roots. This ignores errors in test packages.
+func GetTestPackageList(roots []*Package) []*Package {
+ seen := map[*Package]bool{}
+ all := []*Package{}
+ var walk func(*Package)
+ walk = func(p *Package) {
+ if seen[p] {
+ return
+ }
+ seen[p] = true
+ for _, p1 := range p.Internal.Imports {
+ walk(p1)
+ }
+ all = append(all, p)
+ }
+ walkTest := func(root *Package, path string) {
+ var stk ImportStack
+ p1 := LoadImport(path, root.Dir, root, &stk, root.Internal.Build.TestImportPos[path], ResolveImport)
+ if p1.Error == nil {
+ walk(p1)
+ }
+ }
+ for _, root := range roots {
+ walk(root)
+ for _, path := range root.TestImports {
+ walkTest(root, path)
+ }
+ for _, path := range root.XTestImports {
+ walkTest(root, path)
+ }
+ }
+ return all
+}
+
var cmdCache = map[string]*Package{}
func ClearCmdCache() {
@@ -1522,11 +1725,31 @@ func ClearCmdCache() {
}
}
+// LoadPackage loads the package named by arg.
+func LoadPackage(arg string, stk *ImportStack) *Package {
+ p := loadPackage(arg, stk)
+ setToolFlags(p)
+ return p
+}
+
+// LoadPackageNoFlags is like LoadPackage
+// but does not guarantee that the build tool flags are set in the result.
+// It is only for use by GOPATH-based "go get"
+// and is only appropriate for preliminary loading of packages.
+// A real load using LoadPackage or (more likely)
+// Packages, PackageAndErrors, or PackagesForBuild
+// must be done before passing the package to any build
+// steps, so that the tool flags can be set properly.
+// TODO(rsc): When GOPATH-based "go get" is removed, delete this function.
+func LoadPackageNoFlags(arg string, stk *ImportStack) *Package {
+ return loadPackage(arg, stk)
+}
+
// loadPackage is like loadImport but is used for command-line arguments,
// not for paths found in import statements. In addition to ordinary import paths,
// loadPackage accepts pseudo-paths beginning with cmd/ to denote commands
// in the Go command directory, as well as paths to those directories.
-func LoadPackage(arg string, stk *ImportStack) *Package {
+func loadPackage(arg string, stk *ImportStack) *Package {
if build.IsLocalImport(arg) {
dir := arg
if !filepath.IsAbs(dir) {
@@ -1573,8 +1796,12 @@ func LoadPackage(arg string, stk *ImportStack) *Package {
// This lets you run go test ./ioutil in package io and be
// referring to io/ioutil rather than a hypothetical import of
// "./ioutil".
- if build.IsLocalImport(arg) {
- bp, _ := cfg.BuildContext.ImportDir(filepath.Join(base.Cwd, arg), build.FindOnly)
+ if build.IsLocalImport(arg) || filepath.IsAbs(arg) {
+ dir := arg
+ if !filepath.IsAbs(arg) {
+ dir = filepath.Join(base.Cwd, arg)
+ }
+ bp, _ := cfg.BuildContext.ImportDir(dir, build.FindOnly)
if bp.ImportPath != "" && bp.ImportPath != "." {
arg = bp.ImportPath
}
@@ -1583,7 +1810,7 @@ func LoadPackage(arg string, stk *ImportStack) *Package {
return LoadImport(arg, base.Cwd, nil, stk, nil, 0)
}
-// packages returns the packages named by the
+// Packages returns the packages named by the
// command line arguments 'args'. If a named package
// cannot be loaded at all (for example, if the directory does not exist),
// then packages prints an error and does not include that
@@ -1603,41 +1830,68 @@ func Packages(args []string) []*Package {
return pkgs
}
-// packagesAndErrors is like 'packages' but returns a
+// PackagesAndErrors is like 'packages' but returns a
// *Package for every argument, even the ones that
// cannot be loaded at all.
// The packages that fail to load will have p.Error != nil.
-func PackagesAndErrors(args []string) []*Package {
- if len(args) > 0 && strings.HasSuffix(args[0], ".go") {
- return []*Package{GoFilesPackage(args)}
+func PackagesAndErrors(patterns []string) []*Package {
+ if len(patterns) > 0 && strings.HasSuffix(patterns[0], ".go") {
+ return []*Package{GoFilesPackage(patterns)}
}
- args = ImportPaths(args)
+ matches := ImportPaths(patterns)
var (
pkgs []*Package
stk ImportStack
- seenArg = make(map[string]bool)
seenPkg = make(map[*Package]bool)
)
- for _, arg := range args {
- if seenArg[arg] {
- continue
- }
- seenArg[arg] = true
- pkg := LoadPackage(arg, &stk)
- if seenPkg[pkg] {
- continue
+ for _, m := range matches {
+ for _, pkg := range m.Pkgs {
+ p := loadPackage(pkg, &stk)
+ p.Match = append(p.Match, m.Pattern)
+ p.Internal.CmdlinePkg = true
+ if m.Literal {
+ // Note: do not set = m.Literal unconditionally
+ // because maybe we'll see p matching both
+ // a literal and also a non-literal pattern.
+ p.Internal.CmdlinePkgLiteral = true
+ }
+ if seenPkg[p] {
+ continue
+ }
+ seenPkg[p] = true
+ pkgs = append(pkgs, p)
}
- seenPkg[pkg] = true
- pkgs = append(pkgs, pkg)
}
+ // Now that CmdlinePkg is set correctly,
+ // compute the effective flags for all loaded packages
+ // (not just the ones matching the patterns but also
+ // their dependencies).
+ setToolFlags(pkgs...)
+
return pkgs
}
-// packagesForBuild is like 'packages' but fails if any of
-// the packages or their dependencies have errors
+func setToolFlags(pkgs ...*Package) {
+ for _, p := range PackageList(pkgs) {
+ p.Internal.Asmflags = BuildAsmflags.For(p)
+ p.Internal.Gcflags = BuildGcflags.For(p)
+ p.Internal.Ldflags = BuildLdflags.For(p)
+ p.Internal.Gccgoflags = BuildGccgoflags.For(p)
+ }
+}
+
+func ImportPaths(args []string) []*search.Match {
+ if ModInit(); cfg.ModulesEnabled {
+ return ModImportPaths(args)
+ }
+ return search.ImportPaths(args)
+}
+
+// PackagesForBuild is like Packages but exits
+// if any of the packages or their dependencies have errors
// (cannot be built).
func PackagesForBuild(args []string) []*Package {
pkgs := PackagesAndErrors(args)
@@ -1645,6 +1899,7 @@ func PackagesForBuild(args []string) []*Package {
for _, pkg := range pkgs {
if pkg.Error != nil {
base.Errorf("can't load package: %s", pkg.Error)
+ printed[pkg.Error] = true
}
for _, err := range pkg.DepsErrors {
// Since these are errors in dependencies,
@@ -1682,7 +1937,8 @@ func PackagesForBuild(args []string) []*Package {
// (typically named on the command line). The target is named p.a for
// package p or named after the first Go file for package main.
func GoFilesPackage(gofiles []string) *Package {
- // TODO: Remove this restriction.
+ ModInit()
+
for _, f := range gofiles {
if !strings.HasSuffix(f, ".go") {
base.Fatalf("named files must be .go files")
@@ -1720,6 +1976,10 @@ func GoFilesPackage(gofiles []string) *Package {
}
ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil }
+ if cfg.ModulesEnabled {
+ ModImportFromFiles(gofiles)
+ }
+
var err error
if dir == "" {
dir = base.Cwd
@@ -1730,6 +1990,11 @@ func GoFilesPackage(gofiles []string) *Package {
}
bp, err := ctxt.ImportDir(dir, 0)
+ if ModDirImportPath != nil {
+ // Use the effective import path of the directory
+ // for deciding visibility during pkg.load.
+ bp.ImportPath = ModDirImportPath(dir)
+ }
pkg := new(Package)
pkg.Internal.Local = true
pkg.Internal.CmdlineFiles = true
@@ -1739,6 +2004,7 @@ func GoFilesPackage(gofiles []string) *Package {
pkg.Internal.LocalPrefix = dirToImportPath(dir)
pkg.ImportPath = "command-line-arguments"
pkg.Target = ""
+ pkg.Match = gofiles
if pkg.Name == "main" {
_, elem := filepath.Split(gofiles[0])
@@ -1748,152 +2014,12 @@ func GoFilesPackage(gofiles []string) *Package {
}
if cfg.GOBIN != "" {
pkg.Target = filepath.Join(cfg.GOBIN, exe)
+ } else if cfg.ModulesEnabled {
+ pkg.Target = filepath.Join(ModBinDir(), exe)
}
}
- return pkg
-}
-
-// GetTestPackagesFor returns package structs ptest, the package p plus
-// its test files, and pxtest, the external tests of package p.
-// pxtest may be nil. If there are no test files, forceTest decides
-// whether this returns a new package struct or just returns p.
-func GetTestPackagesFor(p *Package, forceTest bool) (ptest, pxtest *Package, err error) {
- var imports, ximports []*Package
- var stk ImportStack
- stk.Push(p.ImportPath + " (test)")
- rawTestImports := str.StringList(p.TestImports)
- for i, path := range p.TestImports {
- p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], ResolveImport)
- if p1.Error != nil {
- return nil, nil, p1.Error
- }
- if len(p1.DepsErrors) > 0 {
- err := p1.DepsErrors[0]
- err.Pos = "" // show full import stack
- return nil, nil, err
- }
- if str.Contains(p1.Deps, p.ImportPath) || p1.ImportPath == p.ImportPath {
- // Same error that loadPackage returns (via reusePackage) in pkg.go.
- // Can't change that code, because that code is only for loading the
- // non-test copy of a package.
- err := &PackageError{
- ImportStack: testImportStack(stk[0], p1, p.ImportPath),
- Err: "import cycle not allowed in test",
- IsImportCycle: true,
- }
- return nil, nil, err
- }
- p.TestImports[i] = p1.ImportPath
- imports = append(imports, p1)
- }
- stk.Pop()
- stk.Push(p.ImportPath + "_test")
- pxtestNeedsPtest := false
- rawXTestImports := str.StringList(p.XTestImports)
- for i, path := range p.XTestImports {
- p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], ResolveImport)
- if p1.Error != nil {
- return nil, nil, p1.Error
- }
- if len(p1.DepsErrors) > 0 {
- err := p1.DepsErrors[0]
- err.Pos = "" // show full import stack
- return nil, nil, err
- }
- if p1.ImportPath == p.ImportPath {
- pxtestNeedsPtest = true
- } else {
- ximports = append(ximports, p1)
- }
- p.XTestImports[i] = p1.ImportPath
- }
- stk.Pop()
-
- // Test package.
- if len(p.TestGoFiles) > 0 || forceTest {
- ptest = new(Package)
- *ptest = *p
- ptest.GoFiles = nil
- ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...)
- ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...)
- ptest.Target = ""
- // Note: The preparation of the vet config requires that common
- // indexes in ptest.Imports, ptest.Internal.Imports, and ptest.Internal.RawImports
- // all line up (but RawImports can be shorter than the others).
- // That is, for 0 ≤ i < len(RawImports),
- // RawImports[i] is the import string in the program text,
- // Imports[i] is the expanded import string (vendoring applied or relative path expanded away),
- // and Internal.Imports[i] is the corresponding *Package.
- // Any implicitly added imports appear in Imports and Internal.Imports
- // but not RawImports (because they were not in the source code).
- // We insert TestImports, imports, and rawTestImports at the start of
- // these lists to preserve the alignment.
- ptest.Imports = str.StringList(p.TestImports, p.Imports)
- ptest.Internal.Imports = append(imports, p.Internal.Imports...)
- ptest.Internal.RawImports = str.StringList(rawTestImports, p.Internal.RawImports)
- ptest.Internal.ForceLibrary = true
- ptest.Internal.Build = new(build.Package)
- *ptest.Internal.Build = *p.Internal.Build
- m := map[string][]token.Position{}
- for k, v := range p.Internal.Build.ImportPos {
- m[k] = append(m[k], v...)
- }
- for k, v := range p.Internal.Build.TestImportPos {
- m[k] = append(m[k], v...)
- }
- ptest.Internal.Build.ImportPos = m
- } else {
- ptest = p
- }
-
- // External test package.
- if len(p.XTestGoFiles) > 0 {
- pxtest = &Package{
- PackagePublic: PackagePublic{
- Name: p.Name + "_test",
- ImportPath: p.ImportPath + "_test",
- Root: p.Root,
- Dir: p.Dir,
- GoFiles: p.XTestGoFiles,
- Imports: p.XTestImports,
- },
- Internal: PackageInternal{
- LocalPrefix: p.Internal.LocalPrefix,
- Build: &build.Package{
- ImportPos: p.Internal.Build.XTestImportPos,
- },
- Imports: ximports,
- RawImports: rawXTestImports,
-
- Asmflags: p.Internal.Asmflags,
- Gcflags: p.Internal.Gcflags,
- Ldflags: p.Internal.Ldflags,
- Gccgoflags: p.Internal.Gccgoflags,
- },
- }
- if pxtestNeedsPtest {
- pxtest.Internal.Imports = append(pxtest.Internal.Imports, ptest)
- }
- }
-
- return ptest, pxtest, nil
-}
+ setToolFlags(pkg)
-func testImportStack(top string, p *Package, target string) []string {
- stk := []string{top, p.ImportPath}
-Search:
- for p.ImportPath != target {
- for _, p1 := range p.Internal.Imports {
- if p1.ImportPath == target || str.Contains(p1.Deps, target) {
- stk = append(stk, p1.ImportPath)
- p = p1
- continue Search
- }
- }
- // Can't happen, but in case it does...
- stk = append(stk, "<lost path to cycle>")
- break
- }
- return stk
+ return pkg
}
diff --git a/libgo/go/cmd/go/internal/load/search.go b/libgo/go/cmd/go/internal/load/search.go
index 595de079046..cf09c7b0a89 100644
--- a/libgo/go/cmd/go/internal/load/search.go
+++ b/libgo/go/cmd/go/internal/load/search.go
@@ -5,271 +5,16 @@
package load
import (
- "cmd/go/internal/cfg"
- "fmt"
- "go/build"
- "log"
- "os"
- "path"
"path/filepath"
- "regexp"
"strings"
-)
-
-// allPackages returns all the packages that can be found
-// under the $GOPATH directories and $GOROOT matching pattern.
-// The pattern is either "all" (all packages), "std" (standard packages),
-// "cmd" (standard commands), or a path including "...".
-func allPackages(pattern string) []string {
- pkgs := MatchPackages(pattern)
- if len(pkgs) == 0 {
- fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
- }
- return pkgs
-}
-
-// allPackagesInFS is like allPackages but is passed a pattern
-// beginning ./ or ../, meaning it should scan the tree rooted
-// at the given directory. There are ... in the pattern too.
-func allPackagesInFS(pattern string) []string {
- pkgs := MatchPackagesInFS(pattern)
- if len(pkgs) == 0 {
- fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
- }
- return pkgs
-}
-
-// MatchPackages returns a list of package paths matching pattern
-// (see go help packages for pattern syntax).
-func MatchPackages(pattern string) []string {
- match := func(string) bool { return true }
- treeCanMatch := func(string) bool { return true }
- if !IsMetaPackage(pattern) {
- match = matchPattern(pattern)
- treeCanMatch = treeCanMatchPattern(pattern)
- }
-
- have := map[string]bool{
- "builtin": true, // ignore pseudo-package that exists only for documentation
- }
- if !cfg.BuildContext.CgoEnabled {
- have["runtime/cgo"] = true // ignore during walk
- }
- var pkgs []string
-
- for _, src := range cfg.BuildContext.SrcDirs() {
- if (pattern == "std" || pattern == "cmd") && src != cfg.GOROOTsrc {
- continue
- }
- src = filepath.Clean(src) + string(filepath.Separator)
- root := src
- if pattern == "cmd" {
- root += "cmd" + string(filepath.Separator)
- }
- filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
- if err != nil || path == src {
- return nil
- }
-
- want := true
- // Avoid .foo, _foo, and testdata directory trees.
- _, elem := filepath.Split(path)
- if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
- want = false
- }
-
- name := filepath.ToSlash(path[len(src):])
- if pattern == "std" && (!isStandardImportPath(name) || name == "cmd") {
- // The name "std" is only the standard library.
- // If the name is cmd, it's the root of the command tree.
- want = false
- }
- if !treeCanMatch(name) {
- want = false
- }
-
- if !fi.IsDir() {
- if fi.Mode()&os.ModeSymlink != 0 && want {
- if target, err := os.Stat(path); err == nil && target.IsDir() {
- fmt.Fprintf(os.Stderr, "warning: ignoring symlink %s\n", path)
- }
- }
- return nil
- }
- if !want {
- return filepath.SkipDir
- }
-
- if have[name] {
- return nil
- }
- have[name] = true
- if !match(name) {
- return nil
- }
- pkg, err := cfg.BuildContext.ImportDir(path, 0)
- if err != nil {
- if _, noGo := err.(*build.NoGoError); noGo {
- return nil
- }
- }
-
- // If we are expanding "cmd", skip main
- // packages under cmd/vendor. At least as of
- // March, 2017, there is one there for the
- // vendored pprof tool.
- if pattern == "cmd" && strings.HasPrefix(pkg.ImportPath, "cmd/vendor") && pkg.Name == "main" {
- return nil
- }
-
- pkgs = append(pkgs, name)
- return nil
- })
- }
- return pkgs
-}
-
-// MatchPackagesInFS returns a list of package paths matching pattern,
-// which must begin with ./ or ../
-// (see go help packages for pattern syntax).
-func MatchPackagesInFS(pattern string) []string {
- // Find directory to begin the scan.
- // Could be smarter but this one optimization
- // is enough for now, since ... is usually at the
- // end of a path.
- i := strings.Index(pattern, "...")
- dir, _ := path.Split(pattern[:i])
-
- // pattern begins with ./ or ../.
- // path.Clean will discard the ./ but not the ../.
- // We need to preserve the ./ for pattern matching
- // and in the returned import paths.
- prefix := ""
- if strings.HasPrefix(pattern, "./") {
- prefix = "./"
- }
- match := matchPattern(pattern)
-
- var pkgs []string
- filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
- if err != nil || !fi.IsDir() {
- return nil
- }
- if path == dir {
- // filepath.Walk starts at dir and recurses. For the recursive case,
- // the path is the result of filepath.Join, which calls filepath.Clean.
- // The initial case is not Cleaned, though, so we do this explicitly.
- //
- // This converts a path like "./io/" to "io". Without this step, running
- // "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io
- // package, because prepending the prefix "./" to the unclean path would
- // result in "././io", and match("././io") returns false.
- path = filepath.Clean(path)
- }
-
- // Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..".
- _, elem := filepath.Split(path)
- dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".."
- if dot || strings.HasPrefix(elem, "_") || elem == "testdata" {
- return filepath.SkipDir
- }
-
- name := prefix + filepath.ToSlash(path)
- if !match(name) {
- return nil
- }
- // We keep the directory if we can import it, or if we can't import it
- // due to invalid Go source files. This means that directories containing
- // parse errors will be built (and fail) instead of being silently skipped
- // as not matching the pattern. Go 1.5 and earlier skipped, but that
- // behavior means people miss serious mistakes.
- // See golang.org/issue/11407.
- if p, err := cfg.BuildContext.ImportDir(path, 0); err != nil && (p == nil || len(p.InvalidGoFiles) == 0) {
- if _, noGo := err.(*build.NoGoError); !noGo {
- log.Print(err)
- }
- return nil
- }
- pkgs = append(pkgs, name)
- return nil
- })
- return pkgs
-}
-
-// treeCanMatchPattern(pattern)(name) reports whether
-// name or children of name can possibly match pattern.
-// Pattern is the same limited glob accepted by matchPattern.
-func treeCanMatchPattern(pattern string) func(name string) bool {
- wildCard := false
- if i := strings.Index(pattern, "..."); i >= 0 {
- wildCard = true
- pattern = pattern[:i]
- }
- return func(name string) bool {
- return len(name) <= len(pattern) && hasPathPrefix(pattern, name) ||
- wildCard && strings.HasPrefix(name, pattern)
- }
-}
-
-// matchPattern(pattern)(name) reports whether
-// name matches pattern. Pattern is a limited glob
-// pattern in which '...' means 'any string' and there
-// is no other special syntax.
-// Unfortunately, there are two special cases. Quoting "go help packages":
-//
-// First, /... at the end of the pattern can match an empty string,
-// so that net/... matches both net and packages in its subdirectories, like net/http.
-// Second, any slash-separted pattern element containing a wildcard never
-// participates in a match of the "vendor" element in the path of a vendored
-// package, so that ./... does not match packages in subdirectories of
-// ./vendor or ./mycode/vendor, but ./vendor/... and ./mycode/vendor/... do.
-// Note, however, that a directory named vendor that itself contains code
-// is not a vendored package: cmd/vendor would be a command named vendor,
-// and the pattern cmd/... matches it.
-func matchPattern(pattern string) func(name string) bool {
- // Convert pattern to regular expression.
- // The strategy for the trailing /... is to nest it in an explicit ? expression.
- // The strategy for the vendor exclusion is to change the unmatchable
- // vendor strings to a disallowed code point (vendorChar) and to use
- // "(anything but that codepoint)*" as the implementation of the ... wildcard.
- // This is a bit complicated but the obvious alternative,
- // namely a hand-written search like in most shell glob matchers,
- // is too easy to make accidentally exponential.
- // Using package regexp guarantees linear-time matching.
-
- const vendorChar = "\x00"
-
- if strings.Contains(pattern, vendorChar) {
- return func(name string) bool { return false }
- }
-
- re := regexp.QuoteMeta(pattern)
- re = replaceVendor(re, vendorChar)
- switch {
- case strings.HasSuffix(re, `/`+vendorChar+`/\.\.\.`):
- re = strings.TrimSuffix(re, `/`+vendorChar+`/\.\.\.`) + `(/vendor|/` + vendorChar + `/\.\.\.)`
- case re == vendorChar+`/\.\.\.`:
- re = `(/vendor|/` + vendorChar + `/\.\.\.)`
- case strings.HasSuffix(re, `/\.\.\.`):
- re = strings.TrimSuffix(re, `/\.\.\.`) + `(/\.\.\.)?`
- }
- re = strings.Replace(re, `\.\.\.`, `[^`+vendorChar+`]*`, -1)
-
- reg := regexp.MustCompile(`^` + re + `$`)
-
- return func(name string) bool {
- if strings.Contains(name, vendorChar) {
- return false
- }
- return reg.MatchString(replaceVendor(name, vendorChar))
- }
-}
+ "cmd/go/internal/search"
+)
// MatchPackage(pattern, cwd)(p) reports whether package p matches pattern in the working directory cwd.
func MatchPackage(pattern, cwd string) func(*Package) bool {
switch {
- case strings.HasPrefix(pattern, "./") || strings.HasPrefix(pattern, "../") || pattern == "." || pattern == "..":
+ case search.IsRelativePath(pattern):
// Split pattern into leading pattern-free directory path
// (including all . and .. elements) and the final pattern.
var dir string
@@ -284,7 +29,7 @@ func MatchPackage(pattern, cwd string) func(*Package) bool {
if pattern == "" {
return func(p *Package) bool { return p.Dir == dir }
}
- matchPath := matchPattern(pattern)
+ matchPath := search.MatchPattern(pattern)
return func(p *Package) bool {
// Compute relative path to dir and see if it matches the pattern.
rel, err := filepath.Rel(dir, p.Dir)
@@ -305,81 +50,7 @@ func MatchPackage(pattern, cwd string) func(*Package) bool {
case pattern == "cmd":
return func(p *Package) bool { return p.Standard && strings.HasPrefix(p.ImportPath, "cmd/") }
default:
- matchPath := matchPattern(pattern)
+ matchPath := search.MatchPattern(pattern)
return func(p *Package) bool { return matchPath(p.ImportPath) }
}
}
-
-// replaceVendor returns the result of replacing
-// non-trailing vendor path elements in x with repl.
-func replaceVendor(x, repl string) string {
- if !strings.Contains(x, "vendor") {
- return x
- }
- elem := strings.Split(x, "/")
- for i := 0; i < len(elem)-1; i++ {
- if elem[i] == "vendor" {
- elem[i] = repl
- }
- }
- return strings.Join(elem, "/")
-}
-
-// ImportPaths returns the import paths to use for the given command line.
-func ImportPaths(args []string) []string {
- args = ImportPathsNoDotExpansion(args)
- var out []string
- for _, a := range args {
- if strings.Contains(a, "...") {
- if build.IsLocalImport(a) {
- out = append(out, allPackagesInFS(a)...)
- } else {
- out = append(out, allPackages(a)...)
- }
- continue
- }
- out = append(out, a)
- }
- return out
-}
-
-// ImportPathsNoDotExpansion returns the import paths to use for the given
-// command line, but it does no ... expansion.
-func ImportPathsNoDotExpansion(args []string) []string {
- if cmdlineMatchers == nil {
- SetCmdlinePatterns(args)
- }
- if len(args) == 0 {
- return []string{"."}
- }
- var out []string
- for _, a := range args {
- // Arguments are supposed to be import paths, but
- // as a courtesy to Windows developers, rewrite \ to /
- // in command-line arguments. Handles .\... and so on.
- if filepath.Separator == '\\' {
- a = strings.Replace(a, `\`, `/`, -1)
- }
-
- // Put argument in canonical form, but preserve leading ./.
- if strings.HasPrefix(a, "./") {
- a = "./" + path.Clean(a)
- if a == "./." {
- a = "."
- }
- } else {
- a = path.Clean(a)
- }
- if IsMetaPackage(a) {
- out = append(out, allPackages(a)...)
- continue
- }
- out = append(out, a)
- }
- return out
-}
-
-// IsMetaPackage checks if name is a reserved package name that expands to multiple packages.
-func IsMetaPackage(name string) bool {
- return name == "std" || name == "cmd" || name == "all"
-}
diff --git a/libgo/go/cmd/go/internal/load/test.go b/libgo/go/cmd/go/internal/load/test.go
new file mode 100644
index 00000000000..0eab21b1761
--- /dev/null
+++ b/libgo/go/cmd/go/internal/load/test.go
@@ -0,0 +1,654 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package load
+
+import (
+ "bytes"
+ "cmd/go/internal/base"
+ "cmd/go/internal/str"
+ "errors"
+ "fmt"
+ "go/ast"
+ "go/build"
+ "go/doc"
+ "go/parser"
+ "go/token"
+ "path/filepath"
+ "sort"
+ "strings"
+ "text/template"
+ "unicode"
+ "unicode/utf8"
+)
+
+var TestMainDeps = []string{
+ // Dependencies for testmain.
+ "os",
+ "testing",
+ "testing/internal/testdeps",
+}
+
+type TestCover struct {
+ Mode string
+ Local bool
+ Pkgs []*Package
+ Paths []string
+ Vars []coverInfo
+ DeclVars func(*Package, ...string) map[string]*CoverVar
+}
+
+// TestPackagesFor returns three packages:
+// - ptest, the package p compiled with added "package p" test files.
+// - pxtest, the result of compiling any "package p_test" (external) test files.
+// - pmain, the package main corresponding to the test binary (running tests in ptest and pxtest).
+//
+// If the package has no "package p_test" test files, pxtest will be nil.
+// If the non-test compilation of package p can be reused
+// (for example, if there are no "package p" test files and
+// package p need not be instrumented for coverage or any other reason),
+// then the returned ptest == p.
+//
+// The caller is expected to have checked that len(p.TestGoFiles)+len(p.XTestGoFiles) > 0,
+// or else there's no point in any of this.
+func GetTestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Package, err error) {
+ var imports, ximports []*Package
+ var stk ImportStack
+ stk.Push(p.ImportPath + " (test)")
+ rawTestImports := str.StringList(p.TestImports)
+ for i, path := range p.TestImports {
+ p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], ResolveImport)
+ if p1.Error != nil {
+ return nil, nil, nil, p1.Error
+ }
+ if len(p1.DepsErrors) > 0 {
+ err := p1.DepsErrors[0]
+ err.Pos = "" // show full import stack
+ return nil, nil, nil, err
+ }
+ if str.Contains(p1.Deps, p.ImportPath) || p1.ImportPath == p.ImportPath {
+ // Same error that loadPackage returns (via reusePackage) in pkg.go.
+ // Can't change that code, because that code is only for loading the
+ // non-test copy of a package.
+ err := &PackageError{
+ ImportStack: testImportStack(stk[0], p1, p.ImportPath),
+ Err: "import cycle not allowed in test",
+ IsImportCycle: true,
+ }
+ return nil, nil, nil, err
+ }
+ p.TestImports[i] = p1.ImportPath
+ imports = append(imports, p1)
+ }
+ stk.Pop()
+ stk.Push(p.ImportPath + "_test")
+ pxtestNeedsPtest := false
+ rawXTestImports := str.StringList(p.XTestImports)
+ for i, path := range p.XTestImports {
+ p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], ResolveImport)
+ if p1.Error != nil {
+ return nil, nil, nil, p1.Error
+ }
+ if len(p1.DepsErrors) > 0 {
+ err := p1.DepsErrors[0]
+ err.Pos = "" // show full import stack
+ return nil, nil, nil, err
+ }
+ if p1.ImportPath == p.ImportPath {
+ pxtestNeedsPtest = true
+ } else {
+ ximports = append(ximports, p1)
+ }
+ p.XTestImports[i] = p1.ImportPath
+ }
+ stk.Pop()
+
+ // Test package.
+ if len(p.TestGoFiles) > 0 || p.Name == "main" || cover != nil && cover.Local {
+ ptest = new(Package)
+ *ptest = *p
+ ptest.ForTest = p.ImportPath
+ ptest.GoFiles = nil
+ ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...)
+ ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...)
+ ptest.Target = ""
+ // Note: The preparation of the vet config requires that common
+ // indexes in ptest.Imports and ptest.Internal.RawImports
+ // all line up (but RawImports can be shorter than the others).
+ // That is, for 0 ≤ i < len(RawImports),
+ // RawImports[i] is the import string in the program text, and
+ // Imports[i] is the expanded import string (vendoring applied or relative path expanded away).
+ // Any implicitly added imports appear in Imports and Internal.Imports
+ // but not RawImports (because they were not in the source code).
+ // We insert TestImports, imports, and rawTestImports at the start of
+ // these lists to preserve the alignment.
+ // Note that p.Internal.Imports may not be aligned with p.Imports/p.Internal.RawImports,
+ // but we insert at the beginning there too just for consistency.
+ ptest.Imports = str.StringList(p.TestImports, p.Imports)
+ ptest.Internal.Imports = append(imports, p.Internal.Imports...)
+ ptest.Internal.RawImports = str.StringList(rawTestImports, p.Internal.RawImports)
+ ptest.Internal.ForceLibrary = true
+ ptest.Internal.Build = new(build.Package)
+ *ptest.Internal.Build = *p.Internal.Build
+ m := map[string][]token.Position{}
+ for k, v := range p.Internal.Build.ImportPos {
+ m[k] = append(m[k], v...)
+ }
+ for k, v := range p.Internal.Build.TestImportPos {
+ m[k] = append(m[k], v...)
+ }
+ ptest.Internal.Build.ImportPos = m
+ } else {
+ ptest = p
+ }
+
+ // External test package.
+ if len(p.XTestGoFiles) > 0 {
+ pxtest = &Package{
+ PackagePublic: PackagePublic{
+ Name: p.Name + "_test",
+ ImportPath: p.ImportPath + "_test",
+ Root: p.Root,
+ Dir: p.Dir,
+ GoFiles: p.XTestGoFiles,
+ Imports: p.XTestImports,
+ ForTest: p.ImportPath,
+ },
+ Internal: PackageInternal{
+ LocalPrefix: p.Internal.LocalPrefix,
+ Build: &build.Package{
+ ImportPos: p.Internal.Build.XTestImportPos,
+ },
+ Imports: ximports,
+ RawImports: rawXTestImports,
+
+ Asmflags: p.Internal.Asmflags,
+ Gcflags: p.Internal.Gcflags,
+ Ldflags: p.Internal.Ldflags,
+ Gccgoflags: p.Internal.Gccgoflags,
+ },
+ }
+ if pxtestNeedsPtest {
+ pxtest.Internal.Imports = append(pxtest.Internal.Imports, ptest)
+ }
+ }
+
+ // Build main package.
+ pmain = &Package{
+ PackagePublic: PackagePublic{
+ Name: "main",
+ Dir: p.Dir,
+ GoFiles: []string{"_testmain.go"},
+ ImportPath: p.ImportPath + ".test",
+ Root: p.Root,
+ Imports: str.StringList(TestMainDeps),
+ },
+ Internal: PackageInternal{
+ Build: &build.Package{Name: "main"},
+ Asmflags: p.Internal.Asmflags,
+ Gcflags: p.Internal.Gcflags,
+ Ldflags: p.Internal.Ldflags,
+ Gccgoflags: p.Internal.Gccgoflags,
+ },
+ }
+
+ // The generated main also imports testing, regexp, and os.
+ // Also the linker introduces implicit dependencies reported by LinkerDeps.
+ stk.Push("testmain")
+ deps := TestMainDeps // cap==len, so safe for append
+ for _, d := range LinkerDeps(p) {
+ deps = append(deps, d)
+ }
+ for _, dep := range deps {
+ if dep == ptest.ImportPath {
+ pmain.Internal.Imports = append(pmain.Internal.Imports, ptest)
+ } else {
+ p1 := LoadImport(dep, "", nil, &stk, nil, 0)
+ if p1.Error != nil {
+ return nil, nil, nil, p1.Error
+ }
+ pmain.Internal.Imports = append(pmain.Internal.Imports, p1)
+ }
+ }
+ stk.Pop()
+
+ if cover != nil && cover.Pkgs != nil {
+ // Add imports, but avoid duplicates.
+ seen := map[*Package]bool{p: true, ptest: true}
+ for _, p1 := range pmain.Internal.Imports {
+ seen[p1] = true
+ }
+ for _, p1 := range cover.Pkgs {
+ if !seen[p1] {
+ seen[p1] = true
+ pmain.Internal.Imports = append(pmain.Internal.Imports, p1)
+ }
+ }
+ }
+
+ // Do initial scan for metadata needed for writing _testmain.go
+ // Use that metadata to update the list of imports for package main.
+ // The list of imports is used by recompileForTest and by the loop
+ // afterward that gathers t.Cover information.
+ t, err := loadTestFuncs(ptest)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ t.Cover = cover
+ if len(ptest.GoFiles)+len(ptest.CgoFiles) > 0 {
+ pmain.Internal.Imports = append(pmain.Internal.Imports, ptest)
+ pmain.Imports = append(pmain.Imports, ptest.ImportPath)
+ t.ImportTest = true
+ }
+ if pxtest != nil {
+ pmain.Internal.Imports = append(pmain.Internal.Imports, pxtest)
+ pmain.Imports = append(pmain.Imports, pxtest.ImportPath)
+ t.ImportXtest = true
+ }
+
+ // Sort and dedup pmain.Imports.
+ // Only matters for go list -test output.
+ sort.Strings(pmain.Imports)
+ w := 0
+ for _, path := range pmain.Imports {
+ if w == 0 || path != pmain.Imports[w-1] {
+ pmain.Imports[w] = path
+ w++
+ }
+ }
+ pmain.Imports = pmain.Imports[:w]
+ pmain.Internal.RawImports = str.StringList(pmain.Imports)
+
+ if ptest != p {
+ // We have made modifications to the package p being tested
+ // and are rebuilding p (as ptest).
+ // Arrange to rebuild all packages q such that
+ // the test depends on q and q depends on p.
+ // This makes sure that q sees the modifications to p.
+ // Strictly speaking, the rebuild is only necessary if the
+ // modifications to p change its export metadata, but
+ // determining that is a bit tricky, so we rebuild always.
+ recompileForTest(pmain, p, ptest, pxtest)
+ }
+
+ // Should we apply coverage analysis locally,
+ // only for this package and only for this test?
+ // Yes, if -cover is on but -coverpkg has not specified
+ // a list of packages for global coverage.
+ if cover != nil && cover.Local {
+ ptest.Internal.CoverMode = cover.Mode
+ var coverFiles []string
+ coverFiles = append(coverFiles, ptest.GoFiles...)
+ coverFiles = append(coverFiles, ptest.CgoFiles...)
+ ptest.Internal.CoverVars = cover.DeclVars(ptest, coverFiles...)
+ }
+
+ for _, cp := range pmain.Internal.Imports {
+ if len(cp.Internal.CoverVars) > 0 {
+ t.Cover.Vars = append(t.Cover.Vars, coverInfo{cp, cp.Internal.CoverVars})
+ }
+ }
+
+ data, err := formatTestmain(t)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ pmain.Internal.TestmainGo = &data
+
+ return pmain, ptest, pxtest, nil
+}
+
+func testImportStack(top string, p *Package, target string) []string {
+ stk := []string{top, p.ImportPath}
+Search:
+ for p.ImportPath != target {
+ for _, p1 := range p.Internal.Imports {
+ if p1.ImportPath == target || str.Contains(p1.Deps, target) {
+ stk = append(stk, p1.ImportPath)
+ p = p1
+ continue Search
+ }
+ }
+ // Can't happen, but in case it does...
+ stk = append(stk, "<lost path to cycle>")
+ break
+ }
+ return stk
+}
+
+func recompileForTest(pmain, preal, ptest, pxtest *Package) {
+ // The "test copy" of preal is ptest.
+ // For each package that depends on preal, make a "test copy"
+ // that depends on ptest. And so on, up the dependency tree.
+ testCopy := map[*Package]*Package{preal: ptest}
+ for _, p := range PackageList([]*Package{pmain}) {
+ if p == preal {
+ continue
+ }
+ // Copy on write.
+ didSplit := p == pmain || p == pxtest
+ split := func() {
+ if didSplit {
+ return
+ }
+ didSplit = true
+ if testCopy[p] != nil {
+ panic("recompileForTest loop")
+ }
+ p1 := new(Package)
+ testCopy[p] = p1
+ *p1 = *p
+ p1.ForTest = preal.ImportPath
+ p1.Internal.Imports = make([]*Package, len(p.Internal.Imports))
+ copy(p1.Internal.Imports, p.Internal.Imports)
+ p1.Imports = make([]string, len(p.Imports))
+ copy(p1.Imports, p.Imports)
+ p = p1
+ p.Target = ""
+ }
+
+ // Update p.Internal.Imports to use test copies.
+ for i, imp := range p.Internal.Imports {
+ if p1 := testCopy[imp]; p1 != nil && p1 != imp {
+ split()
+ p.Internal.Imports[i] = p1
+ }
+ }
+ }
+}
+
+// isTestFunc tells whether fn has the type of a testing function. arg
+// specifies the parameter type we look for: B, M or T.
+func isTestFunc(fn *ast.FuncDecl, arg string) bool {
+ if fn.Type.Results != nil && len(fn.Type.Results.List) > 0 ||
+ fn.Type.Params.List == nil ||
+ len(fn.Type.Params.List) != 1 ||
+ len(fn.Type.Params.List[0].Names) > 1 {
+ return false
+ }
+ ptr, ok := fn.Type.Params.List[0].Type.(*ast.StarExpr)
+ if !ok {
+ return false
+ }
+ // We can't easily check that the type is *testing.M
+ // because we don't know how testing has been imported,
+ // but at least check that it's *M or *something.M.
+ // Same applies for B and T.
+ if name, ok := ptr.X.(*ast.Ident); ok && name.Name == arg {
+ return true
+ }
+ if sel, ok := ptr.X.(*ast.SelectorExpr); ok && sel.Sel.Name == arg {
+ return true
+ }
+ return false
+}
+
+// isTest tells whether name looks like a test (or benchmark, according to prefix).
+// It is a Test (say) if there is a character after Test that is not a lower-case letter.
+// We don't want TesticularCancer.
+func isTest(name, prefix string) bool {
+ if !strings.HasPrefix(name, prefix) {
+ return false
+ }
+ if len(name) == len(prefix) { // "Test" is ok
+ return true
+ }
+ rune, _ := utf8.DecodeRuneInString(name[len(prefix):])
+ return !unicode.IsLower(rune)
+}
+
+type coverInfo struct {
+ Package *Package
+ Vars map[string]*CoverVar
+}
+
+// loadTestFuncs returns the testFuncs describing the tests that will be run.
+func loadTestFuncs(ptest *Package) (*testFuncs, error) {
+ t := &testFuncs{
+ Package: ptest,
+ }
+ for _, file := range ptest.TestGoFiles {
+ if err := t.load(filepath.Join(ptest.Dir, file), "_test", &t.ImportTest, &t.NeedTest); err != nil {
+ return nil, err
+ }
+ }
+ for _, file := range ptest.XTestGoFiles {
+ if err := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.ImportXtest, &t.NeedXtest); err != nil {
+ return nil, err
+ }
+ }
+ return t, nil
+}
+
+// formatTestmain returns the content of the _testmain.go file for t.
+func formatTestmain(t *testFuncs) ([]byte, error) {
+ var buf bytes.Buffer
+ if err := testmainTmpl.Execute(&buf, t); err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+type testFuncs struct {
+ Tests []testFunc
+ Benchmarks []testFunc
+ Examples []testFunc
+ TestMain *testFunc
+ Package *Package
+ ImportTest bool
+ NeedTest bool
+ ImportXtest bool
+ NeedXtest bool
+ Cover *TestCover
+}
+
+// ImportPath returns the import path of the package being tested, if it is within GOPATH.
+// This is printed by the testing package when running benchmarks.
+func (t *testFuncs) ImportPath() string {
+ pkg := t.Package.ImportPath
+ if strings.HasPrefix(pkg, "_/") {
+ return ""
+ }
+ if pkg == "command-line-arguments" {
+ return ""
+ }
+ return pkg
+}
+
+// Covered returns a string describing which packages are being tested for coverage.
+// If the covered package is the same as the tested package, it returns the empty string.
+// Otherwise it is a comma-separated human-readable list of packages beginning with
+// " in", ready for use in the coverage message.
+func (t *testFuncs) Covered() string {
+ if t.Cover == nil || t.Cover.Paths == nil {
+ return ""
+ }
+ return " in " + strings.Join(t.Cover.Paths, ", ")
+}
+
+// Tested returns the name of the package being tested.
+func (t *testFuncs) Tested() string {
+ return t.Package.Name
+}
+
+type testFunc struct {
+ Package string // imported package name (_test or _xtest)
+ Name string // function name
+ Output string // output, for examples
+ Unordered bool // output is allowed to be unordered.
+}
+
+var testFileSet = token.NewFileSet()
+
+func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {
+ f, err := parser.ParseFile(testFileSet, filename, nil, parser.ParseComments)
+ if err != nil {
+ return base.ExpandScanner(err)
+ }
+ for _, d := range f.Decls {
+ n, ok := d.(*ast.FuncDecl)
+ if !ok {
+ continue
+ }
+ if n.Recv != nil {
+ continue
+ }
+ name := n.Name.String()
+ switch {
+ case name == "TestMain":
+ if isTestFunc(n, "T") {
+ t.Tests = append(t.Tests, testFunc{pkg, name, "", false})
+ *doImport, *seen = true, true
+ continue
+ }
+ err := checkTestFunc(n, "M")
+ if err != nil {
+ return err
+ }
+ if t.TestMain != nil {
+ return errors.New("multiple definitions of TestMain")
+ }
+ t.TestMain = &testFunc{pkg, name, "", false}
+ *doImport, *seen = true, true
+ case isTest(name, "Test"):
+ err := checkTestFunc(n, "T")
+ if err != nil {
+ return err
+ }
+ t.Tests = append(t.Tests, testFunc{pkg, name, "", false})
+ *doImport, *seen = true, true
+ case isTest(name, "Benchmark"):
+ err := checkTestFunc(n, "B")
+ if err != nil {
+ return err
+ }
+ t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, "", false})
+ *doImport, *seen = true, true
+ }
+ }
+ ex := doc.Examples(f)
+ sort.Slice(ex, func(i, j int) bool { return ex[i].Order < ex[j].Order })
+ for _, e := range ex {
+ *doImport = true // import test file whether executed or not
+ if e.Output == "" && !e.EmptyOutput {
+ // Don't run examples with no output.
+ continue
+ }
+ t.Examples = append(t.Examples, testFunc{pkg, "Example" + e.Name, e.Output, e.Unordered})
+ *seen = true
+ }
+ return nil
+}
+
+func checkTestFunc(fn *ast.FuncDecl, arg string) error {
+ if !isTestFunc(fn, arg) {
+ name := fn.Name.String()
+ pos := testFileSet.Position(fn.Pos())
+ return fmt.Errorf("%s: wrong signature for %s, must be: func %s(%s *testing.%s)", pos, name, name, strings.ToLower(arg), arg)
+ }
+ return nil
+}
+
+var testmainTmpl = template.Must(template.New("main").Parse(`
+package main
+
+import (
+{{if not .TestMain}}
+ "os"
+{{end}}
+ "testing"
+ "testing/internal/testdeps"
+
+{{if .ImportTest}}
+ {{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}}
+{{end}}
+{{if .ImportXtest}}
+ {{if .NeedXtest}}_xtest{{else}}_{{end}} {{.Package.ImportPath | printf "%s_test" | printf "%q"}}
+{{end}}
+{{if .Cover}}
+{{range $i, $p := .Cover.Vars}}
+ _cover{{$i}} {{$p.Package.ImportPath | printf "%q"}}
+{{end}}
+{{end}}
+)
+
+var tests = []testing.InternalTest{
+{{range .Tests}}
+ {"{{.Name}}", {{.Package}}.{{.Name}}},
+{{end}}
+}
+
+var benchmarks = []testing.InternalBenchmark{
+{{range .Benchmarks}}
+ {"{{.Name}}", {{.Package}}.{{.Name}}},
+{{end}}
+}
+
+var examples = []testing.InternalExample{
+{{range .Examples}}
+ {"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}, {{.Unordered}}},
+{{end}}
+}
+
+func init() {
+ testdeps.ImportPath = {{.ImportPath | printf "%q"}}
+}
+
+{{if .Cover}}
+
+// Only updated by init functions, so no need for atomicity.
+var (
+ coverCounters = make(map[string][]uint32)
+ coverBlocks = make(map[string][]testing.CoverBlock)
+)
+
+func init() {
+ {{range $i, $p := .Cover.Vars}}
+ {{range $file, $cover := $p.Vars}}
+ coverRegisterFile({{printf "%q" $cover.File}}, _cover{{$i}}.{{$cover.Var}}.Count[:], _cover{{$i}}.{{$cover.Var}}.Pos[:], _cover{{$i}}.{{$cover.Var}}.NumStmt[:])
+ {{end}}
+ {{end}}
+}
+
+func coverRegisterFile(fileName string, counter []uint32, pos []uint32, numStmts []uint16) {
+ if 3*len(counter) != len(pos) || len(counter) != len(numStmts) {
+ panic("coverage: mismatched sizes")
+ }
+ if coverCounters[fileName] != nil {
+ // Already registered.
+ return
+ }
+ coverCounters[fileName] = counter
+ block := make([]testing.CoverBlock, len(counter))
+ for i := range counter {
+ block[i] = testing.CoverBlock{
+ Line0: pos[3*i+0],
+ Col0: uint16(pos[3*i+2]),
+ Line1: pos[3*i+1],
+ Col1: uint16(pos[3*i+2]>>16),
+ Stmts: numStmts[i],
+ }
+ }
+ coverBlocks[fileName] = block
+}
+{{end}}
+
+func main() {
+{{if .Cover}}
+ testing.RegisterCover(testing.Cover{
+ Mode: {{printf "%q" .Cover.Mode}},
+ Counters: coverCounters,
+ Blocks: coverBlocks,
+ CoveredPackages: {{printf "%q" .Covered}},
+ })
+{{end}}
+ m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, examples)
+{{with .TestMain}}
+ {{.Package}}.{{.Name}}(m)
+{{else}}
+ os.Exit(m.Run())
+{{end}}
+}
+
+`))
diff --git a/libgo/go/cmd/go/internal/modcmd/download.go b/libgo/go/cmd/go/internal/modcmd/download.go
new file mode 100644
index 00000000000..cf42eff58a1
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modcmd/download.go
@@ -0,0 +1,133 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modcmd
+
+import (
+ "cmd/go/internal/base"
+ "cmd/go/internal/modfetch"
+ "cmd/go/internal/modload"
+ "cmd/go/internal/module"
+ "cmd/go/internal/par"
+ "encoding/json"
+ "os"
+)
+
+var cmdDownload = &base.Command{
+ UsageLine: "go mod download [-dir] [-json] [modules]",
+ Short: "download modules to local cache",
+ Long: `
+Download downloads the named modules, which can be module patterns selecting
+dependencies of the main module or module queries of the form path@version.
+With no arguments, download applies to all dependencies of the main module.
+
+The go command will automatically download modules as needed during ordinary
+execution. The "go mod download" command is useful mainly for pre-filling
+the local cache or to compute the answers for a Go module proxy.
+
+By default, download reports errors to standard error but is otherwise silent.
+The -json flag causes download to print a sequence of JSON objects
+to standard output, describing each downloaded module (or failure),
+corresponding to this Go struct:
+
+ type Module struct {
+ Path string // module path
+ Version string // module version
+ Error string // error loading module
+ Info string // absolute path to cached .info file
+ GoMod string // absolute path to cached .mod file
+ Zip string // absolute path to cached .zip file
+ Dir string // absolute path to cached source root directory
+ Sum string // checksum for path, version (as in go.sum)
+ GoModSum string // checksum for go.mod (as in go.sum)
+ }
+
+See 'go help modules' for more about module queries.
+ `,
+}
+
+var downloadJSON = cmdDownload.Flag.Bool("json", false, "")
+
+func init() {
+ cmdDownload.Run = runDownload // break init cycle
+}
+
+type moduleJSON struct {
+ Path string `json:",omitempty"`
+ Version string `json:",omitempty"`
+ Error string `json:",omitempty"`
+ Info string `json:",omitempty"`
+ GoMod string `json:",omitempty"`
+ Zip string `json:",omitempty"`
+ Dir string `json:",omitempty"`
+ Sum string `json:",omitempty"`
+ GoModSum string `json:",omitempty"`
+}
+
+func runDownload(cmd *base.Command, args []string) {
+ if len(args) == 0 {
+ args = []string{"all"}
+ }
+
+ var mods []*moduleJSON
+ var work par.Work
+ listU := false
+ listVersions := false
+ for _, info := range modload.ListModules(args, listU, listVersions) {
+ if info.Replace != nil {
+ info = info.Replace
+ }
+ if info.Version == "" {
+ continue
+ }
+ m := &moduleJSON{
+ Path: info.Path,
+ Version: info.Version,
+ }
+ mods = append(mods, m)
+ work.Add(m)
+ }
+
+ work.Do(10, func(item interface{}) {
+ m := item.(*moduleJSON)
+ var err error
+ m.Info, err = modfetch.InfoFile(m.Path, m.Version)
+ if err != nil {
+ m.Error = err.Error()
+ return
+ }
+ m.GoMod, err = modfetch.GoModFile(m.Path, m.Version)
+ if err != nil {
+ m.Error = err.Error()
+ return
+ }
+ m.GoModSum, err = modfetch.GoModSum(m.Path, m.Version)
+ if err != nil {
+ m.Error = err.Error()
+ return
+ }
+ mod := module.Version{Path: m.Path, Version: m.Version}
+ m.Zip, err = modfetch.DownloadZip(mod)
+ if err != nil {
+ m.Error = err.Error()
+ return
+ }
+ m.Sum = modfetch.Sum(mod)
+ m.Dir, err = modfetch.Download(mod)
+ if err != nil {
+ m.Error = err.Error()
+ return
+ }
+ })
+
+ if *downloadJSON {
+ for _, m := range mods {
+ b, err := json.MarshalIndent(m, "", "\t")
+ if err != nil {
+ base.Fatalf("%v", err)
+ }
+ os.Stdout.Write(append(b, '\n'))
+ }
+ }
+}
diff --git a/libgo/go/cmd/go/internal/modcmd/edit.go b/libgo/go/cmd/go/internal/modcmd/edit.go
new file mode 100644
index 00000000000..5fea3e48e08
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modcmd/edit.go
@@ -0,0 +1,382 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// go mod edit
+
+package modcmd
+
+import (
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "cmd/go/internal/base"
+ "cmd/go/internal/modfile"
+ "cmd/go/internal/modload"
+ "cmd/go/internal/module"
+)
+
+var cmdEdit = &base.Command{
+ UsageLine: "go mod edit [editing flags] [go.mod]",
+ Short: "edit go.mod from tools or scripts",
+ Long: `
+Edit provides a command-line interface for editing go.mod,
+for use primarily by tools or scripts. It reads only go.mod;
+it does not look up information about the modules involved.
+By default, edit reads and writes the go.mod file of the main module,
+but a different target file can be specified after the editing flags.
+
+The editing flags specify a sequence of editing operations.
+
+The -fmt flag reformats the go.mod file without making other changes.
+This reformatting is also implied by any other modifications that use or
+rewrite the go.mod file. The only time this flag is needed is if no other
+flags are specified, as in 'go mod edit -fmt'.
+
+The -module flag changes the module's path (the go.mod file's module line).
+
+The -require=path@version and -droprequire=path flags
+add and drop a requirement on the given module path and version.
+Note that -require overrides any existing requirements on path.
+These flags are mainly for tools that understand the module graph.
+Users should prefer 'go get path@version' or 'go get path@none',
+which make other go.mod adjustments as needed to satisfy
+constraints imposed by other modules.
+
+The -exclude=path@version and -dropexclude=path@version flags
+add and drop an exclusion for the given module path and version.
+Note that -exclude=path@version is a no-op if that exclusion already exists.
+
+The -replace=old[@v]=new[@v] and -dropreplace=old[@v] flags
+add and drop a replacement of the given module path and version pair.
+If the @v in old@v is omitted, the replacement applies to all versions
+with the old module path. If the @v in new@v is omitted, the new path
+should be a local module root directory, not a module path.
+Note that -replace overrides any existing replacements for old[@v].
+
+The -require, -droprequire, -exclude, -dropexclude, -replace,
+and -dropreplace editing flags may be repeated, and the changes
+are applied in the order given.
+
+The -print flag prints the final go.mod in its text format instead of
+writing it back to go.mod.
+
+The -json flag prints the final go.mod file in JSON format instead of
+writing it back to go.mod. The JSON output corresponds to these Go types:
+
+ type Module struct {
+ Path string
+ Version string
+ }
+
+ type GoMod struct {
+ Module Module
+ Require []Require
+ Exclude []Module
+ Replace []Replace
+ }
+
+ type Require struct {
+ Path string
+ Version string
+ Indirect bool
+ }
+
+ type Replace struct {
+ Old Module
+ New Module
+ }
+
+Note that this only describes the go.mod file itself, not other modules
+referred to indirectly. For the full set of modules available to a build,
+use 'go list -m -json all'.
+
+For example, a tool can obtain the go.mod as a data structure by
+parsing the output of 'go mod edit -json' and can then make changes
+by invoking 'go mod edit' with -require, -exclude, and so on.
+ `,
+}
+
+var (
+ editFmt = cmdEdit.Flag.Bool("fmt", false, "")
+ // editGo = cmdEdit.Flag.String("go", "", "")
+ editJSON = cmdEdit.Flag.Bool("json", false, "")
+ editPrint = cmdEdit.Flag.Bool("print", false, "")
+ editModule = cmdEdit.Flag.String("module", "", "")
+ edits []func(*modfile.File) // edits specified in flags
+)
+
+type flagFunc func(string)
+
+func (f flagFunc) String() string { return "" }
+func (f flagFunc) Set(s string) error { f(s); return nil }
+
+func init() {
+ cmdEdit.Run = runEdit // break init cycle
+
+ cmdEdit.Flag.Var(flagFunc(flagRequire), "require", "")
+ cmdEdit.Flag.Var(flagFunc(flagDropRequire), "droprequire", "")
+ cmdEdit.Flag.Var(flagFunc(flagExclude), "exclude", "")
+ cmdEdit.Flag.Var(flagFunc(flagDropReplace), "dropreplace", "")
+ cmdEdit.Flag.Var(flagFunc(flagReplace), "replace", "")
+ cmdEdit.Flag.Var(flagFunc(flagDropExclude), "dropexclude", "")
+
+ base.AddBuildFlagsNX(&cmdEdit.Flag)
+}
+
+func runEdit(cmd *base.Command, args []string) {
+ anyFlags :=
+ *editModule != "" ||
+ *editJSON ||
+ *editPrint ||
+ *editFmt ||
+ len(edits) > 0
+
+ if !anyFlags {
+ base.Fatalf("go mod edit: no flags specified (see 'go help mod edit').")
+ }
+
+ if *editJSON && *editPrint {
+ base.Fatalf("go mod edit: cannot use both -json and -print")
+ }
+
+ if len(args) > 1 {
+ base.Fatalf("go mod edit: too many arguments")
+ }
+ var gomod string
+ if len(args) == 1 {
+ gomod = args[0]
+ } else {
+ modload.MustInit()
+ gomod = filepath.Join(modload.ModRoot, "go.mod")
+ }
+
+ if *editModule != "" {
+ if err := module.CheckPath(*editModule); err != nil {
+ base.Fatalf("go mod: invalid -module: %v", err)
+ }
+ }
+
+ // TODO(rsc): Implement -go= once we start advertising it.
+
+ data, err := ioutil.ReadFile(gomod)
+ if err != nil {
+ base.Fatalf("go: %v", err)
+ }
+
+ modFile, err := modfile.Parse(gomod, data, nil)
+ if err != nil {
+ base.Fatalf("go: errors parsing %s:\n%s", base.ShortPath(gomod), err)
+ }
+
+ if *editModule != "" {
+ modFile.AddModuleStmt(modload.CmdModModule)
+ }
+
+ if len(edits) > 0 {
+ for _, edit := range edits {
+ edit(modFile)
+ }
+ }
+ modFile.SortBlocks()
+ modFile.Cleanup() // clean file after edits
+
+ if *editJSON {
+ editPrintJSON(modFile)
+ return
+ }
+
+ data, err = modFile.Format()
+ if err != nil {
+ base.Fatalf("go: %v", err)
+ }
+
+ if *editPrint {
+ os.Stdout.Write(data)
+ return
+ }
+
+ if err := ioutil.WriteFile(gomod, data, 0666); err != nil {
+ base.Fatalf("go: %v", err)
+ }
+}
+
+// parsePathVersion parses -flag=arg expecting arg to be path@version.
+func parsePathVersion(flag, arg string) (path, version string) {
+ i := strings.Index(arg, "@")
+ if i < 0 {
+ base.Fatalf("go mod: -%s=%s: need path@version", flag, arg)
+ }
+ path, version = strings.TrimSpace(arg[:i]), strings.TrimSpace(arg[i+1:])
+ if err := module.CheckPath(path); err != nil {
+ base.Fatalf("go mod: -%s=%s: invalid path: %v", flag, arg, err)
+ }
+
+ // We don't call modfile.CheckPathVersion, because that insists
+ // on versions being in semver form, but here we want to allow
+ // versions like "master" or "1234abcdef", which the go command will resolve
+ // the next time it runs (or during -fix).
+ // Even so, we need to make sure the version is a valid token.
+ if modfile.MustQuote(version) {
+ base.Fatalf("go mod: -%s=%s: invalid version %q", flag, arg, version)
+ }
+
+ return path, version
+}
+
+// parsePath parses -flag=arg expecting arg to be path (not path@version).
+func parsePath(flag, arg string) (path string) {
+ if strings.Contains(arg, "@") {
+ base.Fatalf("go mod: -%s=%s: need just path, not path@version", flag, arg)
+ }
+ path = arg
+ if err := module.CheckPath(path); err != nil {
+ base.Fatalf("go mod: -%s=%s: invalid path: %v", flag, arg, err)
+ }
+ return path
+}
+
+// parsePathVersionOptional parses path[@version], using adj to
+// describe any errors.
+func parsePathVersionOptional(adj, arg string, allowDirPath bool) (path, version string, err error) {
+ if i := strings.Index(arg, "@"); i < 0 {
+ path = arg
+ } else {
+ path, version = strings.TrimSpace(arg[:i]), strings.TrimSpace(arg[i+1:])
+ }
+ if err := module.CheckPath(path); err != nil {
+ if !allowDirPath || !modfile.IsDirectoryPath(path) {
+ return path, version, fmt.Errorf("invalid %s path: %v", adj, err)
+ }
+ }
+ if path != arg && modfile.MustQuote(version) {
+ return path, version, fmt.Errorf("invalid %s version: %q", adj, version)
+ }
+ return path, version, nil
+}
+
+// flagRequire implements the -require flag.
+func flagRequire(arg string) {
+ path, version := parsePathVersion("require", arg)
+ edits = append(edits, func(f *modfile.File) {
+ if err := f.AddRequire(path, version); err != nil {
+ base.Fatalf("go mod: -require=%s: %v", arg, err)
+ }
+ })
+}
+
+// flagDropRequire implements the -droprequire flag.
+func flagDropRequire(arg string) {
+ path := parsePath("droprequire", arg)
+ edits = append(edits, func(f *modfile.File) {
+ if err := f.DropRequire(path); err != nil {
+ base.Fatalf("go mod: -droprequire=%s: %v", arg, err)
+ }
+ })
+}
+
+// flagExclude implements the -exclude flag.
+func flagExclude(arg string) {
+ path, version := parsePathVersion("exclude", arg)
+ edits = append(edits, func(f *modfile.File) {
+ if err := f.AddExclude(path, version); err != nil {
+ base.Fatalf("go mod: -exclude=%s: %v", arg, err)
+ }
+ })
+}
+
+// flagDropExclude implements the -dropexclude flag.
+func flagDropExclude(arg string) {
+ path, version := parsePathVersion("dropexclude", arg)
+ edits = append(edits, func(f *modfile.File) {
+ if err := f.DropExclude(path, version); err != nil {
+ base.Fatalf("go mod: -dropexclude=%s: %v", arg, err)
+ }
+ })
+}
+
+// flagReplace implements the -replace flag.
+func flagReplace(arg string) {
+ var i int
+ if i = strings.Index(arg, "="); i < 0 {
+ base.Fatalf("go mod: -replace=%s: need old[@v]=new[@w] (missing =)", arg)
+ }
+ old, new := strings.TrimSpace(arg[:i]), strings.TrimSpace(arg[i+1:])
+ if strings.HasPrefix(new, ">") {
+ base.Fatalf("go mod: -replace=%s: separator between old and new is =, not =>", arg)
+ }
+ oldPath, oldVersion, err := parsePathVersionOptional("old", old, false)
+ if err != nil {
+ base.Fatalf("go mod: -replace=%s: %v", arg, err)
+ }
+ newPath, newVersion, err := parsePathVersionOptional("new", new, true)
+ if err != nil {
+ base.Fatalf("go mod: -replace=%s: %v", arg, err)
+ }
+ if newPath == new && !modfile.IsDirectoryPath(new) {
+ base.Fatalf("go mod: -replace=%s: unversioned new path must be local directory", arg)
+ }
+
+ edits = append(edits, func(f *modfile.File) {
+ if err := f.AddReplace(oldPath, oldVersion, newPath, newVersion); err != nil {
+ base.Fatalf("go mod: -replace=%s: %v", arg, err)
+ }
+ })
+}
+
+// flagDropReplace implements the -dropreplace flag.
+func flagDropReplace(arg string) {
+ path, version, err := parsePathVersionOptional("old", arg, true)
+ if err != nil {
+ base.Fatalf("go mod: -dropreplace=%s: %v", arg, err)
+ }
+ edits = append(edits, func(f *modfile.File) {
+ if err := f.DropReplace(path, version); err != nil {
+ base.Fatalf("go mod: -dropreplace=%s: %v", arg, err)
+ }
+ })
+}
+
+// fileJSON is the -json output data structure.
+type fileJSON struct {
+ Module module.Version
+ Require []requireJSON
+ Exclude []module.Version
+ Replace []replaceJSON
+}
+
+type requireJSON struct {
+ Path string
+ Version string `json:",omitempty"`
+ Indirect bool `json:",omitempty"`
+}
+
+type replaceJSON struct {
+ Old module.Version
+ New module.Version
+}
+
+// editPrintJSON prints the -json output.
+func editPrintJSON(modFile *modfile.File) {
+ var f fileJSON
+ f.Module = modFile.Module.Mod
+ for _, r := range modFile.Require {
+ f.Require = append(f.Require, requireJSON{Path: r.Mod.Path, Version: r.Mod.Version, Indirect: r.Indirect})
+ }
+ for _, x := range modFile.Exclude {
+ f.Exclude = append(f.Exclude, x.Mod)
+ }
+ for _, r := range modFile.Replace {
+ f.Replace = append(f.Replace, replaceJSON{r.Old, r.New})
+ }
+ data, err := json.MarshalIndent(&f, "", "\t")
+ if err != nil {
+ base.Fatalf("go: internal error: %v", err)
+ }
+ data = append(data, '\n')
+ os.Stdout.Write(data)
+}
diff --git a/libgo/go/cmd/go/internal/modcmd/graph.go b/libgo/go/cmd/go/internal/modcmd/graph.go
new file mode 100644
index 00000000000..5825c6d8ca8
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modcmd/graph.go
@@ -0,0 +1,73 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// go mod graph
+
+package modcmd
+
+import (
+ "bufio"
+ "os"
+ "sort"
+
+ "cmd/go/internal/base"
+ "cmd/go/internal/modload"
+ "cmd/go/internal/module"
+ "cmd/go/internal/par"
+)
+
+var cmdGraph = &base.Command{
+ UsageLine: "go mod graph",
+ Short: "print module requirement graph",
+ Long: `
+Graph prints the module requirement graph (with replacements applied)
+in text form. Each line in the output has two space-separated fields: a module
+and one of its requirements. Each module is identified as a string of the form
+path@version, except for the main module, which has no @version suffix.
+ `,
+ Run: runGraph,
+}
+
+func runGraph(cmd *base.Command, args []string) {
+ if len(args) > 0 {
+ base.Fatalf("go mod graph: graph takes no arguments")
+ }
+ modload.LoadBuildList()
+
+ reqs := modload.MinReqs()
+ format := func(m module.Version) string {
+ if m.Version == "" {
+ return m.Path
+ }
+ return m.Path + "@" + m.Version
+ }
+
+ // Note: using par.Work only to manage work queue.
+ // No parallelism here, so no locking.
+ var out []string
+ var deps int // index in out where deps start
+ var work par.Work
+ work.Add(modload.Target)
+ work.Do(1, func(item interface{}) {
+ m := item.(module.Version)
+ list, _ := reqs.Required(m)
+ for _, r := range list {
+ work.Add(r)
+ out = append(out, format(m)+" "+format(r)+"\n")
+ }
+ if m == modload.Target {
+ deps = len(out)
+ }
+ })
+
+ sort.Slice(out[deps:], func(i, j int) bool {
+ return out[deps+i][0] < out[deps+j][0]
+ })
+
+ w := bufio.NewWriter(os.Stdout)
+ for _, line := range out {
+ w.WriteString(line)
+ }
+ w.Flush()
+}
diff --git a/libgo/go/cmd/go/internal/modcmd/init.go b/libgo/go/cmd/go/internal/modcmd/init.go
new file mode 100644
index 00000000000..f510a46262b
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modcmd/init.go
@@ -0,0 +1,41 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// go mod init
+
+package modcmd
+
+import (
+ "cmd/go/internal/base"
+ "cmd/go/internal/modload"
+ "os"
+)
+
+var cmdInit = &base.Command{
+ UsageLine: "go mod init [module]",
+ Short: "initialize new module in current directory",
+ Long: `
+Init initializes and writes a new go.mod to the current directory,
+in effect creating a new module rooted at the current directory.
+The file go.mod must not already exist.
+If possible, init will guess the module path from import comments
+(see 'go help importpath') or from version control configuration.
+To override this guess, supply the module path as an argument.
+ `,
+ Run: runInit,
+}
+
+func runInit(cmd *base.Command, args []string) {
+ modload.CmdModInit = true
+ if len(args) > 1 {
+ base.Fatalf("go mod init: too many arguments")
+ }
+ if len(args) == 1 {
+ modload.CmdModModule = args[0]
+ }
+ if _, err := os.Stat("go.mod"); err == nil {
+ base.Fatalf("go mod init: go.mod already exists")
+ }
+ modload.InitMod() // does all the hard work
+}
diff --git a/libgo/go/cmd/go/internal/modcmd/mod.go b/libgo/go/cmd/go/internal/modcmd/mod.go
new file mode 100644
index 00000000000..f150cc9728a
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modcmd/mod.go
@@ -0,0 +1,31 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package modcmd implements the ``go mod'' command.
+package modcmd
+
+import "cmd/go/internal/base"
+
+var CmdMod = &base.Command{
+ UsageLine: "go mod",
+ Short: "module maintenance",
+ Long: `Go mod provides access to operations on modules.
+
+Note that support for modules is built into all the go commands,
+not just 'go mod'. For example, day-to-day adding, removing, upgrading,
+and downgrading of dependencies should be done using 'go get'.
+See 'go help modules' for an overview of module functionality.
+ `,
+
+ Commands: []*base.Command{
+ cmdDownload,
+ cmdEdit,
+ cmdGraph,
+ cmdInit,
+ cmdTidy,
+ cmdVendor,
+ cmdVerify,
+ cmdWhy,
+ },
+}
diff --git a/libgo/go/cmd/go/internal/modcmd/tidy.go b/libgo/go/cmd/go/internal/modcmd/tidy.go
new file mode 100644
index 00000000000..f2063a9ea60
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modcmd/tidy.go
@@ -0,0 +1,90 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// go mod tidy
+
+package modcmd
+
+import (
+ "fmt"
+ "os"
+
+ "cmd/go/internal/base"
+ "cmd/go/internal/cfg"
+ "cmd/go/internal/modfetch"
+ "cmd/go/internal/modload"
+ "cmd/go/internal/module"
+)
+
+var cmdTidy = &base.Command{
+ UsageLine: "go mod tidy [-v]",
+ Short: "add missing and remove unused modules",
+ Long: `
+Tidy makes sure go.mod matches the source code in the module.
+It adds any missing modules necessary to build the current module's
+packages and dependencies, and it removes unused modules that
+don't provide any relevant packages. It also adds any missing entries
+to go.sum and removes any unnecessary ones.
+
+The -v flag causes tidy to print information about removed modules
+to standard error.
+ `,
+}
+
+func init() {
+ cmdTidy.Run = runTidy // break init cycle
+ cmdTidy.Flag.BoolVar(&cfg.BuildV, "v", false, "")
+}
+
+func runTidy(cmd *base.Command, args []string) {
+ if len(args) > 0 {
+ base.Fatalf("go mod tidy: no arguments allowed")
+ }
+
+ // LoadALL adds missing modules.
+ // Remove unused modules.
+ used := make(map[module.Version]bool)
+ for _, pkg := range modload.LoadALL() {
+ used[modload.PackageModule(pkg)] = true
+ }
+ used[modload.Target] = true // note: LoadALL initializes Target
+
+ inGoMod := make(map[string]bool)
+ for _, r := range modload.ModFile().Require {
+ inGoMod[r.Mod.Path] = true
+ }
+
+ var keep []module.Version
+ for _, m := range modload.BuildList() {
+ if used[m] {
+ keep = append(keep, m)
+ } else if cfg.BuildV && inGoMod[m.Path] {
+ fmt.Fprintf(os.Stderr, "unused %s\n", m.Path)
+ }
+ }
+ modload.SetBuildList(keep)
+ modTidyGoSum() // updates memory copy; WriteGoMod on next line flushes it out
+ modload.WriteGoMod()
+}
+
+// modTidyGoSum resets the go.sum file content
+// to be exactly what's needed for the current go.mod.
+func modTidyGoSum() {
+ // Assuming go.sum already has at least enough from the successful load,
+ // we only have to tell modfetch what needs keeping.
+ reqs := modload.Reqs()
+ keep := make(map[module.Version]bool)
+ var walk func(module.Version)
+ walk = func(m module.Version) {
+ keep[m] = true
+ list, _ := reqs.Required(m)
+ for _, r := range list {
+ if !keep[r] {
+ walk(r)
+ }
+ }
+ }
+ walk(modload.Target)
+ modfetch.TrimGoSum(keep)
+}
diff --git a/libgo/go/cmd/go/internal/modcmd/vendor.go b/libgo/go/cmd/go/internal/modcmd/vendor.go
new file mode 100644
index 00000000000..62e74585359
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modcmd/vendor.go
@@ -0,0 +1,200 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modcmd
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "cmd/go/internal/base"
+ "cmd/go/internal/cfg"
+ "cmd/go/internal/modload"
+ "cmd/go/internal/module"
+)
+
+var cmdVendor = &base.Command{
+ UsageLine: "go mod vendor [-v]",
+ Short: "make vendored copy of dependencies",
+ Long: `
+Vendor resets the main module's vendor directory to include all packages
+needed to build and test all the main module's packages.
+It does not include test code for vendored packages.
+
+The -v flag causes vendor to print the names of vendored
+modules and packages to standard error.
+ `,
+ Run: runVendor,
+}
+
+func init() {
+ cmdVendor.Flag.BoolVar(&cfg.BuildV, "v", false, "")
+}
+
+func runVendor(cmd *base.Command, args []string) {
+ if len(args) != 0 {
+ base.Fatalf("go mod vendor: vendor takes no arguments")
+ }
+ pkgs := modload.LoadVendor()
+
+ vdir := filepath.Join(modload.ModRoot, "vendor")
+ if err := os.RemoveAll(vdir); err != nil {
+ base.Fatalf("go vendor: %v", err)
+ }
+
+ modpkgs := make(map[module.Version][]string)
+ for _, pkg := range pkgs {
+ m := modload.PackageModule(pkg)
+ if m == modload.Target {
+ continue
+ }
+ modpkgs[m] = append(modpkgs[m], pkg)
+ }
+
+ var buf bytes.Buffer
+ for _, m := range modload.BuildList()[1:] {
+ if pkgs := modpkgs[m]; len(pkgs) > 0 {
+ repl := ""
+ if r := modload.Replacement(m); r.Path != "" {
+ repl = " => " + r.Path
+ if r.Version != "" {
+ repl += " " + r.Version
+ }
+ }
+ fmt.Fprintf(&buf, "# %s %s%s\n", m.Path, m.Version, repl)
+ if cfg.BuildV {
+ fmt.Fprintf(os.Stderr, "# %s %s%s\n", m.Path, m.Version, repl)
+ }
+ for _, pkg := range pkgs {
+ fmt.Fprintf(&buf, "%s\n", pkg)
+ if cfg.BuildV {
+ fmt.Fprintf(os.Stderr, "%s\n", pkg)
+ }
+ vendorPkg(vdir, pkg)
+ }
+ }
+ }
+ if buf.Len() == 0 {
+ fmt.Fprintf(os.Stderr, "go: no dependencies to vendor\n")
+ return
+ }
+ if err := ioutil.WriteFile(filepath.Join(vdir, "modules.txt"), buf.Bytes(), 0666); err != nil {
+ base.Fatalf("go vendor: %v", err)
+ }
+}
+
+func vendorPkg(vdir, pkg string) {
+ realPath := modload.ImportMap(pkg)
+ if realPath != pkg && modload.ImportMap(realPath) != "" {
+ fmt.Fprintf(os.Stderr, "warning: %s imported as both %s and %s; making two copies.\n", realPath, realPath, pkg)
+ }
+
+ dst := filepath.Join(vdir, pkg)
+ src := modload.PackageDir(realPath)
+ if src == "" {
+ fmt.Fprintf(os.Stderr, "internal error: no pkg for %s -> %s\n", pkg, realPath)
+ }
+ copyDir(dst, src, matchNonTest)
+ if m := modload.PackageModule(realPath); m.Path != "" {
+ copyMetadata(m.Path, realPath, dst, src)
+ }
+}
+
+type metakey struct {
+ modPath string
+ dst string
+}
+
+var copiedMetadata = make(map[metakey]bool)
+
+// copyMetadata copies metadata files from parents of src to parents of dst,
+// stopping after processing the src parent for modPath.
+func copyMetadata(modPath, pkg, dst, src string) {
+ for parent := 0; ; parent++ {
+ if copiedMetadata[metakey{modPath, dst}] {
+ break
+ }
+ copiedMetadata[metakey{modPath, dst}] = true
+ if parent > 0 {
+ copyDir(dst, src, matchMetadata)
+ }
+ if modPath == pkg {
+ break
+ }
+ pkg = filepath.Dir(pkg)
+ dst = filepath.Dir(dst)
+ src = filepath.Dir(src)
+ }
+}
+
+// metaPrefixes is the list of metadata file prefixes.
+// Vendoring copies metadata files from parents of copied directories.
+// Note that this list could be arbitrarily extended, and it is longer
+// in other tools (such as godep or dep). By using this limited set of
+// prefixes and also insisting on capitalized file names, we are trying
+// to nudge people toward more agreement on the naming
+// and also trying to avoid false positives.
+var metaPrefixes = []string{
+ "AUTHORS",
+ "CONTRIBUTORS",
+ "COPYLEFT",
+ "COPYING",
+ "COPYRIGHT",
+ "LEGAL",
+ "LICENSE",
+ "NOTICE",
+ "PATENTS",
+}
+
+// matchMetadata reports whether info is a metadata file.
+func matchMetadata(info os.FileInfo) bool {
+ name := info.Name()
+ for _, p := range metaPrefixes {
+ if strings.HasPrefix(name, p) {
+ return true
+ }
+ }
+ return false
+}
+
+// matchNonTest reports whether info is any non-test file (including non-Go files).
+func matchNonTest(info os.FileInfo) bool {
+ return !strings.HasSuffix(info.Name(), "_test.go")
+}
+
+// copyDir copies all regular files satisfying match(info) from src to dst.
+func copyDir(dst, src string, match func(os.FileInfo) bool) {
+ files, err := ioutil.ReadDir(src)
+ if err != nil {
+ base.Fatalf("go vendor: %v", err)
+ }
+ if err := os.MkdirAll(dst, 0777); err != nil {
+ base.Fatalf("go vendor: %v", err)
+ }
+ for _, file := range files {
+ if file.IsDir() || !file.Mode().IsRegular() || !match(file) {
+ continue
+ }
+ r, err := os.Open(filepath.Join(src, file.Name()))
+ if err != nil {
+ base.Fatalf("go vendor: %v", err)
+ }
+ w, err := os.Create(filepath.Join(dst, file.Name()))
+ if err != nil {
+ base.Fatalf("go vendor: %v", err)
+ }
+ if _, err := io.Copy(w, r); err != nil {
+ base.Fatalf("go vendor: %v", err)
+ }
+ r.Close()
+ if err := w.Close(); err != nil {
+ base.Fatalf("go vendor: %v", err)
+ }
+ }
+}
diff --git a/libgo/go/cmd/go/internal/modcmd/verify.go b/libgo/go/cmd/go/internal/modcmd/verify.go
new file mode 100644
index 00000000000..381c18d58f1
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modcmd/verify.go
@@ -0,0 +1,96 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modcmd
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+
+ "cmd/go/internal/base"
+ "cmd/go/internal/dirhash"
+ "cmd/go/internal/modfetch"
+ "cmd/go/internal/modload"
+ "cmd/go/internal/module"
+)
+
+var cmdVerify = &base.Command{
+ UsageLine: "go mod verify",
+ Short: "verify dependencies have expected content",
+ Long: `
+Verify checks that the dependencies of the current module,
+which are stored in a local downloaded source cache, have not been
+modified since being downloaded. If all the modules are unmodified,
+verify prints "all modules verified." Otherwise it reports which
+modules have been changed and causes 'go mod' to exit with a
+non-zero status.
+ `,
+ Run: runVerify,
+}
+
+func runVerify(cmd *base.Command, args []string) {
+ if len(args) != 0 {
+ // NOTE(rsc): Could take a module pattern.
+ base.Fatalf("go mod verify: verify takes no arguments")
+ }
+ ok := true
+ for _, mod := range modload.LoadBuildList()[1:] {
+ ok = verifyMod(mod) && ok
+ }
+ if ok {
+ fmt.Printf("all modules verified\n")
+ }
+}
+
+func verifyMod(mod module.Version) bool {
+ ok := true
+ zip, zipErr := modfetch.CachePath(mod, "zip")
+ if zipErr == nil {
+ _, zipErr = os.Stat(zip)
+ }
+ dir, dirErr := modfetch.DownloadDir(mod)
+ if dirErr == nil {
+ _, dirErr = os.Stat(dir)
+ }
+ data, err := ioutil.ReadFile(zip + "hash")
+ if err != nil {
+ if zipErr != nil && os.IsNotExist(zipErr) && dirErr != nil && os.IsNotExist(dirErr) {
+ // Nothing downloaded yet. Nothing to verify.
+ return true
+ }
+ base.Errorf("%s %s: missing ziphash: %v", mod.Path, mod.Version, err)
+ return false
+ }
+ h := string(bytes.TrimSpace(data))
+
+ if zipErr != nil && os.IsNotExist(zipErr) {
+ // ok
+ } else {
+ hZ, err := dirhash.HashZip(zip, dirhash.DefaultHash)
+ if err != nil {
+ base.Errorf("%s %s: %v", mod.Path, mod.Version, err)
+ return false
+ } else if hZ != h {
+ base.Errorf("%s %s: zip has been modified (%v)", mod.Path, mod.Version, zip)
+ ok = false
+ }
+ }
+ if dirErr != nil && os.IsNotExist(dirErr) {
+ // ok
+ } else {
+ hD, err := dirhash.HashDir(dir, mod.Path+"@"+mod.Version, dirhash.DefaultHash)
+ if err != nil {
+
+ base.Errorf("%s %s: %v", mod.Path, mod.Version, err)
+ return false
+ }
+ if hD != h {
+ base.Errorf("%s %s: dir has been modified (%v)", mod.Path, mod.Version, dir)
+ ok = false
+ }
+ }
+ return ok
+}
diff --git a/libgo/go/cmd/go/internal/modcmd/why.go b/libgo/go/cmd/go/internal/modcmd/why.go
new file mode 100644
index 00000000000..03e0a039bc5
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modcmd/why.go
@@ -0,0 +1,121 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modcmd
+
+import (
+ "cmd/go/internal/base"
+ "cmd/go/internal/modload"
+ "cmd/go/internal/module"
+ "fmt"
+ "strings"
+)
+
+var cmdWhy = &base.Command{
+ UsageLine: "go mod why [-m] [-vendor] packages...",
+ Short: "explain why packages or modules are needed",
+ Long: `
+Why shows a shortest path in the import graph from the main module to
+each of the listed packages. If the -m flag is given, why treats the
+arguments as a list of modules and finds a path to any package in each
+of the modules.
+
+By default, why queries the graph of packages matched by "go list all",
+which includes tests for reachable packages. The -vendor flag causes why
+to exclude tests of dependencies.
+
+The output is a sequence of stanzas, one for each package or module
+name on the command line, separated by blank lines. Each stanza begins
+with a comment line "# package" or "# module" giving the target
+package or module. Subsequent lines give a path through the import
+graph, one package per line. If the package or module is not
+referenced from the main module, the stanza will display a single
+parenthesized note indicating that fact.
+
+For example:
+
+ $ go mod why golang.org/x/text/language golang.org/x/text/encoding
+ # golang.org/x/text/language
+ rsc.io/quote
+ rsc.io/sampler
+ golang.org/x/text/language
+
+ # golang.org/x/text/encoding
+ (main module does not need package golang.org/x/text/encoding)
+ $
+ `,
+}
+
+var (
+ whyM = cmdWhy.Flag.Bool("m", false, "")
+ whyVendor = cmdWhy.Flag.Bool("vendor", false, "")
+)
+
+func init() {
+ cmdWhy.Run = runWhy // break init cycle
+}
+
+func runWhy(cmd *base.Command, args []string) {
+ loadALL := modload.LoadALL
+ if *whyVendor {
+ loadALL = modload.LoadVendor
+ }
+ if *whyM {
+ listU := false
+ listVersions := false
+ for _, arg := range args {
+ if strings.Contains(arg, "@") {
+ base.Fatalf("go mod why: module query not allowed")
+ }
+ }
+ mods := modload.ListModules(args, listU, listVersions)
+ byModule := make(map[module.Version][]string)
+ for _, path := range loadALL() {
+ m := modload.PackageModule(path)
+ if m.Path != "" {
+ byModule[m] = append(byModule[m], path)
+ }
+ }
+ sep := ""
+ for _, m := range mods {
+ best := ""
+ bestDepth := 1000000000
+ for _, path := range byModule[module.Version{Path: m.Path, Version: m.Version}] {
+ d := modload.WhyDepth(path)
+ if d > 0 && d < bestDepth {
+ best = path
+ bestDepth = d
+ }
+ }
+ why := modload.Why(best)
+ if why == "" {
+ vendoring := ""
+ if *whyVendor {
+ vendoring = " to vendor"
+ }
+ why = "(main module does not need" + vendoring + " module " + m.Path + ")\n"
+ }
+ fmt.Printf("%s# %s\n%s", sep, m.Path, why)
+ sep = "\n"
+ }
+ } else {
+ matches := modload.ImportPaths(args) // resolve to packages
+ loadALL() // rebuild graph, from main module (not from named packages)
+ sep := ""
+ for _, m := range matches {
+ for _, path := range m.Pkgs {
+ why := modload.Why(path)
+ if why == "" {
+ vendoring := ""
+ if *whyVendor {
+ vendoring = " to vendor"
+ }
+ why = "(main module does not need" + vendoring + " package " + path + ")\n"
+ }
+ fmt.Printf("%s# %s\n%s", sep, path, why)
+ sep = "\n"
+ }
+ }
+ }
+}
diff --git a/libgo/go/cmd/go/internal/modconv/convert.go b/libgo/go/cmd/go/internal/modconv/convert.go
new file mode 100644
index 00000000000..6fc6718e473
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/convert.go
@@ -0,0 +1,90 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modconv
+
+import (
+ "fmt"
+ "os"
+ "sort"
+ "strings"
+ "sync"
+
+ "cmd/go/internal/base"
+ "cmd/go/internal/modfetch"
+ "cmd/go/internal/modfile"
+ "cmd/go/internal/module"
+ "cmd/go/internal/par"
+ "cmd/go/internal/semver"
+)
+
+// ConvertLegacyConfig converts legacy config to modfile.
+// The file argument is slash-delimited.
+func ConvertLegacyConfig(f *modfile.File, file string, data []byte) error {
+ i := strings.LastIndex(file, "/")
+ j := -2
+ if i >= 0 {
+ j = strings.LastIndex(file[:i], "/")
+ }
+ convert := Converters[file[i+1:]]
+ if convert == nil && j != -2 {
+ convert = Converters[file[j+1:]]
+ }
+ if convert == nil {
+ return fmt.Errorf("unknown legacy config file %s", file)
+ }
+ mf, err := convert(file, data)
+ if err != nil {
+ return fmt.Errorf("parsing %s: %v", file, err)
+ }
+
+ // Convert requirements block, which may use raw SHA1 hashes as versions,
+ // to valid semver requirement list, respecting major versions.
+ var work par.Work
+ for _, r := range mf.Require {
+ m := r.Mod
+ if m.Path == "" {
+ continue
+ }
+ work.Add(r.Mod)
+ }
+
+ var (
+ mu sync.Mutex
+ need = make(map[string]string)
+ )
+ work.Do(10, func(item interface{}) {
+ r := item.(module.Version)
+ repo, info, err := modfetch.ImportRepoRev(r.Path, r.Version)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "go: converting %s: stat %s@%s: %v\n", base.ShortPath(file), r.Path, r.Version, err)
+ return
+ }
+ mu.Lock()
+ path := repo.ModulePath()
+ // Don't use semver.Max here; need to preserve +incompatible suffix.
+ if v, ok := need[path]; !ok || semver.Compare(v, info.Version) < 0 {
+ need[path] = info.Version
+ }
+ mu.Unlock()
+ })
+
+ var paths []string
+ for path := range need {
+ paths = append(paths, path)
+ }
+ sort.Strings(paths)
+ for _, path := range paths {
+ f.AddNewRequire(path, need[path], false)
+ }
+
+ for _, r := range mf.Replace {
+ err := f.AddReplace(r.Old.Path, r.Old.Version, r.New.Path, r.New.Version)
+ if err != nil {
+ return fmt.Errorf("add replace: %v", err)
+ }
+ }
+ f.Cleanup()
+ return nil
+}
diff --git a/libgo/go/cmd/go/internal/modconv/convert_test.go b/libgo/go/cmd/go/internal/modconv/convert_test.go
new file mode 100644
index 00000000000..ad27abb8ef7
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/convert_test.go
@@ -0,0 +1,186 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modconv
+
+import (
+ "bytes"
+ "fmt"
+ "internal/testenv"
+ "io/ioutil"
+ "log"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "cmd/go/internal/cfg"
+ "cmd/go/internal/modfetch"
+ "cmd/go/internal/modfetch/codehost"
+ "cmd/go/internal/modfile"
+ "cmd/go/internal/module"
+)
+
+func TestMain(m *testing.M) {
+ os.Exit(testMain(m))
+}
+
+func testMain(m *testing.M) int {
+ if _, err := exec.LookPath("git"); err != nil {
+ fmt.Fprintln(os.Stderr, "skipping because git binary not found")
+ fmt.Println("PASS")
+ return 0
+ }
+
+ dir, err := ioutil.TempDir("", "modconv-test-")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+ modfetch.PkgMod = filepath.Join(dir, "pkg/mod")
+ codehost.WorkRoot = filepath.Join(dir, "codework")
+
+ return m.Run()
+}
+
+func TestConvertLegacyConfig(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ if testing.Verbose() {
+ old := cfg.BuildX
+ defer func() {
+ cfg.BuildX = old
+ }()
+ cfg.BuildX = true
+ }
+
+ var tests = []struct {
+ path string
+ vers string
+ gomod string
+ }{
+ /*
+ Different versions of git seem to find or not find
+ github.com/Masterminds/semver's a93e51b5a57e,
+ which is an unmerged pull request.
+ We'd rather not provide access to unmerged pull requests,
+ so the line is removed from the golden file here,
+ but some git commands still find it somehow.
+
+ {
+ // Gopkg.lock parsing.
+ "github.com/golang/dep", "v0.4.0",
+ `module github.com/golang/dep
+
+ require (
+ github.com/Masterminds/vcs v1.11.1
+ github.com/armon/go-radix v0.0.0-20160115234725-4239b77079c7
+ github.com/boltdb/bolt v1.3.1
+ github.com/go-yaml/yaml v0.0.0-20170407172122-cd8b52f8269e
+ github.com/golang/protobuf v0.0.0-20170901042739-5afd06f9d81a
+ github.com/jmank88/nuts v0.3.0
+ github.com/nightlyone/lockfile v0.0.0-20170707060451-e83dc5e7bba0
+ github.com/pelletier/go-toml v0.0.0-20171218135716-b8b5e7696574
+ github.com/pkg/errors v0.8.0
+ github.com/sdboyer/constext v0.0.0-20170321163424-836a14457353
+ golang.org/x/net v0.0.0-20170828231752-66aacef3dd8a
+ golang.org/x/sync v0.0.0-20170517211232-f52d1811a629
+ golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea
+ )`,
+ },
+ */
+
+ // TODO: https://github.com/docker/distribution uses vendor.conf
+
+ {
+ // Godeps.json parsing.
+ // TODO: Should v2.0.0 work here too?
+ "github.com/docker/distribution", "v0.0.0-20150410205453-85de3967aa93",
+ `module github.com/docker/distribution
+
+ require (
+ github.com/AdRoll/goamz v0.0.0-20150130162828-d3664b76d905
+ github.com/MSOpenTech/azure-sdk-for-go v0.0.0-20150323223030-d90753bcad2e
+ github.com/Sirupsen/logrus v0.7.3
+ github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd
+ github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b
+ github.com/bugsnag/panicwrap v0.0.0-20141110184334-e5f9854865b9
+ github.com/codegangsta/cli v0.0.0-20150131031259-6086d7927ec3
+ github.com/docker/docker v0.0.0-20150204013315-165ea5c158cf
+ github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1
+ github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7
+ github.com/gorilla/context v0.0.0-20140604161150-14f550f51af5
+ github.com/gorilla/handlers v0.0.0-20140825150757-0e84b7d810c1
+ github.com/gorilla/mux v0.0.0-20140926153814-e444e69cbd2e
+ github.com/jlhawn/go-crypto v0.0.0-20150401213827-cd738dde20f0
+ github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43
+ github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50
+ github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f
+ golang.org/x/net v0.0.0-20150202051010-1dfe7915deaf
+ gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789
+ gopkg.in/yaml.v2 v2.0.0-20150116202057-bef53efd0c76
+ )`,
+ },
+
+ {
+ // golang.org/issue/24585 - confusion about v2.0.0 tag in legacy non-v2 module
+ "github.com/fishy/gcsbucket", "v0.0.0-20150410205453-618d60fe84e0",
+ `module github.com/fishy/gcsbucket
+
+ require (
+ cloud.google.com/go v0.18.0
+ github.com/fishy/fsdb v0.0.0-20180217030800-5527ded01371
+ github.com/golang/protobuf v1.0.0
+ github.com/googleapis/gax-go v2.0.0+incompatible
+ golang.org/x/net v0.0.0-20180216171745-136a25c244d3
+ golang.org/x/oauth2 v0.0.0-20180207181906-543e37812f10
+ golang.org/x/text v0.0.0-20180208041248-4e4a3210bb54
+ google.golang.org/api v0.0.0-20180217000815-c7a403bb5fe1
+ google.golang.org/appengine v1.0.0
+ google.golang.org/genproto v0.0.0-20180206005123-2b5a72b8730b
+ google.golang.org/grpc v1.10.0
+ )`,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(strings.Replace(tt.path, "/", "_", -1)+"_"+tt.vers, func(t *testing.T) {
+ f, err := modfile.Parse("golden", []byte(tt.gomod), nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ want, err := f.Format()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ dir, err := modfetch.Download(module.Version{Path: tt.path, Version: tt.vers})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ for name := range Converters {
+ file := filepath.Join(dir, name)
+ data, err := ioutil.ReadFile(file)
+ if err == nil {
+ f := new(modfile.File)
+ f.AddModuleStmt(tt.path)
+ if err := ConvertLegacyConfig(f, filepath.ToSlash(file), data); err != nil {
+ t.Fatal(err)
+ }
+ out, err := f.Format()
+ if err != nil {
+ t.Fatalf("format after conversion: %v", err)
+ }
+ if !bytes.Equal(out, want) {
+ t.Fatalf("final go.mod:\n%s\n\nwant:\n%s", out, want)
+ }
+ return
+ }
+ }
+ t.Fatalf("no converter found for %s@%s", tt.path, tt.vers)
+ })
+ }
+}
diff --git a/libgo/go/cmd/go/internal/modconv/dep.go b/libgo/go/cmd/go/internal/modconv/dep.go
new file mode 100644
index 00000000000..690c206a136
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/dep.go
@@ -0,0 +1,74 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modconv
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+
+ "cmd/go/internal/modfile"
+ "cmd/go/internal/module"
+ "cmd/go/internal/semver"
+)
+
+func ParseGopkgLock(file string, data []byte) (*modfile.File, error) {
+ mf := new(modfile.File)
+ var list []module.Version
+ var r *module.Version
+ for lineno, line := range strings.Split(string(data), "\n") {
+ lineno++
+ if i := strings.Index(line, "#"); i >= 0 {
+ line = line[:i]
+ }
+ line = strings.TrimSpace(line)
+ if line == "[[projects]]" {
+ list = append(list, module.Version{})
+ r = &list[len(list)-1]
+ continue
+ }
+ if strings.HasPrefix(line, "[") {
+ r = nil
+ continue
+ }
+ if r == nil {
+ continue
+ }
+ i := strings.Index(line, "=")
+ if i < 0 {
+ continue
+ }
+ key := strings.TrimSpace(line[:i])
+ val := strings.TrimSpace(line[i+1:])
+ if len(val) >= 2 && val[0] == '"' && val[len(val)-1] == '"' {
+ q, err := strconv.Unquote(val) // Go unquoting, but close enough for now
+ if err != nil {
+ return nil, fmt.Errorf("%s:%d: invalid quoted string: %v", file, lineno, err)
+ }
+ val = q
+ }
+ switch key {
+ case "name":
+ r.Path = val
+ case "revision", "version":
+ // Note: key "version" should take priority over "revision",
+ // and it does, because dep writes toml keys in alphabetical order,
+ // so we see version (if present) second.
+ if key == "version" {
+ if !semver.IsValid(val) || semver.Canonical(val) != val {
+ break
+ }
+ }
+ r.Version = val
+ }
+ }
+ for _, r := range list {
+ if r.Path == "" || r.Version == "" {
+ return nil, fmt.Errorf("%s: empty [[projects]] stanza (%s)", file, r.Path)
+ }
+ mf.Require = append(mf.Require, &modfile.Require{Mod: r})
+ }
+ return mf, nil
+}
diff --git a/libgo/go/cmd/go/internal/modconv/glide.go b/libgo/go/cmd/go/internal/modconv/glide.go
new file mode 100644
index 00000000000..3bc675fcc0e
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/glide.go
@@ -0,0 +1,42 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modconv
+
+import (
+ "strings"
+
+ "cmd/go/internal/modfile"
+ "cmd/go/internal/module"
+)
+
+func ParseGlideLock(file string, data []byte) (*modfile.File, error) {
+ mf := new(modfile.File)
+ imports := false
+ name := ""
+ for lineno, line := range strings.Split(string(data), "\n") {
+ lineno++
+ if line == "" {
+ continue
+ }
+ if strings.HasPrefix(line, "imports:") {
+ imports = true
+ } else if line[0] != '-' && line[0] != ' ' && line[0] != '\t' {
+ imports = false
+ }
+ if !imports {
+ continue
+ }
+ if strings.HasPrefix(line, "- name:") {
+ name = strings.TrimSpace(line[len("- name:"):])
+ }
+ if strings.HasPrefix(line, " version:") {
+ version := strings.TrimSpace(line[len(" version:"):])
+ if name != "" && version != "" {
+ mf.Require = append(mf.Require, &modfile.Require{Mod: module.Version{Path: name, Version: version}})
+ }
+ }
+ }
+ return mf, nil
+}
diff --git a/libgo/go/cmd/go/internal/modconv/glock.go b/libgo/go/cmd/go/internal/modconv/glock.go
new file mode 100644
index 00000000000..1b786a939c7
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/glock.go
@@ -0,0 +1,24 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modconv
+
+import (
+ "strings"
+
+ "cmd/go/internal/modfile"
+ "cmd/go/internal/module"
+)
+
+func ParseGLOCKFILE(file string, data []byte) (*modfile.File, error) {
+ mf := new(modfile.File)
+ for lineno, line := range strings.Split(string(data), "\n") {
+ lineno++
+ f := strings.Fields(line)
+ if len(f) >= 2 && f[0] != "cmd" {
+ mf.Require = append(mf.Require, &modfile.Require{Mod: module.Version{Path: f[0], Version: f[1]}})
+ }
+ }
+ return mf, nil
+}
diff --git a/libgo/go/cmd/go/internal/modconv/godeps.go b/libgo/go/cmd/go/internal/modconv/godeps.go
new file mode 100644
index 00000000000..6398dbe7cd7
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/godeps.go
@@ -0,0 +1,30 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modconv
+
+import (
+ "encoding/json"
+
+ "cmd/go/internal/modfile"
+ "cmd/go/internal/module"
+)
+
+func ParseGodepsJSON(file string, data []byte) (*modfile.File, error) {
+ var cfg struct {
+ ImportPath string
+ Deps []struct {
+ ImportPath string
+ Rev string
+ }
+ }
+ if err := json.Unmarshal(data, &cfg); err != nil {
+ return nil, err
+ }
+ mf := new(modfile.File)
+ for _, d := range cfg.Deps {
+ mf.Require = append(mf.Require, &modfile.Require{Mod: module.Version{Path: d.ImportPath, Version: d.Rev}})
+ }
+ return mf, nil
+}
diff --git a/libgo/go/cmd/go/internal/modconv/modconv.go b/libgo/go/cmd/go/internal/modconv/modconv.go
new file mode 100644
index 00000000000..a58673382e6
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/modconv.go
@@ -0,0 +1,19 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modconv
+
+import "cmd/go/internal/modfile"
+
+var Converters = map[string]func(string, []byte) (*modfile.File, error){
+ "GLOCKFILE": ParseGLOCKFILE,
+ "Godeps/Godeps.json": ParseGodepsJSON,
+ "Gopkg.lock": ParseGopkgLock,
+ "dependencies.tsv": ParseDependenciesTSV,
+ "glide.lock": ParseGlideLock,
+ "vendor.conf": ParseVendorConf,
+ "vendor.yml": ParseVendorYML,
+ "vendor/manifest": ParseVendorManifest,
+ "vendor/vendor.json": ParseVendorJSON,
+}
diff --git a/libgo/go/cmd/go/internal/modconv/modconv_test.go b/libgo/go/cmd/go/internal/modconv/modconv_test.go
new file mode 100644
index 00000000000..353161bc5a3
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/modconv_test.go
@@ -0,0 +1,66 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modconv
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "path/filepath"
+ "testing"
+)
+
+var extMap = map[string]string{
+ ".dep": "Gopkg.lock",
+ ".glide": "glide.lock",
+ ".glock": "GLOCKFILE",
+ ".godeps": "Godeps/Godeps.json",
+ ".tsv": "dependencies.tsv",
+ ".vconf": "vendor.conf",
+ ".vjson": "vendor/vendor.json",
+ ".vyml": "vendor.yml",
+ ".vmanifest": "vendor/manifest",
+}
+
+func Test(t *testing.T) {
+ tests, _ := filepath.Glob("testdata/*")
+ if len(tests) == 0 {
+ t.Fatalf("no tests found")
+ }
+ for _, test := range tests {
+ file := filepath.Base(test)
+ ext := filepath.Ext(file)
+ if ext == ".out" {
+ continue
+ }
+ t.Run(file, func(t *testing.T) {
+ if extMap[ext] == "" {
+ t.Fatal("unknown extension")
+ }
+ if Converters[extMap[ext]] == nil {
+ t.Fatalf("Converters[%q] == nil", extMap[ext])
+ }
+ data, err := ioutil.ReadFile(test)
+ if err != nil {
+ t.Fatal(err)
+ }
+ out, err := Converters[extMap[ext]](test, data)
+ if err != nil {
+ t.Fatal(err)
+ }
+ want, err := ioutil.ReadFile(test[:len(test)-len(ext)] + ".out")
+ if err != nil {
+ t.Error(err)
+ }
+ var buf bytes.Buffer
+ for _, r := range out.Require {
+ fmt.Fprintf(&buf, "%s %s\n", r.Mod.Path, r.Mod.Version)
+ }
+ if !bytes.Equal(buf.Bytes(), want) {
+ t.Errorf("have:\n%s\nwant:\n%s", buf.Bytes(), want)
+ }
+ })
+ }
+}
diff --git a/libgo/go/cmd/go/internal/modconv/testdata/cockroach.glock b/libgo/go/cmd/go/internal/modconv/testdata/cockroach.glock
new file mode 100644
index 00000000000..221c8acdfd8
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/testdata/cockroach.glock
@@ -0,0 +1,41 @@
+cmd github.com/cockroachdb/c-protobuf/cmd/protoc
+cmd github.com/cockroachdb/yacc
+cmd github.com/gogo/protobuf/protoc-gen-gogo
+cmd github.com/golang/lint/golint
+cmd github.com/jteeuwen/go-bindata/go-bindata
+cmd github.com/kisielk/errcheck
+cmd github.com/robfig/glock
+cmd github.com/tebeka/go2xunit
+cmd golang.org/x/tools/cmd/goimports
+cmd golang.org/x/tools/cmd/stringer
+github.com/agtorre/gocolorize f42b554bf7f006936130c9bb4f971afd2d87f671
+github.com/biogo/store e1f74b3c58befe661feed7fa4cf52436de753128
+github.com/cockroachdb/c-lz4 6e71f140a365017bbe0904710007f8725fd3f809
+github.com/cockroachdb/c-protobuf 0f9ab7b988ca7474cf76b9a961ab03c0552abcb3
+github.com/cockroachdb/c-rocksdb 7fc876fe79b96de0e25069c9ae27e6444637bd54
+github.com/cockroachdb/c-snappy 618733f9e5bab8463b9049117a335a7a1bfc9fd5
+github.com/cockroachdb/yacc 572e006f8e6b0061ebda949d13744f5108389514
+github.com/coreos/etcd 18ecc297bc913bed6fc093d66b1fa22020dba7dc
+github.com/docker/docker 7374852be9def787921aea2ca831771982badecf
+github.com/elazarl/go-bindata-assetfs 3dcc96556217539f50599357fb481ac0dc7439b9
+github.com/gogo/protobuf 98e73e511a62a9c232152f94999112c80142a813
+github.com/golang/lint 7b7f4364ff76043e6c3610281525fabc0d90f0e4
+github.com/google/btree cc6329d4279e3f025a53a83c397d2339b5705c45
+github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
+github.com/jteeuwen/go-bindata dce55d09e24ac40a6e725c8420902b86554f8046
+github.com/julienschmidt/httprouter 6aacfd5ab513e34f7e64ea9627ab9670371b34e7
+github.com/kisielk/errcheck 50b84cf7fa18ee2985b8c63ba3de5edd604b9259
+github.com/kisielk/gotool d678387370a2eb9b5b0a33218bc8c9d8de15b6be
+github.com/lib/pq a8d8d01c4f91602f876bf5aa210274e8203a6b45
+github.com/montanaflynn/stats 44fb56da2a2a67d394dec0e18a82dd316f192529
+github.com/peterh/liner 1bb0d1c1a25ed393d8feb09bab039b2b1b1fbced
+github.com/robfig/glock cb3c3ec56de988289cab7bbd284eddc04dfee6c9
+github.com/samalba/dockerclient 12570e600d71374233e5056ba315f657ced496c7
+github.com/spf13/cobra 66816bcd0378e248c613e3c443c020f544c28804
+github.com/spf13/pflag 67cbc198fd11dab704b214c1e629a97af392c085
+github.com/tebeka/go2xunit d45000af2242dd0e7b8c7b07d82a1068adc5fd40
+golang.org/x/crypto cc04154d65fb9296747569b107cfd05380b1ea3e
+golang.org/x/net 8bfde94a845cb31000de3266ac83edbda58dab09
+golang.org/x/text d4cc1b1e16b49d6dafc4982403b40fe89c512cd5
+golang.org/x/tools d02228d1857b9f49cd0252788516ff5584266eb6
+gopkg.in/yaml.v1 9f9df34309c04878acc86042b16630b0f696e1de
diff --git a/libgo/go/cmd/go/internal/modconv/testdata/cockroach.out b/libgo/go/cmd/go/internal/modconv/testdata/cockroach.out
new file mode 100644
index 00000000000..30cdbb7bf29
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/testdata/cockroach.out
@@ -0,0 +1,31 @@
+github.com/agtorre/gocolorize f42b554bf7f006936130c9bb4f971afd2d87f671
+github.com/biogo/store e1f74b3c58befe661feed7fa4cf52436de753128
+github.com/cockroachdb/c-lz4 6e71f140a365017bbe0904710007f8725fd3f809
+github.com/cockroachdb/c-protobuf 0f9ab7b988ca7474cf76b9a961ab03c0552abcb3
+github.com/cockroachdb/c-rocksdb 7fc876fe79b96de0e25069c9ae27e6444637bd54
+github.com/cockroachdb/c-snappy 618733f9e5bab8463b9049117a335a7a1bfc9fd5
+github.com/cockroachdb/yacc 572e006f8e6b0061ebda949d13744f5108389514
+github.com/coreos/etcd 18ecc297bc913bed6fc093d66b1fa22020dba7dc
+github.com/docker/docker 7374852be9def787921aea2ca831771982badecf
+github.com/elazarl/go-bindata-assetfs 3dcc96556217539f50599357fb481ac0dc7439b9
+github.com/gogo/protobuf 98e73e511a62a9c232152f94999112c80142a813
+github.com/golang/lint 7b7f4364ff76043e6c3610281525fabc0d90f0e4
+github.com/google/btree cc6329d4279e3f025a53a83c397d2339b5705c45
+github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
+github.com/jteeuwen/go-bindata dce55d09e24ac40a6e725c8420902b86554f8046
+github.com/julienschmidt/httprouter 6aacfd5ab513e34f7e64ea9627ab9670371b34e7
+github.com/kisielk/errcheck 50b84cf7fa18ee2985b8c63ba3de5edd604b9259
+github.com/kisielk/gotool d678387370a2eb9b5b0a33218bc8c9d8de15b6be
+github.com/lib/pq a8d8d01c4f91602f876bf5aa210274e8203a6b45
+github.com/montanaflynn/stats 44fb56da2a2a67d394dec0e18a82dd316f192529
+github.com/peterh/liner 1bb0d1c1a25ed393d8feb09bab039b2b1b1fbced
+github.com/robfig/glock cb3c3ec56de988289cab7bbd284eddc04dfee6c9
+github.com/samalba/dockerclient 12570e600d71374233e5056ba315f657ced496c7
+github.com/spf13/cobra 66816bcd0378e248c613e3c443c020f544c28804
+github.com/spf13/pflag 67cbc198fd11dab704b214c1e629a97af392c085
+github.com/tebeka/go2xunit d45000af2242dd0e7b8c7b07d82a1068adc5fd40
+golang.org/x/crypto cc04154d65fb9296747569b107cfd05380b1ea3e
+golang.org/x/net 8bfde94a845cb31000de3266ac83edbda58dab09
+golang.org/x/text d4cc1b1e16b49d6dafc4982403b40fe89c512cd5
+golang.org/x/tools d02228d1857b9f49cd0252788516ff5584266eb6
+gopkg.in/yaml.v1 9f9df34309c04878acc86042b16630b0f696e1de
diff --git a/libgo/go/cmd/go/internal/modconv/testdata/dockermachine.godeps b/libgo/go/cmd/go/internal/modconv/testdata/dockermachine.godeps
new file mode 100644
index 00000000000..a551002a049
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/testdata/dockermachine.godeps
@@ -0,0 +1,159 @@
+{
+ "ImportPath": "github.com/docker/machine",
+ "GoVersion": "go1.4.2",
+ "Deps": [
+ {
+ "ImportPath": "code.google.com/p/goauth2/oauth",
+ "Comment": "weekly-56",
+ "Rev": "afe77d958c701557ec5dc56f6936fcc194d15520"
+ },
+ {
+ "ImportPath": "github.com/MSOpenTech/azure-sdk-for-go",
+ "Comment": "v1.1-17-g515f3ec",
+ "Rev": "515f3ec74ce6a5b31e934cefae997c97bd0a1b1e"
+ },
+ {
+ "ImportPath": "github.com/cenkalti/backoff",
+ "Rev": "9831e1e25c874e0a0601b6dc43641071414eec7a"
+ },
+ {
+ "ImportPath": "github.com/codegangsta/cli",
+ "Comment": "1.2.0-64-ge1712f3",
+ "Rev": "e1712f381785e32046927f64a7c86fe569203196"
+ },
+ {
+ "ImportPath": "github.com/digitalocean/godo",
+ "Comment": "v0.5.0",
+ "Rev": "5478aae80694de1d2d0e02c386bbedd201266234"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/dockerversion",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/engine",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/pkg/archive",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/pkg/fileutils",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/pkg/ioutils",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/pkg/mflag",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/pkg/parsers",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/pkg/pools",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/pkg/promise",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/pkg/system",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/pkg/term",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/pkg/timeutils",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/pkg/units",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/pkg/version",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/libtrust",
+ "Rev": "c54fbb67c1f1e68d7d6f8d2ad7c9360404616a41"
+ },
+ {
+ "ImportPath": "github.com/google/go-querystring/query",
+ "Rev": "30f7a39f4a218feb5325f3aebc60c32a572a8274"
+ },
+ {
+ "ImportPath": "github.com/mitchellh/mapstructure",
+ "Rev": "740c764bc6149d3f1806231418adb9f52c11bcbf"
+ },
+ {
+ "ImportPath": "github.com/rackspace/gophercloud",
+ "Comment": "v1.0.0-558-ce0f487",
+ "Rev": "ce0f487f6747ab43c4e4404722df25349385bebd"
+ },
+ {
+ "ImportPath": "github.com/skarademir/naturalsort",
+ "Rev": "983d4d86054d80f91fd04dd62ec52c1d078ce403"
+ },
+ {
+ "ImportPath": "github.com/smartystreets/go-aws-auth",
+ "Rev": "1f0db8c0ee6362470abe06a94e3385927ed72a4b"
+ },
+ {
+ "ImportPath": "github.com/stretchr/testify/assert",
+ "Rev": "e4ec8152c15fc46bd5056ce65997a07c7d415325"
+ },
+ {
+ "ImportPath": "github.com/pyr/egoscale/src/egoscale",
+ "Rev": "bbaa67324aeeacc90430c1fe0a9c620d3929512e"
+ },
+ {
+ "ImportPath": "github.com/tent/http-link-go",
+ "Rev": "ac974c61c2f990f4115b119354b5e0b47550e888"
+ },
+ {
+ "ImportPath": "github.com/vmware/govcloudair",
+ "Comment": "v0.0.2",
+ "Rev": "66a23eaabc61518f91769939ff541886fe1dceef"
+ },
+ {
+ "ImportPath": "golang.org/x/crypto/ssh",
+ "Rev": "1fbbd62cfec66bd39d91e97749579579d4d3037e"
+ },
+ {
+ "ImportPath": "google.golang.org/api/compute/v1",
+ "Rev": "aa91ac681e18e52b1a0dfe29b9d8354e88c0dcf5"
+ },
+ {
+ "ImportPath": "google.golang.org/api/googleapi",
+ "Rev": "aa91ac681e18e52b1a0dfe29b9d8354e88c0dcf5"
+ }
+ ]
+}
diff --git a/libgo/go/cmd/go/internal/modconv/testdata/dockermachine.out b/libgo/go/cmd/go/internal/modconv/testdata/dockermachine.out
new file mode 100644
index 00000000000..0b39ceaccbb
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/testdata/dockermachine.out
@@ -0,0 +1,33 @@
+code.google.com/p/goauth2/oauth afe77d958c701557ec5dc56f6936fcc194d15520
+github.com/MSOpenTech/azure-sdk-for-go 515f3ec74ce6a5b31e934cefae997c97bd0a1b1e
+github.com/cenkalti/backoff 9831e1e25c874e0a0601b6dc43641071414eec7a
+github.com/codegangsta/cli e1712f381785e32046927f64a7c86fe569203196
+github.com/digitalocean/godo 5478aae80694de1d2d0e02c386bbedd201266234
+github.com/docker/docker/dockerversion a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/engine a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/pkg/archive a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/pkg/fileutils a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/pkg/ioutils a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/pkg/mflag a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/pkg/parsers a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/pkg/pools a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/pkg/promise a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/pkg/system a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/pkg/term a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/pkg/timeutils a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/pkg/units a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/pkg/version a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/libtrust c54fbb67c1f1e68d7d6f8d2ad7c9360404616a41
+github.com/google/go-querystring/query 30f7a39f4a218feb5325f3aebc60c32a572a8274
+github.com/mitchellh/mapstructure 740c764bc6149d3f1806231418adb9f52c11bcbf
+github.com/rackspace/gophercloud ce0f487f6747ab43c4e4404722df25349385bebd
+github.com/skarademir/naturalsort 983d4d86054d80f91fd04dd62ec52c1d078ce403
+github.com/smartystreets/go-aws-auth 1f0db8c0ee6362470abe06a94e3385927ed72a4b
+github.com/stretchr/testify/assert e4ec8152c15fc46bd5056ce65997a07c7d415325
+github.com/pyr/egoscale/src/egoscale bbaa67324aeeacc90430c1fe0a9c620d3929512e
+github.com/tent/http-link-go ac974c61c2f990f4115b119354b5e0b47550e888
+github.com/vmware/govcloudair 66a23eaabc61518f91769939ff541886fe1dceef
+golang.org/x/crypto/ssh 1fbbd62cfec66bd39d91e97749579579d4d3037e
+google.golang.org/api/compute/v1 aa91ac681e18e52b1a0dfe29b9d8354e88c0dcf5
+google.golang.org/api/googleapi aa91ac681e18e52b1a0dfe29b9d8354e88c0dcf5
diff --git a/libgo/go/cmd/go/internal/modconv/testdata/dockerman.glide b/libgo/go/cmd/go/internal/modconv/testdata/dockerman.glide
new file mode 100644
index 00000000000..5ec765a4c63
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/testdata/dockerman.glide
@@ -0,0 +1,52 @@
+hash: ead3ea293a6143fe41069ebec814bf197d8c43a92cc7666b1f7e21a419b46feb
+updated: 2016-06-20T21:53:35.420817456Z
+imports:
+- name: github.com/BurntSushi/toml
+ version: f0aeabca5a127c4078abb8c8d64298b147264b55
+- name: github.com/cpuguy83/go-md2man
+ version: a65d4d2de4d5f7c74868dfa9b202a3c8be315aaa
+ subpackages:
+ - md2man
+- name: github.com/fsnotify/fsnotify
+ version: 30411dbcefb7a1da7e84f75530ad3abe4011b4f8
+- name: github.com/hashicorp/hcl
+ version: da486364306ed66c218be9b7953e19173447c18b
+ subpackages:
+ - hcl/ast
+ - hcl/parser
+ - hcl/token
+ - json/parser
+ - hcl/scanner
+ - hcl/strconv
+ - json/scanner
+ - json/token
+- name: github.com/inconshreveable/mousetrap
+ version: 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
+- name: github.com/magiconair/properties
+ version: c265cfa48dda6474e208715ca93e987829f572f8
+- name: github.com/mitchellh/mapstructure
+ version: d2dd0262208475919e1a362f675cfc0e7c10e905
+- name: github.com/russross/blackfriday
+ version: 1d6b8e9301e720b08a8938b8c25c018285885438
+- name: github.com/shurcooL/sanitized_anchor_name
+ version: 10ef21a441db47d8b13ebcc5fd2310f636973c77
+- name: github.com/spf13/cast
+ version: 27b586b42e29bec072fe7379259cc719e1289da6
+- name: github.com/spf13/jwalterweatherman
+ version: 33c24e77fb80341fe7130ee7c594256ff08ccc46
+- name: github.com/spf13/pflag
+ version: dabebe21bf790f782ea4c7bbd2efc430de182afd
+- name: github.com/spf13/viper
+ version: c1ccc378a054ea8d4e38d8c67f6938d4760b53dd
+- name: golang.org/x/sys
+ version: 62bee037599929a6e9146f29d10dd5208c43507d
+ subpackages:
+ - unix
+- name: gopkg.in/yaml.v2
+ version: a83829b6f1293c91addabc89d0571c246397bbf4
+- name: github.com/spf13/cobra
+ repo: https://github.com/dnephin/cobra
+ subpackages:
+ - doc
+ version: v1.3
+devImports: []
diff --git a/libgo/go/cmd/go/internal/modconv/testdata/dockerman.out b/libgo/go/cmd/go/internal/modconv/testdata/dockerman.out
new file mode 100644
index 00000000000..5e6370b31c3
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/testdata/dockerman.out
@@ -0,0 +1,16 @@
+github.com/BurntSushi/toml f0aeabca5a127c4078abb8c8d64298b147264b55
+github.com/cpuguy83/go-md2man a65d4d2de4d5f7c74868dfa9b202a3c8be315aaa
+github.com/fsnotify/fsnotify 30411dbcefb7a1da7e84f75530ad3abe4011b4f8
+github.com/hashicorp/hcl da486364306ed66c218be9b7953e19173447c18b
+github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
+github.com/magiconair/properties c265cfa48dda6474e208715ca93e987829f572f8
+github.com/mitchellh/mapstructure d2dd0262208475919e1a362f675cfc0e7c10e905
+github.com/russross/blackfriday 1d6b8e9301e720b08a8938b8c25c018285885438
+github.com/shurcooL/sanitized_anchor_name 10ef21a441db47d8b13ebcc5fd2310f636973c77
+github.com/spf13/cast 27b586b42e29bec072fe7379259cc719e1289da6
+github.com/spf13/jwalterweatherman 33c24e77fb80341fe7130ee7c594256ff08ccc46
+github.com/spf13/pflag dabebe21bf790f782ea4c7bbd2efc430de182afd
+github.com/spf13/viper c1ccc378a054ea8d4e38d8c67f6938d4760b53dd
+golang.org/x/sys 62bee037599929a6e9146f29d10dd5208c43507d
+gopkg.in/yaml.v2 a83829b6f1293c91addabc89d0571c246397bbf4
+github.com/spf13/cobra v1.3
diff --git a/libgo/go/cmd/go/internal/modconv/testdata/govmomi.out b/libgo/go/cmd/go/internal/modconv/testdata/govmomi.out
new file mode 100644
index 00000000000..188c458b3d6
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/testdata/govmomi.out
@@ -0,0 +1,5 @@
+github.com/davecgh/go-xdr/xdr2 4930550ba2e22f87187498acfd78348b15f4e7a8
+github.com/google/uuid 6a5e28554805e78ea6141142aba763936c4761c0
+github.com/kr/pretty 2ee9d7453c02ef7fa518a83ae23644eb8872186a
+github.com/kr/pty 95d05c1eef33a45bd58676b6ce28d105839b8d0b
+github.com/vmware/vmw-guestinfo 25eff159a728be87e103a0b8045e08273f4dbec4
diff --git a/libgo/go/cmd/go/internal/modconv/testdata/govmomi.vmanifest b/libgo/go/cmd/go/internal/modconv/testdata/govmomi.vmanifest
new file mode 100644
index 00000000000..b89e4ab5eef
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/testdata/govmomi.vmanifest
@@ -0,0 +1,46 @@
+{
+ "version": 0,
+ "dependencies": [
+ {
+ "importpath": "github.com/davecgh/go-xdr/xdr2",
+ "repository": "https://github.com/rasky/go-xdr",
+ "vcs": "git",
+ "revision": "4930550ba2e22f87187498acfd78348b15f4e7a8",
+ "branch": "improvements",
+ "path": "/xdr2",
+ "notests": true
+ },
+ {
+ "importpath": "github.com/google/uuid",
+ "repository": "https://github.com/google/uuid",
+ "vcs": "git",
+ "revision": "6a5e28554805e78ea6141142aba763936c4761c0",
+ "branch": "master",
+ "notests": true
+ },
+ {
+ "importpath": "github.com/kr/pretty",
+ "repository": "https://github.com/dougm/pretty",
+ "vcs": "git",
+ "revision": "2ee9d7453c02ef7fa518a83ae23644eb8872186a",
+ "branch": "govmomi",
+ "notests": true
+ },
+ {
+ "importpath": "github.com/kr/pty",
+ "repository": "https://github.com/kr/pty",
+ "vcs": "git",
+ "revision": "95d05c1eef33a45bd58676b6ce28d105839b8d0b",
+ "branch": "master",
+ "notests": true
+ },
+ {
+ "importpath": "github.com/vmware/vmw-guestinfo",
+ "repository": "https://github.com/vmware/vmw-guestinfo",
+ "vcs": "git",
+ "revision": "25eff159a728be87e103a0b8045e08273f4dbec4",
+ "branch": "master",
+ "notests": true
+ }
+ ]
+}
diff --git a/libgo/go/cmd/go/internal/modconv/testdata/juju.out b/libgo/go/cmd/go/internal/modconv/testdata/juju.out
new file mode 100644
index 00000000000..c2430b1e26d
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/testdata/juju.out
@@ -0,0 +1,106 @@
+github.com/Azure/azure-sdk-for-go 902d95d9f311ae585ee98cfd18f418b467d60d5a
+github.com/Azure/go-autorest 6f40a8acfe03270d792cb8155e2942c09d7cff95
+github.com/ajstarks/svgo 89e3ac64b5b3e403a5e7c35ea4f98d45db7b4518
+github.com/altoros/gosigma 31228935eec685587914528585da4eb9b073c76d
+github.com/beorn7/perks 3ac7bf7a47d159a033b107610db8a1b6575507a4
+github.com/bmizerany/pat c068ca2f0aacee5ac3681d68e4d0a003b7d1fd2c
+github.com/coreos/go-systemd 7b2428fec40033549c68f54e26e89e7ca9a9ce31
+github.com/dgrijalva/jwt-go 01aeca54ebda6e0fbfafd0a524d234159c05ec20
+github.com/dustin/go-humanize 145fabdb1ab757076a70a886d092a3af27f66f4c
+github.com/godbus/dbus 32c6cc29c14570de4cf6d7e7737d68fb2d01ad15
+github.com/golang/protobuf 4bd1920723d7b7c925de087aa32e2187708897f7
+github.com/google/go-querystring 9235644dd9e52eeae6fa48efd539fdc351a0af53
+github.com/gorilla/schema 08023a0215e7fc27a9aecd8b8c50913c40019478
+github.com/gorilla/websocket 804cb600d06b10672f2fbc0a336a7bee507a428e
+github.com/gosuri/uitable 36ee7e946282a3fb1cfecd476ddc9b35d8847e42
+github.com/joyent/gocommon ade826b8b54e81a779ccb29d358a45ba24b7809c
+github.com/joyent/gosdc 2f11feadd2d9891e92296a1077c3e2e56939547d
+github.com/joyent/gosign 0da0d5f1342065321c97812b1f4ac0c2b0bab56c
+github.com/juju/ansiterm b99631de12cf04a906c1d4e4ec54fb86eae5863d
+github.com/juju/blobstore 06056004b3d7b54bbb7984d830c537bad00fec21
+github.com/juju/bundlechanges 7725027b95e0d54635e0fb11efc2debdcdf19f75
+github.com/juju/cmd 9425a576247f348b9b40afe3b60085de63470de5
+github.com/juju/description d3742c23561884cd7d759ef7142340af1d22cab0
+github.com/juju/errors 1b5e39b83d1835fa480e0c2ddefb040ee82d58b3
+github.com/juju/gnuflag 4e76c56581859c14d9d87e1ddbe29e1c0f10195f
+github.com/juju/go4 40d72ab9641a2a8c36a9c46a51e28367115c8e59
+github.com/juju/gojsonpointer afe8b77aa08f272b49e01b82de78510c11f61500
+github.com/juju/gojsonreference f0d24ac5ee330baa21721cdff56d45e4ee42628e
+github.com/juju/gojsonschema e1ad140384f254c82f89450d9a7c8dd38a632838
+github.com/juju/gomaasapi cfbc096bd45f276c17a391efc4db710b60ae3ad7
+github.com/juju/httpprof 14bf14c307672fd2456bdbf35d19cf0ccd3cf565
+github.com/juju/httprequest 266fd1e9debf09c037a63f074d099a2da4559ece
+github.com/juju/idmclient 4dc25171f675da4206b71695d3fd80e519ad05c1
+github.com/juju/jsonschema a0ef8b74ebcffeeff9fc374854deb4af388f037e
+github.com/juju/loggo 21bc4c63e8b435779a080e39e592969b7b90b889
+github.com/juju/mempool 24974d6c264fe5a29716e7d56ea24c4bd904b7cc
+github.com/juju/mutex 59c26ee163447c5c57f63ff71610d433862013de
+github.com/juju/persistent-cookiejar 5243747bf8f2d0897f6c7a52799327dc97d585e8
+github.com/juju/pubsub 9dcaca7eb4340dbf685aa7b3ad4cc4f8691a33d4
+github.com/juju/replicaset 6b5becf2232ce76656ea765d8d915d41755a1513
+github.com/juju/retry 62c62032529169c7ec02fa48f93349604c345e1f
+github.com/juju/rfc ebdbbdb950cd039a531d15cdc2ac2cbd94f068ee
+github.com/juju/romulus 98d6700423d63971f10ca14afea9ecf2b9b99f0f
+github.com/juju/schema 075de04f9b7d7580d60a1e12a0b3f50bb18e6998
+github.com/juju/terms-client 9b925afd677234e4146dde3cb1a11e187cbed64e
+github.com/juju/testing fce9bc4ebf7a77310c262ac4884e03b778eae06a
+github.com/juju/txn 28898197906200d603394d8e4ce537436529f1c5
+github.com/juju/usso 68a59c96c178fbbad65926e7f93db50a2cd14f33
+github.com/juju/utils 9f8aeb9b09e2d8c769be8317ccfa23f7eec62c26
+github.com/juju/version 1f41e27e54f21acccf9b2dddae063a782a8a7ceb
+github.com/juju/webbrowser 54b8c57083b4afb7dc75da7f13e2967b2606a507
+github.com/juju/xml eb759a627588d35166bc505fceb51b88500e291e
+github.com/juju/zip f6b1e93fa2e29a1d7d49b566b2b51efb060c982a
+github.com/julienschmidt/httprouter 77a895ad01ebc98a4dc95d8355bc825ce80a56f6
+github.com/lestrrat/go-jspointer f4881e611bdbe9fb413a7780721ef8400a1f2341
+github.com/lestrrat/go-jsref e452c7b5801d1c6494c9e7e0cbc7498c0f88dfd1
+github.com/lestrrat/go-jsschema b09d7650b822d2ea3dc83d5091a5e2acd8330051
+github.com/lestrrat/go-jsval b1258a10419fe0693f7b35ad65cd5074bc0ba1e5
+github.com/lestrrat/go-pdebug 2e6eaaa5717f81bda41d27070d3c966f40a1e75f
+github.com/lestrrat/go-structinfo f74c056fe41f860aa6264478c664a6fff8a64298
+github.com/lunixbochs/vtclean 4fbf7632a2c6d3fbdb9931439bdbbeded02cbe36
+github.com/lxc/lxd 23da0234979fa6299565b91b529a6dbeb42ee36d
+github.com/masterzen/azure-sdk-for-go ee4f0065d00cd12b542f18f5bc45799e88163b12
+github.com/masterzen/simplexml 4572e39b1ab9fe03ee513ce6fc7e289e98482190
+github.com/masterzen/winrm 7a535cd943fccaeed196718896beec3fb51aff41
+github.com/masterzen/xmlpath 13f4951698adc0fa9c1dda3e275d489a24201161
+github.com/mattn/go-colorable ed8eb9e318d7a84ce5915b495b7d35e0cfe7b5a8
+github.com/mattn/go-isatty 66b8e73f3f5cda9f96b69efd03dd3d7fc4a5cdb8
+github.com/mattn/go-runewidth d96d1bd051f2bd9e7e43d602782b37b93b1b5666
+github.com/matttproud/golang_protobuf_extensions c12348ce28de40eed0136aa2b644d0ee0650e56c
+github.com/nu7hatch/gouuid 179d4d0c4d8d407a32af483c2354df1d2c91e6c3
+github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9
+github.com/prometheus/client_golang 575f371f7862609249a1be4c9145f429fe065e32
+github.com/prometheus/client_model fa8ad6fec33561be4280a8f0514318c79d7f6cb6
+github.com/prometheus/common dd586c1c5abb0be59e60f942c22af711a2008cb4
+github.com/prometheus/procfs abf152e5f3e97f2fafac028d2cc06c1feb87ffa5
+github.com/rogpeppe/fastuuid 6724a57986aff9bff1a1770e9347036def7c89f6
+github.com/vmware/govmomi c0c7ce63df7edd78e713257b924c89d9a2dac119
+golang.org/x/crypto 8e06e8ddd9629eb88639aba897641bff8031f1d3
+golang.org/x/net ea47fc708ee3e20177f3ca3716217c4ab75942cb
+golang.org/x/oauth2 11c60b6f71a6ad48ed6f93c65fa4c6f9b1b5b46a
+golang.org/x/sys 7a6e5648d140666db5d920909e082ca00a87ba2c
+golang.org/x/text 2910a502d2bf9e43193af9d68ca516529614eed3
+google.golang.org/api 0d3983fb069cb6651353fc44c5cb604e263f2a93
+google.golang.org/cloud f20d6dcccb44ed49de45ae3703312cb46e627db1
+gopkg.in/amz.v3 8c3190dff075bf5442c9eedbf8f8ed6144a099e7
+gopkg.in/check.v1 4f90aeace3a26ad7021961c297b22c42160c7b25
+gopkg.in/errgo.v1 442357a80af5c6bf9b6d51ae791a39c3421004f3
+gopkg.in/goose.v1 ac43167b647feacdd9a1e34ee81e574551bc748d
+gopkg.in/ini.v1 776aa739ce9373377cd16f526cdf06cb4c89b40f
+gopkg.in/juju/blobstore.v2 51fa6e26128d74e445c72d3a91af555151cc3654
+gopkg.in/juju/charm.v6-unstable 83771c4919d6810bce5b7e63f46bea5fbfed0b93
+gopkg.in/juju/charmrepo.v2-unstable e79aa298df89ea887c9bffec46063c24bfb730f7
+gopkg.in/juju/charmstore.v5-unstable fd1eef3002fc6b6daff5e97efab6f5056d22dcc7
+gopkg.in/juju/environschema.v1 7359fc7857abe2b11b5b3e23811a9c64cb6b01e0
+gopkg.in/juju/jujusvg.v2 d82160011935ef79fc7aca84aba2c6f74700fe75
+gopkg.in/juju/names.v2 0847c26d322a121e52614f969fb82eae2820c715
+gopkg.in/juju/worker.v1 6965b9d826717287bb002e02d1fd4d079978083e
+gopkg.in/macaroon-bakery.v1 469b44e6f1f9479e115c8ae879ef80695be624d5
+gopkg.in/macaroon.v1 ab3940c6c16510a850e1c2dd628b919f0f3f1464
+gopkg.in/mgo.v2 f2b6f6c918c452ad107eec89615f074e3bd80e33
+gopkg.in/natefinch/lumberjack.v2 514cbda263a734ae8caac038dadf05f8f3f9f738
+gopkg.in/natefinch/npipe.v2 c1b8fa8bdccecb0b8db834ee0b92fdbcfa606dd6
+gopkg.in/retry.v1 c09f6b86ba4d5d2cf5bdf0665364aec9fd4815db
+gopkg.in/tomb.v1 dd632973f1e7218eb1089048e0798ec9ae7dceb8
+gopkg.in/yaml.v2 a3f3340b5840cee44f372bddb5880fcbc419b46a
diff --git a/libgo/go/cmd/go/internal/modconv/testdata/juju.tsv b/libgo/go/cmd/go/internal/modconv/testdata/juju.tsv
new file mode 100644
index 00000000000..0bddcef81ce
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/testdata/juju.tsv
@@ -0,0 +1,106 @@
+github.com/Azure/azure-sdk-for-go git 902d95d9f311ae585ee98cfd18f418b467d60d5a 2016-07-20T05:16:58Z
+github.com/Azure/go-autorest git 6f40a8acfe03270d792cb8155e2942c09d7cff95 2016-07-19T23:14:56Z
+github.com/ajstarks/svgo git 89e3ac64b5b3e403a5e7c35ea4f98d45db7b4518 2014-10-04T21:11:59Z
+github.com/altoros/gosigma git 31228935eec685587914528585da4eb9b073c76d 2015-04-08T14:52:32Z
+github.com/beorn7/perks git 3ac7bf7a47d159a033b107610db8a1b6575507a4 2016-02-29T21:34:45Z
+github.com/bmizerany/pat git c068ca2f0aacee5ac3681d68e4d0a003b7d1fd2c 2016-02-17T10:32:42Z
+github.com/coreos/go-systemd git 7b2428fec40033549c68f54e26e89e7ca9a9ce31 2016-02-02T21:14:25Z
+github.com/dgrijalva/jwt-go git 01aeca54ebda6e0fbfafd0a524d234159c05ec20 2016-07-05T20:30:06Z
+github.com/dustin/go-humanize git 145fabdb1ab757076a70a886d092a3af27f66f4c 2014-12-28T07:11:48Z
+github.com/godbus/dbus git 32c6cc29c14570de4cf6d7e7737d68fb2d01ad15 2016-05-06T22:25:50Z
+github.com/golang/protobuf git 4bd1920723d7b7c925de087aa32e2187708897f7 2016-11-09T07:27:36Z
+github.com/google/go-querystring git 9235644dd9e52eeae6fa48efd539fdc351a0af53 2016-04-01T23:30:42Z
+github.com/gorilla/schema git 08023a0215e7fc27a9aecd8b8c50913c40019478 2016-04-26T23:15:12Z
+github.com/gorilla/websocket git 804cb600d06b10672f2fbc0a336a7bee507a428e 2017-02-14T17:41:18Z
+github.com/gosuri/uitable git 36ee7e946282a3fb1cfecd476ddc9b35d8847e42 2016-04-04T20:39:58Z
+github.com/joyent/gocommon git ade826b8b54e81a779ccb29d358a45ba24b7809c 2016-03-20T19:31:33Z
+github.com/joyent/gosdc git 2f11feadd2d9891e92296a1077c3e2e56939547d 2014-05-24T00:08:15Z
+github.com/joyent/gosign git 0da0d5f1342065321c97812b1f4ac0c2b0bab56c 2014-05-24T00:07:34Z
+github.com/juju/ansiterm git b99631de12cf04a906c1d4e4ec54fb86eae5863d 2016-09-07T23:45:32Z
+github.com/juju/blobstore git 06056004b3d7b54bbb7984d830c537bad00fec21 2015-07-29T11:18:58Z
+github.com/juju/bundlechanges git 7725027b95e0d54635e0fb11efc2debdcdf19f75 2016-12-15T16:06:52Z
+github.com/juju/cmd git 9425a576247f348b9b40afe3b60085de63470de5 2017-03-20T01:37:09Z
+github.com/juju/description git d3742c23561884cd7d759ef7142340af1d22cab0 2017-03-20T07:46:40Z
+github.com/juju/errors git 1b5e39b83d1835fa480e0c2ddefb040ee82d58b3 2015-09-16T12:56:42Z
+github.com/juju/gnuflag git 4e76c56581859c14d9d87e1ddbe29e1c0f10195f 2016-08-09T16:52:14Z
+github.com/juju/go4 git 40d72ab9641a2a8c36a9c46a51e28367115c8e59 2016-02-22T16:32:58Z
+github.com/juju/gojsonpointer git afe8b77aa08f272b49e01b82de78510c11f61500 2015-02-04T19:46:29Z
+github.com/juju/gojsonreference git f0d24ac5ee330baa21721cdff56d45e4ee42628e 2015-02-04T19:46:33Z
+github.com/juju/gojsonschema git e1ad140384f254c82f89450d9a7c8dd38a632838 2015-03-12T17:00:16Z
+github.com/juju/gomaasapi git cfbc096bd45f276c17a391efc4db710b60ae3ad7 2017-02-27T07:51:07Z
+github.com/juju/httpprof git 14bf14c307672fd2456bdbf35d19cf0ccd3cf565 2014-12-17T16:00:36Z
+github.com/juju/httprequest git 266fd1e9debf09c037a63f074d099a2da4559ece 2016-10-06T15:09:09Z
+github.com/juju/idmclient git 4dc25171f675da4206b71695d3fd80e519ad05c1 2017-02-09T16:27:49Z
+github.com/juju/jsonschema git a0ef8b74ebcffeeff9fc374854deb4af388f037e 2016-11-02T18:19:19Z
+github.com/juju/loggo git 21bc4c63e8b435779a080e39e592969b7b90b889 2017-02-22T12:20:47Z
+github.com/juju/mempool git 24974d6c264fe5a29716e7d56ea24c4bd904b7cc 2016-02-05T10:49:27Z
+github.com/juju/mutex git 59c26ee163447c5c57f63ff71610d433862013de 2016-06-17T01:09:07Z
+github.com/juju/persistent-cookiejar git 5243747bf8f2d0897f6c7a52799327dc97d585e8 2016-11-15T13:33:28Z
+github.com/juju/pubsub git 9dcaca7eb4340dbf685aa7b3ad4cc4f8691a33d4 2016-07-28T03:00:34Z
+github.com/juju/replicaset git 6b5becf2232ce76656ea765d8d915d41755a1513 2016-11-25T16:08:49Z
+github.com/juju/retry git 62c62032529169c7ec02fa48f93349604c345e1f 2015-10-29T02:48:21Z
+github.com/juju/rfc git ebdbbdb950cd039a531d15cdc2ac2cbd94f068ee 2016-07-11T02:42:13Z
+github.com/juju/romulus git 98d6700423d63971f10ca14afea9ecf2b9b99f0f 2017-01-23T14:29:29Z
+github.com/juju/schema git 075de04f9b7d7580d60a1e12a0b3f50bb18e6998 2016-04-20T04:42:03Z
+github.com/juju/terms-client git 9b925afd677234e4146dde3cb1a11e187cbed64e 2016-08-09T13:19:00Z
+github.com/juju/testing git fce9bc4ebf7a77310c262ac4884e03b778eae06a 2017-02-22T09:01:19Z
+github.com/juju/txn git 28898197906200d603394d8e4ce537436529f1c5 2016-11-16T04:07:55Z
+github.com/juju/usso git 68a59c96c178fbbad65926e7f93db50a2cd14f33 2016-04-01T10:44:24Z
+github.com/juju/utils git 9f8aeb9b09e2d8c769be8317ccfa23f7eec62c26 2017-02-15T08:19:00Z
+github.com/juju/version git 1f41e27e54f21acccf9b2dddae063a782a8a7ceb 2016-10-31T05:19:06Z
+github.com/juju/webbrowser git 54b8c57083b4afb7dc75da7f13e2967b2606a507 2016-03-09T14:36:29Z
+github.com/juju/xml git eb759a627588d35166bc505fceb51b88500e291e 2015-04-13T13:11:21Z
+github.com/juju/zip git f6b1e93fa2e29a1d7d49b566b2b51efb060c982a 2016-02-05T10:52:21Z
+github.com/julienschmidt/httprouter git 77a895ad01ebc98a4dc95d8355bc825ce80a56f6 2015-10-13T22:55:20Z
+github.com/lestrrat/go-jspointer git f4881e611bdbe9fb413a7780721ef8400a1f2341 2016-02-29T02:13:54Z
+github.com/lestrrat/go-jsref git e452c7b5801d1c6494c9e7e0cbc7498c0f88dfd1 2016-06-01T01:32:40Z
+github.com/lestrrat/go-jsschema git b09d7650b822d2ea3dc83d5091a5e2acd8330051 2016-09-03T13:19:57Z
+github.com/lestrrat/go-jsval git b1258a10419fe0693f7b35ad65cd5074bc0ba1e5 2016-10-12T04:57:17Z
+github.com/lestrrat/go-pdebug git 2e6eaaa5717f81bda41d27070d3c966f40a1e75f 2016-08-17T06:33:33Z
+github.com/lestrrat/go-structinfo git f74c056fe41f860aa6264478c664a6fff8a64298 2016-03-08T13:11:05Z
+github.com/lunixbochs/vtclean git 4fbf7632a2c6d3fbdb9931439bdbbeded02cbe36 2016-01-25T03:51:06Z
+github.com/lxc/lxd git 23da0234979fa6299565b91b529a6dbeb42ee36d 2017-02-16T05:29:42Z
+github.com/masterzen/azure-sdk-for-go git ee4f0065d00cd12b542f18f5bc45799e88163b12 2016-10-14T13:56:28Z
+github.com/masterzen/simplexml git 4572e39b1ab9fe03ee513ce6fc7e289e98482190 2016-06-08T18:30:07Z
+github.com/masterzen/winrm git 7a535cd943fccaeed196718896beec3fb51aff41 2016-10-14T15:10:40Z
+github.com/masterzen/xmlpath git 13f4951698adc0fa9c1dda3e275d489a24201161 2014-02-18T18:59:01Z
+github.com/mattn/go-colorable git ed8eb9e318d7a84ce5915b495b7d35e0cfe7b5a8 2016-07-31T23:54:17Z
+github.com/mattn/go-isatty git 66b8e73f3f5cda9f96b69efd03dd3d7fc4a5cdb8 2016-08-06T12:27:52Z
+github.com/mattn/go-runewidth git d96d1bd051f2bd9e7e43d602782b37b93b1b5666 2015-11-18T07:21:59Z
+github.com/matttproud/golang_protobuf_extensions git c12348ce28de40eed0136aa2b644d0ee0650e56c 2016-04-24T11:30:07Z
+github.com/nu7hatch/gouuid git 179d4d0c4d8d407a32af483c2354df1d2c91e6c3 2013-12-21T20:05:32Z
+github.com/pkg/errors git 839d9e913e063e28dfd0e6c7b7512793e0a48be9 2016-10-02T05:25:12Z
+github.com/prometheus/client_golang git 575f371f7862609249a1be4c9145f429fe065e32 2016-11-24T15:57:32Z
+github.com/prometheus/client_model git fa8ad6fec33561be4280a8f0514318c79d7f6cb6 2015-02-12T10:17:44Z
+github.com/prometheus/common git dd586c1c5abb0be59e60f942c22af711a2008cb4 2016-05-03T22:05:32Z
+github.com/prometheus/procfs git abf152e5f3e97f2fafac028d2cc06c1feb87ffa5 2016-04-11T19:08:41Z
+github.com/rogpeppe/fastuuid git 6724a57986aff9bff1a1770e9347036def7c89f6 2015-01-06T09:32:20Z
+github.com/vmware/govmomi git c0c7ce63df7edd78e713257b924c89d9a2dac119 2016-06-30T15:37:42Z
+golang.org/x/crypto git 8e06e8ddd9629eb88639aba897641bff8031f1d3 2016-09-22T17:06:29Z
+golang.org/x/net git ea47fc708ee3e20177f3ca3716217c4ab75942cb 2015-08-29T23:03:18Z
+golang.org/x/oauth2 git 11c60b6f71a6ad48ed6f93c65fa4c6f9b1b5b46a 2015-03-25T02:00:22Z
+golang.org/x/sys git 7a6e5648d140666db5d920909e082ca00a87ba2c 2017-02-01T05:12:45Z
+golang.org/x/text git 2910a502d2bf9e43193af9d68ca516529614eed3 2016-07-26T16:48:57Z
+google.golang.org/api git 0d3983fb069cb6651353fc44c5cb604e263f2a93 2014-12-10T23:51:26Z
+google.golang.org/cloud git f20d6dcccb44ed49de45ae3703312cb46e627db1 2015-03-19T22:36:35Z
+gopkg.in/amz.v3 git 8c3190dff075bf5442c9eedbf8f8ed6144a099e7 2016-12-15T13:08:49Z
+gopkg.in/check.v1 git 4f90aeace3a26ad7021961c297b22c42160c7b25 2016-01-05T16:49:36Z
+gopkg.in/errgo.v1 git 442357a80af5c6bf9b6d51ae791a39c3421004f3 2016-12-22T12:58:16Z
+gopkg.in/goose.v1 git ac43167b647feacdd9a1e34ee81e574551bc748d 2017-02-15T01:56:23Z
+gopkg.in/ini.v1 git 776aa739ce9373377cd16f526cdf06cb4c89b40f 2016-02-22T23:24:41Z
+gopkg.in/juju/blobstore.v2 git 51fa6e26128d74e445c72d3a91af555151cc3654 2016-01-25T02:37:03Z
+gopkg.in/juju/charm.v6-unstable git 83771c4919d6810bce5b7e63f46bea5fbfed0b93 2016-10-03T20:31:18Z
+gopkg.in/juju/charmrepo.v2-unstable git e79aa298df89ea887c9bffec46063c24bfb730f7 2016-11-17T15:25:28Z
+gopkg.in/juju/charmstore.v5-unstable git fd1eef3002fc6b6daff5e97efab6f5056d22dcc7 2016-09-16T10:09:07Z
+gopkg.in/juju/environschema.v1 git 7359fc7857abe2b11b5b3e23811a9c64cb6b01e0 2015-11-04T11:58:10Z
+gopkg.in/juju/jujusvg.v2 git d82160011935ef79fc7aca84aba2c6f74700fe75 2016-06-09T10:52:15Z
+gopkg.in/juju/names.v2 git 0847c26d322a121e52614f969fb82eae2820c715 2016-11-02T13:43:03Z
+gopkg.in/juju/worker.v1 git 6965b9d826717287bb002e02d1fd4d079978083e 2017-03-08T00:24:58Z
+gopkg.in/macaroon-bakery.v1 git 469b44e6f1f9479e115c8ae879ef80695be624d5 2016-06-22T12:14:21Z
+gopkg.in/macaroon.v1 git ab3940c6c16510a850e1c2dd628b919f0f3f1464 2015-01-21T11:42:31Z
+gopkg.in/mgo.v2 git f2b6f6c918c452ad107eec89615f074e3bd80e33 2016-08-18T01:52:18Z
+gopkg.in/natefinch/lumberjack.v2 git 514cbda263a734ae8caac038dadf05f8f3f9f738 2016-01-25T11:17:49Z
+gopkg.in/natefinch/npipe.v2 git c1b8fa8bdccecb0b8db834ee0b92fdbcfa606dd6 2016-06-21T03:49:01Z
+gopkg.in/retry.v1 git c09f6b86ba4d5d2cf5bdf0665364aec9fd4815db 2016-10-25T18:14:30Z
+gopkg.in/tomb.v1 git dd632973f1e7218eb1089048e0798ec9ae7dceb8 2014-10-24T13:56:13Z
+gopkg.in/yaml.v2 git a3f3340b5840cee44f372bddb5880fcbc419b46a 2017-02-08T14:18:51Z
diff --git a/libgo/go/cmd/go/internal/modconv/testdata/moby.out b/libgo/go/cmd/go/internal/modconv/testdata/moby.out
new file mode 100644
index 00000000000..2cb2e056a83
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/testdata/moby.out
@@ -0,0 +1,105 @@
+github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109
+github.com/Microsoft/hcsshim v0.6.5
+github.com/Microsoft/go-winio v0.4.5
+github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76
+github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
+github.com/go-check/check 4ed411733c5785b40214c70bce814c3a3a689609
+github.com/gorilla/context v1.1
+github.com/gorilla/mux v1.1
+github.com/Microsoft/opengcs v0.3.4
+github.com/kr/pty 5cf931ef8f
+github.com/mattn/go-shellwords v1.0.3
+github.com/sirupsen/logrus v1.0.3
+github.com/tchap/go-patricia v2.2.6
+github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3
+golang.org/x/net 7dcfb8076726a3fdd9353b6b8a1f1b6be6811bd6
+golang.org/x/sys 07c182904dbd53199946ba614a412c61d3c548f5
+github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
+github.com/docker/go-connections 3ede32e2033de7505e6500d6c868c2b9ed9f169d
+golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756
+github.com/stretchr/testify 4d4bfba8f1d1027c4fdbe371823030df51419987
+github.com/pmezard/go-difflib v1.0.0
+github.com/gotestyourself/gotestyourself v1.1.0
+github.com/RackSec/srslog 456df3a81436d29ba874f3590eeeee25d666f8a5
+github.com/imdario/mergo 0.2.1
+golang.org/x/sync de49d9dcd27d4f764488181bea099dfe6179bcf0
+github.com/containerd/continuity 22694c680ee48fb8f50015b44618517e2bde77e8
+github.com/moby/buildkit aaff9d591ef128560018433fe61beb802e149de8
+github.com/tonistiigi/fsutil dea3a0da73aee887fc02142d995be764106ac5e2
+github.com/docker/libnetwork 68f1039f172434709a4550fe92e3e058406c74ce
+github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
+github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
+github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
+github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
+github.com/hashicorp/memberlist v0.1.0
+github.com/sean-/seed e2103e2c35297fb7e17febb81e49b312087a2372
+github.com/hashicorp/go-sockaddr acd314c5781ea706c710d9ea70069fd2e110d61d
+github.com/hashicorp/go-multierror fcdddc395df1ddf4247c69bd436e84cfa0733f7e
+github.com/hashicorp/serf 598c54895cc5a7b1a24a398d635e8c0ea0959870
+github.com/docker/libkv 1d8431073ae03cdaedb198a89722f3aab6d418ef
+github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25
+github.com/vishvananda/netlink bd6d5de5ccef2d66b0a26177928d0d8895d7f969
+github.com/BurntSushi/toml f706d00e3de6abe700c994cdd545a1a4915af060
+github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374
+github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d
+github.com/coreos/etcd v3.2.1
+github.com/coreos/go-semver v0.2.0
+github.com/ugorji/go f1f1a805ed361a0e078bb537e4ea78cd37dcf065
+github.com/hashicorp/consul v0.5.2
+github.com/boltdb/bolt fff57c100f4dea1905678da7e90d92429dff2904
+github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7
+github.com/docker/distribution edc3ab29cdff8694dd6feb85cfeb4b5f1b38ed9c
+github.com/vbatts/tar-split v0.10.1
+github.com/opencontainers/go-digest a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb
+github.com/mistifyio/go-zfs 22c9b32c84eb0d0c6f4043b6e90fc94073de92fa
+github.com/pborman/uuid v1.0
+google.golang.org/grpc v1.3.0
+github.com/opencontainers/runc 0351df1c5a66838d0c392b4ac4cf9450de844e2d
+github.com/opencontainers/image-spec 372ad780f63454fbbbbcc7cf80e5b90245c13e13
+github.com/opencontainers/runtime-spec v1.0.0
+github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0
+github.com/coreos/go-systemd v4
+github.com/godbus/dbus v4.0.0
+github.com/syndtr/gocapability 2c00daeb6c3b45114c80ac44119e7b8801fdd852
+github.com/golang/protobuf 7a211bcf3bce0e3f1d74f9894916e6f116ae83b4
+github.com/Graylog2/go-gelf v2
+github.com/fluent/fluent-logger-golang v1.2.1
+github.com/philhofer/fwd 98c11a7a6ec829d672b03833c3d69a7fae1ca972
+github.com/tinylib/msgp 75ee40d2601edf122ef667e2a07d600d4c44490c
+github.com/fsnotify/fsnotify v1.4.2
+github.com/aws/aws-sdk-go v1.4.22
+github.com/go-ini/ini 060d7da055ba6ec5ea7a31f116332fe5efa04ce0
+github.com/jmespath/go-jmespath 0b12d6b521d83fc7f755e7cfc1b1fbdd35a01a74
+github.com/bsphere/le_go 7a984a84b5492ae539b79b62fb4a10afc63c7bcf
+golang.org/x/oauth2 96382aa079b72d8c014eb0c50f6c223d1e6a2de0
+google.golang.org/api 3cc2e591b550923a2c5f0ab5a803feda924d5823
+cloud.google.com/go 9d965e63e8cceb1b5d7977a202f0fcb8866d6525
+github.com/googleapis/gax-go da06d194a00e19ce00d9011a13931c3f6f6887c7
+google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
+github.com/containerd/containerd 06b9cb35161009dcb7123345749fef02f7cea8e0
+github.com/tonistiigi/fifo 1405643975692217d6720f8b54aeee1bf2cd5cf4
+github.com/docker/swarmkit 872861d2ae46958af7ead1d5fffb092c73afbaf0
+github.com/gogo/protobuf v0.4
+github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a
+github.com/google/certificate-transparency d90e65c3a07988180c5b1ece71791c0b6506826e
+golang.org/x/crypto 558b6879de74bc843225cde5686419267ff707ca
+golang.org/x/time a4bde12657593d5e90d0533a3e4fd95e635124cb
+github.com/hashicorp/go-memdb cb9a474f84cc5e41b273b20c6927680b2a8776ad
+github.com/hashicorp/go-immutable-radix 8e8ed81f8f0bf1bdd829593fdd5c29922c1ea990
+github.com/hashicorp/golang-lru a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4
+github.com/coreos/pkg fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8
+github.com/pivotal-golang/clock 3fd3c1944c59d9742e1cd333672181cd1a6f9fa0
+github.com/prometheus/client_golang 52437c81da6b127a9925d17eb3a382a2e5fd395e
+github.com/beorn7/perks 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
+github.com/prometheus/client_model fa8ad6fec33561be4280a8f0514318c79d7f6cb6
+github.com/prometheus/common ebdfc6da46522d58825777cf1f90490a5b1ef1d8
+github.com/prometheus/procfs abf152e5f3e97f2fafac028d2cc06c1feb87ffa5
+github.com/matttproud/golang_protobuf_extensions v1.0.0
+github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9
+github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f0f7e0
+github.com/spf13/cobra v1.5.1
+github.com/spf13/pflag 9ff6c6923cfffbcd502984b8e0c80539a94968b7
+github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
+github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c
+github.com/docker/go-metrics d466d4f6fd960e01820085bd7e1a24426ee7ef18
+github.com/opencontainers/selinux v1.0.0-rc1
diff --git a/libgo/go/cmd/go/internal/modconv/testdata/moby.vconf b/libgo/go/cmd/go/internal/modconv/testdata/moby.vconf
new file mode 100644
index 00000000000..53b90d1e372
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/testdata/moby.vconf
@@ -0,0 +1,149 @@
+# the following lines are in sorted order, FYI
+github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109
+github.com/Microsoft/hcsshim v0.6.5
+github.com/Microsoft/go-winio v0.4.5
+github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76
+github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
+github.com/go-check/check 4ed411733c5785b40214c70bce814c3a3a689609 https://github.com/cpuguy83/check.git
+github.com/gorilla/context v1.1
+github.com/gorilla/mux v1.1
+github.com/Microsoft/opengcs v0.3.4
+github.com/kr/pty 5cf931ef8f
+github.com/mattn/go-shellwords v1.0.3
+github.com/sirupsen/logrus v1.0.3
+github.com/tchap/go-patricia v2.2.6
+github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3
+golang.org/x/net 7dcfb8076726a3fdd9353b6b8a1f1b6be6811bd6
+golang.org/x/sys 07c182904dbd53199946ba614a412c61d3c548f5
+github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
+github.com/docker/go-connections 3ede32e2033de7505e6500d6c868c2b9ed9f169d
+golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756
+github.com/stretchr/testify 4d4bfba8f1d1027c4fdbe371823030df51419987
+github.com/pmezard/go-difflib v1.0.0
+github.com/gotestyourself/gotestyourself v1.1.0
+
+github.com/RackSec/srslog 456df3a81436d29ba874f3590eeeee25d666f8a5
+github.com/imdario/mergo 0.2.1
+golang.org/x/sync de49d9dcd27d4f764488181bea099dfe6179bcf0
+
+github.com/containerd/continuity 22694c680ee48fb8f50015b44618517e2bde77e8
+github.com/moby/buildkit aaff9d591ef128560018433fe61beb802e149de8
+github.com/tonistiigi/fsutil dea3a0da73aee887fc02142d995be764106ac5e2
+
+#get libnetwork packages
+github.com/docker/libnetwork 68f1039f172434709a4550fe92e3e058406c74ce
+github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
+github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
+github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
+github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
+github.com/hashicorp/memberlist v0.1.0
+github.com/sean-/seed e2103e2c35297fb7e17febb81e49b312087a2372
+github.com/hashicorp/go-sockaddr acd314c5781ea706c710d9ea70069fd2e110d61d
+github.com/hashicorp/go-multierror fcdddc395df1ddf4247c69bd436e84cfa0733f7e
+github.com/hashicorp/serf 598c54895cc5a7b1a24a398d635e8c0ea0959870
+github.com/docker/libkv 1d8431073ae03cdaedb198a89722f3aab6d418ef
+github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25
+github.com/vishvananda/netlink bd6d5de5ccef2d66b0a26177928d0d8895d7f969
+github.com/BurntSushi/toml f706d00e3de6abe700c994cdd545a1a4915af060
+github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374
+github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d
+github.com/coreos/etcd v3.2.1
+github.com/coreos/go-semver v0.2.0
+github.com/ugorji/go f1f1a805ed361a0e078bb537e4ea78cd37dcf065
+github.com/hashicorp/consul v0.5.2
+github.com/boltdb/bolt fff57c100f4dea1905678da7e90d92429dff2904
+github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7
+
+# get graph and distribution packages
+github.com/docker/distribution edc3ab29cdff8694dd6feb85cfeb4b5f1b38ed9c
+github.com/vbatts/tar-split v0.10.1
+github.com/opencontainers/go-digest a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb
+
+# get go-zfs packages
+github.com/mistifyio/go-zfs 22c9b32c84eb0d0c6f4043b6e90fc94073de92fa
+github.com/pborman/uuid v1.0
+
+google.golang.org/grpc v1.3.0
+
+# When updating, also update RUNC_COMMIT in hack/dockerfile/binaries-commits accordingly
+github.com/opencontainers/runc 0351df1c5a66838d0c392b4ac4cf9450de844e2d
+github.com/opencontainers/image-spec 372ad780f63454fbbbbcc7cf80e5b90245c13e13
+github.com/opencontainers/runtime-spec v1.0.0
+
+github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0
+
+# libcontainer deps (see src/github.com/opencontainers/runc/Godeps/Godeps.json)
+github.com/coreos/go-systemd v4
+github.com/godbus/dbus v4.0.0
+github.com/syndtr/gocapability 2c00daeb6c3b45114c80ac44119e7b8801fdd852
+github.com/golang/protobuf 7a211bcf3bce0e3f1d74f9894916e6f116ae83b4
+
+# gelf logging driver deps
+github.com/Graylog2/go-gelf v2
+
+github.com/fluent/fluent-logger-golang v1.2.1
+# fluent-logger-golang deps
+github.com/philhofer/fwd 98c11a7a6ec829d672b03833c3d69a7fae1ca972
+github.com/tinylib/msgp 75ee40d2601edf122ef667e2a07d600d4c44490c
+
+# fsnotify
+github.com/fsnotify/fsnotify v1.4.2
+
+# awslogs deps
+github.com/aws/aws-sdk-go v1.4.22
+github.com/go-ini/ini 060d7da055ba6ec5ea7a31f116332fe5efa04ce0
+github.com/jmespath/go-jmespath 0b12d6b521d83fc7f755e7cfc1b1fbdd35a01a74
+
+# logentries
+github.com/bsphere/le_go 7a984a84b5492ae539b79b62fb4a10afc63c7bcf
+
+# gcplogs deps
+golang.org/x/oauth2 96382aa079b72d8c014eb0c50f6c223d1e6a2de0
+google.golang.org/api 3cc2e591b550923a2c5f0ab5a803feda924d5823
+cloud.google.com/go 9d965e63e8cceb1b5d7977a202f0fcb8866d6525
+github.com/googleapis/gax-go da06d194a00e19ce00d9011a13931c3f6f6887c7
+google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
+
+# containerd
+github.com/containerd/containerd 06b9cb35161009dcb7123345749fef02f7cea8e0
+github.com/tonistiigi/fifo 1405643975692217d6720f8b54aeee1bf2cd5cf4
+
+# cluster
+github.com/docker/swarmkit 872861d2ae46958af7ead1d5fffb092c73afbaf0
+github.com/gogo/protobuf v0.4
+github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a
+github.com/google/certificate-transparency d90e65c3a07988180c5b1ece71791c0b6506826e
+golang.org/x/crypto 558b6879de74bc843225cde5686419267ff707ca
+golang.org/x/time a4bde12657593d5e90d0533a3e4fd95e635124cb
+github.com/hashicorp/go-memdb cb9a474f84cc5e41b273b20c6927680b2a8776ad
+github.com/hashicorp/go-immutable-radix 8e8ed81f8f0bf1bdd829593fdd5c29922c1ea990
+github.com/hashicorp/golang-lru a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4
+github.com/coreos/pkg fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8
+github.com/pivotal-golang/clock 3fd3c1944c59d9742e1cd333672181cd1a6f9fa0
+github.com/prometheus/client_golang 52437c81da6b127a9925d17eb3a382a2e5fd395e
+github.com/beorn7/perks 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
+github.com/prometheus/client_model fa8ad6fec33561be4280a8f0514318c79d7f6cb6
+github.com/prometheus/common ebdfc6da46522d58825777cf1f90490a5b1ef1d8
+github.com/prometheus/procfs abf152e5f3e97f2fafac028d2cc06c1feb87ffa5
+github.com/matttproud/golang_protobuf_extensions v1.0.0
+github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9
+github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f0f7e0
+
+# cli
+github.com/spf13/cobra v1.5.1 https://github.com/dnephin/cobra.git
+github.com/spf13/pflag 9ff6c6923cfffbcd502984b8e0c80539a94968b7
+github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
+github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c https://github.com/ijc25/Gotty
+
+# metrics
+github.com/docker/go-metrics d466d4f6fd960e01820085bd7e1a24426ee7ef18
+
+github.com/opencontainers/selinux v1.0.0-rc1
+
+# archive/tar
+# mkdir -p ./vendor/archive
+# git clone git://github.com/tonistiigi/go-1.git ./go
+# git --git-dir ./go/.git --work-tree ./go checkout revert-prefix-ignore
+# cp -a go/src/archive/tar ./vendor/archive/tar
+# rm -rf ./go
+# vndr
diff --git a/libgo/go/cmd/go/internal/modconv/testdata/panicparse.out b/libgo/go/cmd/go/internal/modconv/testdata/panicparse.out
new file mode 100644
index 00000000000..8830033c6b7
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/testdata/panicparse.out
@@ -0,0 +1,8 @@
+github.com/kr/pretty 737b74a46c4bf788349f72cb256fed10aea4d0ac
+github.com/kr/text 7cafcd837844e784b526369c9bce262804aebc60
+github.com/maruel/ut a9c9f15ccfa6f8b90182a53df32f4745586fbae3
+github.com/mattn/go-colorable 9056b7a9f2d1f2d96498d6d146acd1f9d5ed3d59
+github.com/mattn/go-isatty 56b76bdf51f7708750eac80fa38b952bb9f32639
+github.com/mgutz/ansi c286dcecd19ff979eeb73ea444e479b903f2cfcb
+github.com/pmezard/go-difflib 792786c7400a136282c1664665ae0a8db921c6c2
+golang.org/x/sys a646d33e2ee3172a661fc09bca23bb4889a41bc8
diff --git a/libgo/go/cmd/go/internal/modconv/testdata/panicparse.vyml b/libgo/go/cmd/go/internal/modconv/testdata/panicparse.vyml
new file mode 100644
index 00000000000..ff3d43f5f2d
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/testdata/panicparse.vyml
@@ -0,0 +1,17 @@
+vendors:
+- path: github.com/kr/pretty
+ rev: 737b74a46c4bf788349f72cb256fed10aea4d0ac
+- path: github.com/kr/text
+ rev: 7cafcd837844e784b526369c9bce262804aebc60
+- path: github.com/maruel/ut
+ rev: a9c9f15ccfa6f8b90182a53df32f4745586fbae3
+- path: github.com/mattn/go-colorable
+ rev: 9056b7a9f2d1f2d96498d6d146acd1f9d5ed3d59
+- path: github.com/mattn/go-isatty
+ rev: 56b76bdf51f7708750eac80fa38b952bb9f32639
+- path: github.com/mgutz/ansi
+ rev: c286dcecd19ff979eeb73ea444e479b903f2cfcb
+- path: github.com/pmezard/go-difflib
+ rev: 792786c7400a136282c1664665ae0a8db921c6c2
+- path: golang.org/x/sys
+ rev: a646d33e2ee3172a661fc09bca23bb4889a41bc8
diff --git a/libgo/go/cmd/go/internal/modconv/testdata/prometheus.out b/libgo/go/cmd/go/internal/modconv/testdata/prometheus.out
new file mode 100644
index 00000000000..d11b8ecc726
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/testdata/prometheus.out
@@ -0,0 +1,258 @@
+cloud.google.com/go/compute/metadata c589d0c9f0d81640c518354c7bcae77d99820aa3
+cloud.google.com/go/internal c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/Azure/azure-sdk-for-go/arm/compute bd73d950fa4440dae889bd9917bff7cef539f86e
+github.com/Azure/azure-sdk-for-go/arm/network bd73d950fa4440dae889bd9917bff7cef539f86e
+github.com/Azure/go-autorest/autorest 8a25372bbfec739b8719a9e3987400d15ef9e179
+github.com/Azure/go-autorest/autorest/azure 8a25372bbfec739b8719a9e3987400d15ef9e179
+github.com/Azure/go-autorest/autorest/date 8a25372bbfec739b8719a9e3987400d15ef9e179
+github.com/Azure/go-autorest/autorest/to 8a25372bbfec739b8719a9e3987400d15ef9e179
+github.com/Azure/go-autorest/autorest/validation 8a25372bbfec739b8719a9e3987400d15ef9e179
+github.com/PuerkitoBio/purell c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/PuerkitoBio/urlesc c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/asaskevich/govalidator 7b3beb6df3c42abd3509abfc3bcacc0fbfb7c877
+github.com/aws/aws-sdk-go/aws 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/awserr 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/awsutil 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/client 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/client/metadata 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/corehandlers 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/credentials 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/credentials/endpointcreds 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/credentials/stscreds 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/defaults 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/ec2metadata 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/request 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/session 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/signer/v4 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/private/endpoints 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/private/protocol 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/private/protocol/ec2query 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/private/protocol/query 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/private/protocol/query/queryutil 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/private/protocol/rest 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/private/waiter 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/service/ec2 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/service/sts 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/beorn7/perks/quantile 3ac7bf7a47d159a033b107610db8a1b6575507a4
+github.com/blang/semver c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/coreos/go-oidc/http c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/coreos/go-oidc/jose c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/coreos/go-oidc/key c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/coreos/go-oidc/oauth2 c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/coreos/go-oidc/oidc c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/coreos/pkg/health c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/coreos/pkg/httputil c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/coreos/pkg/timeutil c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/davecgh/go-spew/spew c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/dgrijalva/jwt-go 9ed569b5d1ac936e6494082958d63a6aa4fff99a
+github.com/docker/distribution/digest c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/docker/distribution/reference c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/emicklei/go-restful c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/emicklei/go-restful/log c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/emicklei/go-restful/swagger c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/ghodss/yaml c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/go-ini/ini 6e4869b434bd001f6983749881c7ead3545887d8
+github.com/go-openapi/jsonpointer c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/go-openapi/jsonreference c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/go-openapi/spec c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/go-openapi/swag c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/gogo/protobuf/proto c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/gogo/protobuf/sortkeys c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/golang/glog c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/golang/protobuf/proto 98fa357170587e470c5f27d3c3ea0947b71eb455
+github.com/golang/snappy d9eb7a3d35ec988b8585d4a0068e462c27d28380
+github.com/google/gofuzz c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/hashicorp/consul/api daacc4be8bee214e3fc4b32a6dd385f5ef1b4c36
+github.com/hashicorp/go-cleanhttp ad28ea4487f05916463e2423a55166280e8254b5
+github.com/hashicorp/serf/coordinate 1d4fa605f6ff3ed628d7ae5eda7c0e56803e72a5
+github.com/influxdb/influxdb/client 291aaeb9485b43b16875c238482b2f7d0a22a13b
+github.com/influxdb/influxdb/tsdb 291aaeb9485b43b16875c238482b2f7d0a22a13b
+github.com/jmespath/go-jmespath bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d
+github.com/jonboulle/clockwork c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/juju/ratelimit c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/julienschmidt/httprouter 109e267447e95ad1bb48b758e40dd7453eb7b039
+github.com/mailru/easyjson/buffer c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/mailru/easyjson/jlexer c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/mailru/easyjson/jwriter c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/matttproud/golang_protobuf_extensions/pbutil fc2b8d3a73c4867e51861bbdd5ae3c1f0869dd6a
+github.com/miekg/dns 58f52c57ce9df13460ac68200cef30a008b9c468
+github.com/pborman/uuid c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/pmezard/go-difflib/difflib d77da356e56a7428ad25149ca77381849a6a5232
+github.com/prometheus/client_golang/prometheus c5b7fccd204277076155f10851dad72b76a49317
+github.com/prometheus/client_model/go fa8ad6fec33561be4280a8f0514318c79d7f6cb6
+github.com/prometheus/common/expfmt 85637ea67b04b5c3bb25e671dacded2977f8f9f6
+github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg 85637ea67b04b5c3bb25e671dacded2977f8f9f6
+github.com/prometheus/common/log 85637ea67b04b5c3bb25e671dacded2977f8f9f6
+github.com/prometheus/common/model 85637ea67b04b5c3bb25e671dacded2977f8f9f6
+github.com/prometheus/common/route 85637ea67b04b5c3bb25e671dacded2977f8f9f6
+github.com/prometheus/common/version 85637ea67b04b5c3bb25e671dacded2977f8f9f6
+github.com/prometheus/procfs abf152e5f3e97f2fafac028d2cc06c1feb87ffa5
+github.com/samuel/go-zookeeper/zk 177002e16a0061912f02377e2dd8951a8b3551bc
+github.com/spf13/pflag c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/stretchr/testify/assert d77da356e56a7428ad25149ca77381849a6a5232
+github.com/stretchr/testify/require d77da356e56a7428ad25149ca77381849a6a5232
+github.com/syndtr/goleveldb/leveldb 6b4daa5362b502898ddf367c5c11deb9e7a5c727
+github.com/syndtr/goleveldb/leveldb/cache 6b4daa5362b502898ddf367c5c11deb9e7a5c727
+github.com/syndtr/goleveldb/leveldb/comparer 6b4daa5362b502898ddf367c5c11deb9e7a5c727
+github.com/syndtr/goleveldb/leveldb/errors 6b4daa5362b502898ddf367c5c11deb9e7a5c727
+github.com/syndtr/goleveldb/leveldb/filter 6b4daa5362b502898ddf367c5c11deb9e7a5c727
+github.com/syndtr/goleveldb/leveldb/iterator 6b4daa5362b502898ddf367c5c11deb9e7a5c727
+github.com/syndtr/goleveldb/leveldb/journal 6b4daa5362b502898ddf367c5c11deb9e7a5c727
+github.com/syndtr/goleveldb/leveldb/memdb 6b4daa5362b502898ddf367c5c11deb9e7a5c727
+github.com/syndtr/goleveldb/leveldb/opt 6b4daa5362b502898ddf367c5c11deb9e7a5c727
+github.com/syndtr/goleveldb/leveldb/storage 6b4daa5362b502898ddf367c5c11deb9e7a5c727
+github.com/syndtr/goleveldb/leveldb/table 6b4daa5362b502898ddf367c5c11deb9e7a5c727
+github.com/syndtr/goleveldb/leveldb/util 6b4daa5362b502898ddf367c5c11deb9e7a5c727
+github.com/ugorji/go/codec c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/vaughan0/go-ini a98ad7ee00ec53921f08832bc06ecf7fd600e6a1
+golang.org/x/net/context b336a971b799939dd16ae9b1df8334cb8b977c4d
+golang.org/x/net/context/ctxhttp b336a971b799939dd16ae9b1df8334cb8b977c4d
+golang.org/x/net/http2 c589d0c9f0d81640c518354c7bcae77d99820aa3
+golang.org/x/net/http2/hpack c589d0c9f0d81640c518354c7bcae77d99820aa3
+golang.org/x/net/idna c589d0c9f0d81640c518354c7bcae77d99820aa3
+golang.org/x/net/internal/timeseries 6250b412798208e6c90b03b7c4f226de5aa299e2
+golang.org/x/net/lex/httplex c589d0c9f0d81640c518354c7bcae77d99820aa3
+golang.org/x/net/netutil bc3663df0ac92f928d419e31e0d2af22e683a5a2
+golang.org/x/oauth2 65a8d08c6292395d47053be10b3c5e91960def76
+golang.org/x/oauth2/google 65a8d08c6292395d47053be10b3c5e91960def76
+golang.org/x/oauth2/internal 65a8d08c6292395d47053be10b3c5e91960def76
+golang.org/x/oauth2/jws 65a8d08c6292395d47053be10b3c5e91960def76
+golang.org/x/oauth2/jwt 65a8d08c6292395d47053be10b3c5e91960def76
+golang.org/x/sys/unix c200b10b5d5e122be351b67af224adc6128af5bf
+golang.org/x/sys/windows c200b10b5d5e122be351b67af224adc6128af5bf
+golang.org/x/sys/windows/registry c200b10b5d5e122be351b67af224adc6128af5bf
+golang.org/x/sys/windows/svc/eventlog c200b10b5d5e122be351b67af224adc6128af5bf
+golang.org/x/text/cases c589d0c9f0d81640c518354c7bcae77d99820aa3
+golang.org/x/text/internal/tag c589d0c9f0d81640c518354c7bcae77d99820aa3
+golang.org/x/text/language c589d0c9f0d81640c518354c7bcae77d99820aa3
+golang.org/x/text/runes c589d0c9f0d81640c518354c7bcae77d99820aa3
+golang.org/x/text/secure/bidirule c589d0c9f0d81640c518354c7bcae77d99820aa3
+golang.org/x/text/secure/precis c589d0c9f0d81640c518354c7bcae77d99820aa3
+golang.org/x/text/transform c589d0c9f0d81640c518354c7bcae77d99820aa3
+golang.org/x/text/unicode/bidi c589d0c9f0d81640c518354c7bcae77d99820aa3
+golang.org/x/text/unicode/norm c589d0c9f0d81640c518354c7bcae77d99820aa3
+golang.org/x/text/width c589d0c9f0d81640c518354c7bcae77d99820aa3
+google.golang.org/api/compute/v1 63ade871fd3aec1225809d496e81ec91ab76ea29
+google.golang.org/api/gensupport 63ade871fd3aec1225809d496e81ec91ab76ea29
+google.golang.org/api/googleapi 63ade871fd3aec1225809d496e81ec91ab76ea29
+google.golang.org/api/googleapi/internal/uritemplates 63ade871fd3aec1225809d496e81ec91ab76ea29
+google.golang.org/appengine 267c27e7492265b84fc6719503b14a1e17975d79
+google.golang.org/appengine/internal 267c27e7492265b84fc6719503b14a1e17975d79
+google.golang.org/appengine/internal/app_identity 267c27e7492265b84fc6719503b14a1e17975d79
+google.golang.org/appengine/internal/base 267c27e7492265b84fc6719503b14a1e17975d79
+google.golang.org/appengine/internal/datastore 267c27e7492265b84fc6719503b14a1e17975d79
+google.golang.org/appengine/internal/log 267c27e7492265b84fc6719503b14a1e17975d79
+google.golang.org/appengine/internal/modules 267c27e7492265b84fc6719503b14a1e17975d79
+google.golang.org/appengine/internal/remote_api 4f7eeb5305a4ba1966344836ba4af9996b7b4e05
+google.golang.org/appengine/internal/urlfetch 267c27e7492265b84fc6719503b14a1e17975d79
+google.golang.org/appengine/urlfetch 267c27e7492265b84fc6719503b14a1e17975d79
+google.golang.org/cloud/compute/metadata 0a83eba2cadb60eb22123673c8fb6fca02b03c94
+google.golang.org/cloud/internal 0a83eba2cadb60eb22123673c8fb6fca02b03c94
+gopkg.in/fsnotify.v1 30411dbcefb7a1da7e84f75530ad3abe4011b4f8
+gopkg.in/inf.v0 c589d0c9f0d81640c518354c7bcae77d99820aa3
+gopkg.in/yaml.v2 7ad95dd0798a40da1ccdff6dff35fd177b5edf40
+k8s.io/client-go/1.5/discovery c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/kubernetes c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/kubernetes/typed/apps/v1alpha1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/kubernetes/typed/authentication/v1beta1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/kubernetes/typed/authorization/v1beta1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/kubernetes/typed/autoscaling/v1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/kubernetes/typed/batch/v1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/kubernetes/typed/certificates/v1alpha1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/kubernetes/typed/core/v1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/kubernetes/typed/extensions/v1beta1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/kubernetes/typed/policy/v1alpha1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/kubernetes/typed/rbac/v1alpha1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/kubernetes/typed/storage/v1beta1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/api c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/api/errors c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/api/install c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/api/meta c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/api/meta/metatypes c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/api/resource c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/api/unversioned c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/api/v1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/api/validation/path c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apimachinery c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apimachinery/announced c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apimachinery/registered c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/apps c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/apps/install c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/apps/v1alpha1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/authentication c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/authentication/install c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/authentication/v1beta1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/authorization c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/authorization/install c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/authorization/v1beta1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/autoscaling c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/autoscaling/install c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/autoscaling/v1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/batch c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/batch/install c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/batch/v1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/batch/v2alpha1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/certificates c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/certificates/install c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/certificates/v1alpha1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/extensions c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/extensions/install c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/extensions/v1beta1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/policy c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/policy/install c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/policy/v1alpha1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/rbac c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/rbac/install c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/rbac/v1alpha1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/storage c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/storage/install c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/storage/v1beta1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/auth/user c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/conversion c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/conversion/queryparams c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/fields c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/genericapiserver/openapi/common c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/labels c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/runtime c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/runtime/serializer c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/runtime/serializer/json c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/runtime/serializer/protobuf c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/runtime/serializer/recognizer c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/runtime/serializer/streaming c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/runtime/serializer/versioning c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/selection c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/third_party/forked/golang/reflect c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/types c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/cert c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/clock c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/errors c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/flowcontrol c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/framer c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/integer c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/intstr c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/json c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/labels c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/net c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/parsers c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/rand c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/runtime c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/sets c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/uuid c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/validation c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/validation/field c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/wait c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/yaml c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/version c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/watch c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/watch/versioned c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/plugin/pkg/client/auth c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/plugin/pkg/client/auth/gcp c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/plugin/pkg/client/auth/oidc c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/rest c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/tools/cache c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/tools/clientcmd/api c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/tools/metrics c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/transport c589d0c9f0d81640c518354c7bcae77d99820aa3
diff --git a/libgo/go/cmd/go/internal/modconv/testdata/prometheus.vjson b/libgo/go/cmd/go/internal/modconv/testdata/prometheus.vjson
new file mode 100644
index 00000000000..648bec42608
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/testdata/prometheus.vjson
@@ -0,0 +1,1605 @@
+{
+ "comment": "",
+ "ignore": "test appengine",
+ "package": [
+ {
+ "checksumSHA1": "Cslv4/ITyQmgjSUhNXFu8q5bqOU=",
+ "origin": "k8s.io/client-go/1.5/vendor/cloud.google.com/go/compute/metadata",
+ "path": "cloud.google.com/go/compute/metadata",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "hiJXjkFEGy+sDFf6O58Ocdy9Rnk=",
+ "origin": "k8s.io/client-go/1.5/vendor/cloud.google.com/go/internal",
+ "path": "cloud.google.com/go/internal",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "oIt4tXgFYnZJBsCac1BQLnTWALM=",
+ "path": "github.com/Azure/azure-sdk-for-go/arm/compute",
+ "revision": "bd73d950fa4440dae889bd9917bff7cef539f86e",
+ "revisionTime": "2016-10-28T18:31:11Z"
+ },
+ {
+ "checksumSHA1": "QKi6LiSyD5GnRK8ExpMgZl4XiMI=",
+ "path": "github.com/Azure/azure-sdk-for-go/arm/network",
+ "revision": "bd73d950fa4440dae889bd9917bff7cef539f86e",
+ "revisionTime": "2016-10-28T18:31:11Z"
+ },
+ {
+ "checksumSHA1": "eVSHe6GIHj9/ziFrQLZ1SC7Nn6k=",
+ "path": "github.com/Azure/go-autorest/autorest",
+ "revision": "8a25372bbfec739b8719a9e3987400d15ef9e179",
+ "revisionTime": "2016-10-25T18:07:34Z"
+ },
+ {
+ "checksumSHA1": "0sYi0JprevG/PZjtMbOh8h0pt0g=",
+ "path": "github.com/Azure/go-autorest/autorest/azure",
+ "revision": "8a25372bbfec739b8719a9e3987400d15ef9e179",
+ "revisionTime": "2016-10-25T18:07:34Z"
+ },
+ {
+ "checksumSHA1": "q9Qz8PAxK5FTOZwgYKe5Lj38u4c=",
+ "path": "github.com/Azure/go-autorest/autorest/date",
+ "revision": "8a25372bbfec739b8719a9e3987400d15ef9e179",
+ "revisionTime": "2016-10-25T18:07:34Z"
+ },
+ {
+ "checksumSHA1": "Ev8qCsbFjDlMlX0N2tYAhYQFpUc=",
+ "path": "github.com/Azure/go-autorest/autorest/to",
+ "revision": "8a25372bbfec739b8719a9e3987400d15ef9e179",
+ "revisionTime": "2016-10-25T18:07:34Z"
+ },
+ {
+ "checksumSHA1": "oBixceM+55gdk47iff8DSEIh3po=",
+ "path": "github.com/Azure/go-autorest/autorest/validation",
+ "revision": "8a25372bbfec739b8719a9e3987400d15ef9e179",
+ "revisionTime": "2016-10-25T18:07:34Z"
+ },
+ {
+ "checksumSHA1": "IatnluZB5jTVUncMN134e4VOV34=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/PuerkitoBio/purell",
+ "path": "github.com/PuerkitoBio/purell",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "E/Tz8z0B/gaR551g+XqPKAhcteM=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/PuerkitoBio/urlesc",
+ "path": "github.com/PuerkitoBio/urlesc",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "BdLdZP/C2uOO3lqk9X3NCKFpXa4=",
+ "path": "github.com/asaskevich/govalidator",
+ "revision": "7b3beb6df3c42abd3509abfc3bcacc0fbfb7c877",
+ "revisionTime": "2016-10-01T16:31:30Z"
+ },
+ {
+ "checksumSHA1": "WNfR3yhLjRC5/uccgju/bwrdsxQ=",
+ "path": "github.com/aws/aws-sdk-go/aws",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "Y9W+4GimK4Fuxq+vyIskVYFRnX4=",
+ "path": "github.com/aws/aws-sdk-go/aws/awserr",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "+q4vdl3l1Wom8K1wfIpJ4jlFsbY=",
+ "path": "github.com/aws/aws-sdk-go/aws/awsutil",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "/232RBWA3KnT7U+wciPS2+wmvR0=",
+ "path": "github.com/aws/aws-sdk-go/aws/client",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "ieAJ+Cvp/PKv1LpUEnUXpc3OI6E=",
+ "path": "github.com/aws/aws-sdk-go/aws/client/metadata",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "c1N3Loy3AS9zD+m5CzpPNAED39U=",
+ "path": "github.com/aws/aws-sdk-go/aws/corehandlers",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "zu5C95rmCZff6NYZb62lEaT5ibE=",
+ "path": "github.com/aws/aws-sdk-go/aws/credentials",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "KQiUK/zr3mqnAXD7x/X55/iNme0=",
+ "path": "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "NUJUTWlc1sV8b7WjfiYc4JZbXl0=",
+ "path": "github.com/aws/aws-sdk-go/aws/credentials/endpointcreds",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "4Ipx+5xN0gso+cENC2MHMWmQlR4=",
+ "path": "github.com/aws/aws-sdk-go/aws/credentials/stscreds",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "DwhFsNluCFEwqzyp3hbJR3q2Wqs=",
+ "path": "github.com/aws/aws-sdk-go/aws/defaults",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "8E0fEBUJY/1lJOyVxzTxMGQGInk=",
+ "path": "github.com/aws/aws-sdk-go/aws/ec2metadata",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "5Ac22YMTBmrX/CXaEIXzWljr8UY=",
+ "path": "github.com/aws/aws-sdk-go/aws/request",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "eOo6evLMAxQfo7Qkc5/h5euN1Sw=",
+ "path": "github.com/aws/aws-sdk-go/aws/session",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "diXvBs1LRC0RJ9WK6sllWKdzC04=",
+ "path": "github.com/aws/aws-sdk-go/aws/signer/v4",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "Esab5F8KswqkTdB4TtjSvZgs56k=",
+ "path": "github.com/aws/aws-sdk-go/private/endpoints",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "wk7EyvDaHwb5qqoOP/4d3cV0708=",
+ "path": "github.com/aws/aws-sdk-go/private/protocol",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "1QmQ3FqV37w0Zi44qv8pA1GeR0A=",
+ "path": "github.com/aws/aws-sdk-go/private/protocol/ec2query",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "ZqY5RWavBLWTo6j9xqdyBEaNFRk=",
+ "path": "github.com/aws/aws-sdk-go/private/protocol/query",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "5xzix1R8prUyWxgLnzUQoxTsfik=",
+ "path": "github.com/aws/aws-sdk-go/private/protocol/query/queryutil",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "TW/7U+/8ormL7acf6z2rv2hDD+s=",
+ "path": "github.com/aws/aws-sdk-go/private/protocol/rest",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "eUEkjyMPAuekKBE4ou+nM9tXEas=",
+ "path": "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "Eo9yODN5U99BK0pMzoqnBm7PCrY=",
+ "path": "github.com/aws/aws-sdk-go/private/waiter",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "6h4tJ9wVtbYb9wG4srtUxyPoAYM=",
+ "path": "github.com/aws/aws-sdk-go/service/ec2",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "ouwhxcAsIYQ6oJbMRdLW/Ys/iyg=",
+ "path": "github.com/aws/aws-sdk-go/service/sts",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "4QnLdmB1kG3N+KlDd1N+G9TWAGQ=",
+ "path": "github.com/beorn7/perks/quantile",
+ "revision": "3ac7bf7a47d159a033b107610db8a1b6575507a4",
+ "revisionTime": "2016-02-29T21:34:45Z"
+ },
+ {
+ "checksumSHA1": "n+s4YwtzpMWW5Rt0dEaQa7NHDGQ=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/blang/semver",
+ "path": "github.com/blang/semver",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "Z2AOGSmDKKvI6nuxa+UPjQWpIeM=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/coreos/go-oidc/http",
+ "path": "github.com/coreos/go-oidc/http",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "8yvt1xKCgNwuuavJdxRnvaIjrIc=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/coreos/go-oidc/jose",
+ "path": "github.com/coreos/go-oidc/jose",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "zhXKrWBSSJLqZxVE/Xsw0M9ynFQ=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/coreos/go-oidc/key",
+ "path": "github.com/coreos/go-oidc/key",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "bkW0mnXvmHQwHprW/6wrbpP7lAk=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/coreos/go-oidc/oauth2",
+ "path": "github.com/coreos/go-oidc/oauth2",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "E1x2k5FdhJ+dzFrh3kCmC6aJfVw=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/coreos/go-oidc/oidc",
+ "path": "github.com/coreos/go-oidc/oidc",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "O0UMBRCOD9ItMayDqLQ2MJEjkVE=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/coreos/pkg/health",
+ "path": "github.com/coreos/pkg/health",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "74vyZz/d49FZXMbFaHOfCGvSLj0=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/coreos/pkg/httputil",
+ "path": "github.com/coreos/pkg/httputil",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "etBdQ0LN6ojGunfvUt6B5C3FNrQ=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/coreos/pkg/timeutil",
+ "path": "github.com/coreos/pkg/timeutil",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "SdSd7pyjONWWTHc5XE3AhglLo34=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/davecgh/go-spew/spew",
+ "path": "github.com/davecgh/go-spew/spew",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "2Fy1Y6Z3lRRX1891WF/+HT4XS2I=",
+ "path": "github.com/dgrijalva/jwt-go",
+ "revision": "9ed569b5d1ac936e6494082958d63a6aa4fff99a",
+ "revisionTime": "2016-11-01T19:39:35Z"
+ },
+ {
+ "checksumSHA1": "f1wARLDzsF/JoyN01yoxXEwFIp8=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/docker/distribution/digest",
+ "path": "github.com/docker/distribution/digest",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "PzXRTLmmqWXxmDqdIXLcRYBma18=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/docker/distribution/reference",
+ "path": "github.com/docker/distribution/reference",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "1vQR+ZyudsjKio6RNKmWhwzGTb0=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/emicklei/go-restful",
+ "path": "github.com/emicklei/go-restful",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "3xWz4fZ9xW+CfADpYoPFcZCYJ4E=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/emicklei/go-restful/log",
+ "path": "github.com/emicklei/go-restful/log",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "J7CtF9gIs2yH9A7lPQDDrhYxiRk=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/emicklei/go-restful/swagger",
+ "path": "github.com/emicklei/go-restful/swagger",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "ww7LVo7jNJ1o6sfRcromEHKyY+o=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/ghodss/yaml",
+ "path": "github.com/ghodss/yaml",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "cVyhKIRI2gQrgpn5qrBeAqErmWM=",
+ "path": "github.com/go-ini/ini",
+ "revision": "6e4869b434bd001f6983749881c7ead3545887d8",
+ "revisionTime": "2016-08-27T06:11:18Z"
+ },
+ {
+ "checksumSHA1": "NaZnW0tKj/b0k5WzcMD0twrLbrE=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/go-openapi/jsonpointer",
+ "path": "github.com/go-openapi/jsonpointer",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "3LJXjMDxPY+veIqzQtiAvK3hXnY=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/go-openapi/jsonreference",
+ "path": "github.com/go-openapi/jsonreference",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "faeB3fny260hQ/gEfEXa1ZQTGtk=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/go-openapi/spec",
+ "path": "github.com/go-openapi/spec",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "wGpZwJ5HZtReou8A3WEV1Gdxs6k=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/go-openapi/swag",
+ "path": "github.com/go-openapi/swag",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "BIyZQL97iG7mzZ2UMR3XpiXbZdc=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/gogo/protobuf/proto",
+ "path": "github.com/gogo/protobuf/proto",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "e6cMbpJj41MpihS5eP4SIliRBK4=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/gogo/protobuf/sortkeys",
+ "path": "github.com/gogo/protobuf/sortkeys",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "URsJa4y/sUUw/STmbeYx9EKqaYE=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/golang/glog",
+ "path": "github.com/golang/glog",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "yDh5kmmr0zEF1r+rvYqbZcR7iLs=",
+ "path": "github.com/golang/protobuf/proto",
+ "revision": "98fa357170587e470c5f27d3c3ea0947b71eb455",
+ "revisionTime": "2016-10-12T20:53:35Z"
+ },
+ {
+ "checksumSHA1": "2a/SsTUBMKtcM6VtpbdPGO+c6c8=",
+ "path": "github.com/golang/snappy",
+ "revision": "d9eb7a3d35ec988b8585d4a0068e462c27d28380",
+ "revisionTime": "2016-05-29T05:00:41Z"
+ },
+ {
+ "checksumSHA1": "/yFfUp3tGt6cK22UVzbq8SjPDCU=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/google/gofuzz",
+ "path": "github.com/google/gofuzz",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "LclVLJYrBi03PBjsVPpgoMbUDQ8=",
+ "path": "github.com/hashicorp/consul/api",
+ "revision": "daacc4be8bee214e3fc4b32a6dd385f5ef1b4c36",
+ "revisionTime": "2016-10-28T04:06:46Z"
+ },
+ {
+ "checksumSHA1": "Uzyon2091lmwacNsl1hCytjhHtg=",
+ "path": "github.com/hashicorp/go-cleanhttp",
+ "revision": "ad28ea4487f05916463e2423a55166280e8254b5",
+ "revisionTime": "2016-04-07T17:41:26Z"
+ },
+ {
+ "checksumSHA1": "E3Xcanc9ouQwL+CZGOUyA/+giLg=",
+ "path": "github.com/hashicorp/serf/coordinate",
+ "revision": "1d4fa605f6ff3ed628d7ae5eda7c0e56803e72a5",
+ "revisionTime": "2016-10-07T00:41:22Z"
+ },
+ {
+ "path": "github.com/influxdb/influxdb/client",
+ "revision": "291aaeb9485b43b16875c238482b2f7d0a22a13b",
+ "revisionTime": "2015-09-16T14:41:53+02:00"
+ },
+ {
+ "path": "github.com/influxdb/influxdb/tsdb",
+ "revision": "291aaeb9485b43b16875c238482b2f7d0a22a13b",
+ "revisionTime": "2015-09-16T14:41:53+02:00"
+ },
+ {
+ "checksumSHA1": "0ZrwvB6KoGPj2PoDNSEJwxQ6Mog=",
+ "path": "github.com/jmespath/go-jmespath",
+ "revision": "bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d",
+ "revisionTime": "2016-08-03T19:07:31Z"
+ },
+ {
+ "checksumSHA1": "9ZVOEbIXnTuYpVqce4en8rwlkPE=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/jonboulle/clockwork",
+ "path": "github.com/jonboulle/clockwork",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "gA95N2LM2hEJLoqrTPaFsSWDJ2Y=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/juju/ratelimit",
+ "path": "github.com/juju/ratelimit",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "Farach1xcmsQYrhiUfkwF2rbIaE=",
+ "path": "github.com/julienschmidt/httprouter",
+ "revision": "109e267447e95ad1bb48b758e40dd7453eb7b039",
+ "revisionTime": "2015-09-05T19:25:33+02:00"
+ },
+ {
+ "checksumSHA1": "urY45++NYCue4nh4k8OjUFnIGfU=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/mailru/easyjson/buffer",
+ "path": "github.com/mailru/easyjson/buffer",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "yTDKAM4KBgOvXRsZC50zg0OChvM=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/mailru/easyjson/jlexer",
+ "path": "github.com/mailru/easyjson/jlexer",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "4+d+6rhM1pei6lBguhqSEW7LaXs=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/mailru/easyjson/jwriter",
+ "path": "github.com/mailru/easyjson/jwriter",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "Q2vw4HZBbnU8BLFt8VrzStwqSJg=",
+ "path": "github.com/matttproud/golang_protobuf_extensions/pbutil",
+ "revision": "fc2b8d3a73c4867e51861bbdd5ae3c1f0869dd6a",
+ "revisionTime": "2015-04-06T19:39:34+02:00"
+ },
+ {
+ "checksumSHA1": "Wahi4g/9XiHhSLAJ+8jskg71PCU=",
+ "path": "github.com/miekg/dns",
+ "revision": "58f52c57ce9df13460ac68200cef30a008b9c468",
+ "revisionTime": "2016-10-18T06:08:08Z"
+ },
+ {
+ "checksumSHA1": "3YJklSuzSE1Rt8A+2dhiWSmf/fw=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/pborman/uuid",
+ "path": "github.com/pborman/uuid",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "zKKp5SZ3d3ycKe4EKMNT0BqAWBw=",
+ "origin": "github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/difflib",
+ "path": "github.com/pmezard/go-difflib/difflib",
+ "revision": "d77da356e56a7428ad25149ca77381849a6a5232",
+ "revisionTime": "2016-06-15T09:26:46Z"
+ },
+ {
+ "checksumSHA1": "KkB+77Ziom7N6RzSbyUwYGrmDeU=",
+ "path": "github.com/prometheus/client_golang/prometheus",
+ "revision": "c5b7fccd204277076155f10851dad72b76a49317",
+ "revisionTime": "2016-08-17T15:48:24Z"
+ },
+ {
+ "checksumSHA1": "DvwvOlPNAgRntBzt3b3OSRMS2N4=",
+ "path": "github.com/prometheus/client_model/go",
+ "revision": "fa8ad6fec33561be4280a8f0514318c79d7f6cb6",
+ "revisionTime": "2015-02-12T10:17:44Z"
+ },
+ {
+ "checksumSHA1": "mHyjbJ3BWOfUV6q9f5PBt0gaY1k=",
+ "path": "github.com/prometheus/common/expfmt",
+ "revision": "85637ea67b04b5c3bb25e671dacded2977f8f9f6",
+ "revisionTime": "2016-10-02T21:02:34Z"
+ },
+ {
+ "checksumSHA1": "GWlM3d2vPYyNATtTFgftS10/A9w=",
+ "path": "github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg",
+ "revision": "85637ea67b04b5c3bb25e671dacded2977f8f9f6",
+ "revisionTime": "2016-10-02T21:02:34Z"
+ },
+ {
+ "checksumSHA1": "UU6hIfhVjnAYDADQEfE/3T7Ddm8=",
+ "path": "github.com/prometheus/common/log",
+ "revision": "85637ea67b04b5c3bb25e671dacded2977f8f9f6",
+ "revisionTime": "2016-10-02T21:02:34Z"
+ },
+ {
+ "checksumSHA1": "nFie+rxcX5WdIv1diZ+fu3aj6lE=",
+ "path": "github.com/prometheus/common/model",
+ "revision": "85637ea67b04b5c3bb25e671dacded2977f8f9f6",
+ "revisionTime": "2016-10-02T21:02:34Z"
+ },
+ {
+ "checksumSHA1": "QQKJYoGcY10nIHxhBEHwjwUZQzk=",
+ "path": "github.com/prometheus/common/route",
+ "revision": "85637ea67b04b5c3bb25e671dacded2977f8f9f6",
+ "revisionTime": "2016-10-02T21:02:34Z"
+ },
+ {
+ "checksumSHA1": "91KYK0SpvkaMJJA2+BcxbVnyRO0=",
+ "path": "github.com/prometheus/common/version",
+ "revision": "85637ea67b04b5c3bb25e671dacded2977f8f9f6",
+ "revisionTime": "2016-10-02T21:02:34Z"
+ },
+ {
+ "checksumSHA1": "W218eJZPXJG783fUr/z6IaAZyes=",
+ "path": "github.com/prometheus/procfs",
+ "revision": "abf152e5f3e97f2fafac028d2cc06c1feb87ffa5",
+ "revisionTime": "2016-04-11T19:08:41Z"
+ },
+ {
+ "checksumSHA1": "+49Vr4Me28p3cR+gxX5SUQHbbas=",
+ "path": "github.com/samuel/go-zookeeper/zk",
+ "revision": "177002e16a0061912f02377e2dd8951a8b3551bc",
+ "revisionTime": "2015-08-17T10:50:50-07:00"
+ },
+ {
+ "checksumSHA1": "YuPBOVkkE3uuBh4RcRUTF0n+frs=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/spf13/pflag",
+ "path": "github.com/spf13/pflag",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "iydUphwYqZRq3WhstEdGsbvBAKs=",
+ "path": "github.com/stretchr/testify/assert",
+ "revision": "d77da356e56a7428ad25149ca77381849a6a5232",
+ "revisionTime": "2016-06-15T09:26:46Z"
+ },
+ {
+ "checksumSHA1": "P9FJpir2c4G5PA46qEkaWy3l60U=",
+ "path": "github.com/stretchr/testify/require",
+ "revision": "d77da356e56a7428ad25149ca77381849a6a5232",
+ "revisionTime": "2016-06-15T09:26:46Z"
+ },
+ {
+ "checksumSHA1": "VhcnDY37sYAnL8WjfYQN9YYl+W4=",
+ "path": "github.com/syndtr/goleveldb/leveldb",
+ "revision": "6b4daa5362b502898ddf367c5c11deb9e7a5c727",
+ "revisionTime": "2016-10-11T05:00:08Z"
+ },
+ {
+ "checksumSHA1": "EKIow7XkgNdWvR/982ffIZxKG8Y=",
+ "path": "github.com/syndtr/goleveldb/leveldb/cache",
+ "revision": "6b4daa5362b502898ddf367c5c11deb9e7a5c727",
+ "revisionTime": "2016-10-11T05:00:08Z"
+ },
+ {
+ "checksumSHA1": "5KPgnvCPlR0ysDAqo6jApzRQ3tw=",
+ "path": "github.com/syndtr/goleveldb/leveldb/comparer",
+ "revision": "6b4daa5362b502898ddf367c5c11deb9e7a5c727",
+ "revisionTime": "2016-10-11T05:00:08Z"
+ },
+ {
+ "checksumSHA1": "1DRAxdlWzS4U0xKN/yQ/fdNN7f0=",
+ "path": "github.com/syndtr/goleveldb/leveldb/errors",
+ "revision": "6b4daa5362b502898ddf367c5c11deb9e7a5c727",
+ "revisionTime": "2016-10-11T05:00:08Z"
+ },
+ {
+ "checksumSHA1": "eqKeD6DS7eNCtxVYZEHHRKkyZrw=",
+ "path": "github.com/syndtr/goleveldb/leveldb/filter",
+ "revision": "6b4daa5362b502898ddf367c5c11deb9e7a5c727",
+ "revisionTime": "2016-10-11T05:00:08Z"
+ },
+ {
+ "checksumSHA1": "8dXuAVIsbtaMiGGuHjzGR6Ny/5c=",
+ "path": "github.com/syndtr/goleveldb/leveldb/iterator",
+ "revision": "6b4daa5362b502898ddf367c5c11deb9e7a5c727",
+ "revisionTime": "2016-10-11T05:00:08Z"
+ },
+ {
+ "checksumSHA1": "gJY7bRpELtO0PJpZXgPQ2BYFJ88=",
+ "path": "github.com/syndtr/goleveldb/leveldb/journal",
+ "revision": "6b4daa5362b502898ddf367c5c11deb9e7a5c727",
+ "revisionTime": "2016-10-11T05:00:08Z"
+ },
+ {
+ "checksumSHA1": "j+uaQ6DwJ50dkIdfMQu1TXdlQcY=",
+ "path": "github.com/syndtr/goleveldb/leveldb/memdb",
+ "revision": "6b4daa5362b502898ddf367c5c11deb9e7a5c727",
+ "revisionTime": "2016-10-11T05:00:08Z"
+ },
+ {
+ "checksumSHA1": "UmQeotV+m8/FduKEfLOhjdp18rs=",
+ "path": "github.com/syndtr/goleveldb/leveldb/opt",
+ "revision": "6b4daa5362b502898ddf367c5c11deb9e7a5c727",
+ "revisionTime": "2016-10-11T05:00:08Z"
+ },
+ {
+ "checksumSHA1": "/Wvv9HeJTN9UUjdjwUlz7X4ioIo=",
+ "path": "github.com/syndtr/goleveldb/leveldb/storage",
+ "revision": "6b4daa5362b502898ddf367c5c11deb9e7a5c727",
+ "revisionTime": "2016-10-11T05:00:08Z"
+ },
+ {
+ "checksumSHA1": "JTJA+u8zk7EXy1UUmpFPNGvtO2A=",
+ "path": "github.com/syndtr/goleveldb/leveldb/table",
+ "revision": "6b4daa5362b502898ddf367c5c11deb9e7a5c727",
+ "revisionTime": "2016-10-11T05:00:08Z"
+ },
+ {
+ "checksumSHA1": "4zil8Gwg8VPkDn1YzlgCvtukJFU=",
+ "path": "github.com/syndtr/goleveldb/leveldb/util",
+ "revision": "6b4daa5362b502898ddf367c5c11deb9e7a5c727",
+ "revisionTime": "2016-10-11T05:00:08Z"
+ },
+ {
+ "checksumSHA1": "f6Aew+ZA+HBAXCw6/xTST3mB0Lw=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/ugorji/go/codec",
+ "path": "github.com/ugorji/go/codec",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "sFD8LpJPQtWLwGda3edjf5mNUbs=",
+ "path": "github.com/vaughan0/go-ini",
+ "revision": "a98ad7ee00ec53921f08832bc06ecf7fd600e6a1",
+ "revisionTime": "2013-09-23T16:52:12+02:00"
+ },
+ {
+ "checksumSHA1": "9jjO5GjLa0XF/nfWihF02RoH4qc=",
+ "path": "golang.org/x/net/context",
+ "revision": "b336a971b799939dd16ae9b1df8334cb8b977c4d",
+ "revisionTime": "2016-10-27T19:58:04Z"
+ },
+ {
+ "checksumSHA1": "WHc3uByvGaMcnSoI21fhzYgbOgg=",
+ "path": "golang.org/x/net/context/ctxhttp",
+ "revision": "b336a971b799939dd16ae9b1df8334cb8b977c4d",
+ "revisionTime": "2016-10-27T19:58:04Z"
+ },
+ {
+ "checksumSHA1": "SPYGC6DQrH9jICccUsOfbvvhB4g=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/net/http2",
+ "path": "golang.org/x/net/http2",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "EYNaHp7XdLWRydUCE0amEkKAtgk=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/net/http2/hpack",
+ "path": "golang.org/x/net/http2/hpack",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "gXiSniT8fevWOVPVKopYgrdzi60=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/net/idna",
+ "path": "golang.org/x/net/idna",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "/k7k6eJDkxXx6K9Zpo/OwNm58XM=",
+ "path": "golang.org/x/net/internal/timeseries",
+ "revision": "6250b412798208e6c90b03b7c4f226de5aa299e2",
+ "revisionTime": "2016-08-24T22:20:41Z"
+ },
+ {
+ "checksumSHA1": "yhndhWXMs/VSEDLks4dNyFMQStA=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/net/lex/httplex",
+ "path": "golang.org/x/net/lex/httplex",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "7WASrg0PEueWDDRHkFhEEN6Qrms=",
+ "path": "golang.org/x/net/netutil",
+ "revision": "bc3663df0ac92f928d419e31e0d2af22e683a5a2",
+ "revisionTime": "2016-06-21T20:48:10Z"
+ },
+ {
+ "checksumSHA1": "mktBVED98G2vv+OKcSgtnFVZC1Y=",
+ "path": "golang.org/x/oauth2",
+ "revision": "65a8d08c6292395d47053be10b3c5e91960def76",
+ "revisionTime": "2016-06-07T03:33:14Z"
+ },
+ {
+ "checksumSHA1": "2rk6lthfQa5Rfydj8j7+dilKGbo=",
+ "path": "golang.org/x/oauth2/google",
+ "revision": "65a8d08c6292395d47053be10b3c5e91960def76",
+ "revisionTime": "2016-06-07T03:33:14Z"
+ },
+ {
+ "checksumSHA1": "W/GiDqzsagBnR7/yEvxatMhUDBs=",
+ "path": "golang.org/x/oauth2/internal",
+ "revision": "65a8d08c6292395d47053be10b3c5e91960def76",
+ "revisionTime": "2016-06-07T03:33:14Z"
+ },
+ {
+ "checksumSHA1": "CPTYHWrVL4jA0B1IuC0hvgcE2AQ=",
+ "path": "golang.org/x/oauth2/jws",
+ "revision": "65a8d08c6292395d47053be10b3c5e91960def76",
+ "revisionTime": "2016-06-07T03:33:14Z"
+ },
+ {
+ "checksumSHA1": "xifBSq0Pn6pIoPA/o3tyzq8X4Ds=",
+ "path": "golang.org/x/oauth2/jwt",
+ "revision": "65a8d08c6292395d47053be10b3c5e91960def76",
+ "revisionTime": "2016-06-07T03:33:14Z"
+ },
+ {
+ "checksumSHA1": "aVgPDgwY3/t4J/JOw9H3FVMHqh0=",
+ "path": "golang.org/x/sys/unix",
+ "revision": "c200b10b5d5e122be351b67af224adc6128af5bf",
+ "revisionTime": "2016-10-22T18:22:21Z"
+ },
+ {
+ "checksumSHA1": "fpW2dhGFC6SrVzipJx7fjg2DIH8=",
+ "path": "golang.org/x/sys/windows",
+ "revision": "c200b10b5d5e122be351b67af224adc6128af5bf",
+ "revisionTime": "2016-10-22T18:22:21Z"
+ },
+ {
+ "checksumSHA1": "PjYlbMS0ttyZYlaevvjA/gV3g1c=",
+ "path": "golang.org/x/sys/windows/registry",
+ "revision": "c200b10b5d5e122be351b67af224adc6128af5bf",
+ "revisionTime": "2016-10-22T18:22:21Z"
+ },
+ {
+ "checksumSHA1": "uVlUSSKplihZG7N+QJ6fzDZ4Kh8=",
+ "path": "golang.org/x/sys/windows/svc/eventlog",
+ "revision": "c200b10b5d5e122be351b67af224adc6128af5bf",
+ "revisionTime": "2016-10-22T18:22:21Z"
+ },
+ {
+ "checksumSHA1": "QQpKbWuqvhmxVr/hfEYdWzzcXRM=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/text/cases",
+ "path": "golang.org/x/text/cases",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "iAsGo/kxvnwILbJVUCd0ZcqZO/Q=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/text/internal/tag",
+ "path": "golang.org/x/text/internal/tag",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "mQ6PCGHY7K0oPjKbYD8wsTjm/P8=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/text/language",
+ "path": "golang.org/x/text/language",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "WpeH2TweiuiZAQVTJNO5vyZAQQA=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/text/runes",
+ "path": "golang.org/x/text/runes",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "1VjEPyjdi0xOiIN/Alkqiad/B/c=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/text/secure/bidirule",
+ "path": "golang.org/x/text/secure/bidirule",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "FcK7VslktIAWj5jnWVnU2SesBq0=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/text/secure/precis",
+ "path": "golang.org/x/text/secure/precis",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "nwlu7UTwYbCj9l5f3a7t2ROwNzM=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/text/transform",
+ "path": "golang.org/x/text/transform",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "nWJ9R1+Xw41f/mM3b7BYtv77CfI=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/text/unicode/bidi",
+ "path": "golang.org/x/text/unicode/bidi",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "BAZ96wCGUj6HdY9sG60Yw09KWA4=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/text/unicode/norm",
+ "path": "golang.org/x/text/unicode/norm",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "AZMILKWqLP99UilLgbGZ+uzIVrM=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/text/width",
+ "path": "golang.org/x/text/width",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "AjdmRXf0fiy6Bec9mNlsGsmZi1k=",
+ "path": "google.golang.org/api/compute/v1",
+ "revision": "63ade871fd3aec1225809d496e81ec91ab76ea29",
+ "revisionTime": "2016-05-31T06:42:46Z"
+ },
+ {
+ "checksumSHA1": "OtsMVXY89Hc/bBXdDp84atFQawM=",
+ "path": "google.golang.org/api/gensupport",
+ "revision": "63ade871fd3aec1225809d496e81ec91ab76ea29",
+ "revisionTime": "2016-05-31T06:42:46Z"
+ },
+ {
+ "checksumSHA1": "yQREK/OWrz9PLljbr127+xFk6J0=",
+ "path": "google.golang.org/api/googleapi",
+ "revision": "63ade871fd3aec1225809d496e81ec91ab76ea29",
+ "revisionTime": "2016-05-31T06:42:46Z"
+ },
+ {
+ "checksumSHA1": "ii4ET3JHk3vkMUEcg+9t/1RZSUU=",
+ "path": "google.golang.org/api/googleapi/internal/uritemplates",
+ "revision": "63ade871fd3aec1225809d496e81ec91ab76ea29",
+ "revisionTime": "2016-05-31T06:42:46Z"
+ },
+ {
+ "checksumSHA1": "N3KZEuQ9O1QwJXcCJbe7Czwroo4=",
+ "path": "google.golang.org/appengine",
+ "revision": "267c27e7492265b84fc6719503b14a1e17975d79",
+ "revisionTime": "2016-06-21T05:59:22Z"
+ },
+ {
+ "checksumSHA1": "G9Xp1ScdsfcKsw+PcWunivRRP3o=",
+ "path": "google.golang.org/appengine/internal",
+ "revision": "267c27e7492265b84fc6719503b14a1e17975d79",
+ "revisionTime": "2016-06-21T05:59:22Z"
+ },
+ {
+ "checksumSHA1": "x6Thdfyasqd68dWZWqzWWeIfAfI=",
+ "path": "google.golang.org/appengine/internal/app_identity",
+ "revision": "267c27e7492265b84fc6719503b14a1e17975d79",
+ "revisionTime": "2016-06-21T05:59:22Z"
+ },
+ {
+ "checksumSHA1": "TsNO8P0xUlLNyh3Ic/tzSp/fDWM=",
+ "path": "google.golang.org/appengine/internal/base",
+ "revision": "267c27e7492265b84fc6719503b14a1e17975d79",
+ "revisionTime": "2016-06-21T05:59:22Z"
+ },
+ {
+ "checksumSHA1": "5QsV5oLGSfKZqTCVXP6NRz5T4Tw=",
+ "path": "google.golang.org/appengine/internal/datastore",
+ "revision": "267c27e7492265b84fc6719503b14a1e17975d79",
+ "revisionTime": "2016-06-21T05:59:22Z"
+ },
+ {
+ "checksumSHA1": "Gep2T9zmVYV8qZfK2gu3zrmG6QE=",
+ "path": "google.golang.org/appengine/internal/log",
+ "revision": "267c27e7492265b84fc6719503b14a1e17975d79",
+ "revisionTime": "2016-06-21T05:59:22Z"
+ },
+ {
+ "checksumSHA1": "eLZVX1EHLclFtQnjDIszsdyWRHo=",
+ "path": "google.golang.org/appengine/internal/modules",
+ "revision": "267c27e7492265b84fc6719503b14a1e17975d79",
+ "revisionTime": "2016-06-21T05:59:22Z"
+ },
+ {
+ "checksumSHA1": "a1XY7rz3BieOVqVI2Et6rKiwQCk=",
+ "path": "google.golang.org/appengine/internal/remote_api",
+ "revision": "4f7eeb5305a4ba1966344836ba4af9996b7b4e05",
+ "revisionTime": "2016-08-19T23:33:10Z"
+ },
+ {
+ "checksumSHA1": "QtAbHtHmDzcf6vOV9eqlCpKgjiw=",
+ "path": "google.golang.org/appengine/internal/urlfetch",
+ "revision": "267c27e7492265b84fc6719503b14a1e17975d79",
+ "revisionTime": "2016-06-21T05:59:22Z"
+ },
+ {
+ "checksumSHA1": "akOV9pYnCbcPA8wJUutSQVibdyg=",
+ "path": "google.golang.org/appengine/urlfetch",
+ "revision": "267c27e7492265b84fc6719503b14a1e17975d79",
+ "revisionTime": "2016-06-21T05:59:22Z"
+ },
+ {
+ "checksumSHA1": "Wp8g9MHRmK8SwcyGVCoGtPx+5Lo=",
+ "path": "google.golang.org/cloud/compute/metadata",
+ "revision": "0a83eba2cadb60eb22123673c8fb6fca02b03c94",
+ "revisionTime": "2016-06-21T15:59:29Z"
+ },
+ {
+ "checksumSHA1": "U7dGDNwEHORvJFMoNSXErKE7ITg=",
+ "path": "google.golang.org/cloud/internal",
+ "revision": "0a83eba2cadb60eb22123673c8fb6fca02b03c94",
+ "revisionTime": "2016-06-21T15:59:29Z"
+ },
+ {
+ "checksumSHA1": "JfVmsMwyeeepbdw4q4wpN07BuFg=",
+ "path": "gopkg.in/fsnotify.v1",
+ "revision": "30411dbcefb7a1da7e84f75530ad3abe4011b4f8",
+ "revisionTime": "2016-04-12T13:37:56Z"
+ },
+ {
+ "checksumSHA1": "pfQwQtWlFezJq0Viroa/L+v+yDM=",
+ "origin": "k8s.io/client-go/1.5/vendor/gopkg.in/inf.v0",
+ "path": "gopkg.in/inf.v0",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "KgT+peLCcuh0/m2mpoOZXuxXmwc=",
+ "path": "gopkg.in/yaml.v2",
+ "revision": "7ad95dd0798a40da1ccdff6dff35fd177b5edf40",
+ "revisionTime": "2015-06-24T11:29:02+01:00"
+ },
+ {
+ "checksumSHA1": "st0Nbu4zwLcP3mz03lDOJVZtn8Y=",
+ "path": "k8s.io/client-go/1.5/discovery",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "S+OzpkipMb46LGZoWuveqSLAcoM=",
+ "path": "k8s.io/client-go/1.5/kubernetes",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "yCBn8ig1TUMrk+ljtK0nDr7E5Vo=",
+ "path": "k8s.io/client-go/1.5/kubernetes/typed/apps/v1alpha1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "ZRnUz5NrpvJsXAjtnRdEv5UYhSI=",
+ "path": "k8s.io/client-go/1.5/kubernetes/typed/authentication/v1beta1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "TY55Np20olmPMzXgfVlIUIyqv04=",
+ "path": "k8s.io/client-go/1.5/kubernetes/typed/authorization/v1beta1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "FRByJsFff/6lPH20FtJPaK1NPWI=",
+ "path": "k8s.io/client-go/1.5/kubernetes/typed/autoscaling/v1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "3Cy2as7HnQ2FDcvpNbatpFWx0P4=",
+ "path": "k8s.io/client-go/1.5/kubernetes/typed/batch/v1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "RUKywApIbSLLsfkYxXzifh7HIvs=",
+ "path": "k8s.io/client-go/1.5/kubernetes/typed/certificates/v1alpha1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "4+Lsxu+sYgzsS2JOHP7CdrZLSKc=",
+ "path": "k8s.io/client-go/1.5/kubernetes/typed/core/v1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "H8jzevN03YUfmf2krJt0qj2P9sU=",
+ "path": "k8s.io/client-go/1.5/kubernetes/typed/extensions/v1beta1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "hrpA6xxtwj3oMcQbFxI2cDhO2ZA=",
+ "path": "k8s.io/client-go/1.5/kubernetes/typed/policy/v1alpha1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "B2+F12NeMwrOHvHK2ALyEcr3UGA=",
+ "path": "k8s.io/client-go/1.5/kubernetes/typed/rbac/v1alpha1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "h2eSNUym87RWPlez7UKujShwrUQ=",
+ "path": "k8s.io/client-go/1.5/kubernetes/typed/storage/v1beta1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "+oIykJ3A0wYjAWbbrGo0jNnMLXw=",
+ "path": "k8s.io/client-go/1.5/pkg/api",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "UsUsIdhuy5Ej2vI0hbmSsrimoaQ=",
+ "path": "k8s.io/client-go/1.5/pkg/api/errors",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "Eo6LLHFqG6YznIAKr2mVjuqUj6k=",
+ "path": "k8s.io/client-go/1.5/pkg/api/install",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "dYznkLcCEai21z1dX8kZY7uDsck=",
+ "path": "k8s.io/client-go/1.5/pkg/api/meta",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "b06esG4xMj/YNFD85Lqq00cx+Yo=",
+ "path": "k8s.io/client-go/1.5/pkg/api/meta/metatypes",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "L9svak1yut0Mx8r9VLDOwpqZzBk=",
+ "path": "k8s.io/client-go/1.5/pkg/api/resource",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "m7jGshKDLH9kdokfa6MwAqzxRQk=",
+ "path": "k8s.io/client-go/1.5/pkg/api/unversioned",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "iI6s5WAexr1PEfqrbvuscB+oVik=",
+ "path": "k8s.io/client-go/1.5/pkg/api/v1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "ikac34qI/IkTWHnfi8pPl9irPyo=",
+ "path": "k8s.io/client-go/1.5/pkg/api/validation/path",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "MJyygSPp8N6z+7SPtcROz4PEwas=",
+ "path": "k8s.io/client-go/1.5/pkg/apimachinery",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "EGb4IcSTQ1VXCmX0xcyG5GpWId8=",
+ "path": "k8s.io/client-go/1.5/pkg/apimachinery/announced",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "vhSyuINHQhCsDKTyBmvJT1HzDHI=",
+ "path": "k8s.io/client-go/1.5/pkg/apimachinery/registered",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "rXeBnwLg8ZFe6m5/Ki7tELVBYDk=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/apps",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "KzHaG858KV1tBh5cuLInNcm+G5s=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/apps/install",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "fynWdchlRbPaxuST2oGDKiKLTqE=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/apps/v1alpha1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "hreIYssoH4Ef/+Aglpitn3GNLR4=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/authentication",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "EgUqJH4CqB9vXVg6T8II2OEt5LE=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/authentication/install",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "Z3DKgomzRPGcBv/8hlL6pfnIpXI=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/authentication/v1beta1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "GpuScB2Z+NOT4WIQg1mVvVSDUts=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/authorization",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "+u3UD+HY9lBH+PFi/2B4W564JEw=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/authorization/install",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "zIFzgWjmlWNLHGHMpCpDCvoLtKY=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/authorization/v1beta1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "tdpzQFQyVkt5kCLTvtKTVqT+maE=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/autoscaling",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "nb6LbYGS5tv8H8Ovptg6M7XuDZ4=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/autoscaling/install",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "DNb1/nl/5RDdckRrJoXBRagzJXs=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/autoscaling/v1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "4bLhH2vNl5l4Qp6MjLhWyWVAPE0=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/batch",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "RpAAEynmxlvOlLLZK1KEUQRnYzk=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/batch/install",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "uWJ2BHmjL/Gq4FFlNkqiN6vvPyM=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/batch/v1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "mHWt/p724dKeP1vqLtWQCye7zaE=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/batch/v2alpha1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "6dJ1dGfXkB3A42TOtMaY/rvv4N8=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/certificates",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "Bkrhm6HbFYANwtzUE8eza9SWBk0=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/certificates/install",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "nRRPIBQ5O3Ad24kscNtK+gPC+fk=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/certificates/v1alpha1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "KUMhoaOg9GXHN/aAVvSLO18SgqU=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/extensions",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "eSo2VhNAYtesvmpEPqn05goW4LY=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/extensions/install",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "DunWIPrCC5iGMWzkaaugMOxD+hg=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/extensions/v1beta1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "rVGYi2ko0E7vL5OZSMYX+NAGPYw=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/policy",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "llJHd2H0LzABGB6BcletzIHnexo=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/policy/install",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "j44bqyY13ldnuCtysYE8nRkMD7o=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/policy/v1alpha1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "vT7rFxowcKMTYc55mddePqUFRgE=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/rbac",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "r1MzUXsG+Zyn30aU8I5R5dgrJPA=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/rbac/install",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "aNfO8xn8VDO3fM9CpVCe6EIB+GA=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/rbac/v1alpha1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "rQCxrbisCXmj2wymlYG63kcTL9I=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/storage",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "wZyxh5nt5Eh6kF7YNAIYukKWWy0=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/storage/install",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "P8ANOt/I4Cs3QtjVXWmDA/gpQdg=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/storage/v1beta1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "qnVPwzvNLz2mmr3BXdU9qIhQXXU=",
+ "path": "k8s.io/client-go/1.5/pkg/auth/user",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "KrIchxhapSs242yAy8yrTS1XlZo=",
+ "path": "k8s.io/client-go/1.5/pkg/conversion",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "weZqKFcOhcnF47eDDHXzluCKSF0=",
+ "path": "k8s.io/client-go/1.5/pkg/conversion/queryparams",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "T3EMfyXZX5939/OOQ1JU+Nmbk4k=",
+ "path": "k8s.io/client-go/1.5/pkg/fields",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "2v11s3EBH8UBl2qfImT29tQN2kM=",
+ "path": "k8s.io/client-go/1.5/pkg/genericapiserver/openapi/common",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "GvBlph6PywK3zguou/T9kKNNdoQ=",
+ "path": "k8s.io/client-go/1.5/pkg/labels",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "Vtrgy827r0rWzIAgvIWY4flu740=",
+ "path": "k8s.io/client-go/1.5/pkg/runtime",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "SEcZqRATexhgHvDn+eHvMc07UJs=",
+ "path": "k8s.io/client-go/1.5/pkg/runtime/serializer",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "qzYKG9YZSj8l/W1QVTOrGAry/BM=",
+ "path": "k8s.io/client-go/1.5/pkg/runtime/serializer/json",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "F7h+8zZ0JPLYkac4KgSVljguBE4=",
+ "path": "k8s.io/client-go/1.5/pkg/runtime/serializer/protobuf",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "CvySOL8C85e3y7EWQ+Au4cwUZJM=",
+ "path": "k8s.io/client-go/1.5/pkg/runtime/serializer/recognizer",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "eCitoKeIun+lJzYFhAfdSIIicSM=",
+ "path": "k8s.io/client-go/1.5/pkg/runtime/serializer/streaming",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "kVWvZuLGltJ4YqQsiaCLRRLDDK0=",
+ "path": "k8s.io/client-go/1.5/pkg/runtime/serializer/versioning",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "m51+LAeQ9RK1KHX+l2iGcwbVCKs=",
+ "path": "k8s.io/client-go/1.5/pkg/selection",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "dp4IWcC3U6a0HeOdVCDQWODWCbw=",
+ "path": "k8s.io/client-go/1.5/pkg/third_party/forked/golang/reflect",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "ER898XJD1ox4d71gKZD8TLtTSpM=",
+ "path": "k8s.io/client-go/1.5/pkg/types",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "BVdXtnLDlmBQksRPfHOIG+qdeVg=",
+ "path": "k8s.io/client-go/1.5/pkg/util",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "nnh8Sa4dCupxRI4bbKaozGp1d/A=",
+ "path": "k8s.io/client-go/1.5/pkg/util/cert",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "S32d5uduNlwouM8+mIz+ALpliUQ=",
+ "path": "k8s.io/client-go/1.5/pkg/util/clock",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "Y6rWC0TUw2/uUeUjJ7kazyEUzBQ=",
+ "path": "k8s.io/client-go/1.5/pkg/util/errors",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "C7IfEAdCOePw3/IraaZCNXuYXLw=",
+ "path": "k8s.io/client-go/1.5/pkg/util/flowcontrol",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "EuslQHnhBSRXaWimYqLEqhMPV48=",
+ "path": "k8s.io/client-go/1.5/pkg/util/framer",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "ByO18NbZwiifFr8qtLyfJAHXguA=",
+ "path": "k8s.io/client-go/1.5/pkg/util/integer",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "ww+RfsoIlUBDwThg2oqC5QVz33Y=",
+ "path": "k8s.io/client-go/1.5/pkg/util/intstr",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "7E8f8dLlXW7u6r9sggMjvB4HEiw=",
+ "path": "k8s.io/client-go/1.5/pkg/util/json",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "d0pFZxMJG9j95acNmaIM1l+X+QU=",
+ "path": "k8s.io/client-go/1.5/pkg/util/labels",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "wCN7u1lE+25neM9jXeI7aE8EAfk=",
+ "path": "k8s.io/client-go/1.5/pkg/util/net",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "g+kBkxcb+tYmFtRRly+VE+JAIfw=",
+ "path": "k8s.io/client-go/1.5/pkg/util/parsers",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "S4wUnE5VkaWWrkLbgPL/1oNLJ4g=",
+ "path": "k8s.io/client-go/1.5/pkg/util/rand",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "8j9c2PqTKybtnymXbStNYRexRj8=",
+ "path": "k8s.io/client-go/1.5/pkg/util/runtime",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "aAz4e8hLGs0+ZAz1TdA5tY/9e1A=",
+ "path": "k8s.io/client-go/1.5/pkg/util/sets",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "P/fwh6QZ5tsjVyHTaASDWL3WaGs=",
+ "path": "k8s.io/client-go/1.5/pkg/util/uuid",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "P9Bq/1qbF4SvnN9HyCTRpbUz7sQ=",
+ "path": "k8s.io/client-go/1.5/pkg/util/validation",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "D0JIEjlP69cuPOZEdsSKeFgsnI8=",
+ "path": "k8s.io/client-go/1.5/pkg/util/validation/field",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "T7ba8t8i+BtgClMgL+aMZM94fcI=",
+ "path": "k8s.io/client-go/1.5/pkg/util/wait",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "6RCTv/KDiw7as4KeyrgU3XrUSQI=",
+ "path": "k8s.io/client-go/1.5/pkg/util/yaml",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "OwKlsSeKtz1FBVC9cQ5gWRL5pKc=",
+ "path": "k8s.io/client-go/1.5/pkg/version",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "Oil9WGw/dODbpBopn6LWQGS3DYg=",
+ "path": "k8s.io/client-go/1.5/pkg/watch",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "r5alnRCbLaPsbTeJjjTVn/bt6uw=",
+ "path": "k8s.io/client-go/1.5/pkg/watch/versioned",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "X1+ltyfHui/XCwDupXIf39+9gWQ=",
+ "path": "k8s.io/client-go/1.5/plugin/pkg/client/auth",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "KYy+js37AS0ZT08g5uBr1ZoMPmE=",
+ "path": "k8s.io/client-go/1.5/plugin/pkg/client/auth/gcp",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "wQ9G5++lbQpejqCzGHo037N3YcY=",
+ "path": "k8s.io/client-go/1.5/plugin/pkg/client/auth/oidc",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "ABe8YfZVEDoRpAUqp2BKP8o1VIA=",
+ "path": "k8s.io/client-go/1.5/rest",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "Gbe0Vs9hkI7X5hhbXUuWdRFffSI=",
+ "path": "k8s.io/client-go/1.5/tools/cache",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "K/oOznXABjqSS1c2Fs407c5F8KA=",
+ "path": "k8s.io/client-go/1.5/tools/clientcmd/api",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "c1PQ4WJRfpA9BYcFHW2+46hu5IE=",
+ "path": "k8s.io/client-go/1.5/tools/metrics",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "e4W2q+6wvjejv3V0UCI1mewTTro=",
+ "path": "k8s.io/client-go/1.5/transport",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ }
+ ],
+ "rootPath": "github.com/prometheus/prometheus"
+}
diff --git a/libgo/go/cmd/go/internal/modconv/testdata/upspin.dep b/libgo/go/cmd/go/internal/modconv/testdata/upspin.dep
new file mode 100644
index 00000000000..be77bcb9284
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/testdata/upspin.dep
@@ -0,0 +1,57 @@
+# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
+
+
+[[projects]]
+ branch = "master"
+ name = "bazil.org/fuse"
+ packages = [".","fs","fuseutil"]
+ revision = "371fbbdaa8987b715bdd21d6adc4c9b20155f748"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/NYTimes/gziphandler"
+ packages = ["."]
+ revision = "97ae7fbaf81620fe97840685304a78a306a39c64"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/golang/protobuf"
+ packages = ["proto"]
+ revision = "1643683e1b54a9e88ad26d98f81400c8c9d9f4f9"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/russross/blackfriday"
+ packages = ["."]
+ revision = "6d1ef893fcb01b4f50cb6e57ed7df3e2e627b6b2"
+
+[[projects]]
+ branch = "master"
+ name = "golang.org/x/crypto"
+ packages = ["acme","acme/autocert","hkdf"]
+ revision = "13931e22f9e72ea58bb73048bc752b48c6d4d4ac"
+
+[[projects]]
+ branch = "master"
+ name = "golang.org/x/net"
+ packages = ["context"]
+ revision = "4b14673ba32bee7f5ac0f990a48f033919fd418b"
+
+[[projects]]
+ branch = "master"
+ name = "golang.org/x/text"
+ packages = ["cases","internal","internal/gen","internal/tag","internal/triegen","internal/ucd","language","runes","secure/bidirule","secure/precis","transform","unicode/bidi","unicode/cldr","unicode/norm","unicode/rangetable","width"]
+ revision = "6eab0e8f74e86c598ec3b6fad4888e0c11482d48"
+
+[[projects]]
+ branch = "v2"
+ name = "gopkg.in/yaml.v2"
+ packages = ["."]
+ revision = "eb3733d160e74a9c7e442f435eb3bea458e1d19f"
+
+[solve-meta]
+ analyzer-name = "dep"
+ analyzer-version = 1
+ inputs-digest = "2246e647ba1c78b0b9f948f9fb072fff1467284fb138709c063e99736f646b90"
+ solver-name = "gps-cdcl"
+ solver-version = 1
diff --git a/libgo/go/cmd/go/internal/modconv/testdata/upspin.out b/libgo/go/cmd/go/internal/modconv/testdata/upspin.out
new file mode 100644
index 00000000000..00597db8484
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/testdata/upspin.out
@@ -0,0 +1,8 @@
+bazil.org/fuse 371fbbdaa8987b715bdd21d6adc4c9b20155f748
+github.com/NYTimes/gziphandler 97ae7fbaf81620fe97840685304a78a306a39c64
+github.com/golang/protobuf 1643683e1b54a9e88ad26d98f81400c8c9d9f4f9
+github.com/russross/blackfriday 6d1ef893fcb01b4f50cb6e57ed7df3e2e627b6b2
+golang.org/x/crypto 13931e22f9e72ea58bb73048bc752b48c6d4d4ac
+golang.org/x/net 4b14673ba32bee7f5ac0f990a48f033919fd418b
+golang.org/x/text 6eab0e8f74e86c598ec3b6fad4888e0c11482d48
+gopkg.in/yaml.v2 eb3733d160e74a9c7e442f435eb3bea458e1d19f
diff --git a/libgo/go/cmd/go/internal/modconv/tsv.go b/libgo/go/cmd/go/internal/modconv/tsv.go
new file mode 100644
index 00000000000..feba181e052
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/tsv.go
@@ -0,0 +1,24 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modconv
+
+import (
+ "strings"
+
+ "cmd/go/internal/modfile"
+ "cmd/go/internal/module"
+)
+
+func ParseDependenciesTSV(file string, data []byte) (*modfile.File, error) {
+ mf := new(modfile.File)
+ for lineno, line := range strings.Split(string(data), "\n") {
+ lineno++
+ f := strings.Split(line, "\t")
+ if len(f) >= 3 {
+ mf.Require = append(mf.Require, &modfile.Require{Mod: module.Version{Path: f[0], Version: f[2]}})
+ }
+ }
+ return mf, nil
+}
diff --git a/libgo/go/cmd/go/internal/modconv/vconf.go b/libgo/go/cmd/go/internal/modconv/vconf.go
new file mode 100644
index 00000000000..a9a8e62518f
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/vconf.go
@@ -0,0 +1,27 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modconv
+
+import (
+ "strings"
+
+ "cmd/go/internal/modfile"
+ "cmd/go/internal/module"
+)
+
+func ParseVendorConf(file string, data []byte) (*modfile.File, error) {
+ mf := new(modfile.File)
+ for lineno, line := range strings.Split(string(data), "\n") {
+ lineno++
+ if i := strings.Index(line, "#"); i >= 0 {
+ line = line[:i]
+ }
+ f := strings.Fields(line)
+ if len(f) >= 2 {
+ mf.Require = append(mf.Require, &modfile.Require{Mod: module.Version{Path: f[0], Version: f[1]}})
+ }
+ }
+ return mf, nil
+}
diff --git a/libgo/go/cmd/go/internal/modconv/vjson.go b/libgo/go/cmd/go/internal/modconv/vjson.go
new file mode 100644
index 00000000000..eec86b73398
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/vjson.go
@@ -0,0 +1,29 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modconv
+
+import (
+ "encoding/json"
+
+ "cmd/go/internal/modfile"
+ "cmd/go/internal/module"
+)
+
+func ParseVendorJSON(file string, data []byte) (*modfile.File, error) {
+ var cfg struct {
+ Package []struct {
+ Path string
+ Revision string
+ }
+ }
+ if err := json.Unmarshal(data, &cfg); err != nil {
+ return nil, err
+ }
+ mf := new(modfile.File)
+ for _, d := range cfg.Package {
+ mf.Require = append(mf.Require, &modfile.Require{Mod: module.Version{Path: d.Path, Version: d.Revision}})
+ }
+ return mf, nil
+}
diff --git a/libgo/go/cmd/go/internal/modconv/vmanifest.go b/libgo/go/cmd/go/internal/modconv/vmanifest.go
new file mode 100644
index 00000000000..c0ef2a98622
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/vmanifest.go
@@ -0,0 +1,29 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modconv
+
+import (
+ "encoding/json"
+
+ "cmd/go/internal/modfile"
+ "cmd/go/internal/module"
+)
+
+func ParseVendorManifest(file string, data []byte) (*modfile.File, error) {
+ var cfg struct {
+ Dependencies []struct {
+ ImportPath string
+ Revision string
+ }
+ }
+ if err := json.Unmarshal(data, &cfg); err != nil {
+ return nil, err
+ }
+ mf := new(modfile.File)
+ for _, d := range cfg.Dependencies {
+ mf.Require = append(mf.Require, &modfile.Require{Mod: module.Version{Path: d.ImportPath, Version: d.Revision}})
+ }
+ return mf, nil
+}
diff --git a/libgo/go/cmd/go/internal/modconv/vyml.go b/libgo/go/cmd/go/internal/modconv/vyml.go
new file mode 100644
index 00000000000..0f017a3c7a6
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modconv/vyml.go
@@ -0,0 +1,42 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modconv
+
+import (
+ "strings"
+
+ "cmd/go/internal/modfile"
+ "cmd/go/internal/module"
+)
+
+func ParseVendorYML(file string, data []byte) (*modfile.File, error) {
+ mf := new(modfile.File)
+ vendors := false
+ path := ""
+ for lineno, line := range strings.Split(string(data), "\n") {
+ lineno++
+ if line == "" {
+ continue
+ }
+ if strings.HasPrefix(line, "vendors:") {
+ vendors = true
+ } else if line[0] != '-' && line[0] != ' ' && line[0] != '\t' {
+ vendors = false
+ }
+ if !vendors {
+ continue
+ }
+ if strings.HasPrefix(line, "- path:") {
+ path = strings.TrimSpace(line[len("- path:"):])
+ }
+ if strings.HasPrefix(line, " rev:") {
+ rev := strings.TrimSpace(line[len(" rev:"):])
+ if path != "" && rev != "" {
+ mf.Require = append(mf.Require, &modfile.Require{Mod: module.Version{Path: path, Version: rev}})
+ }
+ }
+ }
+ return mf, nil
+}
diff --git a/libgo/go/cmd/go/internal/modfetch/cache.go b/libgo/go/cmd/go/internal/modfetch/cache.go
new file mode 100644
index 00000000000..1f9cc96c3ec
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfetch/cache.go
@@ -0,0 +1,522 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modfetch
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "cmd/go/internal/base"
+ "cmd/go/internal/modfetch/codehost"
+ "cmd/go/internal/module"
+ "cmd/go/internal/par"
+ "cmd/go/internal/semver"
+)
+
+var QuietLookup bool // do not print about lookups
+
+var PkgMod string // $GOPATH/pkg/mod; set by package modload
+
+func cacheDir(path string) (string, error) {
+ if PkgMod == "" {
+ return "", fmt.Errorf("internal error: modfetch.PkgMod not set")
+ }
+ enc, err := module.EncodePath(path)
+ if err != nil {
+ return "", err
+ }
+ return filepath.Join(PkgMod, "cache/download", enc, "/@v"), nil
+}
+
+func CachePath(m module.Version, suffix string) (string, error) {
+ dir, err := cacheDir(m.Path)
+ if err != nil {
+ return "", err
+ }
+ if !semver.IsValid(m.Version) {
+ return "", fmt.Errorf("non-semver module version %q", m.Version)
+ }
+ if module.CanonicalVersion(m.Version) != m.Version {
+ return "", fmt.Errorf("non-canonical module version %q", m.Version)
+ }
+ encVer, err := module.EncodeVersion(m.Version)
+ if err != nil {
+ return "", err
+ }
+ return filepath.Join(dir, encVer+"."+suffix), nil
+}
+
+func DownloadDir(m module.Version) (string, error) {
+ if PkgMod == "" {
+ return "", fmt.Errorf("internal error: modfetch.PkgMod not set")
+ }
+ enc, err := module.EncodePath(m.Path)
+ if err != nil {
+ return "", err
+ }
+ if !semver.IsValid(m.Version) {
+ return "", fmt.Errorf("non-semver module version %q", m.Version)
+ }
+ if module.CanonicalVersion(m.Version) != m.Version {
+ return "", fmt.Errorf("non-canonical module version %q", m.Version)
+ }
+ encVer, err := module.EncodeVersion(m.Version)
+ if err != nil {
+ return "", err
+ }
+ return filepath.Join(PkgMod, enc+"@"+encVer), nil
+}
+
+// A cachingRepo is a cache around an underlying Repo,
+// avoiding redundant calls to ModulePath, Versions, Stat, Latest, and GoMod (but not Zip).
+// It is also safe for simultaneous use by multiple goroutines
+// (so that it can be returned from Lookup multiple times).
+// It serializes calls to the underlying Repo.
+type cachingRepo struct {
+ path string
+ cache par.Cache // cache for all operations
+ r Repo
+}
+
+func newCachingRepo(r Repo) *cachingRepo {
+ return &cachingRepo{
+ r: r,
+ path: r.ModulePath(),
+ }
+}
+
+func (r *cachingRepo) ModulePath() string {
+ return r.path
+}
+
+func (r *cachingRepo) Versions(prefix string) ([]string, error) {
+ type cached struct {
+ list []string
+ err error
+ }
+ c := r.cache.Do("versions:"+prefix, func() interface{} {
+ list, err := r.r.Versions(prefix)
+ return cached{list, err}
+ }).(cached)
+
+ if c.err != nil {
+ return nil, c.err
+ }
+ return append([]string(nil), c.list...), nil
+}
+
+type cachedInfo struct {
+ info *RevInfo
+ err error
+}
+
+func (r *cachingRepo) Stat(rev string) (*RevInfo, error) {
+ c := r.cache.Do("stat:"+rev, func() interface{} {
+ file, info, err := readDiskStat(r.path, rev)
+ if err == nil {
+ return cachedInfo{info, nil}
+ }
+
+ if !QuietLookup {
+ fmt.Fprintf(os.Stderr, "go: finding %s %s\n", r.path, rev)
+ }
+ info, err = r.r.Stat(rev)
+ if err == nil {
+ if err := writeDiskStat(file, info); err != nil {
+ fmt.Fprintf(os.Stderr, "go: writing stat cache: %v\n", err)
+ }
+ // If we resolved, say, 1234abcde to v0.0.0-20180604122334-1234abcdef78,
+ // then save the information under the proper version, for future use.
+ if info.Version != rev {
+ r.cache.Do("stat:"+info.Version, func() interface{} {
+ return cachedInfo{info, err}
+ })
+ }
+ }
+ return cachedInfo{info, err}
+ }).(cachedInfo)
+
+ if c.err != nil {
+ return nil, c.err
+ }
+ info := *c.info
+ return &info, nil
+}
+
+func (r *cachingRepo) Latest() (*RevInfo, error) {
+ c := r.cache.Do("latest:", func() interface{} {
+ if !QuietLookup {
+ fmt.Fprintf(os.Stderr, "go: finding %s latest\n", r.path)
+ }
+ info, err := r.r.Latest()
+
+ // Save info for likely future Stat call.
+ if err == nil {
+ r.cache.Do("stat:"+info.Version, func() interface{} {
+ return cachedInfo{info, err}
+ })
+ if file, _, err := readDiskStat(r.path, info.Version); err != nil {
+ writeDiskStat(file, info)
+ }
+ }
+
+ return cachedInfo{info, err}
+ }).(cachedInfo)
+
+ if c.err != nil {
+ return nil, c.err
+ }
+ info := *c.info
+ return &info, nil
+}
+
+func (r *cachingRepo) GoMod(rev string) ([]byte, error) {
+ type cached struct {
+ text []byte
+ err error
+ }
+ c := r.cache.Do("gomod:"+rev, func() interface{} {
+ file, text, err := readDiskGoMod(r.path, rev)
+ if err == nil {
+ // Note: readDiskGoMod already called checkGoMod.
+ return cached{text, nil}
+ }
+
+ // Convert rev to canonical version
+ // so that we use the right identifier in the go.sum check.
+ info, err := r.Stat(rev)
+ if err != nil {
+ return cached{nil, err}
+ }
+ rev = info.Version
+
+ text, err = r.r.GoMod(rev)
+ if err == nil {
+ checkGoMod(r.path, rev, text)
+ if err := writeDiskGoMod(file, text); err != nil {
+ fmt.Fprintf(os.Stderr, "go: writing go.mod cache: %v\n", err)
+ }
+ }
+ return cached{text, err}
+ }).(cached)
+
+ if c.err != nil {
+ return nil, c.err
+ }
+ return append([]byte(nil), c.text...), nil
+}
+
+func (r *cachingRepo) Zip(version, tmpdir string) (string, error) {
+ return r.r.Zip(version, tmpdir)
+}
+
+// Stat is like Lookup(path).Stat(rev) but avoids the
+// repository path resolution in Lookup if the result is
+// already cached on local disk.
+func Stat(path, rev string) (*RevInfo, error) {
+ _, info, err := readDiskStat(path, rev)
+ if err == nil {
+ return info, nil
+ }
+ repo, err := Lookup(path)
+ if err != nil {
+ return nil, err
+ }
+ return repo.Stat(rev)
+}
+
+// InfoFile is like Stat but returns the name of the file containing
+// the cached information.
+func InfoFile(path, version string) (string, error) {
+ if !semver.IsValid(version) {
+ return "", fmt.Errorf("invalid version %q", version)
+ }
+ if _, err := Stat(path, version); err != nil {
+ return "", err
+ }
+ // Stat should have populated the disk cache for us.
+ file, _, err := readDiskStat(path, version)
+ if err != nil {
+ return "", err
+ }
+ return file, nil
+}
+
+// GoMod is like Lookup(path).GoMod(rev) but avoids the
+// repository path resolution in Lookup if the result is
+// already cached on local disk.
+func GoMod(path, rev string) ([]byte, error) {
+ // Convert commit hash to pseudo-version
+ // to increase cache hit rate.
+ if !semver.IsValid(rev) {
+ info, err := Stat(path, rev)
+ if err != nil {
+ return nil, err
+ }
+ rev = info.Version
+ }
+ _, data, err := readDiskGoMod(path, rev)
+ if err == nil {
+ return data, nil
+ }
+ repo, err := Lookup(path)
+ if err != nil {
+ return nil, err
+ }
+ return repo.GoMod(rev)
+}
+
+// GoModFile is like GoMod but returns the name of the file containing
+// the cached information.
+func GoModFile(path, version string) (string, error) {
+ if !semver.IsValid(version) {
+ return "", fmt.Errorf("invalid version %q", version)
+ }
+ if _, err := GoMod(path, version); err != nil {
+ return "", err
+ }
+ // GoMod should have populated the disk cache for us.
+ file, _, err := readDiskGoMod(path, version)
+ if err != nil {
+ return "", err
+ }
+ return file, nil
+}
+
+// GoModSum returns the go.sum entry for the module version's go.mod file.
+// (That is, it returns the entry listed in go.sum as "path version/go.mod".)
+func GoModSum(path, version string) (string, error) {
+ if !semver.IsValid(version) {
+ return "", fmt.Errorf("invalid version %q", version)
+ }
+ data, err := GoMod(path, version)
+ if err != nil {
+ return "", err
+ }
+ sum, err := goModSum(data)
+ if err != nil {
+ return "", err
+ }
+ return sum, nil
+}
+
+var errNotCached = fmt.Errorf("not in cache")
+
+// readDiskStat reads a cached stat result from disk,
+// returning the name of the cache file and the result.
+// If the read fails, the caller can use
+// writeDiskStat(file, info) to write a new cache entry.
+func readDiskStat(path, rev string) (file string, info *RevInfo, err error) {
+ file, data, err := readDiskCache(path, rev, "info")
+ if err != nil {
+ if file, info, err := readDiskStatByHash(path, rev); err == nil {
+ return file, info, nil
+ }
+ return file, nil, err
+ }
+ info = new(RevInfo)
+ if err := json.Unmarshal(data, info); err != nil {
+ return file, nil, errNotCached
+ }
+ // The disk might have stale .info files that have Name and Short fields set.
+ // We want to canonicalize to .info files with those fields omitted.
+ // Remarshal and update the cache file if needed.
+ data2, err := json.Marshal(info)
+ if err == nil && !bytes.Equal(data2, data) {
+ writeDiskCache(file, data)
+ }
+ return file, info, nil
+}
+
+// readDiskStatByHash is a fallback for readDiskStat for the case
+// where rev is a commit hash instead of a proper semantic version.
+// In that case, we look for a cached pseudo-version that matches
+// the commit hash. If we find one, we use it.
+// This matters most for converting legacy package management
+// configs, when we are often looking up commits by full hash.
+// Without this check we'd be doing network I/O to the remote repo
+// just to find out about a commit we already know about
+// (and have cached under its pseudo-version).
+func readDiskStatByHash(path, rev string) (file string, info *RevInfo, err error) {
+ if PkgMod == "" {
+ // Do not download to current directory.
+ return "", nil, errNotCached
+ }
+
+ if !codehost.AllHex(rev) || len(rev) < 12 {
+ return "", nil, errNotCached
+ }
+ rev = rev[:12]
+ cdir, err := cacheDir(path)
+ if err != nil {
+ return "", nil, errNotCached
+ }
+ dir, err := os.Open(cdir)
+ if err != nil {
+ return "", nil, errNotCached
+ }
+ names, err := dir.Readdirnames(-1)
+ dir.Close()
+ if err != nil {
+ return "", nil, errNotCached
+ }
+ suffix := "-" + rev + ".info"
+ for _, name := range names {
+ if strings.HasSuffix(name, suffix) && IsPseudoVersion(strings.TrimSuffix(name, ".info")) {
+ return readDiskStat(path, strings.TrimSuffix(name, ".info"))
+ }
+ }
+ return "", nil, errNotCached
+}
+
+// oldVgoPrefix is the prefix in the old auto-generated cached go.mod files.
+// We stopped trying to auto-generate the go.mod files. Now we use a trivial
+// go.mod with only a module line, and we've dropped the version prefix
+// entirely. If we see a version prefix, that means we're looking at an old copy
+// and should ignore it.
+var oldVgoPrefix = []byte("//vgo 0.0.")
+
+// readDiskGoMod reads a cached stat result from disk,
+// returning the name of the cache file and the result.
+// If the read fails, the caller can use
+// writeDiskGoMod(file, data) to write a new cache entry.
+func readDiskGoMod(path, rev string) (file string, data []byte, err error) {
+ file, data, err = readDiskCache(path, rev, "mod")
+
+ // If the file has an old auto-conversion prefix, pretend it's not there.
+ if bytes.HasPrefix(data, oldVgoPrefix) {
+ err = errNotCached
+ data = nil
+ }
+
+ if err == nil {
+ checkGoMod(path, rev, data)
+ }
+
+ return file, data, err
+}
+
+// readDiskCache is the generic "read from a cache file" implementation.
+// It takes the revision and an identifying suffix for the kind of data being cached.
+// It returns the name of the cache file and the content of the file.
+// If the read fails, the caller can use
+// writeDiskCache(file, data) to write a new cache entry.
+func readDiskCache(path, rev, suffix string) (file string, data []byte, err error) {
+ file, err = CachePath(module.Version{Path: path, Version: rev}, suffix)
+ if err != nil {
+ return "", nil, errNotCached
+ }
+ data, err = ioutil.ReadFile(file)
+ if err != nil {
+ return file, nil, errNotCached
+ }
+ return file, data, nil
+}
+
+// writeDiskStat writes a stat result cache entry.
+// The file name must have been returned by a previous call to readDiskStat.
+func writeDiskStat(file string, info *RevInfo) error {
+ if file == "" {
+ return nil
+ }
+ js, err := json.Marshal(info)
+ if err != nil {
+ return err
+ }
+ return writeDiskCache(file, js)
+}
+
+// writeDiskGoMod writes a go.mod cache entry.
+// The file name must have been returned by a previous call to readDiskGoMod.
+func writeDiskGoMod(file string, text []byte) error {
+ return writeDiskCache(file, text)
+}
+
+// writeDiskCache is the generic "write to a cache file" implementation.
+// The file must have been returned by a previous call to readDiskCache.
+func writeDiskCache(file string, data []byte) error {
+ if file == "" {
+ return nil
+ }
+ // Make sure directory for file exists.
+ if err := os.MkdirAll(filepath.Dir(file), 0777); err != nil {
+ return err
+ }
+ // Write data to temp file next to target file.
+ f, err := ioutil.TempFile(filepath.Dir(file), filepath.Base(file)+".tmp-")
+ if err != nil {
+ return err
+ }
+ defer os.Remove(f.Name())
+ defer f.Close()
+ if _, err := f.Write(data); err != nil {
+ return err
+ }
+ if err := f.Close(); err != nil {
+ return err
+ }
+ // Rename temp file onto cache file,
+ // so that the cache file is always a complete file.
+ if err := os.Rename(f.Name(), file); err != nil {
+ return err
+ }
+
+ if strings.HasSuffix(file, ".mod") {
+ rewriteVersionList(filepath.Dir(file))
+ }
+ return nil
+}
+
+// rewriteVersionList rewrites the version list in dir
+// after a new *.mod file has been written.
+func rewriteVersionList(dir string) {
+ if filepath.Base(dir) != "@v" {
+ base.Fatalf("go: internal error: misuse of rewriteVersionList")
+ }
+
+ // TODO(rsc): We should do some kind of directory locking here,
+ // to avoid lost updates.
+
+ infos, err := ioutil.ReadDir(dir)
+ if err != nil {
+ return
+ }
+ var list []string
+ for _, info := range infos {
+ // We look for *.mod files on the theory that if we can't supply
+ // the .mod file then there's no point in listing that version,
+ // since it's unusable. (We can have *.info without *.mod.)
+ // We don't require *.zip files on the theory that for code only
+ // involved in module graph construction, many *.zip files
+ // will never be requested.
+ name := info.Name()
+ if strings.HasSuffix(name, ".mod") {
+ v := strings.TrimSuffix(name, ".mod")
+ if v != "" && module.CanonicalVersion(v) == v {
+ list = append(list, v)
+ }
+ }
+ }
+ SortVersions(list)
+
+ var buf bytes.Buffer
+ for _, v := range list {
+ buf.WriteString(v)
+ buf.WriteString("\n")
+ }
+ listFile := filepath.Join(dir, "list")
+ old, _ := ioutil.ReadFile(listFile)
+ if bytes.Equal(buf.Bytes(), old) {
+ return
+ }
+ // TODO: Use rename to install file,
+ // so that readers never see an incomplete file.
+ ioutil.WriteFile(listFile, buf.Bytes(), 0666)
+}
diff --git a/libgo/go/cmd/go/internal/modfetch/cache_test.go b/libgo/go/cmd/go/internal/modfetch/cache_test.go
new file mode 100644
index 00000000000..241c800e692
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfetch/cache_test.go
@@ -0,0 +1,25 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modfetch
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "testing"
+)
+
+func TestWriteDiskCache(t *testing.T) {
+ tmpdir, err := ioutil.TempDir("", "go-writeCache-test-")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+
+ err = writeDiskCache(filepath.Join(tmpdir, "file"), []byte("data"))
+ if err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/libgo/go/cmd/go/internal/modfetch/codehost/codehost.go b/libgo/go/cmd/go/internal/modfetch/codehost/codehost.go
new file mode 100644
index 00000000000..4103ddc717f
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfetch/codehost/codehost.go
@@ -0,0 +1,266 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package codehost defines the interface implemented by a code hosting source,
+// along with support code for use by implementations.
+package codehost
+
+import (
+ "bytes"
+ "crypto/sha256"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "sync"
+ "time"
+
+ "cmd/go/internal/cfg"
+ "cmd/go/internal/str"
+)
+
+// Downloaded size limits.
+const (
+ MaxGoMod = 16 << 20 // maximum size of go.mod file
+ MaxLICENSE = 16 << 20 // maximum size of LICENSE file
+ MaxZipFile = 500 << 20 // maximum size of downloaded zip file
+)
+
+// A Repo represents a code hosting source.
+// Typical implementations include local version control repositories,
+// remote version control servers, and code hosting sites.
+// A Repo must be safe for simultaneous use by multiple goroutines.
+type Repo interface {
+ // List lists all tags with the given prefix.
+ Tags(prefix string) (tags []string, err error)
+
+ // Stat returns information about the revision rev.
+ // A revision can be any identifier known to the underlying service:
+ // commit hash, branch, tag, and so on.
+ Stat(rev string) (*RevInfo, error)
+
+ // Latest returns the latest revision on the default branch,
+ // whatever that means in the underlying implementation.
+ Latest() (*RevInfo, error)
+
+ // ReadFile reads the given file in the file tree corresponding to revision rev.
+ // It should refuse to read more than maxSize bytes.
+ //
+ // If the requested file does not exist it should return an error for which
+ // os.IsNotExist(err) returns true.
+ ReadFile(rev, file string, maxSize int64) (data []byte, err error)
+
+ // ReadFileRevs reads a single file at multiple versions.
+ // It should refuse to read more than maxSize bytes.
+ // The result is a map from each requested rev strings
+ // to the associated FileRev. The map must have a non-nil
+ // entry for every requested rev (unless ReadFileRevs returned an error).
+ // A file simply being missing or even corrupted in revs[i]
+ // should be reported only in files[revs[i]].Err, not in the error result
+ // from ReadFileRevs.
+ // The overall call should return an error (and no map) only
+ // in the case of a problem with obtaining the data, such as
+ // a network failure.
+ // Implementations may assume that revs only contain tags,
+ // not direct commit hashes.
+ ReadFileRevs(revs []string, file string, maxSize int64) (files map[string]*FileRev, err error)
+
+ // ReadZip downloads a zip file for the subdir subdirectory
+ // of the given revision to a new file in a given temporary directory.
+ // It should refuse to read more than maxSize bytes.
+ // It returns a ReadCloser for a streamed copy of the zip file,
+ // along with the actual subdirectory (possibly shorter than subdir)
+ // contained in the zip file. All files in the zip file are expected to be
+ // nested in a single top-level directory, whose name is not specified.
+ ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser, actualSubdir string, err error)
+
+ // RecentTag returns the most recent tag at or before the given rev
+ // with the given prefix. It should make a best-effort attempt to
+ // find a tag that is a valid semantic version (following the prefix),
+ // or else the result is not useful to the caller, but it need not
+ // incur great expense in doing so. For example, the git implementation
+ // of RecentTag limits git's search to tags matching the glob expression
+ // "v[0-9]*.[0-9]*.[0-9]*" (after the prefix).
+ RecentTag(rev, prefix string) (tag string, err error)
+}
+
+// A Rev describes a single revision in a source code repository.
+type RevInfo struct {
+ Name string // complete ID in underlying repository
+ Short string // shortened ID, for use in pseudo-version
+ Version string // version used in lookup
+ Time time.Time // commit time
+ Tags []string // known tags for commit
+}
+
+// A FileRev describes the result of reading a file at a given revision.
+type FileRev struct {
+ Rev string // requested revision
+ Data []byte // file data
+ Err error // error if any; os.IsNotExist(Err)==true if rev exists but file does not exist in that rev
+}
+
+// AllHex reports whether the revision rev is entirely lower-case hexadecimal digits.
+func AllHex(rev string) bool {
+ for i := 0; i < len(rev); i++ {
+ c := rev[i]
+ if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' {
+ continue
+ }
+ return false
+ }
+ return true
+}
+
+// ShortenSHA1 shortens a SHA1 hash (40 hex digits) to the canonical length
+// used in pseudo-versions (12 hex digits).
+func ShortenSHA1(rev string) string {
+ if AllHex(rev) && len(rev) == 40 {
+ return rev[:12]
+ }
+ return rev
+}
+
+// WorkRoot is the root of the cached work directory.
+// It is set by cmd/go/internal/modload.InitMod.
+var WorkRoot string
+
+// WorkDir returns the name of the cached work directory to use for the
+// given repository type and name.
+func WorkDir(typ, name string) (string, error) {
+ if WorkRoot == "" {
+ return "", fmt.Errorf("codehost.WorkRoot not set")
+ }
+
+ // We name the work directory for the SHA256 hash of the type and name.
+ // We intentionally avoid the actual name both because of possible
+ // conflicts with valid file system paths and because we want to ensure
+ // that one checkout is never nested inside another. That nesting has
+ // led to security problems in the past.
+ if strings.Contains(typ, ":") {
+ return "", fmt.Errorf("codehost.WorkDir: type cannot contain colon")
+ }
+ key := typ + ":" + name
+ dir := filepath.Join(WorkRoot, fmt.Sprintf("%x", sha256.Sum256([]byte(key))))
+ data, err := ioutil.ReadFile(dir + ".info")
+ info, err2 := os.Stat(dir)
+ if err == nil && err2 == nil && info.IsDir() {
+ // Info file and directory both already exist: reuse.
+ have := strings.TrimSuffix(string(data), "\n")
+ if have != key {
+ return "", fmt.Errorf("%s exists with wrong content (have %q want %q)", dir+".info", have, key)
+ }
+ if cfg.BuildX {
+ fmt.Fprintf(os.Stderr, "# %s for %s %s\n", dir, typ, name)
+ }
+ return dir, nil
+ }
+
+ // Info file or directory missing. Start from scratch.
+ if cfg.BuildX {
+ fmt.Fprintf(os.Stderr, "mkdir -p %s # %s %s\n", dir, typ, name)
+ }
+ os.RemoveAll(dir)
+ if err := os.MkdirAll(dir, 0777); err != nil {
+ return "", err
+ }
+ if err := ioutil.WriteFile(dir+".info", []byte(key), 0666); err != nil {
+ os.RemoveAll(dir)
+ return "", err
+ }
+ return dir, nil
+}
+
+type RunError struct {
+ Cmd string
+ Err error
+ Stderr []byte
+}
+
+func (e *RunError) Error() string {
+ text := e.Cmd + ": " + e.Err.Error()
+ stderr := bytes.TrimRight(e.Stderr, "\n")
+ if len(stderr) > 0 {
+ text += ":\n\t" + strings.Replace(string(stderr), "\n", "\n\t", -1)
+ }
+ return text
+}
+
+var dirLock sync.Map
+
+// Run runs the command line in the given directory
+// (an empty dir means the current directory).
+// It returns the standard output and, for a non-zero exit,
+// a *RunError indicating the command, exit status, and standard error.
+// Standard error is unavailable for commands that exit successfully.
+func Run(dir string, cmdline ...interface{}) ([]byte, error) {
+ return RunWithStdin(dir, nil, cmdline...)
+}
+
+// bashQuoter escapes characters that have special meaning in double-quoted strings in the bash shell.
+// See https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html.
+var bashQuoter = strings.NewReplacer(`"`, `\"`, `$`, `\$`, "`", "\\`", `\`, `\\`)
+
+func RunWithStdin(dir string, stdin io.Reader, cmdline ...interface{}) ([]byte, error) {
+ if dir != "" {
+ muIface, ok := dirLock.Load(dir)
+ if !ok {
+ muIface, _ = dirLock.LoadOrStore(dir, new(sync.Mutex))
+ }
+ mu := muIface.(*sync.Mutex)
+ mu.Lock()
+ defer mu.Unlock()
+ }
+
+ cmd := str.StringList(cmdline...)
+ if cfg.BuildX {
+ text := new(strings.Builder)
+ if dir != "" {
+ text.WriteString("cd ")
+ text.WriteString(dir)
+ text.WriteString("; ")
+ }
+ for i, arg := range cmd {
+ if i > 0 {
+ text.WriteByte(' ')
+ }
+ switch {
+ case strings.ContainsAny(arg, "'"):
+ // Quote args that could be mistaken for quoted args.
+ text.WriteByte('"')
+ text.WriteString(bashQuoter.Replace(arg))
+ text.WriteByte('"')
+ case strings.ContainsAny(arg, "$`\\*?[\"\t\n\v\f\r \u0085\u00a0"):
+ // Quote args that contain special characters, glob patterns, or spaces.
+ text.WriteByte('\'')
+ text.WriteString(arg)
+ text.WriteByte('\'')
+ default:
+ text.WriteString(arg)
+ }
+ }
+ fmt.Fprintf(os.Stderr, "%s\n", text)
+ start := time.Now()
+ defer func() {
+ fmt.Fprintf(os.Stderr, "%.3fs # %s\n", time.Since(start).Seconds(), text)
+ }()
+ }
+ // TODO: Impose limits on command output size.
+ // TODO: Set environment to get English error messages.
+ var stderr bytes.Buffer
+ var stdout bytes.Buffer
+ c := exec.Command(cmd[0], cmd[1:]...)
+ c.Dir = dir
+ c.Stdin = stdin
+ c.Stderr = &stderr
+ c.Stdout = &stdout
+ err := c.Run()
+ if err != nil {
+ err = &RunError{Cmd: strings.Join(cmd, " ") + " in " + dir, Stderr: stderr.Bytes(), Err: err}
+ }
+ return stdout.Bytes(), err
+}
diff --git a/libgo/go/cmd/go/internal/modfetch/codehost/git.go b/libgo/go/cmd/go/internal/modfetch/codehost/git.go
new file mode 100644
index 00000000000..87940a8f02c
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfetch/codehost/git.go
@@ -0,0 +1,711 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package codehost
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "sort"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "cmd/go/internal/par"
+)
+
+// GitRepo returns the code repository at the given Git remote reference.
+func GitRepo(remote string) (Repo, error) {
+ return newGitRepoCached(remote, false)
+}
+
+// LocalGitRepo is like Repo but accepts both Git remote references
+// and paths to repositories on the local file system.
+func LocalGitRepo(remote string) (Repo, error) {
+ return newGitRepoCached(remote, true)
+}
+
+const gitWorkDirType = "git2"
+
+var gitRepoCache par.Cache
+
+func newGitRepoCached(remote string, localOK bool) (Repo, error) {
+ type key struct {
+ remote string
+ localOK bool
+ }
+ type cached struct {
+ repo Repo
+ err error
+ }
+
+ c := gitRepoCache.Do(key{remote, localOK}, func() interface{} {
+ repo, err := newGitRepo(remote, localOK)
+ return cached{repo, err}
+ }).(cached)
+
+ return c.repo, c.err
+}
+
+func newGitRepo(remote string, localOK bool) (Repo, error) {
+ r := &gitRepo{remote: remote}
+ if strings.Contains(remote, "://") {
+ // This is a remote path.
+ dir, err := WorkDir(gitWorkDirType, r.remote)
+ if err != nil {
+ return nil, err
+ }
+ r.dir = dir
+ if _, err := os.Stat(filepath.Join(dir, "objects")); err != nil {
+ if _, err := Run(dir, "git", "init", "--bare"); err != nil {
+ os.RemoveAll(dir)
+ return nil, err
+ }
+ // We could just say git fetch https://whatever later,
+ // but this lets us say git fetch origin instead, which
+ // is a little nicer. More importantly, using a named remote
+ // avoids a problem with Git LFS. See golang.org/issue/25605.
+ if _, err := Run(dir, "git", "remote", "add", "origin", r.remote); err != nil {
+ os.RemoveAll(dir)
+ return nil, err
+ }
+ r.remote = "origin"
+ }
+ } else {
+ // Local path.
+ // Disallow colon (not in ://) because sometimes
+ // that's rcp-style host:path syntax and sometimes it's not (c:\work).
+ // The go command has always insisted on URL syntax for ssh.
+ if strings.Contains(remote, ":") {
+ return nil, fmt.Errorf("git remote cannot use host:path syntax")
+ }
+ if !localOK {
+ return nil, fmt.Errorf("git remote must not be local directory")
+ }
+ r.local = true
+ info, err := os.Stat(remote)
+ if err != nil {
+ return nil, err
+ }
+ if !info.IsDir() {
+ return nil, fmt.Errorf("%s exists but is not a directory", remote)
+ }
+ r.dir = remote
+ }
+ return r, nil
+}
+
+type gitRepo struct {
+ remote string
+ local bool
+ dir string
+
+ mu sync.Mutex // protects fetchLevel, some git repo state
+ fetchLevel int
+
+ statCache par.Cache
+
+ refsOnce sync.Once
+ refs map[string]string
+ refsErr error
+
+ localTagsOnce sync.Once
+ localTags map[string]bool
+}
+
+const (
+ // How much have we fetched into the git repo (in this process)?
+ fetchNone = iota // nothing yet
+ fetchSome // shallow fetches of individual hashes
+ fetchAll // "fetch -t origin": get all remote branches and tags
+)
+
+// loadLocalTags loads tag references from the local git cache
+// into the map r.localTags.
+// Should only be called as r.localTagsOnce.Do(r.loadLocalTags).
+func (r *gitRepo) loadLocalTags() {
+ // The git protocol sends all known refs and ls-remote filters them on the client side,
+ // so we might as well record both heads and tags in one shot.
+ // Most of the time we only care about tags but sometimes we care about heads too.
+ out, err := Run(r.dir, "git", "tag", "-l")
+ if err != nil {
+ return
+ }
+
+ r.localTags = make(map[string]bool)
+ for _, line := range strings.Split(string(out), "\n") {
+ if line != "" {
+ r.localTags[line] = true
+ }
+ }
+}
+
+// loadRefs loads heads and tags references from the remote into the map r.refs.
+// Should only be called as r.refsOnce.Do(r.loadRefs).
+func (r *gitRepo) loadRefs() {
+ // The git protocol sends all known refs and ls-remote filters them on the client side,
+ // so we might as well record both heads and tags in one shot.
+ // Most of the time we only care about tags but sometimes we care about heads too.
+ out, err := Run(r.dir, "git", "ls-remote", "-q", r.remote)
+ if err != nil {
+ r.refsErr = err
+ return
+ }
+
+ r.refs = make(map[string]string)
+ for _, line := range strings.Split(string(out), "\n") {
+ f := strings.Fields(line)
+ if len(f) != 2 {
+ continue
+ }
+ if f[1] == "HEAD" || strings.HasPrefix(f[1], "refs/heads/") || strings.HasPrefix(f[1], "refs/tags/") {
+ r.refs[f[1]] = f[0]
+ }
+ }
+ for ref, hash := range r.refs {
+ if strings.HasSuffix(ref, "^{}") { // record unwrapped annotated tag as value of tag
+ r.refs[strings.TrimSuffix(ref, "^{}")] = hash
+ delete(r.refs, ref)
+ }
+ }
+}
+
+func (r *gitRepo) Tags(prefix string) ([]string, error) {
+ r.refsOnce.Do(r.loadRefs)
+ if r.refsErr != nil {
+ return nil, r.refsErr
+ }
+
+ tags := []string{}
+ for ref := range r.refs {
+ if !strings.HasPrefix(ref, "refs/tags/") {
+ continue
+ }
+ tag := ref[len("refs/tags/"):]
+ if !strings.HasPrefix(tag, prefix) {
+ continue
+ }
+ tags = append(tags, tag)
+ }
+ sort.Strings(tags)
+ return tags, nil
+}
+
+func (r *gitRepo) Latest() (*RevInfo, error) {
+ r.refsOnce.Do(r.loadRefs)
+ if r.refsErr != nil {
+ return nil, r.refsErr
+ }
+ if r.refs["HEAD"] == "" {
+ return nil, fmt.Errorf("no commits")
+ }
+ return r.Stat(r.refs["HEAD"])
+}
+
+// findRef finds some ref name for the given hash,
+// for use when the server requires giving a ref instead of a hash.
+// There may be multiple ref names for a given hash,
+// in which case this returns some name - it doesn't matter which.
+func (r *gitRepo) findRef(hash string) (ref string, ok bool) {
+ r.refsOnce.Do(r.loadRefs)
+ for ref, h := range r.refs {
+ if h == hash {
+ return ref, true
+ }
+ }
+ return "", false
+}
+
+func unshallow(gitDir string) []string {
+ if _, err := os.Stat(filepath.Join(gitDir, "shallow")); err == nil {
+ return []string{"--unshallow"}
+ }
+ return []string{}
+}
+
+// minHashDigits is the minimum number of digits to require
+// before accepting a hex digit sequence as potentially identifying
+// a specific commit in a git repo. (Of course, users can always
+// specify more digits, and many will paste in all 40 digits,
+// but many of git's commands default to printing short hashes
+// as 7 digits.)
+const minHashDigits = 7
+
+// stat stats the given rev in the local repository,
+// or else it fetches more info from the remote repository and tries again.
+func (r *gitRepo) stat(rev string) (*RevInfo, error) {
+ if r.local {
+ return r.statLocal(rev, rev)
+ }
+
+ // Fast path: maybe rev is a hash we already have locally.
+ didStatLocal := false
+ if len(rev) >= minHashDigits && len(rev) <= 40 && AllHex(rev) {
+ if info, err := r.statLocal(rev, rev); err == nil {
+ return info, nil
+ }
+ didStatLocal = true
+ }
+
+ // Maybe rev is a tag we already have locally.
+ // (Note that we're excluding branches, which can be stale.)
+ r.localTagsOnce.Do(r.loadLocalTags)
+ if r.localTags[rev] {
+ return r.statLocal(rev, "refs/tags/"+rev)
+ }
+
+ // Maybe rev is the name of a tag or branch on the remote server.
+ // Or maybe it's the prefix of a hash of a named ref.
+ // Try to resolve to both a ref (git name) and full (40-hex-digit) commit hash.
+ r.refsOnce.Do(r.loadRefs)
+ var ref, hash string
+ if r.refs["refs/tags/"+rev] != "" {
+ ref = "refs/tags/" + rev
+ hash = r.refs[ref]
+ // Keep rev as is: tags are assumed not to change meaning.
+ } else if r.refs["refs/heads/"+rev] != "" {
+ ref = "refs/heads/" + rev
+ hash = r.refs[ref]
+ rev = hash // Replace rev, because meaning of refs/heads/foo can change.
+ } else if rev == "HEAD" && r.refs["HEAD"] != "" {
+ ref = "HEAD"
+ hash = r.refs[ref]
+ rev = hash // Replace rev, because meaning of HEAD can change.
+ } else if len(rev) >= minHashDigits && len(rev) <= 40 && AllHex(rev) {
+ // At the least, we have a hash prefix we can look up after the fetch below.
+ // Maybe we can map it to a full hash using the known refs.
+ prefix := rev
+ // Check whether rev is prefix of known ref hash.
+ for k, h := range r.refs {
+ if strings.HasPrefix(h, prefix) {
+ if hash != "" && hash != h {
+ // Hash is an ambiguous hash prefix.
+ // More information will not change that.
+ return nil, fmt.Errorf("ambiguous revision %s", rev)
+ }
+ if ref == "" || ref > k { // Break ties deterministically when multiple refs point at same hash.
+ ref = k
+ }
+ rev = h
+ hash = h
+ }
+ }
+ if hash == "" && len(rev) == 40 { // Didn't find a ref, but rev is a full hash.
+ hash = rev
+ }
+ } else {
+ return nil, fmt.Errorf("unknown revision %s", rev)
+ }
+
+ // Protect r.fetchLevel and the "fetch more and more" sequence.
+ // TODO(rsc): Add LockDir and use it for protecting that
+ // sequence, so that multiple processes don't collide in their
+ // git commands.
+ r.mu.Lock()
+ defer r.mu.Unlock()
+
+ // Perhaps r.localTags did not have the ref when we loaded local tags,
+ // but we've since done fetches that pulled down the hash we need
+ // (or already have the hash we need, just without its tag).
+ // Either way, try a local stat before falling back to network I/O.
+ if !didStatLocal {
+ if info, err := r.statLocal(rev, hash); err == nil {
+ if strings.HasPrefix(ref, "refs/tags/") {
+ // Make sure tag exists, so it will be in localTags next time the go command is run.
+ Run(r.dir, "git", "tag", strings.TrimPrefix(ref, "refs/tags/"), hash)
+ }
+ return info, nil
+ }
+ }
+
+ // If we know a specific commit we need, fetch it.
+ if r.fetchLevel <= fetchSome && hash != "" && !r.local {
+ r.fetchLevel = fetchSome
+ var refspec string
+ if ref != "" && ref != "HEAD" {
+ // If we do know the ref name, save the mapping locally
+ // so that (if it is a tag) it can show up in localTags
+ // on a future call. Also, some servers refuse to allow
+ // full hashes in ref specs, so prefer a ref name if known.
+ refspec = ref + ":" + ref
+ } else {
+ // Fetch the hash but give it a local name (refs/dummy),
+ // because that triggers the fetch behavior of creating any
+ // other known remote tags for the hash. We never use
+ // refs/dummy (it's not refs/tags/dummy) and it will be
+ // overwritten in the next command, and that's fine.
+ ref = hash
+ refspec = hash + ":refs/dummy"
+ }
+ _, err := Run(r.dir, "git", "fetch", "-f", "--depth=1", r.remote, refspec)
+ if err == nil {
+ return r.statLocal(rev, ref)
+ }
+ // Don't try to be smart about parsing the error.
+ // It's too complex and varies too much by git version.
+ // No matter what went wrong, fall back to a complete fetch.
+ }
+
+ // Last resort.
+ // Fetch all heads and tags and hope the hash we want is in the history.
+ if r.fetchLevel < fetchAll {
+ // TODO(bcmills): should we wait to upgrade fetchLevel until after we check
+ // err? If there is a temporary server error, we want subsequent fetches to
+ // try again instead of proceeding with an incomplete repo.
+ r.fetchLevel = fetchAll
+ if err := r.fetchUnshallow("refs/heads/*:refs/heads/*", "refs/tags/*:refs/tags/*"); err != nil {
+ return nil, err
+ }
+ }
+
+ return r.statLocal(rev, rev)
+}
+
+func (r *gitRepo) fetchUnshallow(refSpecs ...string) error {
+ // To work around a protocol version 2 bug that breaks --unshallow,
+ // add -c protocol.version=0.
+ // TODO(rsc): The bug is believed to be server-side, meaning only
+ // on Google's Git servers. Once the servers are fixed, drop the
+ // protocol.version=0. See Google-internal bug b/110495752.
+ var protoFlag []string
+ unshallowFlag := unshallow(r.dir)
+ if len(unshallowFlag) > 0 {
+ protoFlag = []string{"-c", "protocol.version=0"}
+ }
+ _, err := Run(r.dir, "git", protoFlag, "fetch", unshallowFlag, "-f", r.remote, refSpecs)
+ return err
+}
+
+// statLocal returns a RevInfo describing rev in the local git repository.
+// It uses version as info.Version.
+func (r *gitRepo) statLocal(version, rev string) (*RevInfo, error) {
+ out, err := Run(r.dir, "git", "-c", "log.showsignature=false", "log", "-n1", "--format=format:%H %ct %D", rev)
+ if err != nil {
+ return nil, fmt.Errorf("unknown revision %s", rev)
+ }
+ f := strings.Fields(string(out))
+ if len(f) < 2 {
+ return nil, fmt.Errorf("unexpected response from git log: %q", out)
+ }
+ hash := f[0]
+ if strings.HasPrefix(hash, version) {
+ version = hash // extend to full hash
+ }
+ t, err := strconv.ParseInt(f[1], 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("invalid time from git log: %q", out)
+ }
+
+ info := &RevInfo{
+ Name: hash,
+ Short: ShortenSHA1(hash),
+ Time: time.Unix(t, 0).UTC(),
+ Version: hash,
+ }
+
+ // Add tags. Output looks like:
+ // ede458df7cd0fdca520df19a33158086a8a68e81 1523994202 HEAD -> master, tag: v1.2.4-annotated, tag: v1.2.3, origin/master, origin/HEAD
+ for i := 2; i < len(f); i++ {
+ if f[i] == "tag:" {
+ i++
+ if i < len(f) {
+ info.Tags = append(info.Tags, strings.TrimSuffix(f[i], ","))
+ }
+ }
+ }
+ sort.Strings(info.Tags)
+
+ // Used hash as info.Version above.
+ // Use caller's suggested version if it appears in the tag list
+ // (filters out branch names, HEAD).
+ for _, tag := range info.Tags {
+ if version == tag {
+ info.Version = version
+ }
+ }
+
+ return info, nil
+}
+
+func (r *gitRepo) Stat(rev string) (*RevInfo, error) {
+ if rev == "latest" {
+ return r.Latest()
+ }
+ type cached struct {
+ info *RevInfo
+ err error
+ }
+ c := r.statCache.Do(rev, func() interface{} {
+ info, err := r.stat(rev)
+ return cached{info, err}
+ }).(cached)
+ return c.info, c.err
+}
+
+func (r *gitRepo) ReadFile(rev, file string, maxSize int64) ([]byte, error) {
+ // TODO: Could use git cat-file --batch.
+ info, err := r.Stat(rev) // download rev into local git repo
+ if err != nil {
+ return nil, err
+ }
+ out, err := Run(r.dir, "git", "cat-file", "blob", info.Name+":"+file)
+ if err != nil {
+ return nil, os.ErrNotExist
+ }
+ return out, nil
+}
+
+func (r *gitRepo) ReadFileRevs(revs []string, file string, maxSize int64) (map[string]*FileRev, error) {
+ // Create space to hold results.
+ files := make(map[string]*FileRev)
+ for _, rev := range revs {
+ f := &FileRev{Rev: rev}
+ files[rev] = f
+ }
+
+ // Collect locally-known revs.
+ need, err := r.readFileRevs(revs, file, files)
+ if err != nil {
+ return nil, err
+ }
+ if len(need) == 0 {
+ return files, nil
+ }
+
+ // Build list of known remote refs that might help.
+ var redo []string
+ r.refsOnce.Do(r.loadRefs)
+ if r.refsErr != nil {
+ return nil, r.refsErr
+ }
+ for _, tag := range need {
+ if r.refs["refs/tags/"+tag] != "" {
+ redo = append(redo, tag)
+ }
+ }
+ if len(redo) == 0 {
+ return files, nil
+ }
+
+ // Protect r.fetchLevel and the "fetch more and more" sequence.
+ // See stat method above.
+ r.mu.Lock()
+ defer r.mu.Unlock()
+
+ var refs []string
+ var protoFlag []string
+ var unshallowFlag []string
+ for _, tag := range redo {
+ refs = append(refs, "refs/tags/"+tag+":refs/tags/"+tag)
+ }
+ if len(refs) > 1 {
+ unshallowFlag = unshallow(r.dir)
+ if len(unshallowFlag) > 0 {
+ // To work around a protocol version 2 bug that breaks --unshallow,
+ // add -c protocol.version=0.
+ // TODO(rsc): The bug is believed to be server-side, meaning only
+ // on Google's Git servers. Once the servers are fixed, drop the
+ // protocol.version=0. See Google-internal bug b/110495752.
+ protoFlag = []string{"-c", "protocol.version=0"}
+ }
+ }
+ if _, err := Run(r.dir, "git", protoFlag, "fetch", unshallowFlag, "-f", r.remote, refs); err != nil {
+ return nil, err
+ }
+
+ // TODO(bcmills): after the 1.11 freeze, replace the block above with:
+ // if r.fetchLevel <= fetchSome {
+ // r.fetchLevel = fetchSome
+ // var refs []string
+ // for _, tag := range redo {
+ // refs = append(refs, "refs/tags/"+tag+":refs/tags/"+tag)
+ // }
+ // if _, err := Run(r.dir, "git", "fetch", "--update-shallow", "-f", r.remote, refs); err != nil {
+ // return nil, err
+ // }
+ // }
+
+ if _, err := r.readFileRevs(redo, file, files); err != nil {
+ return nil, err
+ }
+
+ return files, nil
+}
+
+func (r *gitRepo) readFileRevs(tags []string, file string, fileMap map[string]*FileRev) (missing []string, err error) {
+ var stdin bytes.Buffer
+ for _, tag := range tags {
+ fmt.Fprintf(&stdin, "refs/tags/%s\n", tag)
+ fmt.Fprintf(&stdin, "refs/tags/%s:%s\n", tag, file)
+ }
+
+ data, err := RunWithStdin(r.dir, &stdin, "git", "cat-file", "--batch")
+ if err != nil {
+ return nil, err
+ }
+
+ next := func() (typ string, body []byte, ok bool) {
+ var line string
+ i := bytes.IndexByte(data, '\n')
+ if i < 0 {
+ return "", nil, false
+ }
+ line, data = string(bytes.TrimSpace(data[:i])), data[i+1:]
+ if strings.HasSuffix(line, " missing") {
+ return "missing", nil, true
+ }
+ f := strings.Fields(line)
+ if len(f) != 3 {
+ return "", nil, false
+ }
+ n, err := strconv.Atoi(f[2])
+ if err != nil || n > len(data) {
+ return "", nil, false
+ }
+ body, data = data[:n], data[n:]
+ if len(data) > 0 && data[0] == '\r' {
+ data = data[1:]
+ }
+ if len(data) > 0 && data[0] == '\n' {
+ data = data[1:]
+ }
+ return f[1], body, true
+ }
+
+ badGit := func() ([]string, error) {
+ return nil, fmt.Errorf("malformed output from git cat-file --batch")
+ }
+
+ for _, tag := range tags {
+ commitType, _, ok := next()
+ if !ok {
+ return badGit()
+ }
+ fileType, fileData, ok := next()
+ if !ok {
+ return badGit()
+ }
+ f := fileMap[tag]
+ f.Data = nil
+ f.Err = nil
+ switch commitType {
+ default:
+ f.Err = fmt.Errorf("unexpected non-commit type %q for rev %s", commitType, tag)
+
+ case "missing":
+ // Note: f.Err must not satisfy os.IsNotExist. That's reserved for the file not existing in a valid commit.
+ f.Err = fmt.Errorf("no such rev %s", tag)
+ missing = append(missing, tag)
+
+ case "tag", "commit":
+ switch fileType {
+ default:
+ f.Err = &os.PathError{Path: tag + ":" + file, Op: "read", Err: fmt.Errorf("unexpected non-blob type %q", fileType)}
+ case "missing":
+ f.Err = &os.PathError{Path: tag + ":" + file, Op: "read", Err: os.ErrNotExist}
+ case "blob":
+ f.Data = fileData
+ }
+ }
+ }
+ if len(bytes.TrimSpace(data)) != 0 {
+ return badGit()
+ }
+
+ return missing, nil
+}
+
+func (r *gitRepo) RecentTag(rev, prefix string) (tag string, err error) {
+ info, err := r.Stat(rev)
+ if err != nil {
+ return "", err
+ }
+ rev = info.Name // expand hash prefixes
+
+ // describe sets tag and err using 'git describe' and reports whether the
+ // result is definitive.
+ describe := func() (definitive bool) {
+ var out []byte
+ out, err = Run(r.dir, "git", "describe", "--first-parent", "--always", "--abbrev=0", "--match", prefix+"v[0-9]*.[0-9]*.[0-9]*", "--tags", rev)
+ if err != nil {
+ return true // Because we use "--always", describe should never fail.
+ }
+
+ tag = string(bytes.TrimSpace(out))
+ return tag != "" && !AllHex(tag)
+ }
+
+ if describe() {
+ return tag, err
+ }
+
+ // Git didn't find a version tag preceding the requested rev.
+ // See whether any plausible tag exists.
+ tags, err := r.Tags(prefix + "v")
+ if err != nil {
+ return "", err
+ }
+ if len(tags) == 0 {
+ return "", nil
+ }
+
+ // There are plausible tags, but we don't know if rev is a descendent of any of them.
+ // Fetch the history to find out.
+
+ r.mu.Lock()
+ defer r.mu.Unlock()
+
+ if r.fetchLevel < fetchAll {
+ // Fetch all heads and tags and see if that gives us enough history.
+ if err := r.fetchUnshallow("refs/heads/*:refs/heads/*", "refs/tags/*:refs/tags/*"); err != nil {
+ return "", err
+ }
+ r.fetchLevel = fetchAll
+ }
+
+ // If we've reached this point, we have all of the commits that are reachable
+ // from all heads and tags.
+ //
+ // The only refs we should be missing are those that are no longer reachable
+ // (or never were reachable) from any branch or tag, including the master
+ // branch, and we don't want to resolve them anyway (they're probably
+ // unreachable for a reason).
+ //
+ // Try one last time in case some other goroutine fetched rev while we were
+ // waiting on r.mu.
+ describe()
+ return tag, err
+}
+
+func (r *gitRepo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser, actualSubdir string, err error) {
+ // TODO: Use maxSize or drop it.
+ args := []string{}
+ if subdir != "" {
+ args = append(args, "--", subdir)
+ }
+ info, err := r.Stat(rev) // download rev into local git repo
+ if err != nil {
+ return nil, "", err
+ }
+
+ // Incredibly, git produces different archives depending on whether
+ // it is running on a Windows system or not, in an attempt to normalize
+ // text file line endings. Setting -c core.autocrlf=input means only
+ // translate files on the way into the repo, not on the way out (archive).
+ // The -c core.eol=lf should be unnecessary but set it anyway.
+ archive, err := Run(r.dir, "git", "-c", "core.autocrlf=input", "-c", "core.eol=lf", "archive", "--format=zip", "--prefix=prefix/", info.Name, args)
+ if err != nil {
+ if bytes.Contains(err.(*RunError).Stderr, []byte("did not match any files")) {
+ return nil, "", os.ErrNotExist
+ }
+ return nil, "", err
+ }
+
+ return ioutil.NopCloser(bytes.NewReader(archive)), "", nil
+}
diff --git a/libgo/go/cmd/go/internal/modfetch/codehost/git_test.go b/libgo/go/cmd/go/internal/modfetch/codehost/git_test.go
new file mode 100644
index 00000000000..da9e7050407
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfetch/codehost/git_test.go
@@ -0,0 +1,635 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package codehost
+
+import (
+ "archive/zip"
+ "bytes"
+ "flag"
+ "fmt"
+ "internal/testenv"
+ "io/ioutil"
+ "log"
+ "os"
+ "os/exec"
+ "path"
+ "path/filepath"
+ "reflect"
+ "strings"
+ "testing"
+ "time"
+)
+
+func TestMain(m *testing.M) {
+ // needed for initializing the test environment variables as testing.Short
+ // and HasExternalNetwork
+ flag.Parse()
+ os.Exit(testMain(m))
+}
+
+const (
+ gitrepo1 = "https://vcs-test.golang.org/git/gitrepo1"
+ hgrepo1 = "https://vcs-test.golang.org/hg/hgrepo1"
+)
+
+var altRepos = []string{
+ "localGitRepo",
+ hgrepo1,
+}
+
+// TODO: Convert gitrepo1 to svn, bzr, fossil and add tests.
+// For now, at least the hgrepo1 tests check the general vcs.go logic.
+
+// localGitRepo is like gitrepo1 but allows archive access.
+var localGitRepo string
+
+func testMain(m *testing.M) int {
+ if _, err := exec.LookPath("git"); err != nil {
+ fmt.Fprintln(os.Stderr, "skipping because git binary not found")
+ fmt.Println("PASS")
+ return 0
+ }
+
+ dir, err := ioutil.TempDir("", "gitrepo-test-")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+ WorkRoot = dir
+
+ if testenv.HasExternalNetwork() && testenv.HasExec() {
+ // Clone gitrepo1 into a local directory.
+ // If we use a file:// URL to access the local directory,
+ // then git starts up all the usual protocol machinery,
+ // which will let us test remote git archive invocations.
+ localGitRepo = filepath.Join(dir, "gitrepo2")
+ if _, err := Run("", "git", "clone", "--mirror", gitrepo1, localGitRepo); err != nil {
+ log.Fatal(err)
+ }
+ if _, err := Run(localGitRepo, "git", "config", "daemon.uploadarch", "true"); err != nil {
+ log.Fatal(err)
+ }
+ }
+
+ return m.Run()
+}
+
+func testRepo(remote string) (Repo, error) {
+ if remote == "localGitRepo" {
+ return LocalGitRepo(filepath.ToSlash(localGitRepo))
+ }
+ kind := "git"
+ for _, k := range []string{"hg"} {
+ if strings.Contains(remote, "/"+k+"/") {
+ kind = k
+ }
+ }
+ return NewRepo(kind, remote)
+}
+
+var tagsTests = []struct {
+ repo string
+ prefix string
+ tags []string
+}{
+ {gitrepo1, "xxx", []string{}},
+ {gitrepo1, "", []string{"v1.2.3", "v1.2.4-annotated", "v2.0.1", "v2.0.2", "v2.3"}},
+ {gitrepo1, "v", []string{"v1.2.3", "v1.2.4-annotated", "v2.0.1", "v2.0.2", "v2.3"}},
+ {gitrepo1, "v1", []string{"v1.2.3", "v1.2.4-annotated"}},
+ {gitrepo1, "2", []string{}},
+}
+
+func TestTags(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExec(t)
+
+ for _, tt := range tagsTests {
+ f := func(t *testing.T) {
+ r, err := testRepo(tt.repo)
+ if err != nil {
+ t.Fatal(err)
+ }
+ tags, err := r.Tags(tt.prefix)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !reflect.DeepEqual(tags, tt.tags) {
+ t.Errorf("Tags: incorrect tags\nhave %v\nwant %v", tags, tt.tags)
+ }
+ }
+ t.Run(path.Base(tt.repo)+"/"+tt.prefix, f)
+ if tt.repo == gitrepo1 {
+ for _, tt.repo = range altRepos {
+ t.Run(path.Base(tt.repo)+"/"+tt.prefix, f)
+ }
+ }
+ }
+}
+
+var latestTests = []struct {
+ repo string
+ info *RevInfo
+}{
+ {
+ gitrepo1,
+ &RevInfo{
+ Name: "ede458df7cd0fdca520df19a33158086a8a68e81",
+ Short: "ede458df7cd0",
+ Version: "ede458df7cd0fdca520df19a33158086a8a68e81",
+ Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC),
+ Tags: []string{"v1.2.3", "v1.2.4-annotated"},
+ },
+ },
+ {
+ hgrepo1,
+ &RevInfo{
+ Name: "18518c07eb8ed5c80221e997e518cccaa8c0c287",
+ Short: "18518c07eb8e",
+ Version: "18518c07eb8ed5c80221e997e518cccaa8c0c287",
+ Time: time.Date(2018, 6, 27, 16, 16, 30, 0, time.UTC),
+ },
+ },
+}
+
+func TestLatest(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExec(t)
+
+ for _, tt := range latestTests {
+ f := func(t *testing.T) {
+ r, err := testRepo(tt.repo)
+ if err != nil {
+ t.Fatal(err)
+ }
+ info, err := r.Latest()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !reflect.DeepEqual(info, tt.info) {
+ t.Errorf("Latest: incorrect info\nhave %+v\nwant %+v", *info, *tt.info)
+ }
+ }
+ t.Run(path.Base(tt.repo), f)
+ if tt.repo == gitrepo1 {
+ tt.repo = "localGitRepo"
+ t.Run(path.Base(tt.repo), f)
+ }
+ }
+}
+
+var readFileTests = []struct {
+ repo string
+ rev string
+ file string
+ err string
+ data string
+}{
+ {
+ repo: gitrepo1,
+ rev: "latest",
+ file: "README",
+ data: "",
+ },
+ {
+ repo: gitrepo1,
+ rev: "v2",
+ file: "another.txt",
+ data: "another\n",
+ },
+ {
+ repo: gitrepo1,
+ rev: "v2.3.4",
+ file: "another.txt",
+ err: os.ErrNotExist.Error(),
+ },
+}
+
+func TestReadFile(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExec(t)
+
+ for _, tt := range readFileTests {
+ f := func(t *testing.T) {
+ r, err := testRepo(tt.repo)
+ if err != nil {
+ t.Fatal(err)
+ }
+ data, err := r.ReadFile(tt.rev, tt.file, 100)
+ if err != nil {
+ if tt.err == "" {
+ t.Fatalf("ReadFile: unexpected error %v", err)
+ }
+ if !strings.Contains(err.Error(), tt.err) {
+ t.Fatalf("ReadFile: wrong error %q, want %q", err, tt.err)
+ }
+ if len(data) != 0 {
+ t.Errorf("ReadFile: non-empty data %q with error %v", data, err)
+ }
+ return
+ }
+ if tt.err != "" {
+ t.Fatalf("ReadFile: no error, wanted %v", tt.err)
+ }
+ if string(data) != tt.data {
+ t.Errorf("ReadFile: incorrect data\nhave %q\nwant %q", data, tt.data)
+ }
+ }
+ t.Run(path.Base(tt.repo)+"/"+tt.rev+"/"+tt.file, f)
+ if tt.repo == gitrepo1 {
+ for _, tt.repo = range altRepos {
+ t.Run(path.Base(tt.repo)+"/"+tt.rev+"/"+tt.file, f)
+ }
+ }
+ }
+}
+
+var readZipTests = []struct {
+ repo string
+ rev string
+ subdir string
+ actualSubdir string
+ err string
+ files map[string]uint64
+}{
+ {
+ repo: gitrepo1,
+ rev: "v2.3.4",
+ subdir: "",
+ files: map[string]uint64{
+ "prefix/": 0,
+ "prefix/README": 0,
+ "prefix/v2": 3,
+ },
+ },
+ {
+ repo: hgrepo1,
+ rev: "v2.3.4",
+ subdir: "",
+ files: map[string]uint64{
+ "prefix/.hg_archival.txt": ^uint64(0),
+ "prefix/README": 0,
+ "prefix/v2": 3,
+ },
+ },
+
+ {
+ repo: gitrepo1,
+ rev: "v2",
+ subdir: "",
+ files: map[string]uint64{
+ "prefix/": 0,
+ "prefix/README": 0,
+ "prefix/v2": 3,
+ "prefix/another.txt": 8,
+ "prefix/foo.txt": 13,
+ },
+ },
+ {
+ repo: hgrepo1,
+ rev: "v2",
+ subdir: "",
+ files: map[string]uint64{
+ "prefix/.hg_archival.txt": ^uint64(0),
+ "prefix/README": 0,
+ "prefix/v2": 3,
+ "prefix/another.txt": 8,
+ "prefix/foo.txt": 13,
+ },
+ },
+
+ {
+ repo: gitrepo1,
+ rev: "v3",
+ subdir: "",
+ files: map[string]uint64{
+ "prefix/": 0,
+ "prefix/v3/": 0,
+ "prefix/v3/sub/": 0,
+ "prefix/v3/sub/dir/": 0,
+ "prefix/v3/sub/dir/file.txt": 16,
+ "prefix/README": 0,
+ },
+ },
+ {
+ repo: hgrepo1,
+ rev: "v3",
+ subdir: "",
+ files: map[string]uint64{
+ "prefix/.hg_archival.txt": ^uint64(0),
+ "prefix/.hgtags": 405,
+ "prefix/v3/sub/dir/file.txt": 16,
+ "prefix/README": 0,
+ },
+ },
+
+ {
+ repo: gitrepo1,
+ rev: "v3",
+ subdir: "v3/sub/dir",
+ files: map[string]uint64{
+ "prefix/": 0,
+ "prefix/v3/": 0,
+ "prefix/v3/sub/": 0,
+ "prefix/v3/sub/dir/": 0,
+ "prefix/v3/sub/dir/file.txt": 16,
+ },
+ },
+ {
+ repo: hgrepo1,
+ rev: "v3",
+ subdir: "v3/sub/dir",
+ files: map[string]uint64{
+ "prefix/v3/sub/dir/file.txt": 16,
+ },
+ },
+
+ {
+ repo: gitrepo1,
+ rev: "v3",
+ subdir: "v3/sub",
+ files: map[string]uint64{
+ "prefix/": 0,
+ "prefix/v3/": 0,
+ "prefix/v3/sub/": 0,
+ "prefix/v3/sub/dir/": 0,
+ "prefix/v3/sub/dir/file.txt": 16,
+ },
+ },
+ {
+ repo: hgrepo1,
+ rev: "v3",
+ subdir: "v3/sub",
+ files: map[string]uint64{
+ "prefix/v3/sub/dir/file.txt": 16,
+ },
+ },
+
+ {
+ repo: gitrepo1,
+ rev: "aaaaaaaaab",
+ subdir: "",
+ err: "unknown revision",
+ },
+ {
+ repo: hgrepo1,
+ rev: "aaaaaaaaab",
+ subdir: "",
+ err: "unknown revision",
+ },
+
+ {
+ repo: "https://github.com/rsc/vgotest1",
+ rev: "submod/v1.0.4",
+ subdir: "submod",
+ files: map[string]uint64{
+ "prefix/": 0,
+ "prefix/submod/": 0,
+ "prefix/submod/go.mod": 53,
+ "prefix/submod/pkg/": 0,
+ "prefix/submod/pkg/p.go": 31,
+ },
+ },
+}
+
+type zipFile struct {
+ name string
+ size int64
+}
+
+func TestReadZip(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExec(t)
+
+ for _, tt := range readZipTests {
+ f := func(t *testing.T) {
+ r, err := testRepo(tt.repo)
+ if err != nil {
+ t.Fatal(err)
+ }
+ rc, actualSubdir, err := r.ReadZip(tt.rev, tt.subdir, 100000)
+ if err != nil {
+ if tt.err == "" {
+ t.Fatalf("ReadZip: unexpected error %v", err)
+ }
+ if !strings.Contains(err.Error(), tt.err) {
+ t.Fatalf("ReadZip: wrong error %q, want %q", err, tt.err)
+ }
+ if rc != nil {
+ t.Errorf("ReadZip: non-nil io.ReadCloser with error %v", err)
+ }
+ return
+ }
+ defer rc.Close()
+ if tt.err != "" {
+ t.Fatalf("ReadZip: no error, wanted %v", tt.err)
+ }
+ if actualSubdir != tt.actualSubdir {
+ t.Fatalf("ReadZip: actualSubdir = %q, want %q", actualSubdir, tt.actualSubdir)
+ }
+ zipdata, err := ioutil.ReadAll(rc)
+ if err != nil {
+ t.Fatal(err)
+ }
+ z, err := zip.NewReader(bytes.NewReader(zipdata), int64(len(zipdata)))
+ if err != nil {
+ t.Fatalf("ReadZip: cannot read zip file: %v", err)
+ }
+ have := make(map[string]bool)
+ for _, f := range z.File {
+ size, ok := tt.files[f.Name]
+ if !ok {
+ t.Errorf("ReadZip: unexpected file %s", f.Name)
+ continue
+ }
+ have[f.Name] = true
+ if size != ^uint64(0) && f.UncompressedSize64 != size {
+ t.Errorf("ReadZip: file %s has unexpected size %d != %d", f.Name, f.UncompressedSize64, size)
+ }
+ }
+ for name := range tt.files {
+ if !have[name] {
+ t.Errorf("ReadZip: missing file %s", name)
+ }
+ }
+ }
+ t.Run(path.Base(tt.repo)+"/"+tt.rev+"/"+tt.subdir, f)
+ if tt.repo == gitrepo1 {
+ tt.repo = "localGitRepo"
+ t.Run(path.Base(tt.repo)+"/"+tt.rev+"/"+tt.subdir, f)
+ }
+ }
+}
+
+var hgmap = map[string]string{
+ "HEAD": "41964ddce1180313bdc01d0a39a2813344d6261d", // not tip due to bad hgrepo1 conversion
+ "9d02800338b8a55be062c838d1f02e0c5780b9eb": "8f49ee7a6ddcdec6f0112d9dca48d4a2e4c3c09e",
+ "76a00fb249b7f93091bc2c89a789dab1fc1bc26f": "88fde824ec8b41a76baa16b7e84212cee9f3edd0",
+ "ede458df7cd0fdca520df19a33158086a8a68e81": "41964ddce1180313bdc01d0a39a2813344d6261d",
+ "97f6aa59c81c623494825b43d39e445566e429a4": "c0cbbfb24c7c3c50c35c7b88e7db777da4ff625d",
+}
+
+var statTests = []struct {
+ repo string
+ rev string
+ err string
+ info *RevInfo
+}{
+ {
+ repo: gitrepo1,
+ rev: "HEAD",
+ info: &RevInfo{
+ Name: "ede458df7cd0fdca520df19a33158086a8a68e81",
+ Short: "ede458df7cd0",
+ Version: "ede458df7cd0fdca520df19a33158086a8a68e81",
+ Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC),
+ Tags: []string{"v1.2.3", "v1.2.4-annotated"},
+ },
+ },
+ {
+ repo: gitrepo1,
+ rev: "v2", // branch
+ info: &RevInfo{
+ Name: "9d02800338b8a55be062c838d1f02e0c5780b9eb",
+ Short: "9d02800338b8",
+ Version: "9d02800338b8a55be062c838d1f02e0c5780b9eb",
+ Time: time.Date(2018, 4, 17, 20, 00, 32, 0, time.UTC),
+ Tags: []string{"v2.0.2"},
+ },
+ },
+ {
+ repo: gitrepo1,
+ rev: "v2.3.4", // badly-named branch (semver should be a tag)
+ info: &RevInfo{
+ Name: "76a00fb249b7f93091bc2c89a789dab1fc1bc26f",
+ Short: "76a00fb249b7",
+ Version: "76a00fb249b7f93091bc2c89a789dab1fc1bc26f",
+ Time: time.Date(2018, 4, 17, 19, 45, 48, 0, time.UTC),
+ Tags: []string{"v2.0.1", "v2.3"},
+ },
+ },
+ {
+ repo: gitrepo1,
+ rev: "v2.3", // badly-named tag (we only respect full semver v2.3.0)
+ info: &RevInfo{
+ Name: "76a00fb249b7f93091bc2c89a789dab1fc1bc26f",
+ Short: "76a00fb249b7",
+ Version: "v2.3",
+ Time: time.Date(2018, 4, 17, 19, 45, 48, 0, time.UTC),
+ Tags: []string{"v2.0.1", "v2.3"},
+ },
+ },
+ {
+ repo: gitrepo1,
+ rev: "v1.2.3", // tag
+ info: &RevInfo{
+ Name: "ede458df7cd0fdca520df19a33158086a8a68e81",
+ Short: "ede458df7cd0",
+ Version: "v1.2.3",
+ Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC),
+ Tags: []string{"v1.2.3", "v1.2.4-annotated"},
+ },
+ },
+ {
+ repo: gitrepo1,
+ rev: "ede458df", // hash prefix in refs
+ info: &RevInfo{
+ Name: "ede458df7cd0fdca520df19a33158086a8a68e81",
+ Short: "ede458df7cd0",
+ Version: "ede458df7cd0fdca520df19a33158086a8a68e81",
+ Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC),
+ Tags: []string{"v1.2.3", "v1.2.4-annotated"},
+ },
+ },
+ {
+ repo: gitrepo1,
+ rev: "97f6aa59", // hash prefix not in refs
+ info: &RevInfo{
+ Name: "97f6aa59c81c623494825b43d39e445566e429a4",
+ Short: "97f6aa59c81c",
+ Version: "97f6aa59c81c623494825b43d39e445566e429a4",
+ Time: time.Date(2018, 4, 17, 20, 0, 19, 0, time.UTC),
+ },
+ },
+ {
+ repo: gitrepo1,
+ rev: "v1.2.4-annotated", // annotated tag uses unwrapped commit hash
+ info: &RevInfo{
+ Name: "ede458df7cd0fdca520df19a33158086a8a68e81",
+ Short: "ede458df7cd0",
+ Version: "v1.2.4-annotated",
+ Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC),
+ Tags: []string{"v1.2.3", "v1.2.4-annotated"},
+ },
+ },
+ {
+ repo: gitrepo1,
+ rev: "aaaaaaaaab",
+ err: "unknown revision",
+ },
+}
+
+func TestStat(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExec(t)
+
+ for _, tt := range statTests {
+ f := func(t *testing.T) {
+ r, err := testRepo(tt.repo)
+ if err != nil {
+ t.Fatal(err)
+ }
+ info, err := r.Stat(tt.rev)
+ if err != nil {
+ if tt.err == "" {
+ t.Fatalf("Stat: unexpected error %v", err)
+ }
+ if !strings.Contains(err.Error(), tt.err) {
+ t.Fatalf("Stat: wrong error %q, want %q", err, tt.err)
+ }
+ if info != nil {
+ t.Errorf("Stat: non-nil info with error %q", err)
+ }
+ return
+ }
+ if !reflect.DeepEqual(info, tt.info) {
+ t.Errorf("Stat: incorrect info\nhave %+v\nwant %+v", *info, *tt.info)
+ }
+ }
+ t.Run(path.Base(tt.repo)+"/"+tt.rev, f)
+ if tt.repo == gitrepo1 {
+ for _, tt.repo = range altRepos {
+ old := tt
+ var m map[string]string
+ if tt.repo == hgrepo1 {
+ m = hgmap
+ }
+ if tt.info != nil {
+ info := *tt.info
+ tt.info = &info
+ tt.info.Name = remap(tt.info.Name, m)
+ tt.info.Version = remap(tt.info.Version, m)
+ tt.info.Short = remap(tt.info.Short, m)
+ }
+ tt.rev = remap(tt.rev, m)
+ t.Run(path.Base(tt.repo)+"/"+tt.rev, f)
+ tt = old
+ }
+ }
+ }
+}
+
+func remap(name string, m map[string]string) string {
+ if m[name] != "" {
+ return m[name]
+ }
+ if AllHex(name) {
+ for k, v := range m {
+ if strings.HasPrefix(k, name) {
+ return v[:len(name)]
+ }
+ }
+ }
+ return name
+}
diff --git a/libgo/go/cmd/go/internal/modfetch/codehost/shell.go b/libgo/go/cmd/go/internal/modfetch/codehost/shell.go
new file mode 100644
index 00000000000..7b813c37401
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfetch/codehost/shell.go
@@ -0,0 +1,140 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+// Interactive debugging shell for codehost.Repo implementations.
+
+package main
+
+import (
+ "archive/zip"
+ "bufio"
+ "bytes"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os"
+ "strings"
+ "time"
+
+ "cmd/go/internal/modfetch/codehost"
+)
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "usage: go run shell.go vcs remote\n")
+ os.Exit(2)
+}
+
+func main() {
+ codehost.WorkRoot = "/tmp/vcswork"
+ log.SetFlags(0)
+ log.SetPrefix("shell: ")
+ flag.Usage = usage
+ flag.Parse()
+ if flag.NArg() != 2 {
+ usage()
+ }
+
+ repo, err := codehost.NewRepo(flag.Arg(0), flag.Arg(1))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ b := bufio.NewReader(os.Stdin)
+ for {
+ fmt.Fprintf(os.Stderr, ">>> ")
+ line, err := b.ReadString('\n')
+ if err != nil {
+ log.Fatal(err)
+ }
+ f := strings.Fields(line)
+ if len(f) == 0 {
+ continue
+ }
+ switch f[0] {
+ default:
+ fmt.Fprintf(os.Stderr, "?unknown command\n")
+ continue
+ case "tags":
+ prefix := ""
+ if len(f) == 2 {
+ prefix = f[1]
+ }
+ if len(f) > 2 {
+ fmt.Fprintf(os.Stderr, "?usage: tags [prefix]\n")
+ continue
+ }
+ tags, err := repo.Tags(prefix)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "?%s\n", err)
+ continue
+ }
+ for _, tag := range tags {
+ fmt.Printf("%s\n", tag)
+ }
+
+ case "stat":
+ if len(f) != 2 {
+ fmt.Fprintf(os.Stderr, "?usage: stat rev\n")
+ continue
+ }
+ info, err := repo.Stat(f[1])
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "?%s\n", err)
+ continue
+ }
+ fmt.Printf("name=%s short=%s version=%s time=%s\n", info.Name, info.Short, info.Version, info.Time.UTC().Format(time.RFC3339))
+
+ case "read":
+ if len(f) != 3 {
+ fmt.Fprintf(os.Stderr, "?usage: read rev file\n")
+ continue
+ }
+ data, err := repo.ReadFile(f[1], f[2], 10<<20)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "?%s\n", err)
+ continue
+ }
+ os.Stdout.Write(data)
+
+ case "zip":
+ if len(f) != 4 {
+ fmt.Fprintf(os.Stderr, "?usage: zip rev subdir output\n")
+ continue
+ }
+ subdir := f[2]
+ if subdir == "-" {
+ subdir = ""
+ }
+ rc, _, err := repo.ReadZip(f[1], subdir, 10<<20)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "?%s\n", err)
+ continue
+ }
+ data, err := ioutil.ReadAll(rc)
+ rc.Close()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "?%s\n", err)
+ continue
+ }
+
+ if f[3] != "-" {
+ if err := ioutil.WriteFile(f[3], data, 0666); err != nil {
+ fmt.Fprintf(os.Stderr, "?%s\n", err)
+ continue
+ }
+ }
+ z, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "?%s\n", err)
+ continue
+ }
+ for _, f := range z.File {
+ fmt.Printf("%s %d\n", f.Name, f.UncompressedSize64)
+ }
+ }
+ }
+}
diff --git a/libgo/go/cmd/go/internal/modfetch/codehost/vcs.go b/libgo/go/cmd/go/internal/modfetch/codehost/vcs.go
new file mode 100644
index 00000000000..9e862a0ef8c
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfetch/codehost/vcs.go
@@ -0,0 +1,528 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package codehost
+
+import (
+ "encoding/xml"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "regexp"
+ "sort"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "cmd/go/internal/par"
+ "cmd/go/internal/str"
+)
+
+// A VCSError indicates an error using a version control system.
+// The implication of a VCSError is that we know definitively where
+// to get the code, but we can't access it due to the error.
+// The caller should report this error instead of continuing to probe
+// other possible module paths.
+type VCSError struct {
+ Err error
+}
+
+func (e *VCSError) Error() string { return e.Err.Error() }
+
+func NewRepo(vcs, remote string) (Repo, error) {
+ type key struct {
+ vcs string
+ remote string
+ }
+ type cached struct {
+ repo Repo
+ err error
+ }
+ c := vcsRepoCache.Do(key{vcs, remote}, func() interface{} {
+ repo, err := newVCSRepo(vcs, remote)
+ if err != nil {
+ err = &VCSError{err}
+ }
+ return cached{repo, err}
+ }).(cached)
+
+ return c.repo, c.err
+}
+
+var vcsRepoCache par.Cache
+
+type vcsRepo struct {
+ remote string
+ cmd *vcsCmd
+ dir string
+
+ tagsOnce sync.Once
+ tags map[string]bool
+
+ branchesOnce sync.Once
+ branches map[string]bool
+
+ fetchOnce sync.Once
+ fetchErr error
+}
+
+func newVCSRepo(vcs, remote string) (Repo, error) {
+ if vcs == "git" {
+ return newGitRepo(remote, false)
+ }
+ cmd := vcsCmds[vcs]
+ if cmd == nil {
+ return nil, fmt.Errorf("unknown vcs: %s %s", vcs, remote)
+ }
+ if !strings.Contains(remote, "://") {
+ return nil, fmt.Errorf("invalid vcs remote: %s %s", vcs, remote)
+ }
+ r := &vcsRepo{remote: remote, cmd: cmd}
+ if cmd.init == nil {
+ return r, nil
+ }
+ dir, err := WorkDir(vcsWorkDirType+vcs, r.remote)
+ if err != nil {
+ return nil, err
+ }
+ r.dir = dir
+ if _, err := os.Stat(filepath.Join(dir, "."+vcs)); err != nil {
+ if _, err := Run(dir, cmd.init(r.remote)); err != nil {
+ os.RemoveAll(dir)
+ return nil, err
+ }
+ }
+ return r, nil
+}
+
+const vcsWorkDirType = "vcs1."
+
+type vcsCmd struct {
+ vcs string // vcs name "hg"
+ init func(remote string) []string // cmd to init repo to track remote
+ tags func(remote string) []string // cmd to list local tags
+ tagRE *regexp.Regexp // regexp to extract tag names from output of tags cmd
+ branches func(remote string) []string // cmd to list local branches
+ branchRE *regexp.Regexp // regexp to extract branch names from output of tags cmd
+ badLocalRevRE *regexp.Regexp // regexp of names that must not be served out of local cache without doing fetch first
+ statLocal func(rev, remote string) []string // cmd to stat local rev
+ parseStat func(rev, out string) (*RevInfo, error) // cmd to parse output of statLocal
+ fetch []string // cmd to fetch everything from remote
+ latest string // name of latest commit on remote (tip, HEAD, etc)
+ readFile func(rev, file, remote string) []string // cmd to read rev's file
+ readZip func(rev, subdir, remote, target string) []string // cmd to read rev's subdir as zip file
+}
+
+var re = regexp.MustCompile
+
+var vcsCmds = map[string]*vcsCmd{
+ "hg": {
+ vcs: "hg",
+ init: func(remote string) []string {
+ return []string{"hg", "clone", "-U", remote, "."}
+ },
+ tags: func(remote string) []string {
+ return []string{"hg", "tags", "-q"}
+ },
+ tagRE: re(`(?m)^[^\n]+$`),
+ branches: func(remote string) []string {
+ return []string{"hg", "branches", "-c", "-q"}
+ },
+ branchRE: re(`(?m)^[^\n]+$`),
+ badLocalRevRE: re(`(?m)^(tip)$`),
+ statLocal: func(rev, remote string) []string {
+ return []string{"hg", "log", "-l1", "-r", rev, "--template", "{node} {date|hgdate} {tags}"}
+ },
+ parseStat: hgParseStat,
+ fetch: []string{"hg", "pull", "-f"},
+ latest: "tip",
+ readFile: func(rev, file, remote string) []string {
+ return []string{"hg", "cat", "-r", rev, file}
+ },
+ readZip: func(rev, subdir, remote, target string) []string {
+ pattern := []string{}
+ if subdir != "" {
+ pattern = []string{"-I", subdir + "/**"}
+ }
+ return str.StringList("hg", "archive", "-t", "zip", "--no-decode", "-r", rev, "--prefix=prefix/", pattern, target)
+ },
+ },
+
+ "svn": {
+ vcs: "svn",
+ init: nil, // no local checkout
+ tags: func(remote string) []string {
+ return []string{"svn", "list", strings.TrimSuffix(remote, "/trunk") + "/tags"}
+ },
+ tagRE: re(`(?m)^(.*?)/?$`),
+ statLocal: func(rev, remote string) []string {
+ suffix := "@" + rev
+ if rev == "latest" {
+ suffix = ""
+ }
+ return []string{"svn", "log", "-l1", "--xml", remote + suffix}
+ },
+ parseStat: svnParseStat,
+ latest: "latest",
+ readFile: func(rev, file, remote string) []string {
+ return []string{"svn", "cat", remote + "/" + file + "@" + rev}
+ },
+ // TODO: zip
+ },
+
+ "bzr": {
+ vcs: "bzr",
+ init: func(remote string) []string {
+ return []string{"bzr", "branch", "--use-existing-dir", remote, "."}
+ },
+ fetch: []string{
+ "bzr", "pull", "--overwrite-tags",
+ },
+ tags: func(remote string) []string {
+ return []string{"bzr", "tags"}
+ },
+ tagRE: re(`(?m)^\S+`),
+ badLocalRevRE: re(`^revno:-`),
+ statLocal: func(rev, remote string) []string {
+ return []string{"bzr", "log", "-l1", "--long", "--show-ids", "-r", rev}
+ },
+ parseStat: bzrParseStat,
+ latest: "revno:-1",
+ readFile: func(rev, file, remote string) []string {
+ return []string{"bzr", "cat", "-r", rev, file}
+ },
+ readZip: func(rev, subdir, remote, target string) []string {
+ extra := []string{}
+ if subdir != "" {
+ extra = []string{"./" + subdir}
+ }
+ return str.StringList("bzr", "export", "--format=zip", "-r", rev, "--root=prefix/", target, extra)
+ },
+ },
+
+ "fossil": {
+ vcs: "fossil",
+ init: func(remote string) []string {
+ return []string{"fossil", "clone", remote, ".fossil"}
+ },
+ fetch: []string{"fossil", "pull", "-R", ".fossil"},
+ tags: func(remote string) []string {
+ return []string{"fossil", "tag", "-R", ".fossil", "list"}
+ },
+ tagRE: re(`XXXTODO`),
+ statLocal: func(rev, remote string) []string {
+ return []string{"fossil", "info", "-R", ".fossil", rev}
+ },
+ parseStat: fossilParseStat,
+ latest: "trunk",
+ readFile: func(rev, file, remote string) []string {
+ return []string{"fossil", "cat", "-R", ".fossil", "-r", rev, file}
+ },
+ readZip: func(rev, subdir, remote, target string) []string {
+ extra := []string{}
+ if subdir != "" && !strings.ContainsAny(subdir, "*?[],") {
+ extra = []string{"--include", subdir}
+ }
+ // Note that vcsRepo.ReadZip below rewrites this command
+ // to run in a different directory, to work around a fossil bug.
+ return str.StringList("fossil", "zip", "-R", ".fossil", "--name", "prefix", extra, rev, target)
+ },
+ },
+}
+
+func (r *vcsRepo) loadTags() {
+ out, err := Run(r.dir, r.cmd.tags(r.remote))
+ if err != nil {
+ return
+ }
+
+ // Run tag-listing command and extract tags.
+ r.tags = make(map[string]bool)
+ for _, tag := range r.cmd.tagRE.FindAllString(string(out), -1) {
+ if r.cmd.badLocalRevRE != nil && r.cmd.badLocalRevRE.MatchString(tag) {
+ continue
+ }
+ r.tags[tag] = true
+ }
+}
+
+func (r *vcsRepo) loadBranches() {
+ if r.cmd.branches == nil {
+ return
+ }
+
+ out, err := Run(r.dir, r.cmd.branches(r.remote))
+ if err != nil {
+ return
+ }
+
+ r.branches = make(map[string]bool)
+ for _, branch := range r.cmd.branchRE.FindAllString(string(out), -1) {
+ if r.cmd.badLocalRevRE != nil && r.cmd.badLocalRevRE.MatchString(branch) {
+ continue
+ }
+ r.branches[branch] = true
+ }
+}
+
+func (r *vcsRepo) Tags(prefix string) ([]string, error) {
+ r.tagsOnce.Do(r.loadTags)
+
+ tags := []string{}
+ for tag := range r.tags {
+ if strings.HasPrefix(tag, prefix) {
+ tags = append(tags, tag)
+ }
+ }
+ sort.Strings(tags)
+ return tags, nil
+}
+
+func (r *vcsRepo) Stat(rev string) (*RevInfo, error) {
+ if rev == "latest" {
+ rev = r.cmd.latest
+ }
+ r.branchesOnce.Do(r.loadBranches)
+ revOK := (r.cmd.badLocalRevRE == nil || !r.cmd.badLocalRevRE.MatchString(rev)) && !r.branches[rev]
+ if revOK {
+ if info, err := r.statLocal(rev); err == nil {
+ return info, nil
+ }
+ }
+
+ r.fetchOnce.Do(r.fetch)
+ if r.fetchErr != nil {
+ return nil, r.fetchErr
+ }
+ info, err := r.statLocal(rev)
+ if err != nil {
+ return nil, err
+ }
+ if !revOK {
+ info.Version = info.Name
+ }
+ return info, nil
+}
+
+func (r *vcsRepo) fetch() {
+ _, r.fetchErr = Run(r.dir, r.cmd.fetch)
+}
+
+func (r *vcsRepo) statLocal(rev string) (*RevInfo, error) {
+ out, err := Run(r.dir, r.cmd.statLocal(rev, r.remote))
+ if err != nil {
+ return nil, fmt.Errorf("unknown revision %s", rev)
+ }
+ return r.cmd.parseStat(rev, string(out))
+}
+
+func (r *vcsRepo) Latest() (*RevInfo, error) {
+ return r.Stat("latest")
+}
+
+func (r *vcsRepo) ReadFile(rev, file string, maxSize int64) ([]byte, error) {
+ if rev == "latest" {
+ rev = r.cmd.latest
+ }
+ _, err := r.Stat(rev) // download rev into local repo
+ if err != nil {
+ return nil, err
+ }
+ out, err := Run(r.dir, r.cmd.readFile(rev, file, r.remote))
+ if err != nil {
+ return nil, os.ErrNotExist
+ }
+ return out, nil
+}
+
+func (r *vcsRepo) ReadFileRevs(revs []string, file string, maxSize int64) (map[string]*FileRev, error) {
+ return nil, fmt.Errorf("ReadFileRevs not implemented")
+}
+
+func (r *vcsRepo) RecentTag(rev, prefix string) (tag string, err error) {
+ return "", fmt.Errorf("RecentTags not implemented")
+}
+
+func (r *vcsRepo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser, actualSubdir string, err error) {
+ if rev == "latest" {
+ rev = r.cmd.latest
+ }
+ f, err := ioutil.TempFile("", "go-readzip-*.zip")
+ if err != nil {
+ return nil, "", err
+ }
+ if r.cmd.vcs == "fossil" {
+ // If you run
+ // fossil zip -R .fossil --name prefix trunk /tmp/x.zip
+ // fossil fails with "unable to create directory /tmp" [sic].
+ // Change the command to run in /tmp instead,
+ // replacing the -R argument with an absolute path.
+ args := r.cmd.readZip(rev, subdir, r.remote, filepath.Base(f.Name()))
+ for i := range args {
+ if args[i] == ".fossil" {
+ args[i] = filepath.Join(r.dir, ".fossil")
+ }
+ }
+ _, err = Run(filepath.Dir(f.Name()), args)
+ } else {
+ _, err = Run(r.dir, r.cmd.readZip(rev, subdir, r.remote, f.Name()))
+ }
+ if err != nil {
+ f.Close()
+ os.Remove(f.Name())
+ return nil, "", err
+ }
+ return &deleteCloser{f}, "", nil
+}
+
+// deleteCloser is a file that gets deleted on Close.
+type deleteCloser struct {
+ *os.File
+}
+
+func (d *deleteCloser) Close() error {
+ defer os.Remove(d.File.Name())
+ return d.File.Close()
+}
+
+func hgParseStat(rev, out string) (*RevInfo, error) {
+ f := strings.Fields(string(out))
+ if len(f) < 3 {
+ return nil, fmt.Errorf("unexpected response from hg log: %q", out)
+ }
+ hash := f[0]
+ version := rev
+ if strings.HasPrefix(hash, version) {
+ version = hash // extend to full hash
+ }
+ t, err := strconv.ParseInt(f[1], 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("invalid time from hg log: %q", out)
+ }
+
+ var tags []string
+ for _, tag := range f[3:] {
+ if tag != "tip" {
+ tags = append(tags, tag)
+ }
+ }
+ sort.Strings(tags)
+
+ info := &RevInfo{
+ Name: hash,
+ Short: ShortenSHA1(hash),
+ Time: time.Unix(t, 0).UTC(),
+ Version: version,
+ Tags: tags,
+ }
+ return info, nil
+}
+
+func svnParseStat(rev, out string) (*RevInfo, error) {
+ var log struct {
+ Logentry struct {
+ Revision int64 `xml:"revision,attr"`
+ Date string `xml:"date"`
+ } `xml:"logentry"`
+ }
+ if err := xml.Unmarshal([]byte(out), &log); err != nil {
+ return nil, fmt.Errorf("unexpected response from svn log --xml: %v\n%s", err, out)
+ }
+
+ t, err := time.Parse(time.RFC3339, log.Logentry.Date)
+ if err != nil {
+ return nil, fmt.Errorf("unexpected response from svn log --xml: %v\n%s", err, out)
+ }
+
+ info := &RevInfo{
+ Name: fmt.Sprintf("%d", log.Logentry.Revision),
+ Short: fmt.Sprintf("%012d", log.Logentry.Revision),
+ Time: t.UTC(),
+ Version: rev,
+ }
+ return info, nil
+}
+
+func bzrParseStat(rev, out string) (*RevInfo, error) {
+ var revno int64
+ var tm time.Time
+ for _, line := range strings.Split(out, "\n") {
+ if line == "" || line[0] == ' ' || line[0] == '\t' {
+ // End of header, start of commit message.
+ break
+ }
+ if line[0] == '-' {
+ continue
+ }
+ i := strings.Index(line, ":")
+ if i < 0 {
+ // End of header, start of commit message.
+ break
+ }
+ key, val := line[:i], strings.TrimSpace(line[i+1:])
+ switch key {
+ case "revno":
+ if j := strings.Index(val, " "); j >= 0 {
+ val = val[:j]
+ }
+ i, err := strconv.ParseInt(val, 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("unexpected revno from bzr log: %q", line)
+ }
+ revno = i
+ case "timestamp":
+ j := strings.Index(val, " ")
+ if j < 0 {
+ return nil, fmt.Errorf("unexpected timestamp from bzr log: %q", line)
+ }
+ t, err := time.Parse("2006-01-02 15:04:05 -0700", val[j+1:])
+ if err != nil {
+ return nil, fmt.Errorf("unexpected timestamp from bzr log: %q", line)
+ }
+ tm = t.UTC()
+ }
+ }
+ if revno == 0 || tm.IsZero() {
+ return nil, fmt.Errorf("unexpected response from bzr log: %q", out)
+ }
+
+ info := &RevInfo{
+ Name: fmt.Sprintf("%d", revno),
+ Short: fmt.Sprintf("%012d", revno),
+ Time: tm,
+ Version: rev,
+ }
+ return info, nil
+}
+
+func fossilParseStat(rev, out string) (*RevInfo, error) {
+ for _, line := range strings.Split(out, "\n") {
+ if strings.HasPrefix(line, "uuid:") {
+ f := strings.Fields(line)
+ if len(f) != 5 || len(f[1]) != 40 || f[4] != "UTC" {
+ return nil, fmt.Errorf("unexpected response from fossil info: %q", line)
+ }
+ t, err := time.Parse("2006-01-02 15:04:05", f[2]+" "+f[3])
+ if err != nil {
+ return nil, fmt.Errorf("unexpected response from fossil info: %q", line)
+ }
+ hash := f[1]
+ version := rev
+ if strings.HasPrefix(hash, version) {
+ version = hash // extend to full hash
+ }
+ info := &RevInfo{
+ Name: hash,
+ Short: ShortenSHA1(hash),
+ Time: t,
+ Version: version,
+ }
+ return info, nil
+ }
+ }
+ return nil, fmt.Errorf("unexpected response from fossil info: %q", out)
+}
diff --git a/libgo/go/cmd/go/internal/modfetch/coderepo.go b/libgo/go/cmd/go/internal/modfetch/coderepo.go
new file mode 100644
index 00000000000..9cf0e911508
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfetch/coderepo.go
@@ -0,0 +1,605 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modfetch
+
+import (
+ "archive/zip"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path"
+ "strings"
+
+ "cmd/go/internal/modfetch/codehost"
+ "cmd/go/internal/modfile"
+ "cmd/go/internal/module"
+ "cmd/go/internal/semver"
+)
+
+// A codeRepo implements modfetch.Repo using an underlying codehost.Repo.
+type codeRepo struct {
+ modPath string
+
+ code codehost.Repo
+ codeRoot string
+ codeDir string
+
+ path string
+ pathPrefix string
+ pathMajor string
+ pseudoMajor string
+}
+
+func newCodeRepo(code codehost.Repo, root, path string) (Repo, error) {
+ if !hasPathPrefix(path, root) {
+ return nil, fmt.Errorf("mismatched repo: found %s for %s", root, path)
+ }
+ pathPrefix, pathMajor, ok := module.SplitPathVersion(path)
+ if !ok {
+ return nil, fmt.Errorf("invalid module path %q", path)
+ }
+ pseudoMajor := "v0"
+ if pathMajor != "" {
+ pseudoMajor = pathMajor[1:]
+ }
+
+ // At this point we might have:
+ // codeRoot = github.com/rsc/foo
+ // path = github.com/rsc/foo/bar/v2
+ // pathPrefix = github.com/rsc/foo/bar
+ // pathMajor = /v2
+ // pseudoMajor = v2
+ //
+ // Compute codeDir = bar, the subdirectory within the repo
+ // corresponding to the module root.
+ codeDir := strings.Trim(strings.TrimPrefix(pathPrefix, root), "/")
+ if strings.HasPrefix(path, "gopkg.in/") {
+ // But gopkg.in is a special legacy case, in which pathPrefix does not start with codeRoot.
+ // For example we might have:
+ // codeRoot = gopkg.in/yaml.v2
+ // pathPrefix = gopkg.in/yaml
+ // pathMajor = .v2
+ // pseudoMajor = v2
+ // codeDir = pathPrefix (because codeRoot is not a prefix of pathPrefix)
+ // Clear codeDir - the module root is the repo root for gopkg.in repos.
+ codeDir = ""
+ }
+
+ r := &codeRepo{
+ modPath: path,
+ code: code,
+ codeRoot: root,
+ codeDir: codeDir,
+ pathPrefix: pathPrefix,
+ pathMajor: pathMajor,
+ pseudoMajor: pseudoMajor,
+ }
+
+ return r, nil
+}
+
+func (r *codeRepo) ModulePath() string {
+ return r.modPath
+}
+
+func (r *codeRepo) Versions(prefix string) ([]string, error) {
+ // Special case: gopkg.in/macaroon-bakery.v2-unstable
+ // does not use the v2 tags (those are for macaroon-bakery.v2).
+ // It has no possible tags at all.
+ if strings.HasPrefix(r.modPath, "gopkg.in/") && strings.HasSuffix(r.modPath, "-unstable") {
+ return nil, nil
+ }
+
+ p := prefix
+ if r.codeDir != "" {
+ p = r.codeDir + "/" + p
+ }
+ tags, err := r.code.Tags(p)
+ if err != nil {
+ return nil, err
+ }
+
+ list := []string{}
+ var incompatible []string
+ for _, tag := range tags {
+ if !strings.HasPrefix(tag, p) {
+ continue
+ }
+ v := tag
+ if r.codeDir != "" {
+ v = v[len(r.codeDir)+1:]
+ }
+ if v == "" || v != module.CanonicalVersion(v) || IsPseudoVersion(v) {
+ continue
+ }
+ if !module.MatchPathMajor(v, r.pathMajor) {
+ if r.codeDir == "" && r.pathMajor == "" && semver.Major(v) > "v1" {
+ incompatible = append(incompatible, v)
+ }
+ continue
+ }
+ list = append(list, v)
+ }
+
+ if len(incompatible) > 0 {
+ // Check for later versions that were created not following semantic import versioning,
+ // as indicated by the absence of a go.mod file. Those versions can be addressed
+ // by referring to them with a +incompatible suffix, as in v17.0.0+incompatible.
+ files, err := r.code.ReadFileRevs(incompatible, "go.mod", codehost.MaxGoMod)
+ if err != nil {
+ return nil, err
+ }
+ for _, rev := range incompatible {
+ f := files[rev]
+ if os.IsNotExist(f.Err) {
+ list = append(list, rev+"+incompatible")
+ }
+ }
+ }
+
+ SortVersions(list)
+ return list, nil
+}
+
+func (r *codeRepo) Stat(rev string) (*RevInfo, error) {
+ if rev == "latest" {
+ return r.Latest()
+ }
+ codeRev := r.revToRev(rev)
+ if semver.IsValid(codeRev) && r.codeDir != "" {
+ codeRev = r.codeDir + "/" + codeRev
+ }
+ info, err := r.code.Stat(codeRev)
+ if err != nil {
+ return nil, err
+ }
+ return r.convert(info, rev)
+}
+
+func (r *codeRepo) Latest() (*RevInfo, error) {
+ info, err := r.code.Latest()
+ if err != nil {
+ return nil, err
+ }
+ return r.convert(info, "")
+}
+
+func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, error) {
+ info2 := &RevInfo{
+ Name: info.Name,
+ Short: info.Short,
+ Time: info.Time,
+ }
+
+ // Determine version.
+ if module.CanonicalVersion(statVers) == statVers && module.MatchPathMajor(statVers, r.pathMajor) {
+ // The original call was repo.Stat(statVers), and requestedVersion is OK, so use it.
+ info2.Version = statVers
+ } else {
+ // Otherwise derive a version from a code repo tag.
+ // Tag must have a prefix matching codeDir.
+ p := ""
+ if r.codeDir != "" {
+ p = r.codeDir + "/"
+ }
+
+ // If this is a plain tag (no dir/ prefix)
+ // and the module path is unversioned,
+ // and if the underlying file tree has no go.mod,
+ // then allow using the tag with a +incompatible suffix.
+ canUseIncompatible := false
+ if r.codeDir == "" && r.pathMajor == "" {
+ _, errGoMod := r.code.ReadFile(info.Name, "go.mod", codehost.MaxGoMod)
+ if errGoMod != nil {
+ canUseIncompatible = true
+ }
+ }
+
+ tagToVersion := func(v string) string {
+ if !strings.HasPrefix(v, p) {
+ return ""
+ }
+ v = v[len(p):]
+ if module.CanonicalVersion(v) != v || IsPseudoVersion(v) {
+ return ""
+ }
+ if module.MatchPathMajor(v, r.pathMajor) {
+ return v
+ }
+ if canUseIncompatible {
+ return v + "+incompatible"
+ }
+ return ""
+ }
+
+ // If info.Version is OK, use it.
+ if v := tagToVersion(info.Version); v != "" {
+ info2.Version = v
+ } else {
+ // Otherwise look through all known tags for latest in semver ordering.
+ for _, tag := range info.Tags {
+ if v := tagToVersion(tag); v != "" && semver.Compare(info2.Version, v) < 0 {
+ info2.Version = v
+ }
+ }
+ // Otherwise make a pseudo-version.
+ if info2.Version == "" {
+ tag, _ := r.code.RecentTag(statVers, p)
+ v = tagToVersion(tag)
+ // TODO: Check that v is OK for r.pseudoMajor or else is OK for incompatible.
+ info2.Version = PseudoVersion(r.pseudoMajor, v, info.Time, info.Short)
+ }
+ }
+ }
+
+ // Do not allow a successful stat of a pseudo-version for a subdirectory
+ // unless the subdirectory actually does have a go.mod.
+ if IsPseudoVersion(info2.Version) && r.codeDir != "" {
+ _, _, _, err := r.findDir(info2.Version)
+ if err != nil {
+ // TODO: It would be nice to return an error like "not a module".
+ // Right now we return "missing go.mod", which is a little confusing.
+ return nil, err
+ }
+ }
+
+ return info2, nil
+}
+
+func (r *codeRepo) revToRev(rev string) string {
+ if semver.IsValid(rev) {
+ if IsPseudoVersion(rev) {
+ r, _ := PseudoVersionRev(rev)
+ return r
+ }
+ if semver.Build(rev) == "+incompatible" {
+ rev = rev[:len(rev)-len("+incompatible")]
+ }
+ if r.codeDir == "" {
+ return rev
+ }
+ return r.codeDir + "/" + rev
+ }
+ return rev
+}
+
+func (r *codeRepo) versionToRev(version string) (rev string, err error) {
+ if !semver.IsValid(version) {
+ return "", fmt.Errorf("malformed semantic version %q", version)
+ }
+ return r.revToRev(version), nil
+}
+
+func (r *codeRepo) findDir(version string) (rev, dir string, gomod []byte, err error) {
+ rev, err = r.versionToRev(version)
+ if err != nil {
+ return "", "", nil, err
+ }
+
+ // Load info about go.mod but delay consideration
+ // (except I/O error) until we rule out v2/go.mod.
+ file1 := path.Join(r.codeDir, "go.mod")
+ gomod1, err1 := r.code.ReadFile(rev, file1, codehost.MaxGoMod)
+ if err1 != nil && !os.IsNotExist(err1) {
+ return "", "", nil, fmt.Errorf("reading %s/%s at revision %s: %v", r.pathPrefix, file1, rev, err1)
+ }
+ mpath1 := modfile.ModulePath(gomod1)
+ found1 := err1 == nil && isMajor(mpath1, r.pathMajor)
+
+ var file2 string
+ if r.pathMajor != "" && !strings.HasPrefix(r.pathMajor, ".") {
+ // Suppose pathMajor is "/v2".
+ // Either go.mod should claim v2 and v2/go.mod should not exist,
+ // or v2/go.mod should exist and claim v2. Not both.
+ // Note that we don't check the full path, just the major suffix,
+ // because of replacement modules. This might be a fork of
+ // the real module, found at a different path, usable only in
+ // a replace directive.
+ dir2 := path.Join(r.codeDir, r.pathMajor[1:])
+ file2 = path.Join(dir2, "go.mod")
+ gomod2, err2 := r.code.ReadFile(rev, file2, codehost.MaxGoMod)
+ if err2 != nil && !os.IsNotExist(err2) {
+ return "", "", nil, fmt.Errorf("reading %s/%s at revision %s: %v", r.pathPrefix, file2, rev, err2)
+ }
+ mpath2 := modfile.ModulePath(gomod2)
+ found2 := err2 == nil && isMajor(mpath2, r.pathMajor)
+
+ if found1 && found2 {
+ return "", "", nil, fmt.Errorf("%s/%s and ...%s/go.mod both have ...%s module paths at revision %s", r.pathPrefix, file1, r.pathMajor, r.pathMajor, rev)
+ }
+ if found2 {
+ return rev, dir2, gomod2, nil
+ }
+ if err2 == nil {
+ if mpath2 == "" {
+ return "", "", nil, fmt.Errorf("%s/%s is missing module path at revision %s", r.pathPrefix, file2, rev)
+ }
+ return "", "", nil, fmt.Errorf("%s/%s has non-...%s module path %q at revision %s", r.pathPrefix, file2, r.pathMajor, mpath2, rev)
+ }
+ }
+
+ // Not v2/go.mod, so it's either go.mod or nothing. Which is it?
+ if found1 {
+ // Explicit go.mod with matching module path OK.
+ return rev, r.codeDir, gomod1, nil
+ }
+ if err1 == nil {
+ // Explicit go.mod with non-matching module path disallowed.
+ suffix := ""
+ if file2 != "" {
+ suffix = fmt.Sprintf(" (and ...%s/go.mod does not exist)", r.pathMajor)
+ }
+ if mpath1 == "" {
+ return "", "", nil, fmt.Errorf("%s is missing module path%s at revision %s", file1, suffix, rev)
+ }
+ if r.pathMajor != "" { // ".v1", ".v2" for gopkg.in
+ return "", "", nil, fmt.Errorf("%s has non-...%s module path %q%s at revision %s", file1, r.pathMajor, mpath1, suffix, rev)
+ }
+ return "", "", nil, fmt.Errorf("%s has post-%s module path %q%s at revision %s", file1, semver.Major(version), mpath1, suffix, rev)
+ }
+
+ if r.codeDir == "" && (r.pathMajor == "" || strings.HasPrefix(r.pathMajor, ".")) {
+ // Implicit go.mod at root of repo OK for v0/v1 and for gopkg.in.
+ return rev, "", nil, nil
+ }
+
+ // Implicit go.mod below root of repo or at v2+ disallowed.
+ // Be clear about possibility of using either location for v2+.
+ if file2 != "" {
+ return "", "", nil, fmt.Errorf("missing %s/go.mod and ...%s/go.mod at revision %s", r.pathPrefix, r.pathMajor, rev)
+ }
+ return "", "", nil, fmt.Errorf("missing %s/go.mod at revision %s", r.pathPrefix, rev)
+}
+
+func isMajor(mpath, pathMajor string) bool {
+ if mpath == "" {
+ return false
+ }
+ if pathMajor == "" {
+ // mpath must NOT have version suffix.
+ i := len(mpath)
+ for i > 0 && '0' <= mpath[i-1] && mpath[i-1] <= '9' {
+ i--
+ }
+ if i < len(mpath) && i >= 2 && mpath[i-1] == 'v' && mpath[i-2] == '/' {
+ // Found valid suffix.
+ return false
+ }
+ return true
+ }
+ // Otherwise pathMajor is ".v1", ".v2" (gopkg.in), or "/v2", "/v3" etc.
+ return strings.HasSuffix(mpath, pathMajor)
+}
+
+func (r *codeRepo) GoMod(version string) (data []byte, err error) {
+ rev, dir, gomod, err := r.findDir(version)
+ if err != nil {
+ return nil, err
+ }
+ if gomod != nil {
+ return gomod, nil
+ }
+ data, err = r.code.ReadFile(rev, path.Join(dir, "go.mod"), codehost.MaxGoMod)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return r.legacyGoMod(rev, dir), nil
+ }
+ return nil, err
+ }
+ return data, nil
+}
+
+func (r *codeRepo) legacyGoMod(rev, dir string) []byte {
+ // We used to try to build a go.mod reflecting pre-existing
+ // package management metadata files, but the conversion
+ // was inherently imperfect (because those files don't have
+ // exactly the same semantics as go.mod) and, when done
+ // for dependencies in the middle of a build, impossible to
+ // correct. So we stopped.
+ // Return a fake go.mod that simply declares the module path.
+ return []byte(fmt.Sprintf("module %s\n", modfile.AutoQuote(r.modPath)))
+}
+
+func (r *codeRepo) modPrefix(rev string) string {
+ return r.modPath + "@" + rev
+}
+
+func (r *codeRepo) Zip(version string, tmpdir string) (tmpfile string, err error) {
+ rev, dir, _, err := r.findDir(version)
+ if err != nil {
+ return "", err
+ }
+ dl, actualDir, err := r.code.ReadZip(rev, dir, codehost.MaxZipFile)
+ if err != nil {
+ return "", err
+ }
+ if actualDir != "" && !hasPathPrefix(dir, actualDir) {
+ return "", fmt.Errorf("internal error: downloading %v %v: dir=%q but actualDir=%q", r.path, rev, dir, actualDir)
+ }
+ subdir := strings.Trim(strings.TrimPrefix(dir, actualDir), "/")
+
+ // Spool to local file.
+ f, err := ioutil.TempFile(tmpdir, "go-codehost-")
+ if err != nil {
+ dl.Close()
+ return "", err
+ }
+ defer os.Remove(f.Name())
+ defer f.Close()
+ maxSize := int64(codehost.MaxZipFile)
+ lr := &io.LimitedReader{R: dl, N: maxSize + 1}
+ if _, err := io.Copy(f, lr); err != nil {
+ dl.Close()
+ return "", err
+ }
+ dl.Close()
+ if lr.N <= 0 {
+ return "", fmt.Errorf("downloaded zip file too large")
+ }
+ size := (maxSize + 1) - lr.N
+ if _, err := f.Seek(0, 0); err != nil {
+ return "", err
+ }
+
+ // Translate from zip file we have to zip file we want.
+ zr, err := zip.NewReader(f, size)
+ if err != nil {
+ return "", err
+ }
+ f2, err := ioutil.TempFile(tmpdir, "go-codezip-")
+ if err != nil {
+ return "", err
+ }
+
+ zw := zip.NewWriter(f2)
+ newName := f2.Name()
+ defer func() {
+ f2.Close()
+ if err != nil {
+ os.Remove(newName)
+ }
+ }()
+ if subdir != "" {
+ subdir += "/"
+ }
+ haveLICENSE := false
+ topPrefix := ""
+ haveGoMod := make(map[string]bool)
+ for _, zf := range zr.File {
+ if topPrefix == "" {
+ i := strings.Index(zf.Name, "/")
+ if i < 0 {
+ return "", fmt.Errorf("missing top-level directory prefix")
+ }
+ topPrefix = zf.Name[:i+1]
+ }
+ if !strings.HasPrefix(zf.Name, topPrefix) {
+ return "", fmt.Errorf("zip file contains more than one top-level directory")
+ }
+ dir, file := path.Split(zf.Name)
+ if file == "go.mod" {
+ haveGoMod[dir] = true
+ }
+ }
+ root := topPrefix + subdir
+ inSubmodule := func(name string) bool {
+ for {
+ dir, _ := path.Split(name)
+ if len(dir) <= len(root) {
+ return false
+ }
+ if haveGoMod[dir] {
+ return true
+ }
+ name = dir[:len(dir)-1]
+ }
+ }
+ for _, zf := range zr.File {
+ if topPrefix == "" {
+ i := strings.Index(zf.Name, "/")
+ if i < 0 {
+ return "", fmt.Errorf("missing top-level directory prefix")
+ }
+ topPrefix = zf.Name[:i+1]
+ }
+ if strings.HasSuffix(zf.Name, "/") { // drop directory dummy entries
+ continue
+ }
+ if !strings.HasPrefix(zf.Name, topPrefix) {
+ return "", fmt.Errorf("zip file contains more than one top-level directory")
+ }
+ name := strings.TrimPrefix(zf.Name, topPrefix)
+ if !strings.HasPrefix(name, subdir) {
+ continue
+ }
+ if name == ".hg_archival.txt" {
+ // Inserted by hg archive.
+ // Not correct to drop from other version control systems, but too bad.
+ continue
+ }
+ name = strings.TrimPrefix(name, subdir)
+ if isVendoredPackage(name) {
+ continue
+ }
+ if inSubmodule(zf.Name) {
+ continue
+ }
+ base := path.Base(name)
+ if strings.ToLower(base) == "go.mod" && base != "go.mod" {
+ return "", fmt.Errorf("zip file contains %s, want all lower-case go.mod", zf.Name)
+ }
+ if name == "LICENSE" {
+ haveLICENSE = true
+ }
+ size := int64(zf.UncompressedSize)
+ if size < 0 || maxSize < size {
+ return "", fmt.Errorf("module source tree too big")
+ }
+ maxSize -= size
+
+ rc, err := zf.Open()
+ if err != nil {
+ return "", err
+ }
+ w, err := zw.Create(r.modPrefix(version) + "/" + name)
+ lr := &io.LimitedReader{R: rc, N: size + 1}
+ if _, err := io.Copy(w, lr); err != nil {
+ return "", err
+ }
+ if lr.N <= 0 {
+ return "", fmt.Errorf("individual file too large")
+ }
+ }
+
+ if !haveLICENSE && subdir != "" {
+ data, err := r.code.ReadFile(rev, "LICENSE", codehost.MaxLICENSE)
+ if err == nil {
+ w, err := zw.Create(r.modPrefix(version) + "/LICENSE")
+ if err != nil {
+ return "", err
+ }
+ if _, err := w.Write(data); err != nil {
+ return "", err
+ }
+ }
+ }
+ if err := zw.Close(); err != nil {
+ return "", err
+ }
+ if err := f2.Close(); err != nil {
+ return "", err
+ }
+
+ return f2.Name(), nil
+}
+
+// hasPathPrefix reports whether the path s begins with the
+// elements in prefix.
+func hasPathPrefix(s, prefix string) bool {
+ switch {
+ default:
+ return false
+ case len(s) == len(prefix):
+ return s == prefix
+ case len(s) > len(prefix):
+ if prefix != "" && prefix[len(prefix)-1] == '/' {
+ return strings.HasPrefix(s, prefix)
+ }
+ return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
+ }
+}
+
+func isVendoredPackage(name string) bool {
+ var i int
+ if strings.HasPrefix(name, "vendor/") {
+ i += len("vendor/")
+ } else if j := strings.Index(name, "/vendor/"); j >= 0 {
+ i += len("/vendor/")
+ } else {
+ return false
+ }
+ return strings.Contains(name[i:], "/")
+}
diff --git a/libgo/go/cmd/go/internal/modfetch/coderepo_test.go b/libgo/go/cmd/go/internal/modfetch/coderepo_test.go
new file mode 100644
index 00000000000..79b82786cb9
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfetch/coderepo_test.go
@@ -0,0 +1,643 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modfetch
+
+import (
+ "archive/zip"
+ "internal/testenv"
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+ "reflect"
+ "strings"
+ "testing"
+ "time"
+
+ "cmd/go/internal/modfetch/codehost"
+)
+
+func TestMain(m *testing.M) {
+ os.Exit(testMain(m))
+}
+
+func testMain(m *testing.M) int {
+ dir, err := ioutil.TempDir("", "gitrepo-test-")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+
+ codehost.WorkRoot = dir
+ return m.Run()
+}
+
+const (
+ vgotest1git = "github.com/rsc/vgotest1"
+ vgotest1hg = "vcs-test.golang.org/hg/vgotest1.hg"
+)
+
+var altVgotests = []string{
+ vgotest1hg,
+}
+
+var codeRepoTests = []struct {
+ path string
+ lookerr string
+ mpath string
+ rev string
+ err string
+ version string
+ name string
+ short string
+ time time.Time
+ gomod string
+ gomoderr string
+ zip []string
+ ziperr string
+}{
+ {
+ path: "github.com/rsc/vgotest1",
+ rev: "v0.0.0",
+ version: "v0.0.0",
+ name: "80d85c5d4d17598a0e9055e7c175a32b415d6128",
+ short: "80d85c5d4d17",
+ time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC),
+ zip: []string{
+ "LICENSE",
+ "README.md",
+ "pkg/p.go",
+ },
+ },
+ {
+ path: "github.com/rsc/vgotest1",
+ rev: "v1.0.0",
+ version: "v1.0.0",
+ name: "80d85c5d4d17598a0e9055e7c175a32b415d6128",
+ short: "80d85c5d4d17",
+ time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC),
+ zip: []string{
+ "LICENSE",
+ "README.md",
+ "pkg/p.go",
+ },
+ },
+ {
+ path: "github.com/rsc/vgotest1/v2",
+ rev: "v2.0.0",
+ version: "v2.0.0",
+ name: "45f53230a74ad275c7127e117ac46914c8126160",
+ short: "45f53230a74a",
+ time: time.Date(2018, 7, 19, 1, 21, 27, 0, time.UTC),
+ ziperr: "missing github.com/rsc/vgotest1/go.mod and .../v2/go.mod at revision v2.0.0",
+ },
+ {
+ path: "github.com/rsc/vgotest1",
+ rev: "80d85c5",
+ version: "v1.0.0",
+ name: "80d85c5d4d17598a0e9055e7c175a32b415d6128",
+ short: "80d85c5d4d17",
+ time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC),
+ zip: []string{
+ "LICENSE",
+ "README.md",
+ "pkg/p.go",
+ },
+ },
+ {
+ path: "github.com/rsc/vgotest1",
+ rev: "mytag",
+ version: "v1.0.0",
+ name: "80d85c5d4d17598a0e9055e7c175a32b415d6128",
+ short: "80d85c5d4d17",
+ time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC),
+ zip: []string{
+ "LICENSE",
+ "README.md",
+ "pkg/p.go",
+ },
+ },
+ {
+ path: "github.com/rsc/vgotest1/v2",
+ rev: "45f53230a",
+ version: "v2.0.0",
+ name: "45f53230a74ad275c7127e117ac46914c8126160",
+ short: "45f53230a74a",
+ time: time.Date(2018, 7, 19, 1, 21, 27, 0, time.UTC),
+ gomoderr: "missing github.com/rsc/vgotest1/go.mod and .../v2/go.mod at revision v2.0.0",
+ ziperr: "missing github.com/rsc/vgotest1/go.mod and .../v2/go.mod at revision v2.0.0",
+ },
+ {
+ path: "github.com/rsc/vgotest1/v54321",
+ rev: "80d85c5",
+ version: "v54321.0.0-20180219231006-80d85c5d4d17",
+ name: "80d85c5d4d17598a0e9055e7c175a32b415d6128",
+ short: "80d85c5d4d17",
+ time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC),
+ ziperr: "missing github.com/rsc/vgotest1/go.mod and .../v54321/go.mod at revision 80d85c5d4d17",
+ },
+ {
+ path: "github.com/rsc/vgotest1/submod",
+ rev: "v1.0.0",
+ err: "unknown revision submod/v1.0.0",
+ },
+ {
+ path: "github.com/rsc/vgotest1/submod",
+ rev: "v1.0.3",
+ err: "unknown revision submod/v1.0.3",
+ },
+ {
+ path: "github.com/rsc/vgotest1/submod",
+ rev: "v1.0.4",
+ version: "v1.0.4",
+ name: "8afe2b2efed96e0880ecd2a69b98a53b8c2738b6",
+ short: "8afe2b2efed9",
+ time: time.Date(2018, 2, 19, 23, 12, 7, 0, time.UTC),
+ gomod: "module \"github.com/vgotest1/submod\" // submod/go.mod\n",
+ zip: []string{
+ "go.mod",
+ "pkg/p.go",
+ "LICENSE",
+ },
+ },
+ {
+ path: "github.com/rsc/vgotest1",
+ rev: "v1.1.0",
+ version: "v1.1.0",
+ name: "b769f2de407a4db81af9c5de0a06016d60d2ea09",
+ short: "b769f2de407a",
+ time: time.Date(2018, 2, 19, 23, 13, 36, 0, time.UTC),
+ gomod: "module \"github.com/rsc/vgotest1\" // root go.mod\nrequire \"github.com/rsc/vgotest1/submod\" v1.0.5\n",
+ zip: []string{
+ "LICENSE",
+ "README.md",
+ "go.mod",
+ "pkg/p.go",
+ },
+ },
+ {
+ path: "github.com/rsc/vgotest1/v2",
+ rev: "v2.0.1",
+ version: "v2.0.1",
+ name: "ea65f87c8f52c15ea68f3bdd9925ef17e20d91e9",
+ short: "ea65f87c8f52",
+ time: time.Date(2018, 2, 19, 23, 14, 23, 0, time.UTC),
+ gomod: "module \"github.com/rsc/vgotest1/v2\" // root go.mod\n",
+ },
+ {
+ path: "github.com/rsc/vgotest1/v2",
+ rev: "v2.0.3",
+ version: "v2.0.3",
+ name: "f18795870fb14388a21ef3ebc1d75911c8694f31",
+ short: "f18795870fb1",
+ time: time.Date(2018, 2, 19, 23, 16, 4, 0, time.UTC),
+ gomoderr: "github.com/rsc/vgotest1/v2/go.mod has non-.../v2 module path \"github.com/rsc/vgotest\" at revision v2.0.3",
+ },
+ {
+ path: "github.com/rsc/vgotest1/v2",
+ rev: "v2.0.4",
+ version: "v2.0.4",
+ name: "1f863feb76bc7029b78b21c5375644838962f88d",
+ short: "1f863feb76bc",
+ time: time.Date(2018, 2, 20, 0, 3, 38, 0, time.UTC),
+ gomoderr: "github.com/rsc/vgotest1/go.mod and .../v2/go.mod both have .../v2 module paths at revision v2.0.4",
+ },
+ {
+ path: "github.com/rsc/vgotest1/v2",
+ rev: "v2.0.5",
+ version: "v2.0.5",
+ name: "2f615117ce481c8efef46e0cc0b4b4dccfac8fea",
+ short: "2f615117ce48",
+ time: time.Date(2018, 2, 20, 0, 3, 59, 0, time.UTC),
+ gomod: "module \"github.com/rsc/vgotest1/v2\" // v2/go.mod\n",
+ },
+ {
+ // redirect to github
+ path: "rsc.io/quote",
+ rev: "v1.0.0",
+ version: "v1.0.0",
+ name: "f488df80bcdbd3e5bafdc24ad7d1e79e83edd7e6",
+ short: "f488df80bcdb",
+ time: time.Date(2018, 2, 14, 0, 45, 20, 0, time.UTC),
+ gomod: "module \"rsc.io/quote\"\n",
+ },
+ {
+ // redirect to static hosting proxy
+ path: "swtch.com/testmod",
+ rev: "v1.0.0",
+ version: "v1.0.0",
+ // NO name or short - we intentionally ignore those in the proxy protocol
+ time: time.Date(1972, 7, 18, 12, 34, 56, 0, time.UTC),
+ gomod: "module \"swtch.com/testmod\"\n",
+ },
+ {
+ // redirect to googlesource
+ path: "golang.org/x/text",
+ rev: "4e4a3210bb",
+ version: "v0.3.1-0.20180208041248-4e4a3210bb54",
+ name: "4e4a3210bb54bb31f6ab2cdca2edcc0b50c420c1",
+ short: "4e4a3210bb54",
+ time: time.Date(2018, 2, 8, 4, 12, 48, 0, time.UTC),
+ },
+ {
+ path: "github.com/pkg/errors",
+ rev: "v0.8.0",
+ version: "v0.8.0",
+ name: "645ef00459ed84a119197bfb8d8205042c6df63d",
+ short: "645ef00459ed",
+ time: time.Date(2016, 9, 29, 1, 48, 1, 0, time.UTC),
+ },
+ {
+ // package in subdirectory - custom domain
+ // In general we can't reject these definitively in Lookup,
+ // but gopkg.in is special.
+ path: "gopkg.in/yaml.v2/abc",
+ lookerr: "invalid module path \"gopkg.in/yaml.v2/abc\"",
+ },
+ {
+ // package in subdirectory - github
+ // Because it's a package, Stat should fail entirely.
+ path: "github.com/rsc/quote/buggy",
+ rev: "c4d4236f",
+ err: "missing github.com/rsc/quote/buggy/go.mod at revision c4d4236f9242",
+ },
+ {
+ path: "gopkg.in/yaml.v2",
+ rev: "d670f940",
+ version: "v2.0.0",
+ name: "d670f9405373e636a5a2765eea47fac0c9bc91a4",
+ short: "d670f9405373",
+ time: time.Date(2018, 1, 9, 11, 43, 31, 0, time.UTC),
+ gomod: "module gopkg.in/yaml.v2\n",
+ },
+ {
+ path: "gopkg.in/check.v1",
+ rev: "20d25e280405",
+ version: "v1.0.0-20161208181325-20d25e280405",
+ name: "20d25e2804050c1cd24a7eea1e7a6447dd0e74ec",
+ short: "20d25e280405",
+ time: time.Date(2016, 12, 8, 18, 13, 25, 0, time.UTC),
+ gomod: "module gopkg.in/check.v1\n",
+ },
+ {
+ path: "gopkg.in/yaml.v2",
+ rev: "v2",
+ version: "v2.2.1",
+ name: "5420a8b6744d3b0345ab293f6fcba19c978f1183",
+ short: "5420a8b6744d",
+ time: time.Date(2018, 3, 28, 19, 50, 20, 0, time.UTC),
+ gomod: "module \"gopkg.in/yaml.v2\"\n\nrequire (\n\t\"gopkg.in/check.v1\" v0.0.0-20161208181325-20d25e280405\n)\n",
+ },
+ {
+ path: "vcs-test.golang.org/go/mod/gitrepo1",
+ rev: "master",
+ version: "v1.2.4-annotated",
+ name: "ede458df7cd0fdca520df19a33158086a8a68e81",
+ short: "ede458df7cd0",
+ time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC),
+ gomod: "module vcs-test.golang.org/go/mod/gitrepo1\n",
+ },
+ {
+ path: "gopkg.in/natefinch/lumberjack.v2",
+ rev: "latest",
+ version: "v2.0.0-20170531160350-a96e63847dc3",
+ name: "a96e63847dc3c67d17befa69c303767e2f84e54f",
+ short: "a96e63847dc3",
+ time: time.Date(2017, 5, 31, 16, 3, 50, 0, time.UTC),
+ gomod: "module gopkg.in/natefinch/lumberjack.v2\n",
+ },
+ {
+ path: "gopkg.in/natefinch/lumberjack.v2",
+ // This repo has a v2.1 tag.
+ // We only allow semver references to tags that are fully qualified, as in v2.1.0.
+ // Because we can't record v2.1.0 (the actual tag is v2.1), we record a pseudo-version
+ // instead, same as if the tag were any other non-version-looking string.
+ // We use a v2 pseudo-version here because of the .v2 in the path, not because
+ // of the v2 in the rev.
+ rev: "v2.1", // non-canonical semantic version turns into pseudo-version
+ version: "v2.0.0-20170531160350-a96e63847dc3",
+ name: "a96e63847dc3c67d17befa69c303767e2f84e54f",
+ short: "a96e63847dc3",
+ time: time.Date(2017, 5, 31, 16, 3, 50, 0, time.UTC),
+ gomod: "module gopkg.in/natefinch/lumberjack.v2\n",
+ },
+}
+
+func TestCodeRepo(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ tmpdir, err := ioutil.TempDir("", "vgo-modfetch-test-")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+ for _, tt := range codeRepoTests {
+ f := func(t *testing.T) {
+ repo, err := Lookup(tt.path)
+ if tt.lookerr != "" {
+ if err != nil && err.Error() == tt.lookerr {
+ return
+ }
+ t.Errorf("Lookup(%q): %v, want error %q", tt.path, err, tt.lookerr)
+ }
+ if err != nil {
+ t.Fatalf("Lookup(%q): %v", tt.path, err)
+ }
+ if tt.mpath == "" {
+ tt.mpath = tt.path
+ }
+ if mpath := repo.ModulePath(); mpath != tt.mpath {
+ t.Errorf("repo.ModulePath() = %q, want %q", mpath, tt.mpath)
+ }
+ info, err := repo.Stat(tt.rev)
+ if err != nil {
+ if tt.err != "" {
+ if !strings.Contains(err.Error(), tt.err) {
+ t.Fatalf("repoStat(%q): %v, wanted %q", tt.rev, err, tt.err)
+ }
+ return
+ }
+ t.Fatalf("repo.Stat(%q): %v", tt.rev, err)
+ }
+ if tt.err != "" {
+ t.Errorf("repo.Stat(%q): success, wanted error", tt.rev)
+ }
+ if info.Version != tt.version {
+ t.Errorf("info.Version = %q, want %q", info.Version, tt.version)
+ }
+ if info.Name != tt.name {
+ t.Errorf("info.Name = %q, want %q", info.Name, tt.name)
+ }
+ if info.Short != tt.short {
+ t.Errorf("info.Short = %q, want %q", info.Short, tt.short)
+ }
+ if !info.Time.Equal(tt.time) {
+ t.Errorf("info.Time = %v, want %v", info.Time, tt.time)
+ }
+ if tt.gomod != "" || tt.gomoderr != "" {
+ data, err := repo.GoMod(tt.version)
+ if err != nil && tt.gomoderr == "" {
+ t.Errorf("repo.GoMod(%q): %v", tt.version, err)
+ } else if err != nil && tt.gomoderr != "" {
+ if err.Error() != tt.gomoderr {
+ t.Errorf("repo.GoMod(%q): %v, want %q", tt.version, err, tt.gomoderr)
+ }
+ } else if tt.gomoderr != "" {
+ t.Errorf("repo.GoMod(%q) = %q, want error %q", tt.version, data, tt.gomoderr)
+ } else if string(data) != tt.gomod {
+ t.Errorf("repo.GoMod(%q) = %q, want %q", tt.version, data, tt.gomod)
+ }
+ }
+ if tt.zip != nil || tt.ziperr != "" {
+ zipfile, err := repo.Zip(tt.version, tmpdir)
+ if err != nil {
+ if tt.ziperr != "" {
+ if err.Error() == tt.ziperr {
+ return
+ }
+ t.Fatalf("repo.Zip(%q): %v, want error %q", tt.version, err, tt.ziperr)
+ }
+ t.Fatalf("repo.Zip(%q): %v", tt.version, err)
+ }
+ if tt.ziperr != "" {
+ t.Errorf("repo.Zip(%q): success, want error %q", tt.version, tt.ziperr)
+ }
+ prefix := tt.path + "@" + tt.version + "/"
+ z, err := zip.OpenReader(zipfile)
+ if err != nil {
+ t.Fatalf("open zip %s: %v", zipfile, err)
+ }
+ var names []string
+ for _, file := range z.File {
+ if !strings.HasPrefix(file.Name, prefix) {
+ t.Errorf("zip entry %v does not start with prefix %v", file.Name, prefix)
+ continue
+ }
+ names = append(names, file.Name[len(prefix):])
+ }
+ z.Close()
+ if !reflect.DeepEqual(names, tt.zip) {
+ t.Fatalf("zip = %v\nwant %v\n", names, tt.zip)
+ }
+ }
+ }
+ t.Run(strings.Replace(tt.path, "/", "_", -1)+"/"+tt.rev, f)
+ if strings.HasPrefix(tt.path, vgotest1git) {
+ for _, alt := range altVgotests {
+ // Note: Communicating with f through tt; should be cleaned up.
+ old := tt
+ tt.path = alt + strings.TrimPrefix(tt.path, vgotest1git)
+ if strings.HasPrefix(tt.mpath, vgotest1git) {
+ tt.mpath = alt + strings.TrimPrefix(tt.mpath, vgotest1git)
+ }
+ var m map[string]string
+ if alt == vgotest1hg {
+ m = hgmap
+ }
+ tt.version = remap(tt.version, m)
+ tt.name = remap(tt.name, m)
+ tt.short = remap(tt.short, m)
+ tt.rev = remap(tt.rev, m)
+ tt.gomoderr = remap(tt.gomoderr, m)
+ tt.ziperr = remap(tt.ziperr, m)
+ t.Run(strings.Replace(tt.path, "/", "_", -1)+"/"+tt.rev, f)
+ tt = old
+ }
+ }
+ }
+}
+
+var hgmap = map[string]string{
+ "github.com/rsc/vgotest1/": "vcs-test.golang.org/hg/vgotest1.hg/",
+ "f18795870fb14388a21ef3ebc1d75911c8694f31": "a9ad6d1d14eb544f459f446210c7eb3b009807c6",
+ "ea65f87c8f52c15ea68f3bdd9925ef17e20d91e9": "f1fc0f22021b638d073d31c752847e7bf385def7",
+ "b769f2de407a4db81af9c5de0a06016d60d2ea09": "92c7eb888b4fac17f1c6bd2e1060a1b881a3b832",
+ "8afe2b2efed96e0880ecd2a69b98a53b8c2738b6": "4e58084d459ae7e79c8c2264d0e8e9a92eb5cd44",
+ "2f615117ce481c8efef46e0cc0b4b4dccfac8fea": "879ea98f7743c8eff54f59a918f3a24123d1cf46",
+ "80d85c5d4d17598a0e9055e7c175a32b415d6128": "e125018e286a4b09061079a81e7b537070b7ff71",
+ "1f863feb76bc7029b78b21c5375644838962f88d": "bf63880162304a9337477f3858f5b7e255c75459",
+ "45f53230a74ad275c7127e117ac46914c8126160": "814fce58e83abd5bf2a13892e0b0e1198abefcd4",
+}
+
+func remap(name string, m map[string]string) string {
+ if m[name] != "" {
+ return m[name]
+ }
+ if codehost.AllHex(name) {
+ for k, v := range m {
+ if strings.HasPrefix(k, name) {
+ return v[:len(name)]
+ }
+ }
+ }
+ for k, v := range m {
+ name = strings.Replace(name, k, v, -1)
+ if codehost.AllHex(k) {
+ name = strings.Replace(name, k[:12], v[:12], -1)
+ }
+ }
+ return name
+}
+
+var codeRepoVersionsTests = []struct {
+ path string
+ prefix string
+ versions []string
+}{
+ {
+ path: "github.com/rsc/vgotest1",
+ versions: []string{"v0.0.0", "v0.0.1", "v1.0.0", "v1.0.1", "v1.0.2", "v1.0.3", "v1.1.0", "v2.0.0+incompatible"},
+ },
+ {
+ path: "github.com/rsc/vgotest1",
+ prefix: "v1.0",
+ versions: []string{"v1.0.0", "v1.0.1", "v1.0.2", "v1.0.3"},
+ },
+ {
+ path: "github.com/rsc/vgotest1/v2",
+ versions: []string{"v2.0.0", "v2.0.1", "v2.0.2", "v2.0.3", "v2.0.4", "v2.0.5", "v2.0.6"},
+ },
+ {
+ path: "swtch.com/testmod",
+ versions: []string{"v1.0.0", "v1.1.1"},
+ },
+ {
+ path: "gopkg.in/russross/blackfriday.v2",
+ versions: []string{"v2.0.0"},
+ },
+ {
+ path: "gopkg.in/natefinch/lumberjack.v2",
+ versions: nil,
+ },
+}
+
+func TestCodeRepoVersions(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ tmpdir, err := ioutil.TempDir("", "vgo-modfetch-test-")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+ for _, tt := range codeRepoVersionsTests {
+ t.Run(strings.Replace(tt.path, "/", "_", -1), func(t *testing.T) {
+ repo, err := Lookup(tt.path)
+ if err != nil {
+ t.Fatalf("Lookup(%q): %v", tt.path, err)
+ }
+ list, err := repo.Versions(tt.prefix)
+ if err != nil {
+ t.Fatalf("Versions(%q): %v", tt.prefix, err)
+ }
+ if !reflect.DeepEqual(list, tt.versions) {
+ t.Fatalf("Versions(%q):\nhave %v\nwant %v", tt.prefix, list, tt.versions)
+ }
+ })
+ }
+}
+
+var latestTests = []struct {
+ path string
+ version string
+ err string
+}{
+ {
+ path: "github.com/rsc/empty",
+ err: "no commits",
+ },
+ {
+ path: "github.com/rsc/vgotest1",
+ version: "v0.0.0-20180219223237-a08abb797a67",
+ },
+ {
+ path: "github.com/rsc/vgotest1/subdir",
+ err: "missing github.com/rsc/vgotest1/subdir/go.mod at revision a08abb797a67",
+ },
+ {
+ path: "swtch.com/testmod",
+ version: "v1.1.1",
+ },
+}
+
+func TestLatest(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ tmpdir, err := ioutil.TempDir("", "vgo-modfetch-test-")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+ for _, tt := range latestTests {
+ name := strings.Replace(tt.path, "/", "_", -1)
+ t.Run(name, func(t *testing.T) {
+ repo, err := Lookup(tt.path)
+ if err != nil {
+ t.Fatalf("Lookup(%q): %v", tt.path, err)
+ }
+ info, err := repo.Latest()
+ if err != nil {
+ if tt.err != "" {
+ if err.Error() == tt.err {
+ return
+ }
+ t.Fatalf("Latest(): %v, want %q", err, tt.err)
+ }
+ t.Fatalf("Latest(): %v", err)
+ }
+ if tt.err != "" {
+ t.Fatalf("Latest() = %v, want error %q", info.Version, tt.err)
+ }
+ if info.Version != tt.version {
+ t.Fatalf("Latest() = %v, want %v", info.Version, tt.version)
+ }
+ })
+ }
+}
+
+// fixedTagsRepo is a fake codehost.Repo that returns a fixed list of tags
+type fixedTagsRepo struct {
+ tags []string
+}
+
+func (ch *fixedTagsRepo) Tags(string) ([]string, error) { return ch.tags, nil }
+func (ch *fixedTagsRepo) Latest() (*codehost.RevInfo, error) { panic("not impl") }
+func (ch *fixedTagsRepo) ReadFile(string, string, int64) ([]byte, error) { panic("not impl") }
+func (ch *fixedTagsRepo) ReadFileRevs([]string, string, int64) (map[string]*codehost.FileRev, error) {
+ panic("not impl")
+}
+func (ch *fixedTagsRepo) ReadZip(string, string, int64) (io.ReadCloser, string, error) {
+ panic("not impl")
+}
+func (ch *fixedTagsRepo) RecentTag(string, string) (string, error) {
+ panic("not impl")
+}
+func (ch *fixedTagsRepo) Stat(string) (*codehost.RevInfo, error) { panic("not impl") }
+
+func TestNonCanonicalSemver(t *testing.T) {
+ root := "golang.org/x/issue24476"
+ ch := &fixedTagsRepo{
+ tags: []string{
+ "", "huh?", "1.0.1",
+ // what about "version 1 dot dogcow"?
+ "v1.🐕.🐄",
+ "v1", "v0.1",
+ // and one normal one that should pass through
+ "v1.0.1",
+ },
+ }
+
+ cr, err := newCodeRepo(ch, root, root)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ v, err := cr.Versions("")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(v) != 1 || v[0] != "v1.0.1" {
+ t.Fatal("unexpected versions returned:", v)
+ }
+}
diff --git a/libgo/go/cmd/go/internal/modfetch/fetch.go b/libgo/go/cmd/go/internal/modfetch/fetch.go
new file mode 100644
index 00000000000..2e26bac434d
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfetch/fetch.go
@@ -0,0 +1,365 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modfetch
+
+import (
+ "archive/zip"
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+ "sync"
+
+ "cmd/go/internal/base"
+ "cmd/go/internal/cfg"
+ "cmd/go/internal/dirhash"
+ "cmd/go/internal/module"
+ "cmd/go/internal/par"
+)
+
+var downloadCache par.Cache
+
+// Download downloads the specific module version to the
+// local download cache and returns the name of the directory
+// corresponding to the root of the module's file tree.
+func Download(mod module.Version) (dir string, err error) {
+ if PkgMod == "" {
+ // Do not download to current directory.
+ return "", fmt.Errorf("missing modfetch.PkgMod")
+ }
+
+ // The par.Cache here avoids duplicate work but also
+ // avoids conflicts from simultaneous calls by multiple goroutines
+ // for the same version.
+ type cached struct {
+ dir string
+ err error
+ }
+ c := downloadCache.Do(mod, func() interface{} {
+ dir, err := DownloadDir(mod)
+ if err != nil {
+ return cached{"", err}
+ }
+ if files, _ := ioutil.ReadDir(dir); len(files) == 0 {
+ zipfile, err := DownloadZip(mod)
+ if err != nil {
+ return cached{"", err}
+ }
+ modpath := mod.Path + "@" + mod.Version
+ if err := Unzip(dir, zipfile, modpath, 0); err != nil {
+ fmt.Fprintf(os.Stderr, "-> %s\n", err)
+ return cached{"", err}
+ }
+ }
+ checkSum(mod)
+ return cached{dir, nil}
+ }).(cached)
+ return c.dir, c.err
+}
+
+var downloadZipCache par.Cache
+
+// DownloadZip downloads the specific module version to the
+// local zip cache and returns the name of the zip file.
+func DownloadZip(mod module.Version) (zipfile string, err error) {
+ // The par.Cache here avoids duplicate work but also
+ // avoids conflicts from simultaneous calls by multiple goroutines
+ // for the same version.
+ type cached struct {
+ zipfile string
+ err error
+ }
+ c := downloadZipCache.Do(mod, func() interface{} {
+ zipfile, err := CachePath(mod, "zip")
+ if err != nil {
+ return cached{"", err}
+ }
+ if _, err := os.Stat(zipfile); err == nil {
+ // Use it.
+ // This should only happen if the mod/cache directory is preinitialized
+ // or if pkg/mod/path was removed but not pkg/mod/cache/download.
+ if cfg.CmdName != "mod download" {
+ fmt.Fprintf(os.Stderr, "go: extracting %s %s\n", mod.Path, mod.Version)
+ }
+ } else {
+ if err := os.MkdirAll(filepath.Dir(zipfile), 0777); err != nil {
+ return cached{"", err}
+ }
+ if cfg.CmdName != "mod download" {
+ fmt.Fprintf(os.Stderr, "go: downloading %s %s\n", mod.Path, mod.Version)
+ }
+ if err := downloadZip(mod, zipfile); err != nil {
+ return cached{"", err}
+ }
+ }
+ return cached{zipfile, nil}
+ }).(cached)
+ return c.zipfile, c.err
+}
+
+func downloadZip(mod module.Version, target string) error {
+ repo, err := Lookup(mod.Path)
+ if err != nil {
+ return err
+ }
+ tmpfile, err := repo.Zip(mod.Version, os.TempDir())
+ if err != nil {
+ return err
+ }
+ defer os.Remove(tmpfile)
+
+ // Double-check zip file looks OK.
+ z, err := zip.OpenReader(tmpfile)
+ if err != nil {
+ return err
+ }
+ prefix := mod.Path + "@" + mod.Version
+ for _, f := range z.File {
+ if !strings.HasPrefix(f.Name, prefix) {
+ z.Close()
+ return fmt.Errorf("zip for %s has unexpected file %s", prefix[:len(prefix)-1], f.Name)
+ }
+ }
+ z.Close()
+
+ hash, err := dirhash.HashZip(tmpfile, dirhash.DefaultHash)
+ if err != nil {
+ return err
+ }
+ checkOneSum(mod, hash) // check before installing the zip file
+ r, err := os.Open(tmpfile)
+ if err != nil {
+ return err
+ }
+ defer r.Close()
+ w, err := os.Create(target)
+ if err != nil {
+ return err
+ }
+ if _, err := io.Copy(w, r); err != nil {
+ w.Close()
+ return fmt.Errorf("copying: %v", err)
+ }
+ if err := w.Close(); err != nil {
+ return err
+ }
+ return ioutil.WriteFile(target+"hash", []byte(hash), 0666)
+}
+
+var GoSumFile string // path to go.sum; set by package modload
+
+var goSum struct {
+ mu sync.Mutex
+ m map[module.Version][]string // content of go.sum file (+ go.modverify if present)
+ enabled bool // whether to use go.sum at all
+ modverify string // path to go.modverify, to be deleted
+}
+
+// initGoSum initializes the go.sum data.
+// It reports whether use of go.sum is now enabled.
+// The goSum lock must be held.
+func initGoSum() bool {
+ if GoSumFile == "" {
+ return false
+ }
+ if goSum.m != nil {
+ return true
+ }
+
+ goSum.m = make(map[module.Version][]string)
+ data, err := ioutil.ReadFile(GoSumFile)
+ if err != nil && !os.IsNotExist(err) {
+ base.Fatalf("go: %v", err)
+ }
+ goSum.enabled = true
+ readGoSum(GoSumFile, data)
+
+ // Add old go.modverify file.
+ // We'll delete go.modverify in WriteGoSum.
+ alt := strings.TrimSuffix(GoSumFile, ".sum") + ".modverify"
+ if data, err := ioutil.ReadFile(alt); err == nil {
+ readGoSum(alt, data)
+ goSum.modverify = alt
+ }
+ return true
+}
+
+// emptyGoModHash is the hash of a 1-file tree containing a 0-length go.mod.
+// A bug caused us to write these into go.sum files for non-modules.
+// We detect and remove them.
+const emptyGoModHash = "h1:G7mAYYxgmS0lVkHyy2hEOLQCFB0DlQFTMLWggykrydY="
+
+// readGoSum parses data, which is the content of file,
+// and adds it to goSum.m. The goSum lock must be held.
+func readGoSum(file string, data []byte) {
+ lineno := 0
+ for len(data) > 0 {
+ var line []byte
+ lineno++
+ i := bytes.IndexByte(data, '\n')
+ if i < 0 {
+ line, data = data, nil
+ } else {
+ line, data = data[:i], data[i+1:]
+ }
+ f := strings.Fields(string(line))
+ if len(f) == 0 {
+ // blank line; skip it
+ continue
+ }
+ if len(f) != 3 {
+ base.Fatalf("go: malformed go.sum:\n%s:%d: wrong number of fields %v", file, lineno, len(f))
+ }
+ if f[2] == emptyGoModHash {
+ // Old bug; drop it.
+ continue
+ }
+ mod := module.Version{Path: f[0], Version: f[1]}
+ goSum.m[mod] = append(goSum.m[mod], f[2])
+ }
+}
+
+// checkSum checks the given module's checksum.
+func checkSum(mod module.Version) {
+ if PkgMod == "" {
+ // Do not use current directory.
+ return
+ }
+
+ // Do the file I/O before acquiring the go.sum lock.
+ ziphash, err := CachePath(mod, "ziphash")
+ if err != nil {
+ base.Fatalf("go: verifying %s@%s: %v", mod.Path, mod.Version, err)
+ }
+ data, err := ioutil.ReadFile(ziphash)
+ if err != nil {
+ if os.IsNotExist(err) {
+ // This can happen if someone does rm -rf GOPATH/src/cache/download. So it goes.
+ return
+ }
+ base.Fatalf("go: verifying %s@%s: %v", mod.Path, mod.Version, err)
+ }
+ h := strings.TrimSpace(string(data))
+ if !strings.HasPrefix(h, "h1:") {
+ base.Fatalf("go: verifying %s@%s: unexpected ziphash: %q", mod.Path, mod.Version, h)
+ }
+
+ checkOneSum(mod, h)
+}
+
+// goModSum returns the checksum for the go.mod contents.
+func goModSum(data []byte) (string, error) {
+ return dirhash.Hash1([]string{"go.mod"}, func(string) (io.ReadCloser, error) {
+ return ioutil.NopCloser(bytes.NewReader(data)), nil
+ })
+}
+
+// checkGoMod checks the given module's go.mod checksum;
+// data is the go.mod content.
+func checkGoMod(path, version string, data []byte) {
+ h, err := goModSum(data)
+ if err != nil {
+ base.Fatalf("go: verifying %s %s go.mod: %v", path, version, err)
+ }
+
+ checkOneSum(module.Version{Path: path, Version: version + "/go.mod"}, h)
+}
+
+// checkOneSum checks that the recorded hash for mod is h.
+func checkOneSum(mod module.Version, h string) {
+ goSum.mu.Lock()
+ defer goSum.mu.Unlock()
+ if !initGoSum() {
+ return
+ }
+
+ for _, vh := range goSum.m[mod] {
+ if h == vh {
+ return
+ }
+ if strings.HasPrefix(vh, "h1:") {
+ base.Fatalf("go: verifying %s@%s: checksum mismatch\n\tdownloaded: %v\n\tgo.sum: %v", mod.Path, mod.Version, h, vh)
+ }
+ }
+ if len(goSum.m[mod]) > 0 {
+ fmt.Fprintf(os.Stderr, "warning: verifying %s@%s: unknown hashes in go.sum: %v; adding %v", mod.Path, mod.Version, strings.Join(goSum.m[mod], ", "), h)
+ }
+ goSum.m[mod] = append(goSum.m[mod], h)
+}
+
+// Sum returns the checksum for the downloaded copy of the given module,
+// if present in the download cache.
+func Sum(mod module.Version) string {
+ if PkgMod == "" {
+ // Do not use current directory.
+ return ""
+ }
+
+ ziphash, err := CachePath(mod, "ziphash")
+ if err != nil {
+ return ""
+ }
+ data, err := ioutil.ReadFile(ziphash)
+ if err != nil {
+ return ""
+ }
+ return strings.TrimSpace(string(data))
+}
+
+// WriteGoSum writes the go.sum file if it needs to be updated.
+func WriteGoSum() {
+ goSum.mu.Lock()
+ defer goSum.mu.Unlock()
+ if !initGoSum() {
+ return
+ }
+
+ var mods []module.Version
+ for m := range goSum.m {
+ mods = append(mods, m)
+ }
+ module.Sort(mods)
+ var buf bytes.Buffer
+ for _, m := range mods {
+ list := goSum.m[m]
+ sort.Strings(list)
+ for _, h := range list {
+ fmt.Fprintf(&buf, "%s %s %s\n", m.Path, m.Version, h)
+ }
+ }
+
+ data, _ := ioutil.ReadFile(GoSumFile)
+ if !bytes.Equal(data, buf.Bytes()) {
+ if err := ioutil.WriteFile(GoSumFile, buf.Bytes(), 0666); err != nil {
+ base.Fatalf("go: writing go.sum: %v", err)
+ }
+ }
+
+ if goSum.modverify != "" {
+ os.Remove(goSum.modverify)
+ }
+}
+
+// TrimGoSum trims go.sum to contain only the modules for which keep[m] is true.
+func TrimGoSum(keep map[module.Version]bool) {
+ goSum.mu.Lock()
+ defer goSum.mu.Unlock()
+ if !initGoSum() {
+ return
+ }
+
+ for m := range goSum.m {
+ // If we're keeping x@v we also keep x@v/go.mod.
+ // Map x@v/go.mod back to x@v for the keep lookup.
+ noGoMod := module.Version{Path: m.Path, Version: strings.TrimSuffix(m.Version, "/go.mod")}
+ if !keep[m] && !keep[noGoMod] {
+ delete(goSum.m, m)
+ }
+ }
+}
diff --git a/libgo/go/cmd/go/internal/modfetch/noweb.go b/libgo/go/cmd/go/internal/modfetch/noweb.go
new file mode 100644
index 00000000000..9d713dcc669
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfetch/noweb.go
@@ -0,0 +1,24 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build cmd_go_bootstrap
+
+package modfetch
+
+import (
+ "fmt"
+ "io"
+)
+
+func webGetGoGet(url string, body *io.ReadCloser) error {
+ return fmt.Errorf("no network in go_bootstrap")
+}
+
+func webGetBytes(url string, body *[]byte) error {
+ return fmt.Errorf("no network in go_bootstrap")
+}
+
+func webGetBody(url string, body *io.ReadCloser) error {
+ return fmt.Errorf("no network in go_bootstrap")
+}
diff --git a/libgo/go/cmd/go/internal/modfetch/proxy.go b/libgo/go/cmd/go/internal/modfetch/proxy.go
new file mode 100644
index 00000000000..5f856b80d2e
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfetch/proxy.go
@@ -0,0 +1,252 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modfetch
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/url"
+ "os"
+ "strings"
+ "time"
+
+ "cmd/go/internal/base"
+ "cmd/go/internal/modfetch/codehost"
+ "cmd/go/internal/module"
+ "cmd/go/internal/semver"
+)
+
+var HelpGoproxy = &base.Command{
+ UsageLine: "goproxy",
+ Short: "module proxy protocol",
+ Long: `
+The go command by default downloads modules from version control systems
+directly, just as 'go get' always has. The GOPROXY environment variable allows
+further control over the download source. If GOPROXY is unset, is the empty string,
+or is the string "direct", downloads use the default direct connection to version
+control systems. Setting GOPROXY to "off" disallows downloading modules from
+any source. Otherwise, GOPROXY is expected to be the URL of a module proxy,
+in which case the go command will fetch all modules from that proxy.
+No matter the source of the modules, downloaded modules must match existing
+entries in go.sum (see 'go help modules' for discussion of verification).
+
+A Go module proxy is any web server that can respond to GET requests for
+URLs of a specified form. The requests have no query parameters, so even
+a site serving from a fixed file system (including a file:/// URL)
+can be a module proxy.
+
+The GET requests sent to a Go module proxy are:
+
+GET $GOPROXY/<module>/@v/list returns a list of all known versions of the
+given module, one per line.
+
+GET $GOPROXY/<module>/@v/<version>.info returns JSON-formatted metadata
+about that version of the given module.
+
+GET $GOPROXY/<module>/@v/<version>.mod returns the go.mod file
+for that version of the given module.
+
+GET $GOPROXY/<module>/@v/<version>.zip returns the zip archive
+for that version of the given module.
+
+To avoid problems when serving from case-sensitive file systems,
+the <module> and <version> elements are case-encoded, replacing every
+uppercase letter with an exclamation mark followed by the corresponding
+lower-case letter: github.com/Azure encodes as github.com/!azure.
+
+The JSON-formatted metadata about a given module corresponds to
+this Go data structure, which may be expanded in the future:
+
+ type Info struct {
+ Version string // version string
+ Time time.Time // commit time
+ }
+
+The zip archive for a specific version of a given module is a
+standard zip file that contains the file tree corresponding
+to the module's source code and related files. The archive uses
+slash-separated paths, and every file path in the archive must
+begin with <module>@<version>/, where the module and version are
+substituted directly, not case-encoded. The root of the module
+file tree corresponds to the <module>@<version>/ prefix in the
+archive.
+
+Even when downloading directly from version control systems,
+the go command synthesizes explicit info, mod, and zip files
+and stores them in its local cache, $GOPATH/pkg/mod/cache/download,
+the same as if it had downloaded them directly from a proxy.
+The cache layout is the same as the proxy URL space, so
+serving $GOPATH/pkg/mod/cache/download at (or copying it to)
+https://example.com/proxy would let other users access those
+cached module versions with GOPROXY=https://example.com/proxy.
+`,
+}
+
+var proxyURL = os.Getenv("GOPROXY")
+
+func lookupProxy(path string) (Repo, error) {
+ if strings.Contains(proxyURL, ",") {
+ return nil, fmt.Errorf("invalid $GOPROXY setting: cannot have comma")
+ }
+ u, err := url.Parse(proxyURL)
+ if err != nil || u.Scheme != "http" && u.Scheme != "https" && u.Scheme != "file" {
+ // Don't echo $GOPROXY back in case it has user:password in it (sigh).
+ return nil, fmt.Errorf("invalid $GOPROXY setting: malformed URL or invalid scheme (must be http, https, file)")
+ }
+ return newProxyRepo(u.String(), path)
+}
+
+type proxyRepo struct {
+ url string
+ path string
+}
+
+func newProxyRepo(baseURL, path string) (Repo, error) {
+ enc, err := module.EncodePath(path)
+ if err != nil {
+ return nil, err
+ }
+ return &proxyRepo{strings.TrimSuffix(baseURL, "/") + "/" + pathEscape(enc), path}, nil
+}
+
+func (p *proxyRepo) ModulePath() string {
+ return p.path
+}
+
+func (p *proxyRepo) Versions(prefix string) ([]string, error) {
+ var data []byte
+ err := webGetBytes(p.url+"/@v/list", &data)
+ if err != nil {
+ return nil, err
+ }
+ var list []string
+ for _, line := range strings.Split(string(data), "\n") {
+ f := strings.Fields(line)
+ if len(f) >= 1 && semver.IsValid(f[0]) && strings.HasPrefix(f[0], prefix) {
+ list = append(list, f[0])
+ }
+ }
+ SortVersions(list)
+ return list, nil
+}
+
+func (p *proxyRepo) latest() (*RevInfo, error) {
+ var data []byte
+ err := webGetBytes(p.url+"/@v/list", &data)
+ if err != nil {
+ return nil, err
+ }
+ var best time.Time
+ var bestVersion string
+ for _, line := range strings.Split(string(data), "\n") {
+ f := strings.Fields(line)
+ if len(f) >= 2 && semver.IsValid(f[0]) {
+ ft, err := time.Parse(time.RFC3339, f[1])
+ if err == nil && best.Before(ft) {
+ best = ft
+ bestVersion = f[0]
+ }
+ }
+ }
+ if bestVersion == "" {
+ return nil, fmt.Errorf("no commits")
+ }
+ info := &RevInfo{
+ Version: bestVersion,
+ Name: bestVersion,
+ Short: bestVersion,
+ Time: best,
+ }
+ return info, nil
+}
+
+func (p *proxyRepo) Stat(rev string) (*RevInfo, error) {
+ var data []byte
+ encRev, err := module.EncodeVersion(rev)
+ if err != nil {
+ return nil, err
+ }
+ err = webGetBytes(p.url+"/@v/"+pathEscape(encRev)+".info", &data)
+ if err != nil {
+ return nil, err
+ }
+ info := new(RevInfo)
+ if err := json.Unmarshal(data, info); err != nil {
+ return nil, err
+ }
+ return info, nil
+}
+
+func (p *proxyRepo) Latest() (*RevInfo, error) {
+ var data []byte
+ u := p.url + "/@latest"
+ err := webGetBytes(u, &data)
+ if err != nil {
+ // TODO return err if not 404
+ return p.latest()
+ }
+ info := new(RevInfo)
+ if err := json.Unmarshal(data, info); err != nil {
+ return nil, err
+ }
+ return info, nil
+}
+
+func (p *proxyRepo) GoMod(version string) ([]byte, error) {
+ var data []byte
+ encVer, err := module.EncodeVersion(version)
+ if err != nil {
+ return nil, err
+ }
+ err = webGetBytes(p.url+"/@v/"+pathEscape(encVer)+".mod", &data)
+ if err != nil {
+ return nil, err
+ }
+ return data, nil
+}
+
+func (p *proxyRepo) Zip(version string, tmpdir string) (tmpfile string, err error) {
+ var body io.ReadCloser
+ encVer, err := module.EncodeVersion(version)
+ if err != nil {
+ return "", err
+ }
+ err = webGetBody(p.url+"/@v/"+pathEscape(encVer)+".zip", &body)
+ if err != nil {
+ return "", err
+ }
+ defer body.Close()
+
+ // Spool to local file.
+ f, err := ioutil.TempFile(tmpdir, "go-proxy-download-")
+ if err != nil {
+ return "", err
+ }
+ defer f.Close()
+ maxSize := int64(codehost.MaxZipFile)
+ lr := &io.LimitedReader{R: body, N: maxSize + 1}
+ if _, err := io.Copy(f, lr); err != nil {
+ os.Remove(f.Name())
+ return "", err
+ }
+ if lr.N <= 0 {
+ os.Remove(f.Name())
+ return "", fmt.Errorf("downloaded zip file too large")
+ }
+ if err := f.Close(); err != nil {
+ os.Remove(f.Name())
+ return "", err
+ }
+ return f.Name(), nil
+}
+
+// pathEscape escapes s so it can be used in a path.
+// That is, it escapes things like ? and # (which really shouldn't appear anyway).
+// It does not escape / to %2F: our REST API is designed so that / can be left as is.
+func pathEscape(s string) string {
+ return strings.Replace(url.PathEscape(s), "%2F", "/", -1)
+}
diff --git a/libgo/go/cmd/go/internal/modfetch/pseudo.go b/libgo/go/cmd/go/internal/modfetch/pseudo.go
new file mode 100644
index 00000000000..32c7bf883be
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfetch/pseudo.go
@@ -0,0 +1,129 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Pseudo-versions
+//
+// Code authors are expected to tag the revisions they want users to use,
+// including prereleases. However, not all authors tag versions at all,
+// and not all commits a user might want to try will have tags.
+// A pseudo-version is a version with a special form that allows us to
+// address an untagged commit and order that version with respect to
+// other versions we might encounter.
+//
+// A pseudo-version takes one of the general forms:
+//
+// (1) vX.0.0-yyyymmddhhmmss-abcdef123456
+// (2) vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456
+// (3) vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456+incompatible
+// (4) vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456
+// (5) vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456+incompatible
+//
+// If there is no recently tagged version with the right major version vX,
+// then form (1) is used, creating a space of pseudo-versions at the bottom
+// of the vX version range, less than any tagged version, including the unlikely v0.0.0.
+//
+// If the most recent tagged version before the target commit is vX.Y.Z or vX.Y.Z+incompatible,
+// then the pseudo-version uses form (2) or (3), making it a prerelease for the next
+// possible semantic version after vX.Y.Z. The leading 0 segment in the prerelease string
+// ensures that the pseudo-version compares less than possible future explicit prereleases
+// like vX.Y.(Z+1)-rc1 or vX.Y.(Z+1)-1.
+//
+// If the most recent tagged version before the target commit is vX.Y.Z-pre or vX.Y.Z-pre+incompatible,
+// then the pseudo-version uses form (4) or (5), making it a slightly later prerelease.
+
+package modfetch
+
+import (
+ "cmd/go/internal/semver"
+ "fmt"
+ "regexp"
+ "strings"
+ "time"
+)
+
+// PseudoVersion returns a pseudo-version for the given major version ("v1")
+// preexisting older tagged version ("" or "v1.2.3" or "v1.2.3-pre"), revision time,
+// and revision identifier (usually a 12-byte commit hash prefix).
+func PseudoVersion(major, older string, t time.Time, rev string) string {
+ if major == "" {
+ major = "v0"
+ }
+ major = strings.TrimSuffix(major, "-unstable") // make gopkg.in/macaroon-bakery.v2-unstable use "v2"
+ segment := fmt.Sprintf("%s-%s", t.UTC().Format("20060102150405"), rev)
+ build := semver.Build(older)
+ older = semver.Canonical(older)
+ if older == "" {
+ return major + ".0.0-" + segment // form (1)
+ }
+ if semver.Prerelease(older) != "" {
+ return older + ".0." + segment + build // form (4), (5)
+ }
+
+ // Form (2), (3).
+ // Extract patch from vMAJOR.MINOR.PATCH
+ v := older[:len(older)]
+ i := strings.LastIndex(v, ".") + 1
+ v, patch := v[:i], v[i:]
+
+ // Increment PATCH by adding 1 to decimal:
+ // scan right to left turning 9s to 0s until you find a digit to increment.
+ // (Number might exceed int64, but math/big is overkill.)
+ digits := []byte(patch)
+ for i = len(digits) - 1; i >= 0 && digits[i] == '9'; i-- {
+ digits[i] = '0'
+ }
+ if i >= 0 {
+ digits[i]++
+ } else {
+ // digits is all zeros
+ digits[0] = '1'
+ digits = append(digits, '0')
+ }
+ patch = string(digits)
+
+ // Reassemble.
+ return v + patch + "-0." + segment + build
+}
+
+var pseudoVersionRE = regexp.MustCompile(`^v[0-9]+\.(0\.0-|\d+\.\d+-([^+]*\.)?0\.)\d{14}-[A-Za-z0-9]+(\+incompatible)?$`)
+
+// IsPseudoVersion reports whether v is a pseudo-version.
+func IsPseudoVersion(v string) bool {
+ return strings.Count(v, "-") >= 2 && semver.IsValid(v) && pseudoVersionRE.MatchString(v)
+}
+
+// PseudoVersionTime returns the time stamp of the pseudo-version v.
+// It returns an error if v is not a pseudo-version or if the time stamp
+// embedded in the pseudo-version is not a valid time.
+func PseudoVersionTime(v string) (time.Time, error) {
+ timestamp, _, err := parsePseudoVersion(v)
+ t, err := time.Parse("20060102150405", timestamp)
+ if err != nil {
+ return time.Time{}, fmt.Errorf("pseudo-version with malformed time %s: %q", timestamp, v)
+ }
+ return t, nil
+}
+
+// PseudoVersionRev returns the revision identifier of the pseudo-version v.
+// It returns an error if v is not a pseudo-version.
+func PseudoVersionRev(v string) (rev string, err error) {
+ _, rev, err = parsePseudoVersion(v)
+ return
+}
+
+func parsePseudoVersion(v string) (timestamp, rev string, err error) {
+ if !IsPseudoVersion(v) {
+ return "", "", fmt.Errorf("malformed pseudo-version %q", v)
+ }
+ v = strings.TrimSuffix(v, "+incompatible")
+ j := strings.LastIndex(v, "-")
+ v, rev = v[:j], v[j+1:]
+ i := strings.LastIndex(v, "-")
+ if j := strings.LastIndex(v, "."); j > i {
+ timestamp = v[j+1:]
+ } else {
+ timestamp = v[i+1:]
+ }
+ return timestamp, rev, nil
+}
diff --git a/libgo/go/cmd/go/internal/modfetch/pseudo_test.go b/libgo/go/cmd/go/internal/modfetch/pseudo_test.go
new file mode 100644
index 00000000000..3c2fa514689
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfetch/pseudo_test.go
@@ -0,0 +1,74 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modfetch
+
+import (
+ "testing"
+ "time"
+)
+
+var pseudoTests = []struct {
+ major string
+ older string
+ version string
+}{
+ {"", "", "v0.0.0-20060102150405-hash"},
+ {"v0", "", "v0.0.0-20060102150405-hash"},
+ {"v1", "", "v1.0.0-20060102150405-hash"},
+ {"v2", "", "v2.0.0-20060102150405-hash"},
+ {"unused", "v0.0.0", "v0.0.1-0.20060102150405-hash"},
+ {"unused", "v1.2.3", "v1.2.4-0.20060102150405-hash"},
+ {"unused", "v1.2.99999999999999999", "v1.2.100000000000000000-0.20060102150405-hash"},
+ {"unused", "v1.2.3-pre", "v1.2.3-pre.0.20060102150405-hash"},
+ {"unused", "v1.3.0-pre", "v1.3.0-pre.0.20060102150405-hash"},
+}
+
+var pseudoTime = time.Date(2006, 1, 2, 15, 4, 5, 0, time.UTC)
+
+func TestPseudoVersion(t *testing.T) {
+ for _, tt := range pseudoTests {
+ v := PseudoVersion(tt.major, tt.older, pseudoTime, "hash")
+ if v != tt.version {
+ t.Errorf("PseudoVersion(%q, %q, ...) = %v, want %v", tt.major, tt.older, v, tt.version)
+ }
+ }
+}
+
+func TestIsPseudoVersion(t *testing.T) {
+ for _, tt := range pseudoTests {
+ if !IsPseudoVersion(tt.version) {
+ t.Errorf("IsPseudoVersion(%q) = false, want true", tt.version)
+ }
+ if IsPseudoVersion(tt.older) {
+ t.Errorf("IsPseudoVersion(%q) = true, want false", tt.older)
+ }
+ }
+}
+
+func TestPseudoVersionTime(t *testing.T) {
+ for _, tt := range pseudoTests {
+ tm, err := PseudoVersionTime(tt.version)
+ if tm != pseudoTime || err != nil {
+ t.Errorf("PseudoVersionTime(%q) = %v, %v, want %v, nil", tt.version, tm.Format(time.RFC3339), err, pseudoTime.Format(time.RFC3339))
+ }
+ tm, err = PseudoVersionTime(tt.older)
+ if tm != (time.Time{}) || err == nil {
+ t.Errorf("PseudoVersionTime(%q) = %v, %v, want %v, error", tt.older, tm.Format(time.RFC3339), err, time.Time{}.Format(time.RFC3339))
+ }
+ }
+}
+
+func TestPseudoVersionRev(t *testing.T) {
+ for _, tt := range pseudoTests {
+ rev, err := PseudoVersionRev(tt.version)
+ if rev != "hash" || err != nil {
+ t.Errorf("PseudoVersionRev(%q) = %q, %v, want %q, nil", tt.older, rev, err, "hash")
+ }
+ rev, err = PseudoVersionRev(tt.older)
+ if rev != "" || err == nil {
+ t.Errorf("PseudoVersionRev(%q) = %q, %v, want %q, error", tt.older, rev, err, "")
+ }
+ }
+}
diff --git a/libgo/go/cmd/go/internal/modfetch/repo.go b/libgo/go/cmd/go/internal/modfetch/repo.go
new file mode 100644
index 00000000000..0ea8c1f0e35
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfetch/repo.go
@@ -0,0 +1,363 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modfetch
+
+import (
+ "fmt"
+ "os"
+ "sort"
+ "time"
+
+ "cmd/go/internal/cfg"
+ "cmd/go/internal/get"
+ "cmd/go/internal/modfetch/codehost"
+ "cmd/go/internal/par"
+ "cmd/go/internal/semver"
+ web "cmd/go/internal/web"
+)
+
+const traceRepo = false // trace all repo actions, for debugging
+
+// A Repo represents a repository storing all versions of a single module.
+// It must be safe for simultaneous use by multiple goroutines.
+type Repo interface {
+ // ModulePath returns the module path.
+ ModulePath() string
+
+ // Versions lists all known versions with the given prefix.
+ // Pseudo-versions are not included.
+ // Versions should be returned sorted in semver order
+ // (implementations can use SortVersions).
+ Versions(prefix string) (tags []string, err error)
+
+ // Stat returns information about the revision rev.
+ // A revision can be any identifier known to the underlying service:
+ // commit hash, branch, tag, and so on.
+ Stat(rev string) (*RevInfo, error)
+
+ // Latest returns the latest revision on the default branch,
+ // whatever that means in the underlying source code repository.
+ // It is only used when there are no tagged versions.
+ Latest() (*RevInfo, error)
+
+ // GoMod returns the go.mod file for the given version.
+ GoMod(version string) (data []byte, err error)
+
+ // Zip downloads a zip file for the given version
+ // to a new file in a given temporary directory.
+ // It returns the name of the new file.
+ // The caller should remove the file when finished with it.
+ Zip(version, tmpdir string) (tmpfile string, err error)
+}
+
+// A Rev describes a single revision in a module repository.
+type RevInfo struct {
+ Version string // version string
+ Time time.Time // commit time
+
+ // These fields are used for Stat of arbitrary rev,
+ // but they are not recorded when talking about module versions.
+ Name string `json:"-"` // complete ID in underlying repository
+ Short string `json:"-"` // shortened ID, for use in pseudo-version
+}
+
+// Re: module paths, import paths, repository roots, and lookups
+//
+// A module is a collection of Go packages stored in a file tree
+// with a go.mod file at the root of the tree.
+// The go.mod defines the module path, which is the import path
+// corresponding to the root of the file tree.
+// The import path of a directory within that file tree is the module path
+// joined with the name of the subdirectory relative to the root.
+//
+// For example, the module with path rsc.io/qr corresponds to the
+// file tree in the repository https://github.com/rsc/qr.
+// That file tree has a go.mod that says "module rsc.io/qr".
+// The package in the root directory has import path "rsc.io/qr".
+// The package in the gf256 subdirectory has import path "rsc.io/qr/gf256".
+// In this example, "rsc.io/qr" is both a module path and an import path.
+// But "rsc.io/qr/gf256" is only an import path, not a module path:
+// it names an importable package, but not a module.
+//
+// As a special case to incorporate code written before modules were
+// introduced, if a path p resolves using the pre-module "go get" lookup
+// to the root of a source code repository without a go.mod file,
+// that repository is treated as if it had a go.mod in its root directory
+// declaring module path p. (The go.mod is further considered to
+// contain requirements corresponding to any legacy version
+// tracking format such as Gopkg.lock, vendor/vendor.conf, and so on.)
+//
+// The presentation so far ignores the fact that a source code repository
+// has many different versions of a file tree, and those versions may
+// differ in whether a particular go.mod exists and what it contains.
+// In fact there is a well-defined mapping only from a module path, version
+// pair - often written path@version - to a particular file tree.
+// For example rsc.io/qr@v0.1.0 depends on the "implicit go.mod at root of
+// repository" rule, while rsc.io/qr@v0.2.0 has an explicit go.mod.
+// Because the "go get" import paths rsc.io/qr and github.com/rsc/qr
+// both redirect to the Git repository https://github.com/rsc/qr,
+// github.com/rsc/qr@v0.1.0 is the same file tree as rsc.io/qr@v0.1.0
+// but a different module (a different name). In contrast, since v0.2.0
+// of that repository has an explicit go.mod that declares path rsc.io/qr,
+// github.com/rsc/qr@v0.2.0 is an invalid module path, version pair.
+// Before modules, import comments would have had the same effect.
+//
+// The set of import paths associated with a given module path is
+// clearly not fixed: at the least, new directories with new import paths
+// can always be added. But another potential operation is to split a
+// subtree out of a module into its own module. If done carefully,
+// this operation can be done while preserving compatibility for clients.
+// For example, suppose that we want to split rsc.io/qr/gf256 into its
+// own module, so that there would be two modules rsc.io/qr and rsc.io/qr/gf256.
+// Then we can simultaneously issue rsc.io/qr v0.3.0 (dropping the gf256 subdirectory)
+// and rsc.io/qr/gf256 v0.1.0, including in their respective go.mod
+// cyclic requirements pointing at each other: rsc.io/qr v0.3.0 requires
+// rsc.io/qr/gf256 v0.1.0 and vice versa. Then a build can be
+// using an older rsc.io/qr module that includes the gf256 package, but if
+// it adds a requirement on either the newer rsc.io/qr or the newer
+// rsc.io/qr/gf256 module, it will automatically add the requirement
+// on the complementary half, ensuring both that rsc.io/qr/gf256 is
+// available for importing by the build and also that it is only defined
+// by a single module. The gf256 package could move back into the
+// original by another simultaneous release of rsc.io/qr v0.4.0 including
+// the gf256 subdirectory and an rsc.io/qr/gf256 v0.2.0 with no code
+// in its root directory, along with a new requirement cycle.
+// The ability to shift module boundaries in this way is expected to be
+// important in large-scale program refactorings, similar to the ones
+// described in https://talks.golang.org/2016/refactor.article.
+//
+// The possibility of shifting module boundaries reemphasizes
+// that you must know both the module path and its version
+// to determine the set of packages provided directly by that module.
+//
+// On top of all this, it is possible for a single code repository
+// to contain multiple modules, either in branches or subdirectories,
+// as a limited kind of monorepo. For example rsc.io/qr/v2,
+// the v2.x.x continuation of rsc.io/qr, is expected to be found
+// in v2-tagged commits in https://github.com/rsc/qr, either
+// in the root or in a v2 subdirectory, disambiguated by go.mod.
+// Again the precise file tree corresponding to a module
+// depends on which version we are considering.
+//
+// It is also possible for the underlying repository to change over time,
+// without changing the module path. If I copy the github repo over
+// to https://bitbucket.org/rsc/qr and update https://rsc.io/qr?go-get=1,
+// then clients of all versions should start fetching from bitbucket
+// instead of github. That is, in contrast to the exact file tree,
+// the location of the source code repository associated with a module path
+// does not depend on the module version. (This is by design, as the whole
+// point of these redirects is to allow package authors to establish a stable
+// name that can be updated as code moves from one service to another.)
+//
+// All of this is important background for the lookup APIs defined in this
+// file.
+//
+// The Lookup function takes a module path and returns a Repo representing
+// that module path. Lookup can do only a little with the path alone.
+// It can check that the path is well-formed (see semver.CheckPath)
+// and it can check that the path can be resolved to a target repository.
+// To avoid version control access except when absolutely necessary,
+// Lookup does not attempt to connect to the repository itself.
+//
+// The Import function takes an import path found in source code and
+// determines which module to add to the requirement list to satisfy
+// that import. It checks successive truncations of the import path
+// to determine possible modules and stops when it finds a module
+// in which the latest version satisfies the import path.
+//
+// The ImportRepoRev function is a variant of Import which is limited
+// to code in a source code repository at a particular revision identifier
+// (usually a commit hash or source code repository tag, not necessarily
+// a module version).
+// ImportRepoRev is used when converting legacy dependency requirements
+// from older systems into go.mod files. Those older systems worked
+// at either package or repository granularity, and most of the time they
+// recorded commit hashes, not tagged versions.
+
+var lookupCache par.Cache
+
+// Lookup returns the module with the given module path.
+// A successful return does not guarantee that the module
+// has any defined versions.
+func Lookup(path string) (Repo, error) {
+ if traceRepo {
+ defer logCall("Lookup(%q)", path)()
+ }
+
+ type cached struct {
+ r Repo
+ err error
+ }
+ c := lookupCache.Do(path, func() interface{} {
+ r, err := lookup(path)
+ if err == nil {
+ if traceRepo {
+ r = newLoggingRepo(r)
+ }
+ r = newCachingRepo(r)
+ }
+ return cached{r, err}
+ }).(cached)
+
+ return c.r, c.err
+}
+
+// lookup returns the module with the given module path.
+func lookup(path string) (r Repo, err error) {
+ if cfg.BuildMod == "vendor" {
+ return nil, fmt.Errorf("module lookup disabled by -mod=%s", cfg.BuildMod)
+ }
+ if proxyURL == "off" {
+ return nil, fmt.Errorf("module lookup disabled by GOPROXY=%s", proxyURL)
+ }
+ if proxyURL != "" && proxyURL != "direct" {
+ return lookupProxy(path)
+ }
+
+ security := web.Secure
+ if get.Insecure {
+ security = web.Insecure
+ }
+ rr, err := get.RepoRootForImportPath(path, get.PreferMod, security)
+ if err != nil {
+ // We don't know where to find code for a module with this path.
+ return nil, err
+ }
+
+ if rr.VCS == "mod" {
+ // Fetch module from proxy with base URL rr.Repo.
+ return newProxyRepo(rr.Repo, path)
+ }
+
+ code, err := lookupCodeRepo(rr)
+ if err != nil {
+ return nil, err
+ }
+ return newCodeRepo(code, rr.Root, path)
+}
+
+func lookupCodeRepo(rr *get.RepoRoot) (codehost.Repo, error) {
+ code, err := codehost.NewRepo(rr.VCS, rr.Repo)
+ if err != nil {
+ if _, ok := err.(*codehost.VCSError); ok {
+ return nil, err
+ }
+ return nil, fmt.Errorf("lookup %s: %v", rr.Root, err)
+ }
+ return code, nil
+}
+
+// ImportRepoRev returns the module and version to use to access
+// the given import path loaded from the source code repository that
+// the original "go get" would have used, at the specific repository revision
+// (typically a commit hash, but possibly also a source control tag).
+func ImportRepoRev(path, rev string) (Repo, *RevInfo, error) {
+ if cfg.BuildMod == "vendor" || cfg.BuildMod == "readonly" {
+ return nil, nil, fmt.Errorf("repo version lookup disabled by -mod=%s", cfg.BuildMod)
+ }
+
+ // Note: Because we are converting a code reference from a legacy
+ // version control system, we ignore meta tags about modules
+ // and use only direct source control entries (get.IgnoreMod).
+ security := web.Secure
+ if get.Insecure {
+ security = web.Insecure
+ }
+ rr, err := get.RepoRootForImportPath(path, get.IgnoreMod, security)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ code, err := lookupCodeRepo(rr)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ revInfo, err := code.Stat(rev)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ // TODO: Look in repo to find path, check for go.mod files.
+ // For now we're just assuming rr.Root is the module path,
+ // which is true in the absence of go.mod files.
+
+ repo, err := newCodeRepo(code, rr.Root, rr.Root)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ info, err := repo.(*codeRepo).convert(revInfo, "")
+ if err != nil {
+ return nil, nil, err
+ }
+ return repo, info, nil
+}
+
+func SortVersions(list []string) {
+ sort.Slice(list, func(i, j int) bool {
+ cmp := semver.Compare(list[i], list[j])
+ if cmp != 0 {
+ return cmp < 0
+ }
+ return list[i] < list[j]
+ })
+}
+
+// A loggingRepo is a wrapper around an underlying Repo
+// that prints a log message at the start and end of each call.
+// It can be inserted when debugging.
+type loggingRepo struct {
+ r Repo
+}
+
+func newLoggingRepo(r Repo) *loggingRepo {
+ return &loggingRepo{r}
+}
+
+// logCall prints a log message using format and args and then
+// also returns a function that will print the same message again,
+// along with the elapsed time.
+// Typical usage is:
+//
+// defer logCall("hello %s", arg)()
+//
+// Note the final ().
+func logCall(format string, args ...interface{}) func() {
+ start := time.Now()
+ fmt.Fprintf(os.Stderr, "+++ %s\n", fmt.Sprintf(format, args...))
+ return func() {
+ fmt.Fprintf(os.Stderr, "%.3fs %s\n", time.Since(start).Seconds(), fmt.Sprintf(format, args...))
+ }
+}
+
+func (l *loggingRepo) ModulePath() string {
+ return l.r.ModulePath()
+}
+
+func (l *loggingRepo) Versions(prefix string) (tags []string, err error) {
+ defer logCall("Repo[%s]: Versions(%q)", l.r.ModulePath(), prefix)()
+ return l.r.Versions(prefix)
+}
+
+func (l *loggingRepo) Stat(rev string) (*RevInfo, error) {
+ defer logCall("Repo[%s]: Stat(%q)", l.r.ModulePath(), rev)()
+ return l.r.Stat(rev)
+}
+
+func (l *loggingRepo) Latest() (*RevInfo, error) {
+ defer logCall("Repo[%s]: Latest()", l.r.ModulePath())()
+ return l.r.Latest()
+}
+
+func (l *loggingRepo) GoMod(version string) ([]byte, error) {
+ defer logCall("Repo[%s]: GoMod(%q)", l.r.ModulePath(), version)()
+ return l.r.GoMod(version)
+}
+
+func (l *loggingRepo) Zip(version, tmpdir string) (string, error) {
+ defer logCall("Repo[%s]: Zip(%q, %q)", l.r.ModulePath(), version, tmpdir)()
+ return l.r.Zip(version, tmpdir)
+}
diff --git a/libgo/go/cmd/go/internal/modfetch/unzip.go b/libgo/go/cmd/go/internal/modfetch/unzip.go
new file mode 100644
index 00000000000..a50431fd862
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfetch/unzip.go
@@ -0,0 +1,153 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modfetch
+
+import (
+ "archive/zip"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path"
+ "path/filepath"
+ "sort"
+ "strings"
+
+ "cmd/go/internal/modfetch/codehost"
+ "cmd/go/internal/module"
+ "cmd/go/internal/str"
+)
+
+func Unzip(dir, zipfile, prefix string, maxSize int64) error {
+ if maxSize == 0 {
+ maxSize = codehost.MaxZipFile
+ }
+
+ // Directory can exist, but must be empty.
+ // except maybe
+ files, _ := ioutil.ReadDir(dir)
+ if len(files) > 0 {
+ return fmt.Errorf("target directory %v exists and is not empty", dir)
+ }
+ if err := os.MkdirAll(dir, 0777); err != nil {
+ return err
+ }
+
+ f, err := os.Open(zipfile)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ info, err := f.Stat()
+ if err != nil {
+ return err
+ }
+
+ z, err := zip.NewReader(f, info.Size())
+ if err != nil {
+ return fmt.Errorf("unzip %v: %s", zipfile, err)
+ }
+
+ foldPath := make(map[string]string)
+ var checkFold func(string) error
+ checkFold = func(name string) error {
+ fold := str.ToFold(name)
+ if foldPath[fold] == name {
+ return nil
+ }
+ dir := path.Dir(name)
+ if dir != "." {
+ if err := checkFold(dir); err != nil {
+ return err
+ }
+ }
+ if foldPath[fold] == "" {
+ foldPath[fold] = name
+ return nil
+ }
+ other := foldPath[fold]
+ return fmt.Errorf("unzip %v: case-insensitive file name collision: %q and %q", zipfile, other, name)
+ }
+
+ // Check total size, valid file names.
+ var size int64
+ for _, zf := range z.File {
+ if !str.HasPathPrefix(zf.Name, prefix) {
+ return fmt.Errorf("unzip %v: unexpected file name %s", zipfile, zf.Name)
+ }
+ if zf.Name == prefix || strings.HasSuffix(zf.Name, "/") {
+ continue
+ }
+ name := zf.Name[len(prefix)+1:]
+ if err := module.CheckFilePath(name); err != nil {
+ return fmt.Errorf("unzip %v: %v", zipfile, err)
+ }
+ if err := checkFold(name); err != nil {
+ return err
+ }
+ if path.Clean(zf.Name) != zf.Name || strings.HasPrefix(zf.Name[len(prefix)+1:], "/") {
+ return fmt.Errorf("unzip %v: invalid file name %s", zipfile, zf.Name)
+ }
+ s := int64(zf.UncompressedSize64)
+ if s < 0 || maxSize-size < s {
+ return fmt.Errorf("unzip %v: content too large", zipfile)
+ }
+ size += s
+ }
+
+ // Unzip, enforcing sizes checked earlier.
+ dirs := map[string]bool{dir: true}
+ for _, zf := range z.File {
+ if zf.Name == prefix || strings.HasSuffix(zf.Name, "/") {
+ continue
+ }
+ name := zf.Name[len(prefix):]
+ dst := filepath.Join(dir, name)
+ parent := filepath.Dir(dst)
+ for parent != dir {
+ dirs[parent] = true
+ parent = filepath.Dir(parent)
+ }
+ if err := os.MkdirAll(filepath.Dir(dst), 0777); err != nil {
+ return err
+ }
+ w, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0444)
+ if err != nil {
+ return fmt.Errorf("unzip %v: %v", zipfile, err)
+ }
+ r, err := zf.Open()
+ if err != nil {
+ w.Close()
+ return fmt.Errorf("unzip %v: %v", zipfile, err)
+ }
+ lr := &io.LimitedReader{R: r, N: int64(zf.UncompressedSize64) + 1}
+ _, err = io.Copy(w, lr)
+ r.Close()
+ if err != nil {
+ w.Close()
+ return fmt.Errorf("unzip %v: %v", zipfile, err)
+ }
+ if err := w.Close(); err != nil {
+ return fmt.Errorf("unzip %v: %v", zipfile, err)
+ }
+ if lr.N <= 0 {
+ return fmt.Errorf("unzip %v: content too large", zipfile)
+ }
+ }
+
+ // Mark directories unwritable, best effort.
+ var dirlist []string
+ for dir := range dirs {
+ dirlist = append(dirlist, dir)
+ }
+ sort.Strings(dirlist)
+
+ // Run over list backward to chmod children before parents.
+ for i := len(dirlist) - 1; i >= 0; i-- {
+ os.Chmod(dirlist[i], 0555)
+ }
+
+ return nil
+}
diff --git a/libgo/go/cmd/go/internal/modfetch/web.go b/libgo/go/cmd/go/internal/modfetch/web.go
new file mode 100644
index 00000000000..b327bf293d1
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfetch/web.go
@@ -0,0 +1,31 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !cmd_go_bootstrap
+
+package modfetch
+
+import (
+ "io"
+
+ web "cmd/go/internal/web2"
+)
+
+// webGetGoGet fetches a go-get=1 URL and returns the body in *body.
+// It allows non-200 responses, as usual for these URLs.
+func webGetGoGet(url string, body *io.ReadCloser) error {
+ return web.Get(url, web.Non200OK(), web.Body(body))
+}
+
+// webGetBytes returns the body returned by an HTTP GET, as a []byte.
+// It insists on a 200 response.
+func webGetBytes(url string, body *[]byte) error {
+ return web.Get(url, web.ReadAllBody(body))
+}
+
+// webGetBody returns the body returned by an HTTP GET, as a io.ReadCloser.
+// It insists on a 200 response.
+func webGetBody(url string, body *io.ReadCloser) error {
+ return web.Get(url, web.Body(body))
+}
diff --git a/libgo/go/cmd/go/internal/modfile/gopkgin.go b/libgo/go/cmd/go/internal/modfile/gopkgin.go
new file mode 100644
index 00000000000..c94b3848a0e
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfile/gopkgin.go
@@ -0,0 +1,47 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TODO: Figure out what gopkg.in should do.
+
+package modfile
+
+import "strings"
+
+// ParseGopkgIn splits gopkg.in import paths into their constituent parts
+func ParseGopkgIn(path string) (root, repo, major, subdir string, ok bool) {
+ if !strings.HasPrefix(path, "gopkg.in/") {
+ return
+ }
+ f := strings.Split(path, "/")
+ if len(f) >= 2 {
+ if elem, v, ok := dotV(f[1]); ok {
+ root = strings.Join(f[:2], "/")
+ repo = "github.com/go-" + elem + "/" + elem
+ major = v
+ subdir = strings.Join(f[2:], "/")
+ return root, repo, major, subdir, true
+ }
+ }
+ if len(f) >= 3 {
+ if elem, v, ok := dotV(f[2]); ok {
+ root = strings.Join(f[:3], "/")
+ repo = "github.com/" + f[1] + "/" + elem
+ major = v
+ subdir = strings.Join(f[3:], "/")
+ return root, repo, major, subdir, true
+ }
+ }
+ return
+}
+
+func dotV(name string) (elem, v string, ok bool) {
+ i := len(name) - 1
+ for i >= 0 && '0' <= name[i] && name[i] <= '9' {
+ i--
+ }
+ if i <= 2 || i+1 >= len(name) || name[i-1] != '.' || name[i] != 'v' || name[i+1] == '0' && len(name) != i+2 {
+ return "", "", false
+ }
+ return name[:i-1], name[i:], true
+}
diff --git a/libgo/go/cmd/go/internal/modfile/print.go b/libgo/go/cmd/go/internal/modfile/print.go
new file mode 100644
index 00000000000..cefc43b141c
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfile/print.go
@@ -0,0 +1,164 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Module file printer.
+
+package modfile
+
+import (
+ "bytes"
+ "fmt"
+ "strings"
+)
+
+func Format(f *FileSyntax) []byte {
+ pr := &printer{}
+ pr.file(f)
+ return pr.Bytes()
+}
+
+// A printer collects the state during printing of a file or expression.
+type printer struct {
+ bytes.Buffer // output buffer
+ comment []Comment // pending end-of-line comments
+ margin int // left margin (indent), a number of tabs
+}
+
+// printf prints to the buffer.
+func (p *printer) printf(format string, args ...interface{}) {
+ fmt.Fprintf(p, format, args...)
+}
+
+// indent returns the position on the current line, in bytes, 0-indexed.
+func (p *printer) indent() int {
+ b := p.Bytes()
+ n := 0
+ for n < len(b) && b[len(b)-1-n] != '\n' {
+ n++
+ }
+ return n
+}
+
+// newline ends the current line, flushing end-of-line comments.
+func (p *printer) newline() {
+ if len(p.comment) > 0 {
+ p.printf(" ")
+ for i, com := range p.comment {
+ if i > 0 {
+ p.trim()
+ p.printf("\n")
+ for i := 0; i < p.margin; i++ {
+ p.printf("\t")
+ }
+ }
+ p.printf("%s", strings.TrimSpace(com.Token))
+ }
+ p.comment = p.comment[:0]
+ }
+
+ p.trim()
+ p.printf("\n")
+ for i := 0; i < p.margin; i++ {
+ p.printf("\t")
+ }
+}
+
+// trim removes trailing spaces and tabs from the current line.
+func (p *printer) trim() {
+ // Remove trailing spaces and tabs from line we're about to end.
+ b := p.Bytes()
+ n := len(b)
+ for n > 0 && (b[n-1] == '\t' || b[n-1] == ' ') {
+ n--
+ }
+ p.Truncate(n)
+}
+
+// file formats the given file into the print buffer.
+func (p *printer) file(f *FileSyntax) {
+ for _, com := range f.Before {
+ p.printf("%s", strings.TrimSpace(com.Token))
+ p.newline()
+ }
+
+ for i, stmt := range f.Stmt {
+ switch x := stmt.(type) {
+ case *CommentBlock:
+ // comments already handled
+ p.expr(x)
+
+ default:
+ p.expr(x)
+ p.newline()
+ }
+
+ for _, com := range stmt.Comment().After {
+ p.printf("%s", strings.TrimSpace(com.Token))
+ p.newline()
+ }
+
+ if i+1 < len(f.Stmt) {
+ p.newline()
+ }
+ }
+}
+
+func (p *printer) expr(x Expr) {
+ // Emit line-comments preceding this expression.
+ if before := x.Comment().Before; len(before) > 0 {
+ // Want to print a line comment.
+ // Line comments must be at the current margin.
+ p.trim()
+ if p.indent() > 0 {
+ // There's other text on the line. Start a new line.
+ p.printf("\n")
+ }
+ // Re-indent to margin.
+ for i := 0; i < p.margin; i++ {
+ p.printf("\t")
+ }
+ for _, com := range before {
+ p.printf("%s", strings.TrimSpace(com.Token))
+ p.newline()
+ }
+ }
+
+ switch x := x.(type) {
+ default:
+ panic(fmt.Errorf("printer: unexpected type %T", x))
+
+ case *CommentBlock:
+ // done
+
+ case *LParen:
+ p.printf("(")
+ case *RParen:
+ p.printf(")")
+
+ case *Line:
+ sep := ""
+ for _, tok := range x.Token {
+ p.printf("%s%s", sep, tok)
+ sep = " "
+ }
+
+ case *LineBlock:
+ for _, tok := range x.Token {
+ p.printf("%s ", tok)
+ }
+ p.expr(&x.LParen)
+ p.margin++
+ for _, l := range x.Line {
+ p.newline()
+ p.expr(l)
+ }
+ p.margin--
+ p.newline()
+ p.expr(&x.RParen)
+ }
+
+ // Queue end-of-line comments for printing when we
+ // reach the end of the line.
+ p.comment = append(p.comment, x.Comment().Suffix...)
+}
diff --git a/libgo/go/cmd/go/internal/modfile/read.go b/libgo/go/cmd/go/internal/modfile/read.go
new file mode 100644
index 00000000000..1d81ff1ab7a
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfile/read.go
@@ -0,0 +1,869 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Module file parser.
+// This is a simplified copy of Google's buildifier parser.
+
+package modfile
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+)
+
+// A Position describes the position between two bytes of input.
+type Position struct {
+ Line int // line in input (starting at 1)
+ LineRune int // rune in line (starting at 1)
+ Byte int // byte in input (starting at 0)
+}
+
+// add returns the position at the end of s, assuming it starts at p.
+func (p Position) add(s string) Position {
+ p.Byte += len(s)
+ if n := strings.Count(s, "\n"); n > 0 {
+ p.Line += n
+ s = s[strings.LastIndex(s, "\n")+1:]
+ p.LineRune = 1
+ }
+ p.LineRune += utf8.RuneCountInString(s)
+ return p
+}
+
+// An Expr represents an input element.
+type Expr interface {
+ // Span returns the start and end position of the expression,
+ // excluding leading or trailing comments.
+ Span() (start, end Position)
+
+ // Comment returns the comments attached to the expression.
+ // This method would normally be named 'Comments' but that
+ // would interfere with embedding a type of the same name.
+ Comment() *Comments
+}
+
+// A Comment represents a single // comment.
+type Comment struct {
+ Start Position
+ Token string // without trailing newline
+ Suffix bool // an end of line (not whole line) comment
+}
+
+// Comments collects the comments associated with an expression.
+type Comments struct {
+ Before []Comment // whole-line comments before this expression
+ Suffix []Comment // end-of-line comments after this expression
+
+ // For top-level expressions only, After lists whole-line
+ // comments following the expression.
+ After []Comment
+}
+
+// Comment returns the receiver. This isn't useful by itself, but
+// a Comments struct is embedded into all the expression
+// implementation types, and this gives each of those a Comment
+// method to satisfy the Expr interface.
+func (c *Comments) Comment() *Comments {
+ return c
+}
+
+// A FileSyntax represents an entire go.mod file.
+type FileSyntax struct {
+ Name string // file path
+ Comments
+ Stmt []Expr
+}
+
+func (x *FileSyntax) Span() (start, end Position) {
+ if len(x.Stmt) == 0 {
+ return
+ }
+ start, _ = x.Stmt[0].Span()
+ _, end = x.Stmt[len(x.Stmt)-1].Span()
+ return start, end
+}
+
+func (x *FileSyntax) addLine(hint Expr, tokens ...string) *Line {
+ if hint == nil {
+ // If no hint given, add to the last statement of the given type.
+ Loop:
+ for i := len(x.Stmt) - 1; i >= 0; i-- {
+ stmt := x.Stmt[i]
+ switch stmt := stmt.(type) {
+ case *Line:
+ if stmt.Token != nil && stmt.Token[0] == tokens[0] {
+ hint = stmt
+ break Loop
+ }
+ case *LineBlock:
+ if stmt.Token[0] == tokens[0] {
+ hint = stmt
+ break Loop
+ }
+ }
+ }
+ }
+
+ if hint != nil {
+ for i, stmt := range x.Stmt {
+ switch stmt := stmt.(type) {
+ case *Line:
+ if stmt == hint {
+ // Convert line to line block.
+ stmt.InBlock = true
+ block := &LineBlock{Token: stmt.Token[:1], Line: []*Line{stmt}}
+ stmt.Token = stmt.Token[1:]
+ x.Stmt[i] = block
+ new := &Line{Token: tokens[1:], InBlock: true}
+ block.Line = append(block.Line, new)
+ return new
+ }
+ case *LineBlock:
+ if stmt == hint {
+ new := &Line{Token: tokens[1:], InBlock: true}
+ stmt.Line = append(stmt.Line, new)
+ return new
+ }
+ for j, line := range stmt.Line {
+ if line == hint {
+ // Add new line after hint.
+ stmt.Line = append(stmt.Line, nil)
+ copy(stmt.Line[j+2:], stmt.Line[j+1:])
+ new := &Line{Token: tokens[1:], InBlock: true}
+ stmt.Line[j+1] = new
+ return new
+ }
+ }
+ }
+ }
+ }
+
+ new := &Line{Token: tokens}
+ x.Stmt = append(x.Stmt, new)
+ return new
+}
+
+func (x *FileSyntax) updateLine(line *Line, tokens ...string) {
+ if line.InBlock {
+ tokens = tokens[1:]
+ }
+ line.Token = tokens
+}
+
+func (x *FileSyntax) removeLine(line *Line) {
+ line.Token = nil
+}
+
+// Cleanup cleans up the file syntax x after any edit operations.
+// To avoid quadratic behavior, removeLine marks the line as dead
+// by setting line.Token = nil but does not remove it from the slice
+// in which it appears. After edits have all been indicated,
+// calling Cleanup cleans out the dead lines.
+func (x *FileSyntax) Cleanup() {
+ w := 0
+ for _, stmt := range x.Stmt {
+ switch stmt := stmt.(type) {
+ case *Line:
+ if stmt.Token == nil {
+ continue
+ }
+ case *LineBlock:
+ ww := 0
+ for _, line := range stmt.Line {
+ if line.Token != nil {
+ stmt.Line[ww] = line
+ ww++
+ }
+ }
+ if ww == 0 {
+ continue
+ }
+ if ww == 1 {
+ // Collapse block into single line.
+ line := &Line{
+ Comments: Comments{
+ Before: commentsAdd(stmt.Before, stmt.Line[0].Before),
+ Suffix: commentsAdd(stmt.Line[0].Suffix, stmt.Suffix),
+ After: commentsAdd(stmt.Line[0].After, stmt.After),
+ },
+ Token: stringsAdd(stmt.Token, stmt.Line[0].Token),
+ }
+ x.Stmt[w] = line
+ w++
+ continue
+ }
+ stmt.Line = stmt.Line[:ww]
+ }
+ x.Stmt[w] = stmt
+ w++
+ }
+ x.Stmt = x.Stmt[:w]
+}
+
+func commentsAdd(x, y []Comment) []Comment {
+ return append(x[:len(x):len(x)], y...)
+}
+
+func stringsAdd(x, y []string) []string {
+ return append(x[:len(x):len(x)], y...)
+}
+
+// A CommentBlock represents a top-level block of comments separate
+// from any rule.
+type CommentBlock struct {
+ Comments
+ Start Position
+}
+
+func (x *CommentBlock) Span() (start, end Position) {
+ return x.Start, x.Start
+}
+
+// A Line is a single line of tokens.
+type Line struct {
+ Comments
+ Start Position
+ Token []string
+ InBlock bool
+ End Position
+}
+
+func (x *Line) Span() (start, end Position) {
+ return x.Start, x.End
+}
+
+// A LineBlock is a factored block of lines, like
+//
+// require (
+// "x"
+// "y"
+// )
+//
+type LineBlock struct {
+ Comments
+ Start Position
+ LParen LParen
+ Token []string
+ Line []*Line
+ RParen RParen
+}
+
+func (x *LineBlock) Span() (start, end Position) {
+ return x.Start, x.RParen.Pos.add(")")
+}
+
+// An LParen represents the beginning of a parenthesized line block.
+// It is a place to store suffix comments.
+type LParen struct {
+ Comments
+ Pos Position
+}
+
+func (x *LParen) Span() (start, end Position) {
+ return x.Pos, x.Pos.add(")")
+}
+
+// An RParen represents the end of a parenthesized line block.
+// It is a place to store whole-line (before) comments.
+type RParen struct {
+ Comments
+ Pos Position
+}
+
+func (x *RParen) Span() (start, end Position) {
+ return x.Pos, x.Pos.add(")")
+}
+
+// An input represents a single input file being parsed.
+type input struct {
+ // Lexing state.
+ filename string // name of input file, for errors
+ complete []byte // entire input
+ remaining []byte // remaining input
+ token []byte // token being scanned
+ lastToken string // most recently returned token, for error messages
+ pos Position // current input position
+ comments []Comment // accumulated comments
+ endRule int // position of end of current rule
+
+ // Parser state.
+ file *FileSyntax // returned top-level syntax tree
+ parseError error // error encountered during parsing
+
+ // Comment assignment state.
+ pre []Expr // all expressions, in preorder traversal
+ post []Expr // all expressions, in postorder traversal
+}
+
+func newInput(filename string, data []byte) *input {
+ return &input{
+ filename: filename,
+ complete: data,
+ remaining: data,
+ pos: Position{Line: 1, LineRune: 1, Byte: 0},
+ }
+}
+
+// parse parses the input file.
+func parse(file string, data []byte) (f *FileSyntax, err error) {
+ in := newInput(file, data)
+ // The parser panics for both routine errors like syntax errors
+ // and for programmer bugs like array index errors.
+ // Turn both into error returns. Catching bug panics is
+ // especially important when processing many files.
+ defer func() {
+ if e := recover(); e != nil {
+ if e == in.parseError {
+ err = in.parseError
+ } else {
+ err = fmt.Errorf("%s:%d:%d: internal error: %v", in.filename, in.pos.Line, in.pos.LineRune, e)
+ }
+ }
+ }()
+
+ // Invoke the parser.
+ in.parseFile()
+ if in.parseError != nil {
+ return nil, in.parseError
+ }
+ in.file.Name = in.filename
+
+ // Assign comments to nearby syntax.
+ in.assignComments()
+
+ return in.file, nil
+}
+
+// Error is called to report an error.
+// The reason s is often "syntax error".
+// Error does not return: it panics.
+func (in *input) Error(s string) {
+ if s == "syntax error" && in.lastToken != "" {
+ s += " near " + in.lastToken
+ }
+ in.parseError = fmt.Errorf("%s:%d:%d: %v", in.filename, in.pos.Line, in.pos.LineRune, s)
+ panic(in.parseError)
+}
+
+// eof reports whether the input has reached end of file.
+func (in *input) eof() bool {
+ return len(in.remaining) == 0
+}
+
+// peekRune returns the next rune in the input without consuming it.
+func (in *input) peekRune() int {
+ if len(in.remaining) == 0 {
+ return 0
+ }
+ r, _ := utf8.DecodeRune(in.remaining)
+ return int(r)
+}
+
+// peekPrefix reports whether the remaining input begins with the given prefix.
+func (in *input) peekPrefix(prefix string) bool {
+ // This is like bytes.HasPrefix(in.remaining, []byte(prefix))
+ // but without the allocation of the []byte copy of prefix.
+ for i := 0; i < len(prefix); i++ {
+ if i >= len(in.remaining) || in.remaining[i] != prefix[i] {
+ return false
+ }
+ }
+ return true
+}
+
+// readRune consumes and returns the next rune in the input.
+func (in *input) readRune() int {
+ if len(in.remaining) == 0 {
+ in.Error("internal lexer error: readRune at EOF")
+ }
+ r, size := utf8.DecodeRune(in.remaining)
+ in.remaining = in.remaining[size:]
+ if r == '\n' {
+ in.pos.Line++
+ in.pos.LineRune = 1
+ } else {
+ in.pos.LineRune++
+ }
+ in.pos.Byte += size
+ return int(r)
+}
+
+type symType struct {
+ pos Position
+ endPos Position
+ text string
+}
+
+// startToken marks the beginning of the next input token.
+// It must be followed by a call to endToken, once the token has
+// been consumed using readRune.
+func (in *input) startToken(sym *symType) {
+ in.token = in.remaining
+ sym.text = ""
+ sym.pos = in.pos
+}
+
+// endToken marks the end of an input token.
+// It records the actual token string in sym.text if the caller
+// has not done that already.
+func (in *input) endToken(sym *symType) {
+ if sym.text == "" {
+ tok := string(in.token[:len(in.token)-len(in.remaining)])
+ sym.text = tok
+ in.lastToken = sym.text
+ }
+ sym.endPos = in.pos
+}
+
+// lex is called from the parser to obtain the next input token.
+// It returns the token value (either a rune like '+' or a symbolic token _FOR)
+// and sets val to the data associated with the token.
+// For all our input tokens, the associated data is
+// val.Pos (the position where the token begins)
+// and val.Token (the input string corresponding to the token).
+func (in *input) lex(sym *symType) int {
+ // Skip past spaces, stopping at non-space or EOF.
+ countNL := 0 // number of newlines we've skipped past
+ for !in.eof() {
+ // Skip over spaces. Count newlines so we can give the parser
+ // information about where top-level blank lines are,
+ // for top-level comment assignment.
+ c := in.peekRune()
+ if c == ' ' || c == '\t' || c == '\r' {
+ in.readRune()
+ continue
+ }
+
+ // Comment runs to end of line.
+ if in.peekPrefix("//") {
+ in.startToken(sym)
+
+ // Is this comment the only thing on its line?
+ // Find the last \n before this // and see if it's all
+ // spaces from there to here.
+ i := bytes.LastIndex(in.complete[:in.pos.Byte], []byte("\n"))
+ suffix := len(bytes.TrimSpace(in.complete[i+1:in.pos.Byte])) > 0
+ in.readRune()
+ in.readRune()
+
+ // Consume comment.
+ for len(in.remaining) > 0 && in.readRune() != '\n' {
+ }
+ in.endToken(sym)
+
+ sym.text = strings.TrimRight(sym.text, "\n")
+ in.lastToken = "comment"
+
+ // If we are at top level (not in a statement), hand the comment to
+ // the parser as a _COMMENT token. The grammar is written
+ // to handle top-level comments itself.
+ if !suffix {
+ // Not in a statement. Tell parser about top-level comment.
+ return _COMMENT
+ }
+
+ // Otherwise, save comment for later attachment to syntax tree.
+ if countNL > 1 {
+ in.comments = append(in.comments, Comment{sym.pos, "", false})
+ }
+ in.comments = append(in.comments, Comment{sym.pos, sym.text, suffix})
+ countNL = 1
+ return _EOL
+ }
+
+ if in.peekPrefix("/*") {
+ in.Error(fmt.Sprintf("mod files must use // comments (not /* */ comments)"))
+ }
+
+ // Found non-space non-comment.
+ break
+ }
+
+ // Found the beginning of the next token.
+ in.startToken(sym)
+ defer in.endToken(sym)
+
+ // End of file.
+ if in.eof() {
+ in.lastToken = "EOF"
+ return _EOF
+ }
+
+ // Punctuation tokens.
+ switch c := in.peekRune(); c {
+ case '\n':
+ in.readRune()
+ return c
+
+ case '(':
+ in.readRune()
+ return c
+
+ case ')':
+ in.readRune()
+ return c
+
+ case '"', '`': // quoted string
+ quote := c
+ in.readRune()
+ for {
+ if in.eof() {
+ in.pos = sym.pos
+ in.Error("unexpected EOF in string")
+ }
+ if in.peekRune() == '\n' {
+ in.Error("unexpected newline in string")
+ }
+ c := in.readRune()
+ if c == quote {
+ break
+ }
+ if c == '\\' && quote != '`' {
+ if in.eof() {
+ in.pos = sym.pos
+ in.Error("unexpected EOF in string")
+ }
+ in.readRune()
+ }
+ }
+ in.endToken(sym)
+ return _STRING
+ }
+
+ // Checked all punctuation. Must be identifier token.
+ if c := in.peekRune(); !isIdent(c) {
+ in.Error(fmt.Sprintf("unexpected input character %#q", c))
+ }
+
+ // Scan over identifier.
+ for isIdent(in.peekRune()) {
+ if in.peekPrefix("//") {
+ break
+ }
+ if in.peekPrefix("/*") {
+ in.Error(fmt.Sprintf("mod files must use // comments (not /* */ comments)"))
+ }
+ in.readRune()
+ }
+ return _IDENT
+}
+
+// isIdent reports whether c is an identifier rune.
+// We treat nearly all runes as identifier runes.
+func isIdent(c int) bool {
+ return c != 0 && !unicode.IsSpace(rune(c))
+}
+
+// Comment assignment.
+// We build two lists of all subexpressions, preorder and postorder.
+// The preorder list is ordered by start location, with outer expressions first.
+// The postorder list is ordered by end location, with outer expressions last.
+// We use the preorder list to assign each whole-line comment to the syntax
+// immediately following it, and we use the postorder list to assign each
+// end-of-line comment to the syntax immediately preceding it.
+
+// order walks the expression adding it and its subexpressions to the
+// preorder and postorder lists.
+func (in *input) order(x Expr) {
+ if x != nil {
+ in.pre = append(in.pre, x)
+ }
+ switch x := x.(type) {
+ default:
+ panic(fmt.Errorf("order: unexpected type %T", x))
+ case nil:
+ // nothing
+ case *LParen, *RParen:
+ // nothing
+ case *CommentBlock:
+ // nothing
+ case *Line:
+ // nothing
+ case *FileSyntax:
+ for _, stmt := range x.Stmt {
+ in.order(stmt)
+ }
+ case *LineBlock:
+ in.order(&x.LParen)
+ for _, l := range x.Line {
+ in.order(l)
+ }
+ in.order(&x.RParen)
+ }
+ if x != nil {
+ in.post = append(in.post, x)
+ }
+}
+
+// assignComments attaches comments to nearby syntax.
+func (in *input) assignComments() {
+ const debug = false
+
+ // Generate preorder and postorder lists.
+ in.order(in.file)
+
+ // Split into whole-line comments and suffix comments.
+ var line, suffix []Comment
+ for _, com := range in.comments {
+ if com.Suffix {
+ suffix = append(suffix, com)
+ } else {
+ line = append(line, com)
+ }
+ }
+
+ if debug {
+ for _, c := range line {
+ fmt.Fprintf(os.Stderr, "LINE %q :%d:%d #%d\n", c.Token, c.Start.Line, c.Start.LineRune, c.Start.Byte)
+ }
+ }
+
+ // Assign line comments to syntax immediately following.
+ for _, x := range in.pre {
+ start, _ := x.Span()
+ if debug {
+ fmt.Printf("pre %T :%d:%d #%d\n", x, start.Line, start.LineRune, start.Byte)
+ }
+ xcom := x.Comment()
+ for len(line) > 0 && start.Byte >= line[0].Start.Byte {
+ if debug {
+ fmt.Fprintf(os.Stderr, "ASSIGN LINE %q #%d\n", line[0].Token, line[0].Start.Byte)
+ }
+ xcom.Before = append(xcom.Before, line[0])
+ line = line[1:]
+ }
+ }
+
+ // Remaining line comments go at end of file.
+ in.file.After = append(in.file.After, line...)
+
+ if debug {
+ for _, c := range suffix {
+ fmt.Fprintf(os.Stderr, "SUFFIX %q :%d:%d #%d\n", c.Token, c.Start.Line, c.Start.LineRune, c.Start.Byte)
+ }
+ }
+
+ // Assign suffix comments to syntax immediately before.
+ for i := len(in.post) - 1; i >= 0; i-- {
+ x := in.post[i]
+
+ start, end := x.Span()
+ if debug {
+ fmt.Printf("post %T :%d:%d #%d :%d:%d #%d\n", x, start.Line, start.LineRune, start.Byte, end.Line, end.LineRune, end.Byte)
+ }
+
+ // Do not assign suffix comments to end of line block or whole file.
+ // Instead assign them to the last element inside.
+ switch x.(type) {
+ case *FileSyntax:
+ continue
+ }
+
+ // Do not assign suffix comments to something that starts
+ // on an earlier line, so that in
+ //
+ // x ( y
+ // z ) // comment
+ //
+ // we assign the comment to z and not to x ( ... ).
+ if start.Line != end.Line {
+ continue
+ }
+ xcom := x.Comment()
+ for len(suffix) > 0 && end.Byte <= suffix[len(suffix)-1].Start.Byte {
+ if debug {
+ fmt.Fprintf(os.Stderr, "ASSIGN SUFFIX %q #%d\n", suffix[len(suffix)-1].Token, suffix[len(suffix)-1].Start.Byte)
+ }
+ xcom.Suffix = append(xcom.Suffix, suffix[len(suffix)-1])
+ suffix = suffix[:len(suffix)-1]
+ }
+ }
+
+ // We assigned suffix comments in reverse.
+ // If multiple suffix comments were appended to the same
+ // expression node, they are now in reverse. Fix that.
+ for _, x := range in.post {
+ reverseComments(x.Comment().Suffix)
+ }
+
+ // Remaining suffix comments go at beginning of file.
+ in.file.Before = append(in.file.Before, suffix...)
+}
+
+// reverseComments reverses the []Comment list.
+func reverseComments(list []Comment) {
+ for i, j := 0, len(list)-1; i < j; i, j = i+1, j-1 {
+ list[i], list[j] = list[j], list[i]
+ }
+}
+
+func (in *input) parseFile() {
+ in.file = new(FileSyntax)
+ var sym symType
+ var cb *CommentBlock
+ for {
+ tok := in.lex(&sym)
+ switch tok {
+ case '\n':
+ if cb != nil {
+ in.file.Stmt = append(in.file.Stmt, cb)
+ cb = nil
+ }
+ case _COMMENT:
+ if cb == nil {
+ cb = &CommentBlock{Start: sym.pos}
+ }
+ com := cb.Comment()
+ com.Before = append(com.Before, Comment{Start: sym.pos, Token: sym.text})
+ case _EOF:
+ if cb != nil {
+ in.file.Stmt = append(in.file.Stmt, cb)
+ }
+ return
+ default:
+ in.parseStmt(&sym)
+ if cb != nil {
+ in.file.Stmt[len(in.file.Stmt)-1].Comment().Before = cb.Before
+ cb = nil
+ }
+ }
+ }
+}
+
+func (in *input) parseStmt(sym *symType) {
+ start := sym.pos
+ end := sym.endPos
+ token := []string{sym.text}
+ for {
+ tok := in.lex(sym)
+ switch tok {
+ case '\n', _EOF, _EOL:
+ in.file.Stmt = append(in.file.Stmt, &Line{
+ Start: start,
+ Token: token,
+ End: end,
+ })
+ return
+ case '(':
+ in.file.Stmt = append(in.file.Stmt, in.parseLineBlock(start, token, sym))
+ return
+ default:
+ token = append(token, sym.text)
+ end = sym.endPos
+ }
+ }
+}
+
+func (in *input) parseLineBlock(start Position, token []string, sym *symType) *LineBlock {
+ x := &LineBlock{
+ Start: start,
+ Token: token,
+ LParen: LParen{Pos: sym.pos},
+ }
+ var comments []Comment
+ for {
+ tok := in.lex(sym)
+ switch tok {
+ case _EOL:
+ // ignore
+ case '\n':
+ if len(comments) == 0 && len(x.Line) > 0 || len(comments) > 0 && comments[len(comments)-1].Token != "" {
+ comments = append(comments, Comment{})
+ }
+ case _COMMENT:
+ comments = append(comments, Comment{Start: sym.pos, Token: sym.text})
+ case _EOF:
+ in.Error(fmt.Sprintf("syntax error (unterminated block started at %s:%d:%d)", in.filename, x.Start.Line, x.Start.LineRune))
+ case ')':
+ x.RParen.Before = comments
+ x.RParen.Pos = sym.pos
+ tok = in.lex(sym)
+ if tok != '\n' && tok != _EOF && tok != _EOL {
+ in.Error("syntax error (expected newline after closing paren)")
+ }
+ return x
+ default:
+ l := in.parseLine(sym)
+ x.Line = append(x.Line, l)
+ l.Comment().Before = comments
+ comments = nil
+ }
+ }
+}
+
+func (in *input) parseLine(sym *symType) *Line {
+ start := sym.pos
+ end := sym.endPos
+ token := []string{sym.text}
+ for {
+ tok := in.lex(sym)
+ switch tok {
+ case '\n', _EOF, _EOL:
+ return &Line{
+ Start: start,
+ Token: token,
+ End: end,
+ InBlock: true,
+ }
+ default:
+ token = append(token, sym.text)
+ end = sym.endPos
+ }
+ }
+}
+
+const (
+ _EOF = -(1 + iota)
+ _EOL
+ _IDENT
+ _STRING
+ _COMMENT
+)
+
+var (
+ slashSlash = []byte("//")
+ moduleStr = []byte("module")
+)
+
+// ModulePath returns the module path from the gomod file text.
+// If it cannot find a module path, it returns an empty string.
+// It is tolerant of unrelated problems in the go.mod file.
+func ModulePath(mod []byte) string {
+ for len(mod) > 0 {
+ line := mod
+ mod = nil
+ if i := bytes.IndexByte(line, '\n'); i >= 0 {
+ line, mod = line[:i], line[i+1:]
+ }
+ if i := bytes.Index(line, slashSlash); i >= 0 {
+ line = line[:i]
+ }
+ line = bytes.TrimSpace(line)
+ if !bytes.HasPrefix(line, moduleStr) {
+ continue
+ }
+ line = line[len(moduleStr):]
+ n := len(line)
+ line = bytes.TrimSpace(line)
+ if len(line) == n || len(line) == 0 {
+ continue
+ }
+
+ if line[0] == '"' || line[0] == '`' {
+ p, err := strconv.Unquote(string(line))
+ if err != nil {
+ return "" // malformed quoted string or multiline module path
+ }
+ return p
+ }
+
+ return string(line)
+ }
+ return "" // missing module path
+}
diff --git a/libgo/go/cmd/go/internal/modfile/read_test.go b/libgo/go/cmd/go/internal/modfile/read_test.go
new file mode 100644
index 00000000000..8cb1a3908c5
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfile/read_test.go
@@ -0,0 +1,365 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modfile
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "reflect"
+ "strings"
+ "testing"
+)
+
+// exists reports whether the named file exists.
+func exists(name string) bool {
+ _, err := os.Stat(name)
+ return err == nil
+}
+
+// Test that reading and then writing the golden files
+// does not change their output.
+func TestPrintGolden(t *testing.T) {
+ outs, err := filepath.Glob("testdata/*.golden")
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, out := range outs {
+ testPrint(t, out, out)
+ }
+}
+
+// testPrint is a helper for testing the printer.
+// It reads the file named in, reformats it, and compares
+// the result to the file named out.
+func testPrint(t *testing.T, in, out string) {
+ data, err := ioutil.ReadFile(in)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ golden, err := ioutil.ReadFile(out)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ base := "testdata/" + filepath.Base(in)
+ f, err := parse(in, data)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ ndata := Format(f)
+
+ if !bytes.Equal(ndata, golden) {
+ t.Errorf("formatted %s incorrectly: diff shows -golden, +ours", base)
+ tdiff(t, string(golden), string(ndata))
+ return
+ }
+}
+
+func TestParseLax(t *testing.T) {
+ badFile := []byte(`module m
+ surprise attack
+ x y (
+ z
+ )
+ exclude v1.2.3
+ replace <-!!!
+ `)
+ _, err := ParseLax("file", badFile, nil)
+ if err != nil {
+ t.Fatalf("ParseLax did not ignore irrelevant errors: %v", err)
+ }
+}
+
+// Test that when files in the testdata directory are parsed
+// and printed and parsed again, we get the same parse tree
+// both times.
+func TestPrintParse(t *testing.T) {
+ outs, err := filepath.Glob("testdata/*")
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, out := range outs {
+ data, err := ioutil.ReadFile(out)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+
+ base := "testdata/" + filepath.Base(out)
+ f, err := parse(base, data)
+ if err != nil {
+ t.Errorf("parsing original: %v", err)
+ continue
+ }
+
+ ndata := Format(f)
+ f2, err := parse(base, ndata)
+ if err != nil {
+ t.Errorf("parsing reformatted: %v", err)
+ continue
+ }
+
+ eq := eqchecker{file: base}
+ if err := eq.check(f, f2); err != nil {
+ t.Errorf("not equal (parse/Format/parse): %v", err)
+ }
+
+ pf1, err := Parse(base, data, nil)
+ if err != nil {
+ switch base {
+ case "testdata/replace2.in", "testdata/gopkg.in.golden":
+ t.Errorf("should parse %v: %v", base, err)
+ }
+ }
+ if err == nil {
+ pf2, err := Parse(base, ndata, nil)
+ if err != nil {
+ t.Errorf("Parsing reformatted: %v", err)
+ continue
+ }
+ eq := eqchecker{file: base}
+ if err := eq.check(pf1, pf2); err != nil {
+ t.Errorf("not equal (parse/Format/Parse): %v", err)
+ }
+
+ ndata2, err := pf1.Format()
+ if err != nil {
+ t.Errorf("reformat: %v", err)
+ }
+ pf3, err := Parse(base, ndata2, nil)
+ if err != nil {
+ t.Errorf("Parsing reformatted2: %v", err)
+ continue
+ }
+ eq = eqchecker{file: base}
+ if err := eq.check(pf1, pf3); err != nil {
+ t.Errorf("not equal (Parse/Format/Parse): %v", err)
+ }
+ ndata = ndata2
+ }
+
+ if strings.HasSuffix(out, ".in") {
+ golden, err := ioutil.ReadFile(strings.TrimSuffix(out, ".in") + ".golden")
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ if !bytes.Equal(ndata, golden) {
+ t.Errorf("formatted %s incorrectly: diff shows -golden, +ours", base)
+ tdiff(t, string(golden), string(ndata))
+ return
+ }
+ }
+ }
+}
+
+// An eqchecker holds state for checking the equality of two parse trees.
+type eqchecker struct {
+ file string
+ pos Position
+}
+
+// errorf returns an error described by the printf-style format and arguments,
+// inserting the current file position before the error text.
+func (eq *eqchecker) errorf(format string, args ...interface{}) error {
+ return fmt.Errorf("%s:%d: %s", eq.file, eq.pos.Line,
+ fmt.Sprintf(format, args...))
+}
+
+// check checks that v and w represent the same parse tree.
+// If not, it returns an error describing the first difference.
+func (eq *eqchecker) check(v, w interface{}) error {
+ return eq.checkValue(reflect.ValueOf(v), reflect.ValueOf(w))
+}
+
+var (
+ posType = reflect.TypeOf(Position{})
+ commentsType = reflect.TypeOf(Comments{})
+)
+
+// checkValue checks that v and w represent the same parse tree.
+// If not, it returns an error describing the first difference.
+func (eq *eqchecker) checkValue(v, w reflect.Value) error {
+ // inner returns the innermost expression for v.
+ // if v is a non-nil interface value, it returns the concrete
+ // value in the interface.
+ inner := func(v reflect.Value) reflect.Value {
+ for {
+ if v.Kind() == reflect.Interface && !v.IsNil() {
+ v = v.Elem()
+ continue
+ }
+ break
+ }
+ return v
+ }
+
+ v = inner(v)
+ w = inner(w)
+ if v.Kind() == reflect.Invalid && w.Kind() == reflect.Invalid {
+ return nil
+ }
+ if v.Kind() == reflect.Invalid {
+ return eq.errorf("nil interface became %s", w.Type())
+ }
+ if w.Kind() == reflect.Invalid {
+ return eq.errorf("%s became nil interface", v.Type())
+ }
+
+ if v.Type() != w.Type() {
+ return eq.errorf("%s became %s", v.Type(), w.Type())
+ }
+
+ if p, ok := v.Interface().(Expr); ok {
+ eq.pos, _ = p.Span()
+ }
+
+ switch v.Kind() {
+ default:
+ return eq.errorf("unexpected type %s", v.Type())
+
+ case reflect.Bool, reflect.Int, reflect.String:
+ vi := v.Interface()
+ wi := w.Interface()
+ if vi != wi {
+ return eq.errorf("%v became %v", vi, wi)
+ }
+
+ case reflect.Slice:
+ vl := v.Len()
+ wl := w.Len()
+ for i := 0; i < vl || i < wl; i++ {
+ if i >= vl {
+ return eq.errorf("unexpected %s", w.Index(i).Type())
+ }
+ if i >= wl {
+ return eq.errorf("missing %s", v.Index(i).Type())
+ }
+ if err := eq.checkValue(v.Index(i), w.Index(i)); err != nil {
+ return err
+ }
+ }
+
+ case reflect.Struct:
+ // Fields in struct must match.
+ t := v.Type()
+ n := t.NumField()
+ for i := 0; i < n; i++ {
+ tf := t.Field(i)
+ switch {
+ default:
+ if err := eq.checkValue(v.Field(i), w.Field(i)); err != nil {
+ return err
+ }
+
+ case tf.Type == posType: // ignore positions
+ case tf.Type == commentsType: // ignore comment assignment
+ }
+ }
+
+ case reflect.Ptr, reflect.Interface:
+ if v.IsNil() != w.IsNil() {
+ if v.IsNil() {
+ return eq.errorf("unexpected %s", w.Elem().Type())
+ }
+ return eq.errorf("missing %s", v.Elem().Type())
+ }
+ if err := eq.checkValue(v.Elem(), w.Elem()); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// diff returns the output of running diff on b1 and b2.
+func diff(b1, b2 []byte) (data []byte, err error) {
+ f1, err := ioutil.TempFile("", "testdiff")
+ if err != nil {
+ return nil, err
+ }
+ defer os.Remove(f1.Name())
+ defer f1.Close()
+
+ f2, err := ioutil.TempFile("", "testdiff")
+ if err != nil {
+ return nil, err
+ }
+ defer os.Remove(f2.Name())
+ defer f2.Close()
+
+ f1.Write(b1)
+ f2.Write(b2)
+
+ data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
+ if len(data) > 0 {
+ // diff exits with a non-zero status when the files don't match.
+ // Ignore that failure as long as we get output.
+ err = nil
+ }
+ return
+}
+
+// tdiff logs the diff output to t.Error.
+func tdiff(t *testing.T, a, b string) {
+ data, err := diff([]byte(a), []byte(b))
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ t.Error(string(data))
+}
+
+var modulePathTests = []struct {
+ input []byte
+ expected string
+}{
+ {input: []byte("module \"github.com/rsc/vgotest\""), expected: "github.com/rsc/vgotest"},
+ {input: []byte("module github.com/rsc/vgotest"), expected: "github.com/rsc/vgotest"},
+ {input: []byte("module \"github.com/rsc/vgotest\""), expected: "github.com/rsc/vgotest"},
+ {input: []byte("module github.com/rsc/vgotest"), expected: "github.com/rsc/vgotest"},
+ {input: []byte("module `github.com/rsc/vgotest`"), expected: "github.com/rsc/vgotest"},
+ {input: []byte("module \"github.com/rsc/vgotest/v2\""), expected: "github.com/rsc/vgotest/v2"},
+ {input: []byte("module github.com/rsc/vgotest/v2"), expected: "github.com/rsc/vgotest/v2"},
+ {input: []byte("module \"gopkg.in/yaml.v2\""), expected: "gopkg.in/yaml.v2"},
+ {input: []byte("module gopkg.in/yaml.v2"), expected: "gopkg.in/yaml.v2"},
+ {input: []byte("module \"gopkg.in/check.v1\"\n"), expected: "gopkg.in/check.v1"},
+ {input: []byte("module \"gopkg.in/check.v1\n\""), expected: ""},
+ {input: []byte("module gopkg.in/check.v1\n"), expected: "gopkg.in/check.v1"},
+ {input: []byte("module \"gopkg.in/check.v1\"\r\n"), expected: "gopkg.in/check.v1"},
+ {input: []byte("module gopkg.in/check.v1\r\n"), expected: "gopkg.in/check.v1"},
+ {input: []byte("module \"gopkg.in/check.v1\"\n\n"), expected: "gopkg.in/check.v1"},
+ {input: []byte("module gopkg.in/check.v1\n\n"), expected: "gopkg.in/check.v1"},
+ {input: []byte("module \n\"gopkg.in/check.v1\"\n\n"), expected: ""},
+ {input: []byte("module \ngopkg.in/check.v1\n\n"), expected: ""},
+ {input: []byte("module \"gopkg.in/check.v1\"asd"), expected: ""},
+ {input: []byte("module \n\"gopkg.in/check.v1\"\n\n"), expected: ""},
+ {input: []byte("module \ngopkg.in/check.v1\n\n"), expected: ""},
+ {input: []byte("module \"gopkg.in/check.v1\"asd"), expected: ""},
+ {input: []byte("module \nmodule a/b/c "), expected: "a/b/c"},
+ {input: []byte("module \" \""), expected: " "},
+ {input: []byte("module "), expected: ""},
+ {input: []byte("module \" a/b/c \""), expected: " a/b/c "},
+ {input: []byte("module \"github.com/rsc/vgotest1\" // with a comment"), expected: "github.com/rsc/vgotest1"},
+}
+
+func TestModulePath(t *testing.T) {
+ for _, test := range modulePathTests {
+ t.Run(string(test.input), func(t *testing.T) {
+ result := ModulePath(test.input)
+ if result != test.expected {
+ t.Fatalf("ModulePath(%q): %s, want %s", string(test.input), result, test.expected)
+ }
+ })
+ }
+}
diff --git a/libgo/go/cmd/go/internal/modfile/rule.go b/libgo/go/cmd/go/internal/modfile/rule.go
new file mode 100644
index 00000000000..e11f0a6e31e
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfile/rule.go
@@ -0,0 +1,724 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modfile
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "path/filepath"
+ "regexp"
+ "sort"
+ "strconv"
+ "strings"
+ "unicode"
+
+ "cmd/go/internal/module"
+ "cmd/go/internal/semver"
+)
+
+// A File is the parsed, interpreted form of a go.mod file.
+type File struct {
+ Module *Module
+ Go *Go
+ Require []*Require
+ Exclude []*Exclude
+ Replace []*Replace
+
+ Syntax *FileSyntax
+}
+
+// A Module is the module statement.
+type Module struct {
+ Mod module.Version
+ Syntax *Line
+}
+
+// A Go is the go statement.
+type Go struct {
+ Version string // "1.23"
+ Syntax *Line
+}
+
+// A Require is a single require statement.
+type Require struct {
+ Mod module.Version
+ Indirect bool // has "// indirect" comment
+ Syntax *Line
+}
+
+// An Exclude is a single exclude statement.
+type Exclude struct {
+ Mod module.Version
+ Syntax *Line
+}
+
+// A Replace is a single replace statement.
+type Replace struct {
+ Old module.Version
+ New module.Version
+ Syntax *Line
+}
+
+func (f *File) AddModuleStmt(path string) error {
+ if f.Syntax == nil {
+ f.Syntax = new(FileSyntax)
+ }
+ if f.Module == nil {
+ f.Module = &Module{
+ Mod: module.Version{Path: path},
+ Syntax: f.Syntax.addLine(nil, "module", AutoQuote(path)),
+ }
+ } else {
+ f.Module.Mod.Path = path
+ f.Syntax.updateLine(f.Module.Syntax, "module", AutoQuote(path))
+ }
+ return nil
+}
+
+func (f *File) AddComment(text string) {
+ if f.Syntax == nil {
+ f.Syntax = new(FileSyntax)
+ }
+ f.Syntax.Stmt = append(f.Syntax.Stmt, &CommentBlock{
+ Comments: Comments{
+ Before: []Comment{
+ {
+ Token: text,
+ },
+ },
+ },
+ })
+}
+
+type VersionFixer func(path, version string) (string, error)
+
+// Parse parses the data, reported in errors as being from file,
+// into a File struct. It applies fix, if non-nil, to canonicalize all module versions found.
+func Parse(file string, data []byte, fix VersionFixer) (*File, error) {
+ return parseToFile(file, data, fix, true)
+}
+
+// ParseLax is like Parse but ignores unknown statements.
+// It is used when parsing go.mod files other than the main module,
+// under the theory that most statement types we add in the future will
+// only apply in the main module, like exclude and replace,
+// and so we get better gradual deployments if old go commands
+// simply ignore those statements when found in go.mod files
+// in dependencies.
+func ParseLax(file string, data []byte, fix VersionFixer) (*File, error) {
+ return parseToFile(file, data, fix, false)
+}
+
+func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (*File, error) {
+ fs, err := parse(file, data)
+ if err != nil {
+ return nil, err
+ }
+ f := &File{
+ Syntax: fs,
+ }
+
+ var errs bytes.Buffer
+ for _, x := range fs.Stmt {
+ switch x := x.(type) {
+ case *Line:
+ f.add(&errs, x, x.Token[0], x.Token[1:], fix, strict)
+
+ case *LineBlock:
+ if len(x.Token) > 1 {
+ if strict {
+ fmt.Fprintf(&errs, "%s:%d: unknown block type: %s\n", file, x.Start.Line, strings.Join(x.Token, " "))
+ }
+ continue
+ }
+ switch x.Token[0] {
+ default:
+ if strict {
+ fmt.Fprintf(&errs, "%s:%d: unknown block type: %s\n", file, x.Start.Line, strings.Join(x.Token, " "))
+ }
+ continue
+ case "module", "require", "exclude", "replace":
+ for _, l := range x.Line {
+ f.add(&errs, l, x.Token[0], l.Token, fix, strict)
+ }
+ }
+ }
+ }
+
+ if errs.Len() > 0 {
+ return nil, errors.New(strings.TrimRight(errs.String(), "\n"))
+ }
+ return f, nil
+}
+
+var goVersionRE = regexp.MustCompile(`([1-9][0-9]*)\.(0|[1-9][0-9]*)`)
+
+func (f *File) add(errs *bytes.Buffer, line *Line, verb string, args []string, fix VersionFixer, strict bool) {
+ // If strict is false, this module is a dependency.
+ // We ignore all unknown directives as well as main-module-only
+ // directives like replace and exclude. It will work better for
+ // forward compatibility if we can depend on modules that have unknown
+ // statements (presumed relevant only when acting as the main module)
+ // and simply ignore those statements.
+ if !strict {
+ switch verb {
+ case "module", "require", "go":
+ // want these even for dependency go.mods
+ default:
+ return
+ }
+ }
+
+ switch verb {
+ default:
+ fmt.Fprintf(errs, "%s:%d: unknown directive: %s\n", f.Syntax.Name, line.Start.Line, verb)
+
+ case "go":
+ if f.Go != nil {
+ fmt.Fprintf(errs, "%s:%d: repeated go statement\n", f.Syntax.Name, line.Start.Line)
+ return
+ }
+ if len(args) != 1 || !goVersionRE.MatchString(args[0]) {
+ fmt.Fprintf(errs, "%s:%d: usage: go 1.23\n", f.Syntax.Name, line.Start.Line)
+ return
+ }
+ f.Go = &Go{Syntax: line}
+ f.Go.Version = args[0]
+ case "module":
+ if f.Module != nil {
+ fmt.Fprintf(errs, "%s:%d: repeated module statement\n", f.Syntax.Name, line.Start.Line)
+ return
+ }
+ f.Module = &Module{Syntax: line}
+ if len(args) != 1 {
+
+ fmt.Fprintf(errs, "%s:%d: usage: module module/path [version]\n", f.Syntax.Name, line.Start.Line)
+ return
+ }
+ s, err := parseString(&args[0])
+ if err != nil {
+ fmt.Fprintf(errs, "%s:%d: invalid quoted string: %v\n", f.Syntax.Name, line.Start.Line, err)
+ return
+ }
+ f.Module.Mod = module.Version{Path: s}
+ case "require", "exclude":
+ if len(args) != 2 {
+ fmt.Fprintf(errs, "%s:%d: usage: %s module/path v1.2.3\n", f.Syntax.Name, line.Start.Line, verb)
+ return
+ }
+ s, err := parseString(&args[0])
+ if err != nil {
+ fmt.Fprintf(errs, "%s:%d: invalid quoted string: %v\n", f.Syntax.Name, line.Start.Line, err)
+ return
+ }
+ old := args[1]
+ v, err := parseVersion(s, &args[1], fix)
+ if err != nil {
+ fmt.Fprintf(errs, "%s:%d: invalid module version %q: %v\n", f.Syntax.Name, line.Start.Line, old, err)
+ return
+ }
+ pathMajor, err := modulePathMajor(s)
+ if err != nil {
+ fmt.Fprintf(errs, "%s:%d: %v\n", f.Syntax.Name, line.Start.Line, err)
+ return
+ }
+ if !module.MatchPathMajor(v, pathMajor) {
+ if pathMajor == "" {
+ pathMajor = "v0 or v1"
+ }
+ fmt.Fprintf(errs, "%s:%d: invalid module: %s should be %s, not %s (%s)\n", f.Syntax.Name, line.Start.Line, s, pathMajor, semver.Major(v), v)
+ return
+ }
+ if verb == "require" {
+ f.Require = append(f.Require, &Require{
+ Mod: module.Version{Path: s, Version: v},
+ Syntax: line,
+ Indirect: isIndirect(line),
+ })
+ } else {
+ f.Exclude = append(f.Exclude, &Exclude{
+ Mod: module.Version{Path: s, Version: v},
+ Syntax: line,
+ })
+ }
+ case "replace":
+ arrow := 2
+ if len(args) >= 2 && args[1] == "=>" {
+ arrow = 1
+ }
+ if len(args) < arrow+2 || len(args) > arrow+3 || args[arrow] != "=>" {
+ fmt.Fprintf(errs, "%s:%d: usage: %s module/path [v1.2.3] => other/module v1.4\n\t or %s module/path [v1.2.3] => ../local/directory\n", f.Syntax.Name, line.Start.Line, verb, verb)
+ return
+ }
+ s, err := parseString(&args[0])
+ if err != nil {
+ fmt.Fprintf(errs, "%s:%d: invalid quoted string: %v\n", f.Syntax.Name, line.Start.Line, err)
+ return
+ }
+ pathMajor, err := modulePathMajor(s)
+ if err != nil {
+ fmt.Fprintf(errs, "%s:%d: %v\n", f.Syntax.Name, line.Start.Line, err)
+ return
+ }
+ var v string
+ if arrow == 2 {
+ old := args[1]
+ v, err = parseVersion(s, &args[1], fix)
+ if err != nil {
+ fmt.Fprintf(errs, "%s:%d: invalid module version %v: %v\n", f.Syntax.Name, line.Start.Line, old, err)
+ return
+ }
+ if !module.MatchPathMajor(v, pathMajor) {
+ if pathMajor == "" {
+ pathMajor = "v0 or v1"
+ }
+ fmt.Fprintf(errs, "%s:%d: invalid module: %s should be %s, not %s (%s)\n", f.Syntax.Name, line.Start.Line, s, pathMajor, semver.Major(v), v)
+ return
+ }
+ }
+ ns, err := parseString(&args[arrow+1])
+ if err != nil {
+ fmt.Fprintf(errs, "%s:%d: invalid quoted string: %v\n", f.Syntax.Name, line.Start.Line, err)
+ return
+ }
+ nv := ""
+ if len(args) == arrow+2 {
+ if !IsDirectoryPath(ns) {
+ fmt.Fprintf(errs, "%s:%d: replacement module without version must be directory path (rooted or starting with ./ or ../)\n", f.Syntax.Name, line.Start.Line)
+ return
+ }
+ if filepath.Separator == '/' && strings.Contains(ns, `\`) {
+ fmt.Fprintf(errs, "%s:%d: replacement directory appears to be Windows path (on a non-windows system)\n", f.Syntax.Name, line.Start.Line)
+ return
+ }
+ }
+ if len(args) == arrow+3 {
+ old := args[arrow+1]
+ nv, err = parseVersion(ns, &args[arrow+2], fix)
+ if err != nil {
+ fmt.Fprintf(errs, "%s:%d: invalid module version %v: %v\n", f.Syntax.Name, line.Start.Line, old, err)
+ return
+ }
+ if IsDirectoryPath(ns) {
+ fmt.Fprintf(errs, "%s:%d: replacement module directory path %q cannot have version\n", f.Syntax.Name, line.Start.Line, ns)
+ return
+ }
+ }
+ f.Replace = append(f.Replace, &Replace{
+ Old: module.Version{Path: s, Version: v},
+ New: module.Version{Path: ns, Version: nv},
+ Syntax: line,
+ })
+ }
+}
+
+// isIndirect reports whether line has a "// indirect" comment,
+// meaning it is in go.mod only for its effect on indirect dependencies,
+// so that it can be dropped entirely once the effective version of the
+// indirect dependency reaches the given minimum version.
+func isIndirect(line *Line) bool {
+ if len(line.Suffix) == 0 {
+ return false
+ }
+ f := strings.Fields(line.Suffix[0].Token)
+ return (len(f) == 2 && f[1] == "indirect" || len(f) > 2 && f[1] == "indirect;") && f[0] == "//"
+}
+
+// setIndirect sets line to have (or not have) a "// indirect" comment.
+func setIndirect(line *Line, indirect bool) {
+ if isIndirect(line) == indirect {
+ return
+ }
+ if indirect {
+ // Adding comment.
+ if len(line.Suffix) == 0 {
+ // New comment.
+ line.Suffix = []Comment{{Token: "// indirect", Suffix: true}}
+ return
+ }
+ // Insert at beginning of existing comment.
+ com := &line.Suffix[0]
+ space := " "
+ if len(com.Token) > 2 && com.Token[2] == ' ' || com.Token[2] == '\t' {
+ space = ""
+ }
+ com.Token = "// indirect;" + space + com.Token[2:]
+ return
+ }
+
+ // Removing comment.
+ f := strings.Fields(line.Suffix[0].Token)
+ if len(f) == 2 {
+ // Remove whole comment.
+ line.Suffix = nil
+ return
+ }
+
+ // Remove comment prefix.
+ com := &line.Suffix[0]
+ i := strings.Index(com.Token, "indirect;")
+ com.Token = "//" + com.Token[i+len("indirect;"):]
+}
+
+// IsDirectoryPath reports whether the given path should be interpreted
+// as a directory path. Just like on the go command line, relative paths
+// and rooted paths are directory paths; the rest are module paths.
+func IsDirectoryPath(ns string) bool {
+ // Because go.mod files can move from one system to another,
+ // we check all known path syntaxes, both Unix and Windows.
+ return strings.HasPrefix(ns, "./") || strings.HasPrefix(ns, "../") || strings.HasPrefix(ns, "/") ||
+ strings.HasPrefix(ns, `.\`) || strings.HasPrefix(ns, `..\`) || strings.HasPrefix(ns, `\`) ||
+ len(ns) >= 2 && ('A' <= ns[0] && ns[0] <= 'Z' || 'a' <= ns[0] && ns[0] <= 'z') && ns[1] == ':'
+}
+
+// MustQuote reports whether s must be quoted in order to appear as
+// a single token in a go.mod line.
+func MustQuote(s string) bool {
+ for _, r := range s {
+ if !unicode.IsPrint(r) || r == ' ' || r == '"' || r == '\'' || r == '`' {
+ return true
+ }
+ }
+ return s == "" || strings.Contains(s, "//") || strings.Contains(s, "/*")
+}
+
+// AutoQuote returns s or, if quoting is required for s to appear in a go.mod,
+// the quotation of s.
+func AutoQuote(s string) string {
+ if MustQuote(s) {
+ return strconv.Quote(s)
+ }
+ return s
+}
+
+func parseString(s *string) (string, error) {
+ t := *s
+ if strings.HasPrefix(t, `"`) {
+ var err error
+ if t, err = strconv.Unquote(t); err != nil {
+ return "", err
+ }
+ } else if strings.ContainsAny(t, "\"'`") {
+ // Other quotes are reserved both for possible future expansion
+ // and to avoid confusion. For example if someone types 'x'
+ // we want that to be a syntax error and not a literal x in literal quotation marks.
+ return "", fmt.Errorf("unquoted string cannot contain quote")
+ }
+ *s = AutoQuote(t)
+ return t, nil
+}
+
+func parseVersion(path string, s *string, fix VersionFixer) (string, error) {
+ t, err := parseString(s)
+ if err != nil {
+ return "", err
+ }
+ if fix != nil {
+ var err error
+ t, err = fix(path, t)
+ if err != nil {
+ return "", err
+ }
+ }
+ if v := module.CanonicalVersion(t); v != "" {
+ *s = v
+ return *s, nil
+ }
+ return "", fmt.Errorf("version must be of the form v1.2.3")
+}
+
+func modulePathMajor(path string) (string, error) {
+ _, major, ok := module.SplitPathVersion(path)
+ if !ok {
+ return "", fmt.Errorf("invalid module path")
+ }
+ return major, nil
+}
+
+func (f *File) Format() ([]byte, error) {
+ return Format(f.Syntax), nil
+}
+
+// Cleanup cleans up the file f after any edit operations.
+// To avoid quadratic behavior, modifications like DropRequire
+// clear the entry but do not remove it from the slice.
+// Cleanup cleans out all the cleared entries.
+func (f *File) Cleanup() {
+ w := 0
+ for _, r := range f.Require {
+ if r.Mod.Path != "" {
+ f.Require[w] = r
+ w++
+ }
+ }
+ f.Require = f.Require[:w]
+
+ w = 0
+ for _, x := range f.Exclude {
+ if x.Mod.Path != "" {
+ f.Exclude[w] = x
+ w++
+ }
+ }
+ f.Exclude = f.Exclude[:w]
+
+ w = 0
+ for _, r := range f.Replace {
+ if r.Old.Path != "" {
+ f.Replace[w] = r
+ w++
+ }
+ }
+ f.Replace = f.Replace[:w]
+
+ f.Syntax.Cleanup()
+}
+
+func (f *File) AddRequire(path, vers string) error {
+ need := true
+ for _, r := range f.Require {
+ if r.Mod.Path == path {
+ if need {
+ r.Mod.Version = vers
+ f.Syntax.updateLine(r.Syntax, "require", AutoQuote(path), vers)
+ need = false
+ } else {
+ f.Syntax.removeLine(r.Syntax)
+ *r = Require{}
+ }
+ }
+ }
+
+ if need {
+ f.AddNewRequire(path, vers, false)
+ }
+ return nil
+}
+
+func (f *File) AddNewRequire(path, vers string, indirect bool) {
+ line := f.Syntax.addLine(nil, "require", AutoQuote(path), vers)
+ setIndirect(line, indirect)
+ f.Require = append(f.Require, &Require{module.Version{Path: path, Version: vers}, indirect, line})
+}
+
+func (f *File) SetRequire(req []*Require) {
+ need := make(map[string]string)
+ indirect := make(map[string]bool)
+ for _, r := range req {
+ need[r.Mod.Path] = r.Mod.Version
+ indirect[r.Mod.Path] = r.Indirect
+ }
+
+ for _, r := range f.Require {
+ if v, ok := need[r.Mod.Path]; ok {
+ r.Mod.Version = v
+ r.Indirect = indirect[r.Mod.Path]
+ }
+ }
+
+ var newStmts []Expr
+ for _, stmt := range f.Syntax.Stmt {
+ switch stmt := stmt.(type) {
+ case *LineBlock:
+ if len(stmt.Token) > 0 && stmt.Token[0] == "require" {
+ var newLines []*Line
+ for _, line := range stmt.Line {
+ if p, err := parseString(&line.Token[0]); err == nil && need[p] != "" {
+ line.Token[1] = need[p]
+ delete(need, p)
+ setIndirect(line, indirect[p])
+ newLines = append(newLines, line)
+ }
+ }
+ if len(newLines) == 0 {
+ continue // drop stmt
+ }
+ stmt.Line = newLines
+ }
+
+ case *Line:
+ if len(stmt.Token) > 0 && stmt.Token[0] == "require" {
+ if p, err := parseString(&stmt.Token[1]); err == nil && need[p] != "" {
+ stmt.Token[2] = need[p]
+ delete(need, p)
+ setIndirect(stmt, indirect[p])
+ } else {
+ continue // drop stmt
+ }
+ }
+ }
+ newStmts = append(newStmts, stmt)
+ }
+ f.Syntax.Stmt = newStmts
+
+ for path, vers := range need {
+ f.AddNewRequire(path, vers, indirect[path])
+ }
+ f.SortBlocks()
+}
+
+func (f *File) DropRequire(path string) error {
+ for _, r := range f.Require {
+ if r.Mod.Path == path {
+ f.Syntax.removeLine(r.Syntax)
+ *r = Require{}
+ }
+ }
+ return nil
+}
+
+func (f *File) AddExclude(path, vers string) error {
+ var hint *Line
+ for _, x := range f.Exclude {
+ if x.Mod.Path == path && x.Mod.Version == vers {
+ return nil
+ }
+ if x.Mod.Path == path {
+ hint = x.Syntax
+ }
+ }
+
+ f.Exclude = append(f.Exclude, &Exclude{Mod: module.Version{Path: path, Version: vers}, Syntax: f.Syntax.addLine(hint, "exclude", AutoQuote(path), vers)})
+ return nil
+}
+
+func (f *File) DropExclude(path, vers string) error {
+ for _, x := range f.Exclude {
+ if x.Mod.Path == path && x.Mod.Version == vers {
+ f.Syntax.removeLine(x.Syntax)
+ *x = Exclude{}
+ }
+ }
+ return nil
+}
+
+func (f *File) AddReplace(oldPath, oldVers, newPath, newVers string) error {
+ need := true
+ old := module.Version{Path: oldPath, Version: oldVers}
+ new := module.Version{Path: newPath, Version: newVers}
+ tokens := []string{"replace", AutoQuote(oldPath)}
+ if oldVers != "" {
+ tokens = append(tokens, oldVers)
+ }
+ tokens = append(tokens, "=>", AutoQuote(newPath))
+ if newVers != "" {
+ tokens = append(tokens, newVers)
+ }
+
+ var hint *Line
+ for _, r := range f.Replace {
+ if r.Old.Path == oldPath && (oldVers == "" || r.Old.Version == oldVers) {
+ if need {
+ // Found replacement for old; update to use new.
+ r.New = new
+ f.Syntax.updateLine(r.Syntax, tokens...)
+ need = false
+ continue
+ }
+ // Already added; delete other replacements for same.
+ f.Syntax.removeLine(r.Syntax)
+ *r = Replace{}
+ }
+ if r.Old.Path == oldPath {
+ hint = r.Syntax
+ }
+ }
+ if need {
+ f.Replace = append(f.Replace, &Replace{Old: old, New: new, Syntax: f.Syntax.addLine(hint, tokens...)})
+ }
+ return nil
+}
+
+func (f *File) DropReplace(oldPath, oldVers string) error {
+ for _, r := range f.Replace {
+ if r.Old.Path == oldPath && r.Old.Version == oldVers {
+ f.Syntax.removeLine(r.Syntax)
+ *r = Replace{}
+ }
+ }
+ return nil
+}
+
+func (f *File) SortBlocks() {
+ f.removeDups() // otherwise sorting is unsafe
+
+ for _, stmt := range f.Syntax.Stmt {
+ block, ok := stmt.(*LineBlock)
+ if !ok {
+ continue
+ }
+ sort.Slice(block.Line, func(i, j int) bool {
+ li := block.Line[i]
+ lj := block.Line[j]
+ for k := 0; k < len(li.Token) && k < len(lj.Token); k++ {
+ if li.Token[k] != lj.Token[k] {
+ return li.Token[k] < lj.Token[k]
+ }
+ }
+ return len(li.Token) < len(lj.Token)
+ })
+ }
+}
+
+func (f *File) removeDups() {
+ have := make(map[module.Version]bool)
+ kill := make(map[*Line]bool)
+ for _, x := range f.Exclude {
+ if have[x.Mod] {
+ kill[x.Syntax] = true
+ continue
+ }
+ have[x.Mod] = true
+ }
+ var excl []*Exclude
+ for _, x := range f.Exclude {
+ if !kill[x.Syntax] {
+ excl = append(excl, x)
+ }
+ }
+ f.Exclude = excl
+
+ have = make(map[module.Version]bool)
+ // Later replacements take priority over earlier ones.
+ for i := len(f.Replace) - 1; i >= 0; i-- {
+ x := f.Replace[i]
+ if have[x.Old] {
+ kill[x.Syntax] = true
+ continue
+ }
+ have[x.Old] = true
+ }
+ var repl []*Replace
+ for _, x := range f.Replace {
+ if !kill[x.Syntax] {
+ repl = append(repl, x)
+ }
+ }
+ f.Replace = repl
+
+ var stmts []Expr
+ for _, stmt := range f.Syntax.Stmt {
+ switch stmt := stmt.(type) {
+ case *Line:
+ if kill[stmt] {
+ continue
+ }
+ case *LineBlock:
+ var lines []*Line
+ for _, line := range stmt.Line {
+ if !kill[line] {
+ lines = append(lines, line)
+ }
+ }
+ stmt.Line = lines
+ if len(lines) == 0 {
+ continue
+ }
+ }
+ stmts = append(stmts, stmt)
+ }
+ f.Syntax.Stmt = stmts
+}
diff --git a/libgo/go/cmd/go/internal/modfile/rule_test.go b/libgo/go/cmd/go/internal/modfile/rule_test.go
new file mode 100644
index 00000000000..b88ad629168
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfile/rule_test.go
@@ -0,0 +1,90 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modfile
+
+import (
+ "bytes"
+ "fmt"
+ "testing"
+)
+
+var addRequireTests = []struct {
+ in string
+ path string
+ vers string
+ out string
+}{
+ {
+ `
+ module m
+ require x.y/z v1.2.3
+ `,
+ "x.y/z", "v1.5.6",
+ `
+ module m
+ require x.y/z v1.5.6
+ `,
+ },
+ {
+ `
+ module m
+ require x.y/z v1.2.3
+ `,
+ "x.y/w", "v1.5.6",
+ `
+ module m
+ require (
+ x.y/z v1.2.3
+ x.y/w v1.5.6
+ )
+ `,
+ },
+ {
+ `
+ module m
+ require x.y/z v1.2.3
+ require x.y/q/v2 v2.3.4
+ `,
+ "x.y/w", "v1.5.6",
+ `
+ module m
+ require x.y/z v1.2.3
+ require (
+ x.y/q/v2 v2.3.4
+ x.y/w v1.5.6
+ )
+ `,
+ },
+}
+
+func TestAddRequire(t *testing.T) {
+ for i, tt := range addRequireTests {
+ t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
+ f, err := Parse("in", []byte(tt.in), nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ g, err := Parse("out", []byte(tt.out), nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ golden, err := g.Format()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if err := f.AddRequire(tt.path, tt.vers); err != nil {
+ t.Fatal(err)
+ }
+ out, err := f.Format()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(out, golden) {
+ t.Errorf("have:\n%s\nwant:\n%s", out, golden)
+ }
+ })
+ }
+}
diff --git a/libgo/go/cmd/go/internal/modfile/testdata/block.golden b/libgo/go/cmd/go/internal/modfile/testdata/block.golden
new file mode 100644
index 00000000000..4aa2d634fc9
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfile/testdata/block.golden
@@ -0,0 +1,29 @@
+// comment
+x "y" z
+
+// block
+block ( // block-eol
+ // x-before-line
+
+ "x" ( y // x-eol
+ "x1"
+ "x2"
+ // line
+ "x3"
+ "x4"
+
+ "x5"
+
+ // y-line
+ "y" // y-eol
+
+ "z" // z-eol
+) // block-eol2
+
+block2 (
+ x
+ y
+ z
+)
+
+// eof
diff --git a/libgo/go/cmd/go/internal/modfile/testdata/block.in b/libgo/go/cmd/go/internal/modfile/testdata/block.in
new file mode 100644
index 00000000000..1dfae65f5c0
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfile/testdata/block.in
@@ -0,0 +1,29 @@
+// comment
+x "y" z
+
+// block
+block ( // block-eol
+ // x-before-line
+
+ "x" ( y // x-eol
+ "x1"
+ "x2"
+ // line
+ "x3"
+ "x4"
+
+ "x5"
+
+ // y-line
+ "y" // y-eol
+
+ "z" // z-eol
+) // block-eol2
+
+
+block2 (x
+ y
+ z
+)
+
+// eof
diff --git a/libgo/go/cmd/go/internal/modfile/testdata/comment.golden b/libgo/go/cmd/go/internal/modfile/testdata/comment.golden
new file mode 100644
index 00000000000..75f3b84478c
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfile/testdata/comment.golden
@@ -0,0 +1,10 @@
+// comment
+module "x" // eol
+
+// mid comment
+
+// comment 2
+// comment 2 line 2
+module "y" // eoy
+
+// comment 3
diff --git a/libgo/go/cmd/go/internal/modfile/testdata/comment.in b/libgo/go/cmd/go/internal/modfile/testdata/comment.in
new file mode 100644
index 00000000000..bfc2492b264
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfile/testdata/comment.in
@@ -0,0 +1,8 @@
+// comment
+module "x" // eol
+// mid comment
+
+// comment 2
+// comment 2 line 2
+module "y" // eoy
+// comment 3
diff --git a/libgo/go/cmd/go/internal/modfile/testdata/empty.golden b/libgo/go/cmd/go/internal/modfile/testdata/empty.golden
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfile/testdata/empty.golden
diff --git a/libgo/go/cmd/go/internal/modfile/testdata/empty.in b/libgo/go/cmd/go/internal/modfile/testdata/empty.in
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfile/testdata/empty.in
diff --git a/libgo/go/cmd/go/internal/modfile/testdata/gopkg.in.golden b/libgo/go/cmd/go/internal/modfile/testdata/gopkg.in.golden
new file mode 100644
index 00000000000..41669b3a737
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfile/testdata/gopkg.in.golden
@@ -0,0 +1,6 @@
+module x
+
+require (
+ gopkg.in/mgo.v2 v2.0.0-20160818020120-3f83fa500528
+ gopkg.in/yaml.v2 v2.2.1
+)
diff --git a/libgo/go/cmd/go/internal/modfile/testdata/module.golden b/libgo/go/cmd/go/internal/modfile/testdata/module.golden
new file mode 100644
index 00000000000..78ba94398c3
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfile/testdata/module.golden
@@ -0,0 +1 @@
+module abc
diff --git a/libgo/go/cmd/go/internal/modfile/testdata/module.in b/libgo/go/cmd/go/internal/modfile/testdata/module.in
new file mode 100644
index 00000000000..08f383623f9
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfile/testdata/module.in
@@ -0,0 +1 @@
+module "abc"
diff --git a/libgo/go/cmd/go/internal/modfile/testdata/replace.golden b/libgo/go/cmd/go/internal/modfile/testdata/replace.golden
new file mode 100644
index 00000000000..5d6abcfcdad
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfile/testdata/replace.golden
@@ -0,0 +1,5 @@
+module abc
+
+replace xyz v1.2.3 => /tmp/z
+
+replace xyz v1.3.4 => my/xyz v1.3.4-me
diff --git a/libgo/go/cmd/go/internal/modfile/testdata/replace.in b/libgo/go/cmd/go/internal/modfile/testdata/replace.in
new file mode 100644
index 00000000000..685249946a2
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfile/testdata/replace.in
@@ -0,0 +1,5 @@
+module "abc"
+
+replace "xyz" v1.2.3 => "/tmp/z"
+
+replace "xyz" v1.3.4 => "my/xyz" v1.3.4-me
diff --git a/libgo/go/cmd/go/internal/modfile/testdata/replace2.golden b/libgo/go/cmd/go/internal/modfile/testdata/replace2.golden
new file mode 100644
index 00000000000..e1d9c728df4
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfile/testdata/replace2.golden
@@ -0,0 +1,10 @@
+module abc
+
+replace (
+ xyz v1.2.3 => /tmp/z
+ xyz v1.3.4 => my/xyz v1.3.4-me
+ xyz v1.4.5 => "/tmp/my dir"
+ xyz v1.5.6 => my/xyz v1.5.6
+
+ xyz => my/other/xyz v1.5.4
+)
diff --git a/libgo/go/cmd/go/internal/modfile/testdata/replace2.in b/libgo/go/cmd/go/internal/modfile/testdata/replace2.in
new file mode 100644
index 00000000000..786469866f9
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfile/testdata/replace2.in
@@ -0,0 +1,10 @@
+module "abc"
+
+replace (
+ "xyz" v1.2.3 => "/tmp/z"
+ "xyz" v1.3.4 => "my/xyz" "v1.3.4-me"
+ xyz "v1.4.5" => "/tmp/my dir"
+ xyz v1.5.6 => my/xyz v1.5.6
+
+ xyz => my/other/xyz v1.5.4
+)
diff --git a/libgo/go/cmd/go/internal/modfile/testdata/rule1.golden b/libgo/go/cmd/go/internal/modfile/testdata/rule1.golden
new file mode 100644
index 00000000000..8a5c7258948
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modfile/testdata/rule1.golden
@@ -0,0 +1,7 @@
+module "x"
+
+module "y"
+
+require "x"
+
+require x
diff --git a/libgo/go/cmd/go/internal/modget/get.go b/libgo/go/cmd/go/internal/modget/get.go
new file mode 100644
index 00000000000..90a5bd81302
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modget/get.go
@@ -0,0 +1,656 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package modget implements the module-aware ``go get'' command.
+package modget
+
+import (
+ "cmd/go/internal/base"
+ "cmd/go/internal/cfg"
+ "cmd/go/internal/get"
+ "cmd/go/internal/load"
+ "cmd/go/internal/modfetch"
+ "cmd/go/internal/modload"
+ "cmd/go/internal/module"
+ "cmd/go/internal/mvs"
+ "cmd/go/internal/par"
+ "cmd/go/internal/search"
+ "cmd/go/internal/semver"
+ "cmd/go/internal/str"
+ "cmd/go/internal/work"
+ "fmt"
+ "os"
+ pathpkg "path"
+ "path/filepath"
+ "strings"
+)
+
+var CmdGet = &base.Command{
+ // Note: -d -m -u are listed explicitly because they are the most common get flags.
+ // Do not send CLs removing them because they're covered by [get flags].
+ UsageLine: "go get [-d] [-m] [-u] [-v] [-insecure] [build flags] [packages]",
+ Short: "add dependencies to current module and install them",
+ Long: `
+Get resolves and adds dependencies to the current development module
+and then builds and installs them.
+
+The first step is to resolve which dependencies to add.
+
+For each named package or package pattern, get must decide which version of
+the corresponding module to use. By default, get chooses the latest tagged
+release version, such as v0.4.5 or v1.2.3. If there are no tagged release
+versions, get chooses the latest tagged prerelease version, such as
+v0.0.1-pre1. If there are no tagged versions at all, get chooses the latest
+known commit.
+
+This default version selection can be overridden by adding an @version
+suffix to the package argument, as in 'go get golang.org/x/text@v0.3.0'.
+For modules stored in source control repositories, the version suffix can
+also be a commit hash, branch identifier, or other syntax known to the
+source control system, as in 'go get golang.org/x/text@master'.
+The version suffix @latest explicitly requests the default behavior
+described above.
+
+If a module under consideration is already a dependency of the current
+development module, then get will update the required version.
+Specifying a version earlier than the current required version is valid and
+downgrades the dependency. The version suffix @none indicates that the
+dependency should be removed entirely.
+
+Although get defaults to using the latest version of the module containing
+a named package, it does not use the latest version of that module's
+dependencies. Instead it prefers to use the specific dependency versions
+requested by that module. For example, if the latest A requires module
+B v1.2.3, while B v1.2.4 and v1.3.1 are also available, then 'go get A'
+will use the latest A but then use B v1.2.3, as requested by A. (If there
+are competing requirements for a particular module, then 'go get' resolves
+those requirements by taking the maximum requested version.)
+
+The -u flag instructs get to update dependencies to use newer minor or
+patch releases when available. Continuing the previous example,
+'go get -u A' will use the latest A with B v1.3.1 (not B v1.2.3).
+
+The -u=patch flag (not -u patch) instructs get to update dependencies
+to use newer patch releases when available. Continuing the previous example,
+'go get -u=patch A' will use the latest A with B v1.2.4 (not B v1.2.3).
+
+In general, adding a new dependency may require upgrading
+existing dependencies to keep a working build, and 'go get' does
+this automatically. Similarly, downgrading one dependency may
+require downgrading other dependenceis, and 'go get' does
+this automatically as well.
+
+The -m flag instructs get to stop here, after resolving, upgrading,
+and downgrading modules and updating go.mod. When using -m,
+each specified package path must be a module path as well,
+not the import path of a package below the module root.
+
+The -insecure flag permits fetching from repositories and resolving
+custom domains using insecure schemes such as HTTP. Use with caution.
+
+The second step is to download (if needed), build, and install
+the named packages.
+
+If an argument names a module but not a package (because there is no
+Go source code in the module's root directory), then the install step
+is skipped for that argument, instead of causing a build failure.
+For example 'go get golang.org/x/perf' succeeds even though there
+is no code corresponding to that import path.
+
+Note that package patterns are allowed and are expanded after resolving
+the module versions. For example, 'go get golang.org/x/perf/cmd/...'
+adds the latest golang.org/x/perf and then installs the commands in that
+latest version.
+
+The -d flag instructs get to download the source code needed to build
+the named packages, including downloading necessary dependencies,
+but not to build and install them.
+
+With no package arguments, 'go get' applies to the main module,
+and to the Go package in the current directory, if any. In particular,
+'go get -u' and 'go get -u=patch' update all the dependencies of the
+main module. With no package arguments and also without -u,
+'go get' is not much more than 'go install', and 'go get -d' not much
+more than 'go list'.
+
+For more about modules, see 'go help modules'.
+
+For more about specifying packages, see 'go help packages'.
+
+This text describes the behavior of get using modules to manage source
+code and dependencies. If instead the go command is running in GOPATH
+mode, the details of get's flags and effects change, as does 'go help get'.
+See 'go help modules' and 'go help gopath-get'.
+
+See also: go build, go install, go clean, go mod.
+ `,
+}
+
+// Note that this help text is a stopgap to make the module-aware get help text
+// available even in non-module settings. It should be deleted when the old get
+// is deleted. It should NOT be considered to set a precedent of having hierarchical
+// help names with dashes.
+var HelpModuleGet = &base.Command{
+ UsageLine: "module-get",
+ Short: "module-aware go get",
+ Long: `
+The 'go get' command changes behavior depending on whether the
+go command is running in module-aware mode or legacy GOPATH mode.
+This help text, accessible as 'go help module-get' even in legacy GOPATH mode,
+describes 'go get' as it operates in module-aware mode.
+
+Usage: ` + CmdGet.UsageLine + `
+` + CmdGet.Long,
+}
+
+var (
+ getD = CmdGet.Flag.Bool("d", false, "")
+ getF = CmdGet.Flag.Bool("f", false, "")
+ getFix = CmdGet.Flag.Bool("fix", false, "")
+ getM = CmdGet.Flag.Bool("m", false, "")
+ getT = CmdGet.Flag.Bool("t", false, "")
+ getU upgradeFlag
+ // -insecure is get.Insecure
+ // -v is cfg.BuildV
+)
+
+// upgradeFlag is a custom flag.Value for -u.
+type upgradeFlag string
+
+func (*upgradeFlag) IsBoolFlag() bool { return true } // allow -u
+
+func (v *upgradeFlag) Set(s string) error {
+ if s == "false" {
+ s = ""
+ }
+ *v = upgradeFlag(s)
+ return nil
+}
+
+func (v *upgradeFlag) String() string { return "" }
+
+func init() {
+ work.AddBuildFlags(CmdGet)
+ CmdGet.Run = runGet // break init loop
+ CmdGet.Flag.BoolVar(&get.Insecure, "insecure", get.Insecure, "")
+ CmdGet.Flag.Var(&getU, "u", "")
+}
+
+// A task holds the state for processing a single get argument (path@vers).
+type task struct {
+ arg string // original argument
+ index int
+ path string // package path part of arg
+ forceModulePath bool // path must be interpreted as a module path
+ vers string // version part of arg
+ m module.Version // module version indicated by argument
+ req []module.Version // m's requirement list (not upgraded)
+}
+
+func runGet(cmd *base.Command, args []string) {
+ // -mod=readonly has no effect on "go get".
+ if cfg.BuildMod == "readonly" {
+ cfg.BuildMod = ""
+ }
+
+ switch getU {
+ case "", "patch", "true":
+ // ok
+ default:
+ base.Fatalf("go get: unknown upgrade flag -u=%s", getU)
+ }
+ if *getF {
+ fmt.Fprintf(os.Stderr, "go get: -f flag is a no-op when using modules\n")
+ }
+ if *getFix {
+ fmt.Fprintf(os.Stderr, "go get: -fix flag is a no-op when using modules\n")
+ }
+ if *getT {
+ fmt.Fprintf(os.Stderr, "go get: -t flag is a no-op when using modules\n")
+ }
+
+ if cfg.BuildMod == "vendor" {
+ base.Fatalf("go get: disabled by -mod=%s", cfg.BuildMod)
+ }
+
+ modload.LoadBuildList()
+
+ // Do not allow any updating of go.mod until we've applied
+ // all the requested changes and checked that the result matches
+ // what was requested.
+ modload.DisallowWriteGoMod()
+
+ // Build task and install lists.
+ // The command-line arguments are of the form path@version
+ // or simply path, with implicit @latest. path@none is "downgrade away".
+ // At the end of the loop, we've resolved the list of arguments into
+ // a list of tasks (a path@vers that needs further processing)
+ // and a list of install targets (for the "go install" at the end).
+ var tasks []*task
+ var install []string
+ for _, arg := range search.CleanPatterns(args) {
+ // Argument is module query path@vers, or else path with implicit @latest.
+ path := arg
+ vers := ""
+ if i := strings.Index(arg, "@"); i >= 0 {
+ path, vers = arg[:i], arg[i+1:]
+ }
+ if strings.Contains(vers, "@") || arg != path && vers == "" {
+ base.Errorf("go get %s: invalid module version syntax", arg)
+ continue
+ }
+ if vers != "none" {
+ install = append(install, path)
+ }
+
+ // Deciding which module to upgrade/downgrade for a particular argument is difficult.
+ // Patterns only make it more difficult.
+ // We impose restrictions to avoid needing to interlace pattern expansion,
+ // like in in modload.ImportPaths.
+ // Specifically, these patterns are supported:
+ //
+ // - Relative paths like ../../foo or ../../foo... are restricted to matching directories
+ // in the current module and therefore map to the current module.
+ // It's possible that the pattern matches no packages, but we will still treat it
+ // as mapping to the current module.
+ // TODO: In followup, could just expand the full list and remove the discrepancy.
+ // - The pattern "all" has its usual package meaning and maps to the list of modules
+ // from which the matched packages are drawn. This is potentially a subset of the
+ // module pattern "all". If module A requires B requires C but A does not import
+ // the parts of B that import C, the packages matched by "all" are only from A and B,
+ // so only A and B end up on the tasks list.
+ // TODO: Even in -m mode?
+ // - The patterns "std" and "cmd" expand to packages in the standard library,
+ // which aren't upgradable, so we skip over those.
+ // In -m mode they expand to non-module-paths, so they are disallowed.
+ // - Import path patterns like foo/bar... are matched against the module list,
+ // assuming any package match would imply a module pattern match.
+ // TODO: What about -m mode?
+ // - Import paths without patterns are left as is, for resolution by getQuery (eventually modload.Import).
+ //
+ if search.IsRelativePath(path) {
+ // Check that this relative pattern only matches directories in the current module,
+ // and then record the current module as the target.
+ dir := path
+ if i := strings.Index(path, "..."); i >= 0 {
+ dir, _ = pathpkg.Split(path[:i])
+ }
+ abs, err := filepath.Abs(dir)
+ if err != nil {
+ base.Errorf("go get %s: %v", arg, err)
+ continue
+ }
+ if !str.HasFilePathPrefix(abs, modload.ModRoot) {
+ base.Errorf("go get %s: directory %s is outside module root %s", arg, abs, modload.ModRoot)
+ continue
+ }
+ // TODO: Check if abs is inside a nested module.
+ tasks = append(tasks, &task{arg: arg, path: modload.Target.Path, vers: ""})
+ continue
+ }
+ if path == "all" {
+ // TODO: If *getM, should this be the module pattern "all"?
+
+ // This is the package pattern "all" not the module pattern "all":
+ // enumerate all the modules actually needed by builds of the packages
+ // in the main module, not incidental modules that happen to be
+ // in the package graph (and therefore build list).
+ // Note that LoadALL may add new modules to the build list to
+ // satisfy new imports, but vers == "latest" implicitly anyway,
+ // so we'll assume that's OK.
+ seen := make(map[module.Version]bool)
+ pkgs := modload.LoadALL()
+ for _, pkg := range pkgs {
+ m := modload.PackageModule(pkg)
+ if m.Path != "" && !seen[m] {
+ seen[m] = true
+ tasks = append(tasks, &task{arg: arg, path: m.Path, vers: "latest", forceModulePath: true})
+ }
+ }
+ continue
+ }
+ if search.IsMetaPackage(path) {
+ // Already handled "all", so this must be "std" or "cmd",
+ // which are entirely in the standard library.
+ if path != arg {
+ base.Errorf("go get %s: cannot use pattern %q with explicit version", arg, arg)
+ }
+ if *getM {
+ base.Errorf("go get %s: cannot use pattern %q with -m", arg, arg)
+ continue
+ }
+ continue
+ }
+ if strings.Contains(path, "...") {
+ // Apply to modules in build list matched by pattern (golang.org/x/...), if any.
+ match := search.MatchPattern(path)
+ matched := false
+ for _, m := range modload.BuildList() {
+ if match(m.Path) || str.HasPathPrefix(path, m.Path) {
+ tasks = append(tasks, &task{arg: arg, path: m.Path, vers: vers, forceModulePath: true})
+ matched = true
+ }
+ }
+ // If matched, we're done.
+ // Otherwise assume pattern is inside a single module
+ // (golang.org/x/text/unicode/...) and leave for usual lookup.
+ // Unless we're using -m.
+ if matched {
+ continue
+ }
+ if *getM {
+ base.Errorf("go get %s: pattern matches no modules in build list", arg)
+ continue
+ }
+ }
+ tasks = append(tasks, &task{arg: arg, path: path, vers: vers})
+ }
+ base.ExitIfErrors()
+
+ // Now we've reduced the upgrade/downgrade work to a list of path@vers pairs (tasks).
+ // Resolve each one in parallel.
+ reqs := modload.Reqs()
+ var lookup par.Work
+ for _, t := range tasks {
+ lookup.Add(t)
+ }
+ lookup.Do(10, func(item interface{}) {
+ t := item.(*task)
+ if t.vers == "none" {
+ // Wait for downgrade step.
+ t.m = module.Version{Path: t.path, Version: "none"}
+ return
+ }
+ m, err := getQuery(t.path, t.vers, t.forceModulePath)
+ if err != nil {
+ base.Errorf("go get %v: %v", t.arg, err)
+ return
+ }
+ t.m = m
+ })
+ base.ExitIfErrors()
+
+ // Now we know the specific version of each path@vers.
+ // The final build list will be the union of three build lists:
+ // 1. the original build list
+ // 2. the modules named on the command line (other than @none)
+ // 3. the upgraded requirements of those modules (if upgrading)
+ // Start building those lists.
+ // This loop collects (2).
+ // Also, because the list of paths might have named multiple packages in a single module
+ // (or even the same package multiple times), now that we know the module for each
+ // package, this loop deduplicates multiple references to a given module.
+ // (If a module is mentioned multiple times, the listed target version must be the same each time.)
+ var named []module.Version
+ byPath := make(map[string]*task)
+ for _, t := range tasks {
+ prev, ok := byPath[t.m.Path]
+ if prev != nil && prev.m != t.m {
+ base.Errorf("go get: conflicting versions for module %s: %s and %s", t.m.Path, prev.m.Version, t.m.Version)
+ byPath[t.m.Path] = nil // sentinel to stop errors
+ continue
+ }
+ if ok {
+ continue // already added
+ }
+ byPath[t.m.Path] = t
+ if t.m.Version != "none" {
+ named = append(named, t.m)
+ }
+ }
+ base.ExitIfErrors()
+
+ // If the modules named on the command line have any dependencies
+ // and we're supposed to upgrade dependencies,
+ // chase down the full list of upgraded dependencies.
+ // This turns required from a not-yet-upgraded (3) to the final (3).
+ // (See list above.)
+ var required []module.Version
+ if getU != "" {
+ upgraded, err := mvs.UpgradeAll(upgradeTarget, &upgrader{
+ Reqs: modload.Reqs(),
+ targets: named,
+ patch: getU == "patch",
+ tasks: byPath,
+ })
+ if err != nil {
+ base.Fatalf("go get: %v", err)
+ }
+ required = upgraded[1:] // slice off upgradeTarget
+ base.ExitIfErrors()
+ }
+
+ // Put together the final build list as described above (1) (2) (3).
+ // If we're not using -u, then len(required) == 0 and ReloadBuildList
+ // chases down the dependencies of all the named module versions
+ // in one operation.
+ var list []module.Version
+ list = append(list, modload.BuildList()...)
+ list = append(list, named...)
+ list = append(list, required...)
+ modload.SetBuildList(list)
+ modload.ReloadBuildList() // note: does not update go.mod
+ base.ExitIfErrors()
+
+ // Scan for and apply any needed downgrades.
+ var down []module.Version
+ for _, m := range modload.BuildList() {
+ t := byPath[m.Path]
+ if t != nil && semver.Compare(m.Version, t.m.Version) > 0 {
+ down = append(down, module.Version{Path: m.Path, Version: t.m.Version})
+ }
+ }
+ if len(down) > 0 {
+ list, err := mvs.Downgrade(modload.Target, modload.Reqs(), down...)
+ if err != nil {
+ base.Fatalf("go get: %v", err)
+ }
+ modload.SetBuildList(list)
+ modload.ReloadBuildList() // note: does not update go.mod
+ }
+ base.ExitIfErrors()
+
+ // Scan for any upgrades lost by the downgrades.
+ lost := make(map[string]string)
+ for _, m := range modload.BuildList() {
+ t := byPath[m.Path]
+ if t != nil && semver.Compare(m.Version, t.m.Version) != 0 {
+ lost[m.Path] = m.Version
+ }
+ }
+ if len(lost) > 0 {
+ desc := func(m module.Version) string {
+ s := m.Path + "@" + m.Version
+ t := byPath[m.Path]
+ if t != nil && t.arg != s {
+ s += " from " + t.arg
+ }
+ return s
+ }
+ downByPath := make(map[string]module.Version)
+ for _, d := range down {
+ downByPath[d.Path] = d
+ }
+ var buf strings.Builder
+ fmt.Fprintf(&buf, "go get: inconsistent versions:")
+ for _, t := range tasks {
+ if lost[t.m.Path] == "" {
+ continue
+ }
+ // We lost t because its build list requires a newer version of something in down.
+ // Figure out exactly what.
+ // Repeatedly constructing the build list is inefficient
+ // if there are MANY command-line arguments,
+ // but at least all the necessary requirement lists are cached at this point.
+ list, err := mvs.BuildList(t.m, reqs)
+ if err != nil {
+ base.Fatalf("go get: %v", err)
+ }
+
+ fmt.Fprintf(&buf, "\n\t%s", desc(t.m))
+ sep := " requires"
+ for _, m := range list {
+ if down, ok := downByPath[m.Path]; ok && semver.Compare(down.Version, m.Version) < 0 {
+ fmt.Fprintf(&buf, "%s %s@%s (not %s)", sep, m.Path, m.Version, desc(down))
+ sep = ","
+ }
+ }
+ if sep != "," {
+ // We have no idea why this happened.
+ // At least report the problem.
+ fmt.Fprintf(&buf, " ended up at %v unexpectedly (please report at golang.org/issue/new)", lost[t.m.Path])
+ }
+ }
+ base.Fatalf("%v", buf.String())
+ }
+
+ // Everything succeeded. Update go.mod.
+ modload.AllowWriteGoMod()
+ modload.WriteGoMod()
+
+ // If -m was specified, we're done after the module work. No download, no build.
+ if *getM {
+ return
+ }
+
+ if len(install) > 0 {
+ // All requested versions were explicitly @none.
+ // Note that 'go get -u' without any arguments results in len(install) == 1:
+ // search.CleanImportPaths returns "." for empty args.
+ work.BuildInit()
+ pkgs := load.PackagesAndErrors(install)
+ var todo []*load.Package
+ for _, p := range pkgs {
+ // Ignore "no Go source files" errors for 'go get' operations on modules.
+ if p.Error != nil {
+ if len(args) == 0 && getU != "" && strings.HasPrefix(p.Error.Err, "no Go files") {
+ // Upgrading modules: skip the implicitly-requested package at the
+ // current directory, even if it is not tho module root.
+ continue
+ }
+ if strings.Contains(p.Error.Err, "cannot find module providing") && modload.ModuleInfo(p.ImportPath) != nil {
+ // Explicitly-requested module, but it doesn't contain a package at the
+ // module root.
+ continue
+ }
+ }
+ todo = append(todo, p)
+ }
+
+ // If -d was specified, we're done after the download: no build.
+ // (The load.PackagesAndErrors is what did the download
+ // of the named packages and their dependencies.)
+ if len(todo) > 0 && !*getD {
+ work.InstallPackages(install, todo)
+ }
+ }
+}
+
+// getQuery evaluates the given package path, version pair
+// to determine the underlying module version being requested.
+// If forceModulePath is set, getQuery must interpret path
+// as a module path.
+func getQuery(path, vers string, forceModulePath bool) (module.Version, error) {
+ if vers == "" {
+ vers = "latest"
+ }
+
+ // First choice is always to assume path is a module path.
+ // If that works out, we're done.
+ info, err := modload.Query(path, vers, modload.Allowed)
+ if err == nil {
+ return module.Version{Path: path, Version: info.Version}, nil
+ }
+
+ // Even if the query fails, if the path must be a real module, then report the query error.
+ if forceModulePath || *getM {
+ return module.Version{}, err
+ }
+
+ // Otherwise, try a package path.
+ m, _, err := modload.QueryPackage(path, vers, modload.Allowed)
+ return m, err
+}
+
+// An upgrader adapts an underlying mvs.Reqs to apply an
+// upgrade policy to a list of targets and their dependencies.
+// If patch=false, the upgrader implements "get -u".
+// If patch=true, the upgrader implements "get -u=patch".
+type upgrader struct {
+ mvs.Reqs
+ targets []module.Version
+ patch bool
+ tasks map[string]*task
+}
+
+// upgradeTarget is a fake "target" requiring all the modules to be upgraded.
+var upgradeTarget = module.Version{Path: "upgrade target", Version: ""}
+
+// Required returns the requirement list for m.
+// Other than the upgradeTarget, we defer to u.Reqs.
+func (u *upgrader) Required(m module.Version) ([]module.Version, error) {
+ if m == upgradeTarget {
+ return u.targets, nil
+ }
+ return u.Reqs.Required(m)
+}
+
+// Upgrade returns the desired upgrade for m.
+// If m is a tagged version, then Upgrade returns the latest tagged version.
+// If m is a pseudo-version, then Upgrade returns the latest tagged version
+// when that version has a time-stamp newer than m.
+// Otherwise Upgrade returns m (preserving the pseudo-version).
+// This special case prevents accidental downgrades
+// when already using a pseudo-version newer than the latest tagged version.
+func (u *upgrader) Upgrade(m module.Version) (module.Version, error) {
+ // Allow pkg@vers on the command line to override the upgrade choice v.
+ // If t's version is < v, then we're going to downgrade anyway,
+ // and it's cleaner to avoid moving back and forth and picking up
+ // extraneous other newer dependencies.
+ // If t's version is > v, then we're going to upgrade past v anyway,
+ // and again it's cleaner to avoid moving back and forth picking up
+ // extraneous other newer dependencies.
+ if t := u.tasks[m.Path]; t != nil {
+ return t.m, nil
+ }
+
+ // Note that query "latest" is not the same as
+ // using repo.Latest.
+ // The query only falls back to untagged versions
+ // if nothing is tagged. The Latest method
+ // only ever returns untagged versions,
+ // which is not what we want.
+ query := "latest"
+ if u.patch {
+ // For patch upgrade, query "v1.2".
+ query = semver.MajorMinor(m.Version)
+ }
+ info, err := modload.Query(m.Path, query, modload.Allowed)
+ if err != nil {
+ // Report error but return m, to let version selection continue.
+ // (Reporting the error will fail the command at the next base.ExitIfErrors.)
+ // Special case: if the error is "no matching versions" then don't
+ // even report the error. Because Query does not consider pseudo-versions,
+ // it may happen that we have a pseudo-version but during -u=patch
+ // the query v0.0 matches no versions (not even the one we're using).
+ if !strings.Contains(err.Error(), "no matching versions") {
+ base.Errorf("go get: upgrading %s@%s: %v", m.Path, m.Version, err)
+ }
+ return m, nil
+ }
+
+ // If we're on a later prerelease, keep using it,
+ // even though normally an Upgrade will ignore prereleases.
+ if semver.Compare(info.Version, m.Version) < 0 {
+ return m, nil
+ }
+
+ // If we're on a pseudo-version chronologically after the latest tagged version, keep using it.
+ // This avoids some accidental downgrades.
+ if mTime, err := modfetch.PseudoVersionTime(m.Version); err == nil && info.Time.Before(mTime) {
+ return m, nil
+ }
+
+ return module.Version{Path: m.Path, Version: info.Version}, nil
+}
diff --git a/libgo/go/cmd/go/internal/modinfo/info.go b/libgo/go/cmd/go/internal/modinfo/info.go
new file mode 100644
index 00000000000..7341ce44d20
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modinfo/info.go
@@ -0,0 +1,49 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modinfo
+
+import "time"
+
+// Note that these structs are publicly visible (part of go list's API)
+// and the fields are documented in the help text in ../list/list.go
+
+type ModulePublic struct {
+ Path string `json:",omitempty"` // module path
+ Version string `json:",omitempty"` // module version
+ Versions []string `json:",omitempty"` // available module versions
+ Replace *ModulePublic `json:",omitempty"` // replaced by this module
+ Time *time.Time `json:",omitempty"` // time version was created
+ Update *ModulePublic `json:",omitempty"` // available update (with -u)
+ Main bool `json:",omitempty"` // is this the main module?
+ Indirect bool `json:",omitempty"` // module is only indirectly needed by main module
+ Dir string `json:",omitempty"` // directory holding local copy of files, if any
+ GoMod string `json:",omitempty"` // path to go.mod file describing module, if any
+ Error *ModuleError `json:",omitempty"` // error loading module
+ GoVersion string `json:",omitempty"` // go version used in module
+}
+
+type ModuleError struct {
+ Err string // error text
+}
+
+func (m *ModulePublic) String() string {
+ s := m.Path
+ if m.Version != "" {
+ s += " " + m.Version
+ if m.Update != nil {
+ s += " [" + m.Update.Version + "]"
+ }
+ }
+ if m.Replace != nil {
+ s += " => " + m.Replace.Path
+ if m.Replace.Version != "" {
+ s += " " + m.Replace.Version
+ if m.Replace.Update != nil {
+ s += " [" + m.Replace.Update.Version + "]"
+ }
+ }
+ }
+ return s
+}
diff --git a/libgo/go/cmd/go/internal/modload/build.go b/libgo/go/cmd/go/internal/modload/build.go
new file mode 100644
index 00000000000..558401d01f6
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modload/build.go
@@ -0,0 +1,243 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modload
+
+import (
+ "bytes"
+ "cmd/go/internal/base"
+ "cmd/go/internal/cfg"
+ "cmd/go/internal/modfetch"
+ "cmd/go/internal/modinfo"
+ "cmd/go/internal/module"
+ "cmd/go/internal/search"
+ "encoding/hex"
+ "fmt"
+ "internal/goroot"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+var (
+ infoStart, _ = hex.DecodeString("3077af0c9274080241e1c107e6d618e6")
+ infoEnd, _ = hex.DecodeString("f932433186182072008242104116d8f2")
+)
+
+func isStandardImportPath(path string) bool {
+ return findStandardImportPath(path) != ""
+}
+
+func findStandardImportPath(path string) string {
+ if search.IsStandardImportPath(path) {
+ if goroot.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, path) {
+ return filepath.Join(cfg.GOROOT, "src", path)
+ }
+ if goroot.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, "vendor/"+path) {
+ return filepath.Join(cfg.GOROOT, "src/vendor", path)
+ }
+ }
+ return ""
+}
+
+func PackageModuleInfo(pkgpath string) *modinfo.ModulePublic {
+ if isStandardImportPath(pkgpath) || !Enabled() {
+ return nil
+ }
+ return moduleInfo(findModule(pkgpath, pkgpath), true)
+}
+
+func ModuleInfo(path string) *modinfo.ModulePublic {
+ if !Enabled() {
+ return nil
+ }
+
+ if i := strings.Index(path, "@"); i >= 0 {
+ return moduleInfo(module.Version{Path: path[:i], Version: path[i+1:]}, false)
+ }
+
+ for _, m := range BuildList() {
+ if m.Path == path {
+ return moduleInfo(m, true)
+ }
+ }
+
+ return &modinfo.ModulePublic{
+ Path: path,
+ Error: &modinfo.ModuleError{
+ Err: "module not in current build",
+ },
+ }
+}
+
+// addUpdate fills in m.Update if an updated version is available.
+func addUpdate(m *modinfo.ModulePublic) {
+ if m.Version != "" {
+ if info, err := Query(m.Path, "latest", Allowed); err == nil && info.Version != m.Version {
+ m.Update = &modinfo.ModulePublic{
+ Path: m.Path,
+ Version: info.Version,
+ Time: &info.Time,
+ }
+ }
+ }
+}
+
+// addVersions fills in m.Versions with the list of known versions.
+func addVersions(m *modinfo.ModulePublic) {
+ m.Versions, _ = versions(m.Path)
+}
+
+func moduleInfo(m module.Version, fromBuildList bool) *modinfo.ModulePublic {
+ if m == Target {
+ info := &modinfo.ModulePublic{
+ Path: m.Path,
+ Version: m.Version,
+ Main: true,
+ Dir: ModRoot,
+ GoMod: filepath.Join(ModRoot, "go.mod"),
+ }
+ if modFile.Go != nil {
+ info.GoVersion = modFile.Go.Version
+ }
+ return info
+ }
+
+ info := &modinfo.ModulePublic{
+ Path: m.Path,
+ Version: m.Version,
+ Indirect: fromBuildList && loaded != nil && !loaded.direct[m.Path],
+ }
+ if loaded != nil {
+ info.GoVersion = loaded.goVersion[m.Path]
+ }
+
+ if cfg.BuildMod == "vendor" {
+ info.Dir = filepath.Join(ModRoot, "vendor", m.Path)
+ return info
+ }
+
+ // complete fills in the extra fields in m.
+ complete := func(m *modinfo.ModulePublic) {
+ if m.Version != "" {
+ if q, err := Query(m.Path, m.Version, nil); err != nil {
+ m.Error = &modinfo.ModuleError{Err: err.Error()}
+ } else {
+ m.Version = q.Version
+ m.Time = &q.Time
+ }
+
+ mod := module.Version{Path: m.Path, Version: m.Version}
+ gomod, err := modfetch.CachePath(mod, "mod")
+ if err == nil {
+ if info, err := os.Stat(gomod); err == nil && info.Mode().IsRegular() {
+ m.GoMod = gomod
+ }
+ }
+ dir, err := modfetch.DownloadDir(mod)
+ if err == nil {
+ if info, err := os.Stat(dir); err == nil && info.IsDir() {
+ m.Dir = dir
+ }
+ }
+ }
+ if cfg.BuildMod == "vendor" {
+ m.Dir = filepath.Join(ModRoot, "vendor", m.Path)
+ }
+ }
+
+ complete(info)
+
+ if fromBuildList {
+ if r := Replacement(m); r.Path != "" {
+ info.Replace = &modinfo.ModulePublic{
+ Path: r.Path,
+ Version: r.Version,
+ GoVersion: info.GoVersion,
+ }
+ if r.Version == "" {
+ if filepath.IsAbs(r.Path) {
+ info.Replace.Dir = r.Path
+ } else {
+ info.Replace.Dir = filepath.Join(ModRoot, r.Path)
+ }
+ }
+ complete(info.Replace)
+ info.Dir = info.Replace.Dir
+ info.GoMod = filepath.Join(info.Dir, "go.mod")
+ info.Error = nil // ignore error loading original module version (it has been replaced)
+ }
+ }
+
+ return info
+}
+
+func PackageBuildInfo(path string, deps []string) string {
+ if isStandardImportPath(path) || !Enabled() {
+ return ""
+ }
+ target := findModule(path, path)
+ mdeps := make(map[module.Version]bool)
+ for _, dep := range deps {
+ if !isStandardImportPath(dep) {
+ mdeps[findModule(path, dep)] = true
+ }
+ }
+ var mods []module.Version
+ delete(mdeps, target)
+ for mod := range mdeps {
+ mods = append(mods, mod)
+ }
+ module.Sort(mods)
+
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "path\t%s\n", path)
+ tv := target.Version
+ if tv == "" {
+ tv = "(devel)"
+ }
+ fmt.Fprintf(&buf, "mod\t%s\t%s\t%s\n", target.Path, tv, modfetch.Sum(target))
+ for _, mod := range mods {
+ mv := mod.Version
+ if mv == "" {
+ mv = "(devel)"
+ }
+ r := Replacement(mod)
+ h := ""
+ if r.Path == "" {
+ h = "\t" + modfetch.Sum(mod)
+ }
+ fmt.Fprintf(&buf, "dep\t%s\t%s%s\n", mod.Path, mod.Version, h)
+ if r.Path != "" {
+ fmt.Fprintf(&buf, "=>\t%s\t%s\t%s\n", r.Path, r.Version, modfetch.Sum(r))
+ }
+ }
+ return buf.String()
+}
+
+func findModule(target, path string) module.Version {
+ // TODO: This should use loaded.
+ if path == "." {
+ return buildList[0]
+ }
+ for _, mod := range buildList {
+ if maybeInModule(path, mod.Path) {
+ return mod
+ }
+ }
+ base.Fatalf("build %v: cannot find module for path %v", target, path)
+ panic("unreachable")
+}
+
+func ModInfoProg(info string) []byte {
+ return []byte(fmt.Sprintf(`
+ package main
+ import _ "unsafe"
+ //go:linkname __debug_modinfo__ runtime/debug.modinfo
+ var __debug_modinfo__ string
+ func init() {
+ __debug_modinfo__ = %q
+ }
+ `, string(infoStart)+info+string(infoEnd)))
+}
diff --git a/libgo/go/cmd/go/internal/modload/help.go b/libgo/go/cmd/go/internal/modload/help.go
new file mode 100644
index 00000000000..f2f34197244
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modload/help.go
@@ -0,0 +1,462 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modload
+
+import "cmd/go/internal/base"
+
+// TODO(rsc): The "module code layout" section needs to be written.
+
+var HelpModules = &base.Command{
+ UsageLine: "modules",
+ Short: "modules, module versions, and more",
+ Long: `
+A module is a collection of related Go packages.
+Modules are the unit of source code interchange and versioning.
+The go command has direct support for working with modules,
+including recording and resolving dependencies on other modules.
+Modules replace the old GOPATH-based approach to specifying
+which source files are used in a given build.
+
+Preliminary module support
+
+Go 1.11 includes preliminary support for Go modules,
+including a new module-aware 'go get' command.
+We intend to keep revising this support, while preserving compatibility,
+until it can be declared official (no longer preliminary),
+and then at a later point we may remove support for work
+in GOPATH and the old 'go get' command.
+
+The quickest way to take advantage of the new Go 1.11 module support
+is to check out your repository into a directory outside GOPATH/src,
+create a go.mod file (described in the next section) there, and run
+go commands from within that file tree.
+
+For more fine-grained control, the module support in Go 1.11 respects
+a temporary environment variable, GO111MODULE, which can be set to one
+of three string values: off, on, or auto (the default).
+If GO111MODULE=off, then the go command never uses the
+new module support. Instead it looks in vendor directories and GOPATH
+to find dependencies; we now refer to this as "GOPATH mode."
+If GO111MODULE=on, then the go command requires the use of modules,
+never consulting GOPATH. We refer to this as the command being
+module-aware or running in "module-aware mode".
+If GO111MODULE=auto or is unset, then the go command enables or
+disables module support based on the current directory.
+Module support is enabled only when the current directory is outside
+GOPATH/src and itself contains a go.mod file or is below a directory
+containing a go.mod file.
+
+In module-aware mode, GOPATH no longer defines the meaning of imports
+during a build, but it still stores downloaded dependencies (in GOPATH/pkg/mod)
+and installed commands (in GOPATH/bin, unless GOBIN is set).
+
+Defining a module
+
+A module is defined by a tree of Go source files with a go.mod file
+in the tree's root directory. The directory containing the go.mod file
+is called the module root. Typically the module root will also correspond
+to a source code repository root (but in general it need not).
+The module is the set of all Go packages in the module root and its
+subdirectories, but excluding subtrees with their own go.mod files.
+
+The "module path" is the import path prefix corresponding to the module root.
+The go.mod file defines the module path and lists the specific versions
+of other modules that should be used when resolving imports during a build,
+by giving their module paths and versions.
+
+For example, this go.mod declares that the directory containing it is the root
+of the module with path example.com/m, and it also declares that the module
+depends on specific versions of golang.org/x/text and gopkg.in/yaml.v2:
+
+ module example.com/m
+
+ require (
+ golang.org/x/text v0.3.0
+ gopkg.in/yaml.v2 v2.1.0
+ )
+
+The go.mod file can also specify replacements and excluded versions
+that only apply when building the module directly; they are ignored
+when the module is incorporated into a larger build.
+For more about the go.mod file, see 'go help go.mod'.
+
+To start a new module, simply create a go.mod file in the root of the
+module's directory tree, containing only a module statement.
+The 'go mod init' command can be used to do this:
+
+ go mod init example.com/m
+
+In a project already using an existing dependency management tool like
+godep, glide, or dep, 'go mod init' will also add require statements
+matching the existing configuration.
+
+Once the go.mod file exists, no additional steps are required:
+go commands like 'go build', 'go test', or even 'go list' will automatically
+add new dependencies as needed to satisfy imports.
+
+The main module and the build list
+
+The "main module" is the module containing the directory where the go command
+is run. The go command finds the module root by looking for a go.mod in the
+current directory, or else the current directory's parent directory,
+or else the parent's parent directory, and so on.
+
+The main module's go.mod file defines the precise set of packages available
+for use by the go command, through require, replace, and exclude statements.
+Dependency modules, found by following require statements, also contribute
+to the definition of that set of packages, but only through their go.mod
+files' require statements: any replace and exclude statements in dependency
+modules are ignored. The replace and exclude statements therefore allow the
+main module complete control over its own build, without also being subject
+to complete control by dependencies.
+
+The set of modules providing packages to builds is called the "build list".
+The build list initially contains only the main module. Then the go command
+adds to the list the exact module versions required by modules already
+on the list, recursively, until there is nothing left to add to the list.
+If multiple versions of a particular module are added to the list,
+then at the end only the latest version (according to semantic version
+ordering) is kept for use in the build.
+
+The 'go list' command provides information about the main module
+and the build list. For example:
+
+ go list -m # print path of main module
+ go list -m -f={{.Dir}} # print root directory of main module
+ go list -m all # print build list
+
+Maintaining module requirements
+
+The go.mod file is meant to be readable and editable by both
+programmers and tools. The go command itself automatically updates the go.mod file
+to maintain a standard formatting and the accuracy of require statements.
+
+Any go command that finds an unfamiliar import will look up the module
+containing that import and add the latest version of that module
+to go.mod automatically. In most cases, therefore, it suffices to
+add an import to source code and run 'go build', 'go test', or even 'go list':
+as part of analyzing the package, the go command will discover
+and resolve the import and update the go.mod file.
+
+Any go command can determine that a module requirement is
+missing and must be added, even when considering only a single
+package from the module. On the other hand, determining that a module requirement
+is no longer necessary and can be deleted requires a full view of
+all packages in the module, across all possible build configurations
+(architectures, operating systems, build tags, and so on).
+The 'go mod tidy' command builds that view and then
+adds any missing module requirements and removes unnecessary ones.
+
+As part of maintaining the require statements in go.mod, the go command
+tracks which ones provide packages imported directly by the current module
+and which ones provide packages only used indirectly by other module
+dependencies. Requirements needed only for indirect uses are marked with a
+"// indirect" comment in the go.mod file. Indirect requirements are
+automatically removed from the go.mod file once they are implied by other
+direct requirements. Indirect requirements only arise when using modules
+that fail to state some of their own dependencies or when explicitly
+upgrading a module's dependencies ahead of its own stated requirements.
+
+Because of this automatic maintenance, the information in go.mod is an
+up-to-date, readable description of the build.
+
+The 'go get' command updates go.mod to change the module versions used in a
+build. An upgrade of one module may imply upgrading others, and similarly a
+downgrade of one module may imply downgrading others. The 'go get' command
+makes these implied changes as well. If go.mod is edited directly, commands
+like 'go build' or 'go list' will assume that an upgrade is intended and
+automatically make any implied upgrades and update go.mod to reflect them.
+
+The 'go mod' command provides other functionality for use in maintaining
+and understanding modules and go.mod files. See 'go help mod'.
+
+The -mod build flag provides additional control over updating and use of go.mod.
+
+If invoked with -mod=readonly, the go command is disallowed from the implicit
+automatic updating of go.mod described above. Instead, it fails when any changes
+to go.mod are needed. This setting is most useful to check that go.mod does
+not need updates, such as in a continuous integration and testing system.
+The "go get" command remains permitted to update go.mod even with -mod=readonly,
+and the "go mod" commands do not take the -mod flag (or any other build flags).
+
+If invoked with -mod=vendor, the go command assumes that the vendor
+directory holds the correct copies of dependencies and ignores
+the dependency descriptions in go.mod.
+
+Pseudo-versions
+
+The go.mod file and the go command more generally use semantic versions as
+the standard form for describing module versions, so that versions can be
+compared to determine which should be considered earlier or later than another.
+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. The time portion ensures that two pseudo-versions can
+be compared to determine which happened later, the commit hash identifes
+the underlying commit, and the prefix (v0.0.0- in this example) is derived from
+the most recent tagged version in the commit graph before this commit.
+
+There are three pseudo-version forms:
+
+vX.0.0-yyyymmddhhmmss-abcdefabcdef is used when there is no earlier
+versioned commit with an appropriate major version before the target commit.
+(This was originally the only form, so some older go.mod files use this form
+even for commits that do follow tags.)
+
+vX.Y.Z-pre.0.yyyymmddhhmmss-abcdefabcdef is used when the most
+recent versioned commit before the target commit is vX.Y.Z-pre.
+
+vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdefabcdef is used when the most
+recent versioned commit before the target commit is vX.Y.Z.
+
+Pseudo-versions never need to be typed by hand: the go command will accept
+the plain commit hash and translate it into a pseudo-version (or a tagged
+version if available) automatically. This conversion is an example of a
+module query.
+
+Module queries
+
+The go command accepts a "module query" in place of a module version
+both on the command line and in the main module's go.mod file.
+(After evaluating a query found in the main module's go.mod file,
+the go command updates the file to replace the query with its result.)
+
+A fully-specified semantic version, such as "v1.2.3",
+evaluates to that specific version.
+
+A semantic version prefix, such as "v1" or "v1.2",
+evaluates to the latest available tagged version with that prefix.
+
+A semantic version comparison, such as "<v1.2.3" or ">=v1.5.6",
+evaluates to the available tagged version nearest to the comparison target
+(the latest version for < and <=, the earliest version for > and >=).
+
+The string "latest" matches the latest available tagged version,
+or else the underlying source repository's latest untagged revision.
+
+A revision identifier for the underlying source repository,
+such as a commit hash prefix, revision tag, or branch name,
+selects that specific code revision. If the revision is
+also tagged with a semantic version, the query evaluates to
+that semantic version. Otherwise the query evaluates to a
+pseudo-version for the commit.
+
+All queries prefer release versions to pre-release versions.
+For example, "<v1.2.3" will prefer to return "v1.2.2"
+instead of "v1.2.3-pre1", even though "v1.2.3-pre1" is nearer
+to the comparison target.
+
+Module versions disallowed by exclude statements in the
+main module's go.mod are considered unavailable and cannot
+be returned by queries.
+
+For example, these commands are all valid:
+
+ go get github.com/gorilla/mux@latest # same (@latest is default for 'go get')
+ go get github.com/gorilla/mux@v1.6.2 # records v1.6.2
+ go get github.com/gorilla/mux@e3702bed2 # records v1.6.2
+ go get github.com/gorilla/mux@c856192 # records v0.0.0-20180517173623-c85619274f5d
+ go get github.com/gorilla/mux@master # records current meaning of master
+
+Module compatibility and semantic versioning
+
+The go command requires that modules use semantic versions and expects that
+the versions accurately describe compatibility: it assumes that v1.5.4 is a
+backwards-compatible replacement for v1.5.3, v1.4.0, and even v1.0.0.
+More generally the go command expects that packages follow the
+"import compatibility rule", which says:
+
+"If an old package and a new package have the same import path,
+the new package must be backwards compatible with the old package."
+
+Because the go command assumes the import compatibility rule,
+a module definition can only set the minimum required version of one
+of its dependencies: it cannot set a maximum or exclude selected versions.
+Still, the import compatibility rule is not a guarantee: it may be that
+v1.5.4 is buggy and not a backwards-compatible replacement for v1.5.3.
+Because of this, the go command never updates from an older version
+to a newer version of a module unasked.
+
+In semantic versioning, changing the major version number indicates a lack
+of backwards compatibility with earlier versions. To preserve import
+compatibility, the go command requires that modules with major version v2
+or later use a module path with that major version as the final element.
+For example, version v2.0.0 of example.com/m must instead use module path
+example.com/m/v2, and packages in that module would use that path as
+their import path prefix, as in example.com/m/v2/sub/pkg. Including the
+major version number in the module path and import paths in this way is
+called "semantic import versioning". Pseudo-versions for modules with major
+version v2 and later begin with that major version instead of v0, as in
+v2.0.0-20180326061214-4fc5987536ef.
+
+As a special case, module paths beginning with gopkg.in/ continue to use the
+conventions established on that system: the major version is always present,
+and it is preceded by a dot instead of a slash: gopkg.in/yaml.v1
+and gopkg.in/yaml.v2, not gopkg.in/yaml and gopkg.in/yaml/v2.
+
+The go command treats modules with different module paths as unrelated:
+it makes no connection between example.com/m and example.com/m/v2.
+Modules with different major versions can be used together in a build
+and are kept separate by the fact that their packages use different
+import paths.
+
+In semantic versioning, major version v0 is for initial development,
+indicating no expectations of stability or backwards compatibility.
+Major version v0 does not appear in the module path, because those
+versions are preparation for v1.0.0, and v1 does not appear in the
+module path either.
+
+Code written before the semantic import versioning convention
+was introduced may use major versions v2 and later to describe
+the same set of unversioned import paths as used in v0 and v1.
+To accommodate such code, 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 when converted to a module
+version, as in v2.0.0+incompatible. The +incompatible tag is also
+applied to pseudo-versions derived from such versions, as in
+v2.0.1-0.yyyymmddhhmmss-abcdefabcdef+incompatible.
+
+In general, having a dependency in the build list (as reported by 'go list -m all')
+on a v0 version, pre-release version, pseudo-version, or +incompatible version
+is an indication that problems are more likely when upgrading that
+dependency, since there is no expectation of compatibility for those.
+
+See https://research.swtch.com/vgo-import for more information about
+semantic import versioning, and see https://semver.org/ for more about
+semantic versioning.
+
+Module code layout
+
+For now, see https://research.swtch.com/vgo-module for information
+about how source code in version control systems is mapped to
+module file trees.
+
+Module downloading and verification
+
+The go command maintains, in the main module's root directory alongside
+go.mod, a file named go.sum containing the expected cryptographic checksums
+of the content of specific module versions. Each time a dependency is
+used, its checksum is added to go.sum if missing or else required to match
+the existing entry in go.sum.
+
+The go command maintains a cache of downloaded packages and computes
+and records the cryptographic checksum of each package at download time.
+In normal operation, the go command checks these pre-computed checksums
+against the main module's go.sum file, instead of recomputing them on
+each command invocation. The 'go mod verify' command checks that
+the cached copies of module downloads still match both their recorded
+checksums and the entries in go.sum.
+
+The go command can fetch modules from a proxy instead of connecting
+to source control systems directly, according to the setting of the GOPROXY
+environment variable.
+
+See 'go help goproxy' for details about the proxy and also the format of
+the cached downloaded packages.
+
+Modules and vendoring
+
+When using modules, the go command completely ignores vendor directories.
+
+By default, the go command satisfies dependencies by downloading modules
+from their sources and using those downloaded copies (after verification,
+as described in the previous section). To allow interoperation with older
+versions of Go, or to ensure that all files used for a build are stored
+together in a single file tree, 'go mod vendor' creates a directory named
+vendor in the root directory of the main module and stores there all the
+packages from dependency modules that are needed to support builds and
+tests of packages in the main module.
+
+To build using the main module's top-level vendor directory to satisfy
+dependencies (disabling use of the usual network sources and local
+caches), use 'go build -mod=vendor'. Note that only the main module's
+top-level vendor directory is used; vendor directories in other locations
+are still ignored.
+ `,
+}
+
+var HelpGoMod = &base.Command{
+ UsageLine: "go.mod",
+ Short: "the go.mod file",
+ Long: `
+A module version is defined by a tree of source files, with a go.mod
+file in its root. When the go command is run, it looks in the current
+directory and then successive parent directories to find the go.mod
+marking the root of the main (current) module.
+
+The go.mod file itself is line-oriented, with // comments but
+no /* */ comments. Each line holds a single directive, made up of a
+verb followed by arguments. For example:
+
+ module my/thing
+ require other/thing v1.0.2
+ require new/thing v2.3.4
+ exclude old/thing v1.2.3
+ replace bad/thing v1.4.5 => good/thing v1.4.5
+
+The verbs are module, to define the module path; require, to require
+a particular module at a given version or later; exclude, to exclude
+a particular module version from use; and replace, to replace a module
+version with a different module version. Exclude and replace apply only
+in the main module's go.mod and are ignored in dependencies.
+See https://research.swtch.com/vgo-mvs for details.
+
+The leading verb can be factored out of adjacent lines to create a block,
+like in Go imports:
+
+ require (
+ new/thing v2.3.4
+ old/thing v1.2.3
+ )
+
+The go.mod file is designed both to be edited directly and to be
+easily updated by tools. The 'go mod edit' command can be used to
+parse and edit the go.mod file from programs and tools.
+See 'go help mod edit'.
+
+The go command automatically updates go.mod each time it uses the
+module graph, to make sure go.mod always accurately reflects reality
+and is properly formatted. For example, consider this go.mod file:
+
+ module M
+
+ require (
+ A v1
+ B v1.0.0
+ C v1.0.0
+ D v1.2.3
+ E dev
+ )
+
+ exclude D v1.2.3
+
+The update rewrites non-canonical version identifiers to semver form,
+so A's v1 becomes v1.0.0 and E's dev becomes the pseudo-version for the
+latest commit on the dev branch, perhaps v0.0.0-20180523231146-b3f5c0f6e5f1.
+
+The update modifies requirements to respect exclusions, so the
+requirement on the excluded D v1.2.3 is updated to use the next
+available version of D, perhaps D v1.2.4 or D v1.3.0.
+
+The update removes redundant or misleading requirements.
+For example, if A v1.0.0 itself requires B v1.2.0 and C v1.0.0,
+then go.mod's requirement of B v1.0.0 is misleading (superseded by
+A's need for v1.2.0), and its requirement of C v1.0.0 is redundant
+(implied by A's need for the same version), so both will be removed.
+If module M contains packages that directly import packages from B or
+C, then the requirements will be kept but updated to the actual
+versions being used.
+
+Finally, the update reformats the go.mod in a canonical formatting, so
+that future mechanical changes will result in minimal diffs.
+
+Because the module graph defines the meaning of import statements, any
+commands that load packages also use and therefore update go.mod,
+including go build, go get, go install, go list, go test, go mod graph,
+go mod tidy, and go mod why.
+ `,
+}
diff --git a/libgo/go/cmd/go/internal/modload/import.go b/libgo/go/cmd/go/internal/modload/import.go
new file mode 100644
index 00000000000..44c2a237267
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modload/import.go
@@ -0,0 +1,228 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modload
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "go/build"
+ "internal/goroot"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "cmd/go/internal/cfg"
+ "cmd/go/internal/modfetch/codehost"
+ "cmd/go/internal/module"
+ "cmd/go/internal/par"
+ "cmd/go/internal/search"
+)
+
+type ImportMissingError struct {
+ ImportPath string
+ Module module.Version
+}
+
+func (e *ImportMissingError) Error() string {
+ if e.Module.Path == "" {
+ return "cannot find module providing package " + e.ImportPath
+ }
+ return "missing module for import: " + e.Module.Path + "@" + e.Module.Version + " provides " + e.ImportPath
+}
+
+// Import finds the module and directory in the build list
+// containing the package with the given import path.
+// The answer must be unique: Import returns an error
+// if multiple modules attempt to provide the same package.
+// Import can return a module with an empty m.Path, for packages in the standard library.
+// Import can return an empty directory string, for fake packages like "C" and "unsafe".
+//
+// If the package cannot be found in the current build list,
+// Import returns an ImportMissingError as the error.
+// If Import can identify a module that could be added to supply the package,
+// the ImportMissingError records that module.
+func Import(path string) (m module.Version, dir string, err error) {
+ if strings.Contains(path, "@") {
+ return module.Version{}, "", fmt.Errorf("import path should not have @version")
+ }
+ if build.IsLocalImport(path) {
+ return module.Version{}, "", fmt.Errorf("relative import not supported")
+ }
+ if path == "C" || path == "unsafe" {
+ // There's no directory for import "C" or import "unsafe".
+ return module.Version{}, "", nil
+ }
+
+ // Is the package in the standard library?
+ if search.IsStandardImportPath(path) {
+ if strings.HasPrefix(path, "golang_org/") {
+ return module.Version{}, filepath.Join(cfg.GOROOT, "src/vendor", path), nil
+ }
+ if goroot.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, path) {
+ dir := filepath.Join(cfg.GOROOT, "src", path)
+ return module.Version{}, dir, nil
+ }
+ }
+
+ // -mod=vendor is special.
+ // Everything must be in the main module or the main module's vendor directory.
+ if cfg.BuildMod == "vendor" {
+ mainDir, mainOK := dirInModule(path, Target.Path, ModRoot, true)
+ vendorDir, vendorOK := dirInModule(path, "", filepath.Join(ModRoot, "vendor"), false)
+ if mainOK && vendorOK {
+ return module.Version{}, "", fmt.Errorf("ambiguous import: found %s in multiple directories:\n\t%s\n\t%s", path, mainDir, vendorDir)
+ }
+ // Prefer to return main directory if there is one,
+ // Note that we're not checking that the package exists.
+ // We'll leave that for load.
+ if !vendorOK && mainDir != "" {
+ return Target, mainDir, nil
+ }
+ readVendorList()
+ return vendorMap[path], vendorDir, nil
+ }
+
+ // Check each module on the build list.
+ var dirs []string
+ var mods []module.Version
+ for _, m := range buildList {
+ if !maybeInModule(path, m.Path) {
+ // Avoid possibly downloading irrelevant modules.
+ continue
+ }
+ root, isLocal, err := fetch(m)
+ if err != nil {
+ // Report fetch error.
+ // Note that we don't know for sure this module is necessary,
+ // but it certainly _could_ provide the package, and even if we
+ // continue the loop and find the package in some other module,
+ // we need to look at this module to make sure the import is
+ // not ambiguous.
+ return module.Version{}, "", err
+ }
+ dir, ok := dirInModule(path, m.Path, root, isLocal)
+ if ok {
+ mods = append(mods, m)
+ dirs = append(dirs, dir)
+ }
+ }
+ if len(mods) == 1 {
+ return mods[0], dirs[0], nil
+ }
+ if len(mods) > 0 {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "ambiguous import: found %s in multiple modules:", path)
+ for i, m := range mods {
+ fmt.Fprintf(&buf, "\n\t%s", m.Path)
+ if m.Version != "" {
+ fmt.Fprintf(&buf, " %s", m.Version)
+ }
+ fmt.Fprintf(&buf, " (%s)", dirs[i])
+ }
+ return module.Version{}, "", errors.New(buf.String())
+ }
+
+ // Not on build list.
+
+ // Look up module containing the package, for addition to the build list.
+ // Goal is to determine the module, download it to dir, and return m, dir, ErrMissing.
+ if cfg.BuildMod == "readonly" {
+ return module.Version{}, "", fmt.Errorf("import lookup disabled by -mod=%s", cfg.BuildMod)
+ }
+
+ m, _, err = QueryPackage(path, "latest", Allowed)
+ if err != nil {
+ if _, ok := err.(*codehost.VCSError); ok {
+ return module.Version{}, "", err
+ }
+ return module.Version{}, "", &ImportMissingError{ImportPath: path}
+ }
+ return m, "", &ImportMissingError{ImportPath: path, Module: m}
+}
+
+// maybeInModule reports whether, syntactically,
+// a package with the given import path could be supplied
+// by a module with the given module path (mpath).
+func maybeInModule(path, mpath string) bool {
+ return mpath == path ||
+ len(path) > len(mpath) && path[len(mpath)] == '/' && path[:len(mpath)] == mpath
+}
+
+var haveGoModCache, haveGoFilesCache par.Cache
+
+// dirInModule locates the directory that would hold the package named by the given path,
+// if it were in the module with module path mpath and root mdir.
+// If path is syntactically not within mpath,
+// or if mdir is a local file tree (isLocal == true) and the directory
+// that would hold path is in a sub-module (covered by a go.mod below mdir),
+// dirInModule returns "", false.
+//
+// Otherwise, dirInModule returns the name of the directory where
+// Go source files would be expected, along with a boolean indicating
+// whether there are in fact Go source files in that directory.
+func dirInModule(path, mpath, mdir string, isLocal bool) (dir string, haveGoFiles bool) {
+ // Determine where to expect the package.
+ if path == mpath {
+ dir = mdir
+ } else if mpath == "" { // vendor directory
+ dir = filepath.Join(mdir, path)
+ } else if len(path) > len(mpath) && path[len(mpath)] == '/' && path[:len(mpath)] == mpath {
+ dir = filepath.Join(mdir, path[len(mpath)+1:])
+ } else {
+ return "", false
+ }
+
+ // Check that there aren't other modules in the way.
+ // This check is unnecessary inside the module cache
+ // and important to skip in the vendor directory,
+ // where all the module trees have been overlaid.
+ // So we only check local module trees
+ // (the main module, and any directory trees pointed at by replace directives).
+ if isLocal {
+ for d := dir; d != mdir && len(d) > len(mdir); {
+ haveGoMod := haveGoModCache.Do(d, func() interface{} {
+ _, err := os.Stat(filepath.Join(d, "go.mod"))
+ return err == nil
+ }).(bool)
+
+ if haveGoMod {
+ return "", false
+ }
+ parent := filepath.Dir(d)
+ if parent == d {
+ // Break the loop, as otherwise we'd loop
+ // forever if d=="." and mdir=="".
+ break
+ }
+ d = parent
+ }
+ }
+
+ // Now committed to returning dir (not "").
+
+ // Are there Go source files in the directory?
+ // We don't care about build tags, not even "+build ignore".
+ // We're just looking for a plausible directory.
+ haveGoFiles = haveGoFilesCache.Do(dir, func() interface{} {
+ f, err := os.Open(dir)
+ if err != nil {
+ return false
+ }
+ defer f.Close()
+ names, _ := f.Readdirnames(-1)
+ for _, name := range names {
+ if strings.HasSuffix(name, ".go") {
+ info, err := os.Stat(filepath.Join(dir, name))
+ if err == nil && info.Mode().IsRegular() {
+ return true
+ }
+ }
+ }
+ return false
+ }).(bool)
+
+ return dir, haveGoFiles
+}
diff --git a/libgo/go/cmd/go/internal/modload/import_test.go b/libgo/go/cmd/go/internal/modload/import_test.go
new file mode 100644
index 00000000000..3f4ddab436c
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modload/import_test.go
@@ -0,0 +1,59 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modload
+
+import (
+ "internal/testenv"
+ "regexp"
+ "strings"
+ "testing"
+)
+
+var importTests = []struct {
+ path string
+ err string
+}{
+ {
+ path: "golang.org/x/net/context",
+ err: "missing module for import: golang.org/x/net@.* provides golang.org/x/net/context",
+ },
+ {
+ path: "golang.org/x/net",
+ err: "cannot find module providing package golang.org/x/net",
+ },
+ {
+ path: "golang.org/x/text",
+ err: "missing module for import: golang.org/x/text@.* provides golang.org/x/text",
+ },
+ {
+ path: "github.com/rsc/quote/buggy",
+ err: "missing module for import: github.com/rsc/quote@v1.5.2 provides github.com/rsc/quote/buggy",
+ },
+ {
+ path: "github.com/rsc/quote",
+ err: "missing module for import: github.com/rsc/quote@v1.5.2 provides github.com/rsc/quote",
+ },
+ {
+ path: "golang.org/x/foo/bar",
+ err: "cannot find module providing package golang.org/x/foo/bar",
+ },
+}
+
+func TestImport(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ for _, tt := range importTests {
+ t.Run(strings.Replace(tt.path, "/", "_", -1), func(t *testing.T) {
+ // Note that there is no build list, so Import should always fail.
+ m, dir, err := Import(tt.path)
+ if err == nil {
+ t.Fatalf("Import(%q) = %v, %v, nil; expected error", tt.path, m, dir)
+ }
+ if !regexp.MustCompile(tt.err).MatchString(err.Error()) {
+ t.Fatalf("Import(%q): error %q, want error matching %#q", tt.path, err, tt.err)
+ }
+ })
+ }
+}
diff --git a/libgo/go/cmd/go/internal/modload/init.go b/libgo/go/cmd/go/internal/modload/init.go
new file mode 100644
index 00000000000..f995bad13b5
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modload/init.go
@@ -0,0 +1,600 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modload
+
+import (
+ "bytes"
+ "cmd/go/internal/base"
+ "cmd/go/internal/cache"
+ "cmd/go/internal/cfg"
+ "cmd/go/internal/load"
+ "cmd/go/internal/modconv"
+ "cmd/go/internal/modfetch"
+ "cmd/go/internal/modfetch/codehost"
+ "cmd/go/internal/modfile"
+ "cmd/go/internal/module"
+ "cmd/go/internal/mvs"
+ "cmd/go/internal/search"
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path"
+ "path/filepath"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+var (
+ cwd string
+ MustUseModules = mustUseModules()
+ initialized bool
+
+ ModRoot string
+ modFile *modfile.File
+ excluded map[module.Version]bool
+ Target module.Version
+
+ gopath string
+
+ CmdModInit bool // running 'go mod init'
+ CmdModModule string // module argument for 'go mod init'
+)
+
+// ModFile returns the parsed go.mod file.
+//
+// Note that after calling ImportPaths or LoadBuildList,
+// the require statements in the modfile.File are no longer
+// the source of truth and will be ignored: edits made directly
+// will be lost at the next call to WriteGoMod.
+// To make permanent changes to the require statements
+// in go.mod, edit it before calling ImportPaths or LoadBuildList.
+func ModFile() *modfile.File {
+ return modFile
+}
+
+func BinDir() string {
+ MustInit()
+ return filepath.Join(gopath, "bin")
+}
+
+// mustUseModules reports whether we are invoked as vgo
+// (as opposed to go).
+// If so, we only support builds with go.mod files.
+func mustUseModules() bool {
+ name := os.Args[0]
+ name = name[strings.LastIndex(name, "/")+1:]
+ name = name[strings.LastIndex(name, `\`)+1:]
+ return strings.HasPrefix(name, "vgo")
+}
+
+var inGOPATH bool // running in GOPATH/src
+
+func Init() {
+ if initialized {
+ return
+ }
+ initialized = true
+
+ env := os.Getenv("GO111MODULE")
+ switch env {
+ default:
+ base.Fatalf("go: unknown environment setting GO111MODULE=%s", env)
+ case "", "auto":
+ // leave MustUseModules alone
+ case "on":
+ MustUseModules = true
+ case "off":
+ if !MustUseModules {
+ return
+ }
+ }
+
+ // Disable any prompting for passwords by Git.
+ // Only has an effect for 2.3.0 or later, but avoiding
+ // the prompt in earlier versions is just too hard.
+ // If user has explicitly set GIT_TERMINAL_PROMPT=1, keep
+ // prompting.
+ // See golang.org/issue/9341 and golang.org/issue/12706.
+ if os.Getenv("GIT_TERMINAL_PROMPT") == "" {
+ os.Setenv("GIT_TERMINAL_PROMPT", "0")
+ }
+
+ // Disable any ssh connection pooling by Git.
+ // If a Git subprocess forks a child into the background to cache a new connection,
+ // that child keeps stdout/stderr open. After the Git subprocess exits,
+ // os /exec expects to be able to read from the stdout/stderr pipe
+ // until EOF to get all the data that the Git subprocess wrote before exiting.
+ // The EOF doesn't come until the child exits too, because the child
+ // is holding the write end of the pipe.
+ // This is unfortunate, but it has come up at least twice
+ // (see golang.org/issue/13453 and golang.org/issue/16104)
+ // and confuses users when it does.
+ // If the user has explicitly set GIT_SSH or GIT_SSH_COMMAND,
+ // assume they know what they are doing and don't step on it.
+ // But default to turning off ControlMaster.
+ if os.Getenv("GIT_SSH") == "" && os.Getenv("GIT_SSH_COMMAND") == "" {
+ os.Setenv("GIT_SSH_COMMAND", "ssh -o ControlMaster=no")
+ }
+
+ var err error
+ cwd, err = os.Getwd()
+ if err != nil {
+ base.Fatalf("go: %v", err)
+ }
+
+ inGOPATH = false
+ for _, gopath := range filepath.SplitList(cfg.BuildContext.GOPATH) {
+ if gopath == "" {
+ continue
+ }
+ if search.InDir(cwd, filepath.Join(gopath, "src")) != "" {
+ inGOPATH = true
+ break
+ }
+ }
+
+ if inGOPATH && !MustUseModules {
+ // No automatic enabling in GOPATH.
+ if root, _ := FindModuleRoot(cwd, "", false); root != "" {
+ cfg.GoModInGOPATH = filepath.Join(root, "go.mod")
+ }
+ return
+ }
+
+ if CmdModInit {
+ // Running 'go mod init': go.mod will be created in current directory.
+ ModRoot = cwd
+ } else {
+ ModRoot, _ = FindModuleRoot(cwd, "", MustUseModules)
+ if !MustUseModules {
+ if ModRoot == "" {
+ return
+ }
+ if search.InDir(ModRoot, os.TempDir()) == "." {
+ // If you create /tmp/go.mod for experimenting,
+ // then any tests that create work directories under /tmp
+ // will find it and get modules when they're not expecting them.
+ // It's a bit of a peculiar thing to disallow but quite mysterious
+ // when it happens. See golang.org/issue/26708.
+ ModRoot = ""
+ fmt.Fprintf(os.Stderr, "go: warning: ignoring go.mod in system temp root %v\n", os.TempDir())
+ return
+ }
+ }
+ }
+
+ cfg.ModulesEnabled = true
+ load.ModBinDir = BinDir
+ load.ModLookup = Lookup
+ load.ModPackageModuleInfo = PackageModuleInfo
+ load.ModImportPaths = ImportPaths
+ load.ModPackageBuildInfo = PackageBuildInfo
+ load.ModInfoProg = ModInfoProg
+ load.ModImportFromFiles = ImportFromFiles
+ load.ModDirImportPath = DirImportPath
+
+ search.SetModRoot(ModRoot)
+}
+
+func init() {
+ load.ModInit = Init
+
+ // Set modfetch.PkgMod unconditionally, so that go clean -modcache can run even without modules enabled.
+ if list := filepath.SplitList(cfg.BuildContext.GOPATH); len(list) > 0 && list[0] != "" {
+ modfetch.PkgMod = filepath.Join(list[0], "pkg/mod")
+ }
+}
+
+// Enabled reports whether modules are (or must be) enabled.
+// If modules must be enabled but are not, Enabled returns true
+// and then the first use of module information will call die
+// (usually through InitMod and MustInit).
+func Enabled() bool {
+ if !initialized {
+ panic("go: Enabled called before Init")
+ }
+ return ModRoot != "" || MustUseModules
+}
+
+// MustInit calls Init if needed and checks that
+// modules are enabled and the main module has been found.
+// If not, MustInit calls base.Fatalf with an appropriate message.
+func MustInit() {
+ if Init(); ModRoot == "" {
+ die()
+ }
+ if c := cache.Default(); c == nil {
+ // With modules, there are no install locations for packages
+ // other than the build cache.
+ base.Fatalf("go: cannot use modules with build cache disabled")
+ }
+}
+
+// Failed reports whether module loading failed.
+// If Failed returns true, then any use of module information will call die.
+func Failed() bool {
+ Init()
+ return cfg.ModulesEnabled && ModRoot == ""
+}
+
+func die() {
+ if os.Getenv("GO111MODULE") == "off" {
+ base.Fatalf("go: modules disabled by GO111MODULE=off; see 'go help modules'")
+ }
+ if inGOPATH && !MustUseModules {
+ base.Fatalf("go: modules disabled inside GOPATH/src by GO111MODULE=auto; see 'go help modules'")
+ }
+ base.Fatalf("go: cannot find main module; see 'go help modules'")
+}
+
+func InitMod() {
+ MustInit()
+ if modFile != nil {
+ return
+ }
+
+ list := filepath.SplitList(cfg.BuildContext.GOPATH)
+ if len(list) == 0 || list[0] == "" {
+ base.Fatalf("missing $GOPATH")
+ }
+ gopath = list[0]
+ if _, err := os.Stat(filepath.Join(gopath, "go.mod")); err == nil {
+ base.Fatalf("$GOPATH/go.mod exists but should not")
+ }
+
+ oldSrcMod := filepath.Join(list[0], "src/mod")
+ pkgMod := filepath.Join(list[0], "pkg/mod")
+ infoOld, errOld := os.Stat(oldSrcMod)
+ _, errMod := os.Stat(pkgMod)
+ if errOld == nil && infoOld.IsDir() && errMod != nil && os.IsNotExist(errMod) {
+ os.Rename(oldSrcMod, pkgMod)
+ }
+
+ modfetch.PkgMod = pkgMod
+ modfetch.GoSumFile = filepath.Join(ModRoot, "go.sum")
+ codehost.WorkRoot = filepath.Join(pkgMod, "cache/vcs")
+
+ if CmdModInit {
+ // Running go mod init: do legacy module conversion
+ legacyModInit()
+ modFileToBuildList()
+ WriteGoMod()
+ return
+ }
+
+ gomod := filepath.Join(ModRoot, "go.mod")
+ data, err := ioutil.ReadFile(gomod)
+ if err != nil {
+ if os.IsNotExist(err) {
+ legacyModInit()
+ modFileToBuildList()
+ WriteGoMod()
+ return
+ }
+ base.Fatalf("go: %v", err)
+ }
+
+ f, err := modfile.Parse(gomod, data, fixVersion)
+ if err != nil {
+ // Errors returned by modfile.Parse begin with file:line.
+ base.Fatalf("go: errors parsing go.mod:\n%s\n", err)
+ }
+ modFile = f
+
+ if len(f.Syntax.Stmt) == 0 || f.Module == nil {
+ // Empty mod file. Must add module path.
+ path, err := FindModulePath(ModRoot)
+ if err != nil {
+ base.Fatalf("go: %v", err)
+ }
+ f.AddModuleStmt(path)
+ }
+
+ if len(f.Syntax.Stmt) == 1 && f.Module != nil {
+ // Entire file is just a module statement.
+ // Populate require if possible.
+ legacyModInit()
+ }
+
+ excluded = make(map[module.Version]bool)
+ for _, x := range f.Exclude {
+ excluded[x.Mod] = true
+ }
+ modFileToBuildList()
+ WriteGoMod()
+}
+
+// modFileToBuildList initializes buildList from the modFile.
+func modFileToBuildList() {
+ Target = modFile.Module.Mod
+ list := []module.Version{Target}
+ for _, r := range modFile.Require {
+ list = append(list, r.Mod)
+ }
+ buildList = list
+}
+
+// Allowed reports whether module m is allowed (not excluded) by the main module's go.mod.
+func Allowed(m module.Version) bool {
+ return !excluded[m]
+}
+
+func legacyModInit() {
+ if modFile == nil {
+ path, err := FindModulePath(ModRoot)
+ if err != nil {
+ base.Fatalf("go: %v", err)
+ }
+ fmt.Fprintf(os.Stderr, "go: creating new go.mod: module %s\n", path)
+ modFile = new(modfile.File)
+ modFile.AddModuleStmt(path)
+ }
+
+ for _, name := range altConfigs {
+ cfg := filepath.Join(ModRoot, name)
+ data, err := ioutil.ReadFile(cfg)
+ if err == nil {
+ convert := modconv.Converters[name]
+ if convert == nil {
+ return
+ }
+ fmt.Fprintf(os.Stderr, "go: copying requirements from %s\n", base.ShortPath(cfg))
+ cfg = filepath.ToSlash(cfg)
+ if err := modconv.ConvertLegacyConfig(modFile, cfg, data); err != nil {
+ base.Fatalf("go: %v", err)
+ }
+ if len(modFile.Syntax.Stmt) == 1 {
+ // Add comment to avoid re-converting every time it runs.
+ modFile.AddComment("// go: no requirements found in " + name)
+ }
+ return
+ }
+ }
+}
+
+var altConfigs = []string{
+ "Gopkg.lock",
+
+ "GLOCKFILE",
+ "Godeps/Godeps.json",
+ "dependencies.tsv",
+ "glide.lock",
+ "vendor.conf",
+ "vendor.yml",
+ "vendor/manifest",
+ "vendor/vendor.json",
+
+ ".git/config",
+}
+
+// Exported only for testing.
+func FindModuleRoot(dir, limit string, legacyConfigOK bool) (root, file string) {
+ dir = filepath.Clean(dir)
+ dir1 := dir
+ limit = filepath.Clean(limit)
+
+ // Look for enclosing go.mod.
+ for {
+ if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil {
+ return dir, "go.mod"
+ }
+ if dir == limit {
+ break
+ }
+ d := filepath.Dir(dir)
+ if d == dir {
+ break
+ }
+ dir = d
+ }
+
+ // Failing that, look for enclosing alternate version config.
+ if legacyConfigOK {
+ dir = dir1
+ for {
+ for _, name := range altConfigs {
+ if _, err := os.Stat(filepath.Join(dir, name)); err == nil {
+ return dir, name
+ }
+ }
+ if dir == limit {
+ break
+ }
+ d := filepath.Dir(dir)
+ if d == dir {
+ break
+ }
+ dir = d
+ }
+ }
+
+ return "", ""
+}
+
+// Exported only for testing.
+func FindModulePath(dir string) (string, error) {
+ if CmdModModule != "" {
+ // Running go mod init x/y/z; return x/y/z.
+ return CmdModModule, nil
+ }
+
+ // Cast about for import comments,
+ // first in top-level directory, then in subdirectories.
+ list, _ := ioutil.ReadDir(dir)
+ for _, info := range list {
+ if info.Mode().IsRegular() && strings.HasSuffix(info.Name(), ".go") {
+ if com := findImportComment(filepath.Join(dir, info.Name())); com != "" {
+ return com, nil
+ }
+ }
+ }
+ for _, info1 := range list {
+ if info1.IsDir() {
+ files, _ := ioutil.ReadDir(filepath.Join(dir, info1.Name()))
+ for _, info2 := range files {
+ if info2.Mode().IsRegular() && strings.HasSuffix(info2.Name(), ".go") {
+ if com := findImportComment(filepath.Join(dir, info1.Name(), info2.Name())); com != "" {
+ return path.Dir(com), nil
+ }
+ }
+ }
+ }
+ }
+
+ // Look for Godeps.json declaring import path.
+ data, _ := ioutil.ReadFile(filepath.Join(dir, "Godeps/Godeps.json"))
+ var cfg1 struct{ ImportPath string }
+ json.Unmarshal(data, &cfg1)
+ if cfg1.ImportPath != "" {
+ return cfg1.ImportPath, nil
+ }
+
+ // Look for vendor.json declaring import path.
+ data, _ = ioutil.ReadFile(filepath.Join(dir, "vendor/vendor.json"))
+ var cfg2 struct{ RootPath string }
+ json.Unmarshal(data, &cfg2)
+ if cfg2.RootPath != "" {
+ return cfg2.RootPath, nil
+ }
+
+ // Look for path in GOPATH.
+ for _, gpdir := range filepath.SplitList(cfg.BuildContext.GOPATH) {
+ if gpdir == "" {
+ continue
+ }
+ if rel := search.InDir(dir, filepath.Join(gpdir, "src")); rel != "" && rel != "." {
+ return filepath.ToSlash(rel), nil
+ }
+ }
+
+ // Look for .git/config with github origin as last resort.
+ data, _ = ioutil.ReadFile(filepath.Join(dir, ".git/config"))
+ if m := gitOriginRE.FindSubmatch(data); m != nil {
+ return "github.com/" + string(m[1]), nil
+ }
+
+ return "", fmt.Errorf("cannot determine module path for source directory %s (outside GOPATH, no import comments)", dir)
+}
+
+var (
+ gitOriginRE = regexp.MustCompile(`(?m)^\[remote "origin"\]\r?\n\turl = (?:https://github.com/|git@github.com:|gh:)([^/]+/[^/]+?)(\.git)?\r?\n`)
+ importCommentRE = regexp.MustCompile(`(?m)^package[ \t]+[^ \t\r\n/]+[ \t]+//[ \t]+import[ \t]+(\"[^"]+\")[ \t]*\r?\n`)
+)
+
+func findImportComment(file string) string {
+ data, err := ioutil.ReadFile(file)
+ if err != nil {
+ return ""
+ }
+ m := importCommentRE.FindSubmatch(data)
+ if m == nil {
+ return ""
+ }
+ path, err := strconv.Unquote(string(m[1]))
+ if err != nil {
+ return ""
+ }
+ return path
+}
+
+var allowWriteGoMod = true
+
+// DisallowWriteGoMod causes future calls to WriteGoMod to do nothing at all.
+func DisallowWriteGoMod() {
+ allowWriteGoMod = false
+}
+
+// AllowWriteGoMod undoes the effect of DisallowWriteGoMod:
+// future calls to WriteGoMod will update go.mod if needed.
+// Note that any past calls have been discarded, so typically
+// a call to AlowWriteGoMod should be followed by a call to WriteGoMod.
+func AllowWriteGoMod() {
+ allowWriteGoMod = true
+}
+
+// MinReqs returns a Reqs with minimal dependencies of Target,
+// as will be written to go.mod.
+func MinReqs() mvs.Reqs {
+ var direct []string
+ for _, m := range buildList[1:] {
+ if loaded.direct[m.Path] {
+ direct = append(direct, m.Path)
+ }
+ }
+ min, err := mvs.Req(Target, buildList, direct, Reqs())
+ if err != nil {
+ base.Fatalf("go: %v", err)
+ }
+ return &mvsReqs{buildList: append([]module.Version{Target}, min...)}
+}
+
+// WriteGoMod writes the current build list back to go.mod.
+func WriteGoMod() {
+ // If we're using -mod=vendor we basically ignored
+ // go.mod, so definitely don't try to write back our
+ // incomplete view of the world.
+ if !allowWriteGoMod || cfg.BuildMod == "vendor" {
+ return
+ }
+
+ if loaded != nil {
+ reqs := MinReqs()
+ min, err := reqs.Required(Target)
+ if err != nil {
+ base.Fatalf("go: %v", err)
+ }
+ var list []*modfile.Require
+ for _, m := range min {
+ list = append(list, &modfile.Require{
+ Mod: m,
+ Indirect: !loaded.direct[m.Path],
+ })
+ }
+ modFile.SetRequire(list)
+ }
+
+ file := filepath.Join(ModRoot, "go.mod")
+ old, _ := ioutil.ReadFile(file)
+ modFile.Cleanup() // clean file after edits
+ new, err := modFile.Format()
+ if err != nil {
+ base.Fatalf("go: %v", err)
+ }
+ if !bytes.Equal(old, new) {
+ if cfg.BuildMod == "readonly" {
+ base.Fatalf("go: updates to go.mod needed, disabled by -mod=readonly")
+ }
+ if err := ioutil.WriteFile(file, new, 0666); err != nil {
+ base.Fatalf("go: %v", err)
+ }
+ }
+ modfetch.WriteGoSum()
+}
+
+func fixVersion(path, vers string) (string, error) {
+ // Special case: remove the old -gopkgin- hack.
+ if strings.HasPrefix(path, "gopkg.in/") && strings.Contains(vers, "-gopkgin-") {
+ vers = vers[strings.Index(vers, "-gopkgin-")+len("-gopkgin-"):]
+ }
+
+ // fixVersion is called speculatively on every
+ // module, version pair from every go.mod file.
+ // Avoid the query if it looks OK.
+ _, pathMajor, ok := module.SplitPathVersion(path)
+ if !ok {
+ return "", fmt.Errorf("malformed module path: %s", path)
+ }
+ if vers != "" && module.CanonicalVersion(vers) == vers && module.MatchPathMajor(vers, pathMajor) {
+ return vers, nil
+ }
+
+ info, err := Query(path, vers, nil)
+ if err != nil {
+ return "", err
+ }
+ return info.Version, nil
+}
diff --git a/libgo/go/cmd/go/internal/modload/list.go b/libgo/go/cmd/go/internal/modload/list.go
new file mode 100644
index 00000000000..69a832de1df
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modload/list.go
@@ -0,0 +1,109 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modload
+
+import (
+ "fmt"
+ "os"
+ "strings"
+
+ "cmd/go/internal/base"
+ "cmd/go/internal/modinfo"
+ "cmd/go/internal/module"
+ "cmd/go/internal/par"
+ "cmd/go/internal/search"
+)
+
+func ListModules(args []string, listU, listVersions bool) []*modinfo.ModulePublic {
+ mods := listModules(args)
+ if listU || listVersions {
+ var work par.Work
+ for _, m := range mods {
+ work.Add(m)
+ if m.Replace != nil {
+ work.Add(m.Replace)
+ }
+ }
+ work.Do(10, func(item interface{}) {
+ m := item.(*modinfo.ModulePublic)
+ if listU {
+ addUpdate(m)
+ }
+ if listVersions {
+ addVersions(m)
+ }
+ })
+ }
+ return mods
+}
+
+func listModules(args []string) []*modinfo.ModulePublic {
+ LoadBuildList()
+ if len(args) == 0 {
+ return []*modinfo.ModulePublic{moduleInfo(buildList[0], true)}
+ }
+
+ var mods []*modinfo.ModulePublic
+ matchedBuildList := make([]bool, len(buildList))
+ for _, arg := range args {
+ if strings.Contains(arg, `\`) {
+ base.Fatalf("go: module paths never use backslash")
+ }
+ if search.IsRelativePath(arg) {
+ base.Fatalf("go: cannot use relative path %s to specify module", arg)
+ }
+ if i := strings.Index(arg, "@"); i >= 0 {
+ info, err := Query(arg[:i], arg[i+1:], nil)
+ if err != nil {
+ mods = append(mods, &modinfo.ModulePublic{
+ Path: arg[:i],
+ Version: arg[i+1:],
+ Error: &modinfo.ModuleError{
+ Err: err.Error(),
+ },
+ })
+ continue
+ }
+ mods = append(mods, moduleInfo(module.Version{Path: arg[:i], Version: info.Version}, false))
+ continue
+ }
+
+ // Module path or pattern.
+ var match func(string) bool
+ var literal bool
+ if arg == "all" {
+ match = func(string) bool { return true }
+ } else if strings.Contains(arg, "...") {
+ match = search.MatchPattern(arg)
+ } else {
+ match = func(p string) bool { return arg == p }
+ literal = true
+ }
+ matched := false
+ for i, m := range buildList {
+ if match(m.Path) {
+ matched = true
+ if !matchedBuildList[i] {
+ matchedBuildList[i] = true
+ mods = append(mods, moduleInfo(m, true))
+ }
+ }
+ }
+ if !matched {
+ if literal {
+ mods = append(mods, &modinfo.ModulePublic{
+ Path: arg,
+ Error: &modinfo.ModuleError{
+ Err: fmt.Sprintf("module %q is not a known dependency", arg),
+ },
+ })
+ } else {
+ fmt.Fprintf(os.Stderr, "warning: pattern %q matched no module dependencies\n", arg)
+ }
+ }
+ }
+
+ return mods
+}
diff --git a/libgo/go/cmd/go/internal/modload/load.go b/libgo/go/cmd/go/internal/modload/load.go
new file mode 100644
index 00000000000..5bf6c9b1cf9
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modload/load.go
@@ -0,0 +1,1071 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modload
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "go/build"
+ "io/ioutil"
+ "os"
+ "path"
+ "path/filepath"
+ "sort"
+ "strings"
+ "sync"
+
+ "cmd/go/internal/base"
+ "cmd/go/internal/cfg"
+ "cmd/go/internal/imports"
+ "cmd/go/internal/modfetch"
+ "cmd/go/internal/modfile"
+ "cmd/go/internal/module"
+ "cmd/go/internal/mvs"
+ "cmd/go/internal/par"
+ "cmd/go/internal/search"
+ "cmd/go/internal/semver"
+ "cmd/go/internal/str"
+)
+
+// buildList is the list of modules to use for building packages.
+// It is initialized by calling ImportPaths, ImportFromFiles,
+// LoadALL, or LoadBuildList, each of which uses loaded.load.
+//
+// Ideally, exactly ONE of those functions would be called,
+// and exactly once. Most of the time, that's true.
+// During "go get" it may not be. TODO(rsc): Figure out if
+// that restriction can be established, or else document why not.
+//
+var buildList []module.Version
+
+// loaded is the most recently-used package loader.
+// It holds details about individual packages.
+//
+// Note that loaded.buildList is only valid during a load operation;
+// afterward, it is copied back into the global buildList,
+// which should be used instead.
+var loaded *loader
+
+// ImportPaths returns the set of packages matching the args (patterns),
+// adding modules to the build list as needed to satisfy new imports.
+func ImportPaths(patterns []string) []*search.Match {
+ InitMod()
+
+ var matches []*search.Match
+ for _, pattern := range search.CleanPatterns(patterns) {
+ m := &search.Match{
+ Pattern: pattern,
+ Literal: !strings.Contains(pattern, "...") && !search.IsMetaPackage(pattern),
+ }
+ if m.Literal {
+ m.Pkgs = []string{pattern}
+ }
+ matches = append(matches, m)
+ }
+
+ fsDirs := make([][]string, len(matches))
+ loaded = newLoader()
+ updateMatches := func(iterating bool) {
+ for i, m := range matches {
+ switch {
+ case build.IsLocalImport(m.Pattern) || filepath.IsAbs(m.Pattern):
+ // Evaluate list of file system directories on first iteration.
+ if fsDirs[i] == nil {
+ var dirs []string
+ if m.Literal {
+ dirs = []string{m.Pattern}
+ } else {
+ dirs = search.MatchPackagesInFS(m.Pattern).Pkgs
+ }
+ fsDirs[i] = dirs
+ }
+
+ // Make a copy of the directory list and translate to import paths.
+ // Note that whether a directory corresponds to an import path
+ // changes as the build list is updated, and a directory can change
+ // from not being in the build list to being in it and back as
+ // the exact version of a particular module increases during
+ // the loader iterations.
+ m.Pkgs = str.StringList(fsDirs[i])
+ for i, pkg := range m.Pkgs {
+ dir := pkg
+ if !filepath.IsAbs(dir) {
+ dir = filepath.Join(cwd, pkg)
+ } else {
+ dir = filepath.Clean(dir)
+ }
+
+ // Note: The checks for @ here are just to avoid misinterpreting
+ // the module cache directories (formerly GOPATH/src/mod/foo@v1.5.2/bar).
+ // It's not strictly necessary but helpful to keep the checks.
+ if dir == ModRoot {
+ pkg = Target.Path
+ } else if strings.HasPrefix(dir, ModRoot+string(filepath.Separator)) && !strings.Contains(dir[len(ModRoot):], "@") {
+ suffix := filepath.ToSlash(dir[len(ModRoot):])
+ if strings.HasPrefix(suffix, "/vendor/") {
+ // TODO getmode vendor check
+ pkg = strings.TrimPrefix(suffix, "/vendor/")
+ } else {
+ pkg = Target.Path + suffix
+ }
+ } else if sub := search.InDir(dir, cfg.GOROOTsrc); sub != "" && !strings.Contains(sub, "@") {
+ pkg = filepath.ToSlash(sub)
+ } else if path := pathInModuleCache(dir); path != "" {
+ pkg = path
+ } else {
+ pkg = ""
+ if !iterating {
+ base.Errorf("go: directory %s outside available modules", base.ShortPath(dir))
+ }
+ }
+ info, err := os.Stat(dir)
+ if err != nil || !info.IsDir() {
+ // If the directory does not exist,
+ // don't turn it into an import path
+ // that will trigger a lookup.
+ pkg = ""
+ if !iterating {
+ if err != nil {
+ base.Errorf("go: no such directory %v", m.Pattern)
+ } else {
+ base.Errorf("go: %s is not a directory", m.Pattern)
+ }
+ }
+ }
+ m.Pkgs[i] = pkg
+ }
+
+ case strings.Contains(m.Pattern, "..."):
+ m.Pkgs = matchPackages(m.Pattern, loaded.tags, true, buildList)
+
+ case m.Pattern == "all":
+ loaded.testAll = true
+ if iterating {
+ // Enumerate the packages in the main module.
+ // We'll load the dependencies as we find them.
+ m.Pkgs = matchPackages("...", loaded.tags, false, []module.Version{Target})
+ } else {
+ // Starting with the packages in the main module,
+ // enumerate the full list of "all".
+ m.Pkgs = loaded.computePatternAll(m.Pkgs)
+ }
+
+ case search.IsMetaPackage(m.Pattern): // std, cmd
+ if len(m.Pkgs) == 0 {
+ m.Pkgs = search.MatchPackages(m.Pattern).Pkgs
+ }
+ }
+ }
+ }
+
+ loaded.load(func() []string {
+ var roots []string
+ updateMatches(true)
+ for _, m := range matches {
+ for _, pkg := range m.Pkgs {
+ if pkg != "" {
+ roots = append(roots, pkg)
+ }
+ }
+ }
+ return roots
+ })
+
+ // One last pass to finalize wildcards.
+ updateMatches(false)
+
+ // A given module path may be used as itself or as a replacement for another
+ // module, but not both at the same time. Otherwise, the aliasing behavior is
+ // too subtle (see https://golang.org/issue/26607), and we don't want to
+ // commit to a specific behavior at this point.
+ firstPath := make(map[module.Version]string, len(buildList))
+ for _, mod := range buildList {
+ src := mod
+ if rep := Replacement(mod); rep.Path != "" {
+ src = rep
+ }
+ if prev, ok := firstPath[src]; !ok {
+ firstPath[src] = mod.Path
+ } else if prev != mod.Path {
+ base.Errorf("go: %s@%s used for two different module paths (%s and %s)", src.Path, src.Version, prev, mod.Path)
+ }
+ }
+ base.ExitIfErrors()
+ WriteGoMod()
+
+ search.WarnUnmatched(matches)
+ return matches
+}
+
+// pathInModuleCache returns the import path of the directory dir,
+// if dir is in the module cache copy of a module in our build list.
+func pathInModuleCache(dir string) string {
+ for _, m := range buildList[1:] {
+ root, err := modfetch.DownloadDir(m)
+ if err != nil {
+ continue
+ }
+ if sub := search.InDir(dir, root); sub != "" {
+ sub = filepath.ToSlash(sub)
+ if !strings.Contains(sub, "/vendor/") && !strings.HasPrefix(sub, "vendor/") && !strings.Contains(sub, "@") {
+ return path.Join(m.Path, filepath.ToSlash(sub))
+ }
+ }
+ }
+ return ""
+}
+
+// warnPattern returns list, the result of matching pattern,
+// but if list is empty then first it prints a warning about
+// the pattern not matching any packages.
+func warnPattern(pattern string, list []string) []string {
+ if len(list) == 0 {
+ fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
+ }
+ return list
+}
+
+// ImportFromFiles adds modules to the build list as needed
+// to satisfy the imports in the named Go source files.
+func ImportFromFiles(gofiles []string) {
+ InitMod()
+
+ imports, testImports, err := imports.ScanFiles(gofiles, imports.Tags())
+ if err != nil {
+ base.Fatalf("go: %v", err)
+ }
+
+ loaded = newLoader()
+ loaded.load(func() []string {
+ var roots []string
+ roots = append(roots, imports...)
+ roots = append(roots, testImports...)
+ return roots
+ })
+ WriteGoMod()
+}
+
+// DirImportPath returns the effective import path for dir,
+// provided it is within the main module, or else returns ".".
+func DirImportPath(dir string) string {
+ if !filepath.IsAbs(dir) {
+ dir = filepath.Join(cwd, dir)
+ } else {
+ dir = filepath.Clean(dir)
+ }
+
+ if dir == ModRoot {
+ return Target.Path
+ }
+ if strings.HasPrefix(dir, ModRoot+string(filepath.Separator)) {
+ suffix := filepath.ToSlash(dir[len(ModRoot):])
+ if strings.HasPrefix(suffix, "/vendor/") {
+ return strings.TrimPrefix(suffix, "/vendor/")
+ }
+ return Target.Path + suffix
+ }
+ return "."
+}
+
+// LoadBuildList loads and returns the build list from go.mod.
+// The loading of the build list happens automatically in ImportPaths:
+// LoadBuildList need only be called if ImportPaths is not
+// (typically in commands that care about the module but
+// no particular package).
+func LoadBuildList() []module.Version {
+ InitMod()
+ ReloadBuildList()
+ WriteGoMod()
+ return buildList
+}
+
+func ReloadBuildList() []module.Version {
+ loaded = newLoader()
+ loaded.load(func() []string { return nil })
+ return buildList
+}
+
+// LoadALL returns the set of all packages in the current module
+// and their dependencies in any other modules, without filtering
+// due to build tags, except "+build ignore".
+// It adds modules to the build list as needed to satisfy new imports.
+// This set is useful for deciding whether a particular import is needed
+// anywhere in a module.
+func LoadALL() []string {
+ return loadAll(true)
+}
+
+// LoadVendor is like LoadALL but only follows test dependencies
+// for tests in the main module. Tests in dependency modules are
+// ignored completely.
+// This set is useful for identifying the which packages to include in a vendor directory.
+func LoadVendor() []string {
+ return loadAll(false)
+}
+
+func loadAll(testAll bool) []string {
+ InitMod()
+
+ loaded = newLoader()
+ loaded.isALL = true
+ loaded.tags = anyTags
+ loaded.testAll = testAll
+ if !testAll {
+ loaded.testRoots = true
+ }
+ all := TargetPackages()
+ loaded.load(func() []string { return all })
+ WriteGoMod()
+
+ var paths []string
+ for _, pkg := range loaded.pkgs {
+ if e, ok := pkg.err.(*ImportMissingError); ok && e.Module.Path == "" {
+ continue // Package doesn't actually exist.
+ }
+ paths = append(paths, pkg.path)
+ }
+ return paths
+}
+
+// anyTags is a special tags map that satisfies nearly all build tag expressions.
+// Only "ignore" and malformed build tag requirements are considered false.
+var anyTags = map[string]bool{"*": true}
+
+// TargetPackages returns the list of packages in the target (top-level) module,
+// under all build tag settings.
+func TargetPackages() []string {
+ return matchPackages("...", anyTags, false, []module.Version{Target})
+}
+
+// BuildList returns the module build list,
+// typically constructed by a previous call to
+// LoadBuildList or ImportPaths.
+// The caller must not modify the returned list.
+func BuildList() []module.Version {
+ return buildList
+}
+
+// SetBuildList sets the module build list.
+// The caller is responsible for ensuring that the list is valid.
+// SetBuildList does not retain a reference to the original list.
+func SetBuildList(list []module.Version) {
+ buildList = append([]module.Version{}, list...)
+}
+
+// ImportMap returns the actual package import path
+// for an import path found in source code.
+// If the given import path does not appear in the source code
+// for the packages that have been loaded, ImportMap returns the empty string.
+func ImportMap(path string) string {
+ pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
+ if !ok {
+ return ""
+ }
+ return pkg.path
+}
+
+// PackageDir returns the directory containing the source code
+// for the package named by the import path.
+func PackageDir(path string) string {
+ pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
+ if !ok {
+ return ""
+ }
+ return pkg.dir
+}
+
+// PackageModule returns the module providing the package named by the import path.
+func PackageModule(path string) module.Version {
+ pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
+ if !ok {
+ return module.Version{}
+ }
+ return pkg.mod
+}
+
+// ModuleUsedDirectly reports whether the main module directly imports
+// some package in the module with the given path.
+func ModuleUsedDirectly(path string) bool {
+ return loaded.direct[path]
+}
+
+// Lookup returns the source directory, import path, and any loading error for
+// the package at path.
+// Lookup requires that one of the Load functions in this package has already
+// been called.
+func Lookup(path string) (dir, realPath string, err error) {
+ pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
+ if !ok {
+ // The loader should have found all the relevant paths.
+ // There are a few exceptions, though:
+ // - during go list without -test, the p.Resolve calls to process p.TestImports and p.XTestImports
+ // end up here to canonicalize the import paths.
+ // - during any load, non-loaded packages like "unsafe" end up here.
+ // - during any load, build-injected dependencies like "runtime/cgo" end up here.
+ // - because we ignore appengine/* in the module loader,
+ // the dependencies of any actual appengine/* library end up here.
+ dir := findStandardImportPath(path)
+ if dir != "" {
+ return dir, path, nil
+ }
+ return "", "", errMissing
+ }
+ return pkg.dir, pkg.path, pkg.err
+}
+
+// A loader manages the process of loading information about
+// the required packages for a particular build,
+// checking that the packages are available in the module set,
+// and updating the module set if needed.
+// Loading is an iterative process: try to load all the needed packages,
+// but if imports are missing, try to resolve those imports, and repeat.
+//
+// Although most of the loading state is maintained in the loader struct,
+// one key piece - the build list - is a global, so that it can be modified
+// separate from the loading operation, such as during "go get"
+// upgrades/downgrades or in "go mod" operations.
+// TODO(rsc): It might be nice to make the loader take and return
+// a buildList rather than hard-coding use of the global.
+type loader struct {
+ tags map[string]bool // tags for scanDir
+ testRoots bool // include tests for roots
+ isALL bool // created with LoadALL
+ testAll bool // include tests for all packages
+
+ // reset on each iteration
+ roots []*loadPkg
+ pkgs []*loadPkg
+ work *par.Work // current work queue
+ pkgCache *par.Cache // map from string to *loadPkg
+
+ // computed at end of iterations
+ direct map[string]bool // imported directly by main module
+ goVersion map[string]string // go version recorded in each module
+}
+
+// LoadTests controls whether the loaders load tests of the root packages.
+var LoadTests bool
+
+func newLoader() *loader {
+ ld := new(loader)
+ ld.tags = imports.Tags()
+ ld.testRoots = LoadTests
+ return ld
+}
+
+func (ld *loader) reset() {
+ ld.roots = nil
+ ld.pkgs = nil
+ ld.work = new(par.Work)
+ ld.pkgCache = new(par.Cache)
+}
+
+// A loadPkg records information about a single loaded package.
+type loadPkg struct {
+ path string // import path
+ mod module.Version // module providing package
+ dir string // directory containing source code
+ imports []*loadPkg // packages imported by this one
+ err error // error loading package
+ stack *loadPkg // package importing this one in minimal import stack for this pkg
+ test *loadPkg // package with test imports, if we need test
+ testOf *loadPkg
+ testImports []string // test-only imports, saved for use by pkg.test.
+}
+
+var errMissing = errors.New("cannot find package")
+
+// load attempts to load the build graph needed to process a set of root packages.
+// The set of root packages is defined by the addRoots function,
+// which must call add(path) with the import path of each root package.
+func (ld *loader) load(roots func() []string) {
+ var err error
+ reqs := Reqs()
+ buildList, err = mvs.BuildList(Target, reqs)
+ if err != nil {
+ base.Fatalf("go: %v", err)
+ }
+
+ added := make(map[string]bool)
+ for {
+ ld.reset()
+ if roots != nil {
+ // Note: the returned roots can change on each iteration,
+ // since the expansion of package patterns depends on the
+ // build list we're using.
+ for _, path := range roots() {
+ ld.work.Add(ld.pkg(path, true))
+ }
+ }
+ ld.work.Do(10, ld.doPkg)
+ ld.buildStacks()
+ numAdded := 0
+ haveMod := make(map[module.Version]bool)
+ for _, m := range buildList {
+ haveMod[m] = true
+ }
+ for _, pkg := range ld.pkgs {
+ if err, ok := pkg.err.(*ImportMissingError); ok && err.Module.Path != "" {
+ if added[pkg.path] {
+ base.Fatalf("go: %s: looping trying to add package", pkg.stackText())
+ }
+ added[pkg.path] = true
+ numAdded++
+ if !haveMod[err.Module] {
+ haveMod[err.Module] = true
+ buildList = append(buildList, err.Module)
+ }
+ continue
+ }
+ // Leave other errors for Import or load.Packages to report.
+ }
+ base.ExitIfErrors()
+ if numAdded == 0 {
+ break
+ }
+
+ // Recompute buildList with all our additions.
+ reqs = Reqs()
+ buildList, err = mvs.BuildList(Target, reqs)
+ if err != nil {
+ base.Fatalf("go: %v", err)
+ }
+ }
+ base.ExitIfErrors()
+
+ // Compute directly referenced dependency modules.
+ ld.direct = make(map[string]bool)
+ for _, pkg := range ld.pkgs {
+ if pkg.mod == Target {
+ for _, dep := range pkg.imports {
+ if dep.mod.Path != "" {
+ ld.direct[dep.mod.Path] = true
+ }
+ }
+ }
+ }
+
+ // Add Go versions, computed during walk.
+ ld.goVersion = make(map[string]string)
+ for _, m := range buildList {
+ v, _ := reqs.(*mvsReqs).versions.Load(m)
+ ld.goVersion[m.Path], _ = v.(string)
+ }
+
+ // Mix in direct markings (really, lack of indirect markings)
+ // from go.mod, unless we scanned the whole module
+ // and can therefore be sure we know better than go.mod.
+ if !ld.isALL && modFile != nil {
+ for _, r := range modFile.Require {
+ if !r.Indirect {
+ ld.direct[r.Mod.Path] = true
+ }
+ }
+ }
+}
+
+// pkg returns the *loadPkg for path, creating and queuing it if needed.
+// If the package should be tested, its test is created but not queued
+// (the test is queued after processing pkg).
+// If isRoot is true, the pkg is being queued as one of the roots of the work graph.
+func (ld *loader) pkg(path string, isRoot bool) *loadPkg {
+ return ld.pkgCache.Do(path, func() interface{} {
+ pkg := &loadPkg{
+ path: path,
+ }
+ if ld.testRoots && isRoot || ld.testAll {
+ test := &loadPkg{
+ path: path,
+ testOf: pkg,
+ }
+ pkg.test = test
+ }
+ if isRoot {
+ ld.roots = append(ld.roots, pkg)
+ }
+ ld.work.Add(pkg)
+ return pkg
+ }).(*loadPkg)
+}
+
+// doPkg processes a package on the work queue.
+func (ld *loader) doPkg(item interface{}) {
+ // TODO: what about replacements?
+ pkg := item.(*loadPkg)
+ var imports []string
+ if pkg.testOf != nil {
+ pkg.dir = pkg.testOf.dir
+ pkg.mod = pkg.testOf.mod
+ imports = pkg.testOf.testImports
+ } else {
+ if strings.Contains(pkg.path, "@") {
+ // Leave for error during load.
+ return
+ }
+ if build.IsLocalImport(pkg.path) {
+ // Leave for error during load.
+ // (Module mode does not allow local imports.)
+ return
+ }
+
+ pkg.mod, pkg.dir, pkg.err = Import(pkg.path)
+ if pkg.dir == "" {
+ return
+ }
+ if cfg.BuildContext.Compiler == "gccgo" && pkg.mod.Path == "" {
+ return
+ }
+
+ var testImports []string
+ var err error
+ imports, testImports, err = scanDir(pkg.dir, ld.tags)
+ if err != nil {
+ pkg.err = err
+ return
+ }
+ if pkg.test != nil {
+ pkg.testImports = testImports
+ }
+ }
+
+ for _, path := range imports {
+ pkg.imports = append(pkg.imports, ld.pkg(path, false))
+ }
+
+ // Now that pkg.dir, pkg.mod, pkg.testImports are set, we can queue pkg.test.
+ // TODO: All that's left is creating new imports. Why not just do it now?
+ if pkg.test != nil {
+ ld.work.Add(pkg.test)
+ }
+}
+
+// computePatternAll returns the list of packages matching pattern "all",
+// starting with a list of the import paths for the packages in the main module.
+func (ld *loader) computePatternAll(paths []string) []string {
+ seen := make(map[*loadPkg]bool)
+ var all []string
+ var walk func(*loadPkg)
+ walk = func(pkg *loadPkg) {
+ if seen[pkg] {
+ return
+ }
+ seen[pkg] = true
+ if pkg.testOf == nil {
+ all = append(all, pkg.path)
+ }
+ for _, p := range pkg.imports {
+ walk(p)
+ }
+ if p := pkg.test; p != nil {
+ walk(p)
+ }
+ }
+ for _, path := range paths {
+ walk(ld.pkg(path, false))
+ }
+ sort.Strings(all)
+
+ return all
+}
+
+// scanDir is like imports.ScanDir but elides known magic imports from the list,
+// so that we do not go looking for packages that don't really exist.
+//
+// The standard magic import is "C", for cgo.
+//
+// The only other known magic imports are appengine and appengine/*.
+// These are so old that they predate "go get" and did not use URL-like paths.
+// Most code today now uses google.golang.org/appengine instead,
+// but not all code has been so updated. When we mostly ignore build tags
+// during "go vendor", we look into "// +build appengine" files and
+// may see these legacy imports. We drop them so that the module
+// search does not look for modules to try to satisfy them.
+func scanDir(dir string, tags map[string]bool) (imports_, testImports []string, err error) {
+ imports_, testImports, err = imports.ScanDir(dir, tags)
+
+ filter := func(x []string) []string {
+ w := 0
+ for _, pkg := range x {
+ if pkg != "C" && pkg != "appengine" && !strings.HasPrefix(pkg, "appengine/") &&
+ pkg != "appengine_internal" && !strings.HasPrefix(pkg, "appengine_internal/") {
+ x[w] = pkg
+ w++
+ }
+ }
+ return x[:w]
+ }
+
+ return filter(imports_), filter(testImports), err
+}
+
+// buildStacks computes minimal import stacks for each package,
+// for use in error messages. When it completes, packages that
+// are part of the original root set have pkg.stack == nil,
+// and other packages have pkg.stack pointing at the next
+// package up the import stack in their minimal chain.
+// As a side effect, buildStacks also constructs ld.pkgs,
+// the list of all packages loaded.
+func (ld *loader) buildStacks() {
+ if len(ld.pkgs) > 0 {
+ panic("buildStacks")
+ }
+ for _, pkg := range ld.roots {
+ pkg.stack = pkg // sentinel to avoid processing in next loop
+ ld.pkgs = append(ld.pkgs, pkg)
+ }
+ for i := 0; i < len(ld.pkgs); i++ { // not range: appending to ld.pkgs in loop
+ pkg := ld.pkgs[i]
+ for _, next := range pkg.imports {
+ if next.stack == nil {
+ next.stack = pkg
+ ld.pkgs = append(ld.pkgs, next)
+ }
+ }
+ if next := pkg.test; next != nil && next.stack == nil {
+ next.stack = pkg
+ ld.pkgs = append(ld.pkgs, next)
+ }
+ }
+ for _, pkg := range ld.roots {
+ pkg.stack = nil
+ }
+}
+
+// stackText builds the import stack text to use when
+// reporting an error in pkg. It has the general form
+//
+// import root ->
+// import other ->
+// import other2 ->
+// import pkg
+//
+func (pkg *loadPkg) stackText() string {
+ var stack []*loadPkg
+ for p := pkg.stack; p != nil; p = p.stack {
+ stack = append(stack, p)
+ }
+
+ var buf bytes.Buffer
+ for i := len(stack) - 1; i >= 0; i-- {
+ p := stack[i]
+ if p.testOf != nil {
+ fmt.Fprintf(&buf, "test ->\n\t")
+ } else {
+ fmt.Fprintf(&buf, "import %q ->\n\t", p.path)
+ }
+ }
+ fmt.Fprintf(&buf, "import %q", pkg.path)
+ return buf.String()
+}
+
+// why returns the text to use in "go mod why" output about the given package.
+// It is less ornate than the stackText but conatins the same information.
+func (pkg *loadPkg) why() string {
+ var buf strings.Builder
+ var stack []*loadPkg
+ for p := pkg; p != nil; p = p.stack {
+ stack = append(stack, p)
+ }
+
+ for i := len(stack) - 1; i >= 0; i-- {
+ p := stack[i]
+ if p.testOf != nil {
+ fmt.Fprintf(&buf, "%s.test\n", p.testOf.path)
+ } else {
+ fmt.Fprintf(&buf, "%s\n", p.path)
+ }
+ }
+ return buf.String()
+}
+
+// Why returns the "go mod why" output stanza for the given package,
+// without the leading # comment.
+// The package graph must have been loaded already, usually by LoadALL.
+// If there is no reason for the package to be in the current build,
+// Why returns an empty string.
+func Why(path string) string {
+ pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
+ if !ok {
+ return ""
+ }
+ return pkg.why()
+}
+
+// WhyDepth returns the number of steps in the Why listing.
+// If there is no reason for the package to be in the current build,
+// WhyDepth returns 0.
+func WhyDepth(path string) int {
+ n := 0
+ pkg, _ := loaded.pkgCache.Get(path).(*loadPkg)
+ for p := pkg; p != nil; p = p.stack {
+ n++
+ }
+ return n
+}
+
+// Replacement returns the replacement for mod, if any, from go.mod.
+// If there is no replacement for mod, Replacement returns
+// a module.Version with Path == "".
+func Replacement(mod module.Version) module.Version {
+ if modFile == nil {
+ // Happens during testing.
+ return module.Version{}
+ }
+
+ var found *modfile.Replace
+ for _, r := range modFile.Replace {
+ if r.Old.Path == mod.Path && (r.Old.Version == "" || r.Old.Version == mod.Version) {
+ found = r // keep going
+ }
+ }
+ if found == nil {
+ return module.Version{}
+ }
+ return found.New
+}
+
+// mvsReqs implements mvs.Reqs for module semantic versions,
+// with any exclusions or replacements applied internally.
+type mvsReqs struct {
+ buildList []module.Version
+ cache par.Cache
+ versions sync.Map
+}
+
+// Reqs returns the current module requirement graph.
+// Future calls to SetBuildList do not affect the operation
+// of the returned Reqs.
+func Reqs() mvs.Reqs {
+ r := &mvsReqs{
+ buildList: buildList,
+ }
+ return r
+}
+
+func (r *mvsReqs) Required(mod module.Version) ([]module.Version, error) {
+ type cached struct {
+ list []module.Version
+ err error
+ }
+
+ c := r.cache.Do(mod, func() interface{} {
+ list, err := r.required(mod)
+ if err != nil {
+ return cached{nil, err}
+ }
+ for i, mv := range list {
+ for excluded[mv] {
+ mv1, err := r.next(mv)
+ if err != nil {
+ return cached{nil, err}
+ }
+ if mv1.Version == "none" {
+ return cached{nil, fmt.Errorf("%s(%s) depends on excluded %s(%s) with no newer version available", mod.Path, mod.Version, mv.Path, mv.Version)}
+ }
+ mv = mv1
+ }
+ list[i] = mv
+ }
+
+ return cached{list, nil}
+ }).(cached)
+
+ return c.list, c.err
+}
+
+var vendorOnce sync.Once
+
+var (
+ vendorList []module.Version
+ vendorMap map[string]module.Version
+)
+
+// readVendorList reads the list of vendored modules from vendor/modules.txt.
+func readVendorList() {
+ vendorOnce.Do(func() {
+ vendorList = nil
+ vendorMap = make(map[string]module.Version)
+ data, _ := ioutil.ReadFile(filepath.Join(ModRoot, "vendor/modules.txt"))
+ var m module.Version
+ for _, line := range strings.Split(string(data), "\n") {
+ if strings.HasPrefix(line, "# ") {
+ f := strings.Fields(line)
+ m = module.Version{}
+ if len(f) == 3 && semver.IsValid(f[2]) {
+ m = module.Version{Path: f[1], Version: f[2]}
+ vendorList = append(vendorList, m)
+ }
+ } else if m.Path != "" {
+ f := strings.Fields(line)
+ if len(f) == 1 {
+ vendorMap[f[0]] = m
+ }
+ }
+ }
+ })
+}
+
+func (r *mvsReqs) modFileToList(f *modfile.File) []module.Version {
+ var list []module.Version
+ for _, r := range f.Require {
+ list = append(list, r.Mod)
+ }
+ return list
+}
+
+func (r *mvsReqs) required(mod module.Version) ([]module.Version, error) {
+ if mod == Target {
+ if modFile.Go != nil {
+ r.versions.LoadOrStore(mod, modFile.Go.Version)
+ }
+ var list []module.Version
+ return append(list, r.buildList[1:]...), nil
+ }
+
+ if cfg.BuildMod == "vendor" {
+ // For every module other than the target,
+ // return the full list of modules from modules.txt.
+ readVendorList()
+ return vendorList, nil
+ }
+
+ origPath := mod.Path
+ if repl := Replacement(mod); repl.Path != "" {
+ if repl.Version == "" {
+ // TODO: need to slip the new version into the tags list etc.
+ dir := repl.Path
+ if !filepath.IsAbs(dir) {
+ dir = filepath.Join(ModRoot, dir)
+ }
+ gomod := filepath.Join(dir, "go.mod")
+ data, err := ioutil.ReadFile(gomod)
+ if err != nil {
+ base.Errorf("go: parsing %s: %v", base.ShortPath(gomod), err)
+ return nil, ErrRequire
+ }
+ f, err := modfile.ParseLax(gomod, data, nil)
+ if err != nil {
+ base.Errorf("go: parsing %s: %v", base.ShortPath(gomod), err)
+ return nil, ErrRequire
+ }
+ if f.Go != nil {
+ r.versions.LoadOrStore(mod, f.Go.Version)
+ }
+ return r.modFileToList(f), nil
+ }
+ mod = repl
+ }
+
+ if mod.Version == "none" {
+ return nil, nil
+ }
+
+ if !semver.IsValid(mod.Version) {
+ // Disallow the broader queries supported by fetch.Lookup.
+ base.Fatalf("go: internal error: %s@%s: unexpected invalid semantic version", mod.Path, mod.Version)
+ }
+
+ data, err := modfetch.GoMod(mod.Path, mod.Version)
+ if err != nil {
+ base.Errorf("go: %s@%s: %v\n", mod.Path, mod.Version, err)
+ return nil, ErrRequire
+ }
+ f, err := modfile.ParseLax("go.mod", data, nil)
+ if err != nil {
+ base.Errorf("go: %s@%s: parsing go.mod: %v", mod.Path, mod.Version, err)
+ return nil, ErrRequire
+ }
+
+ if f.Module == nil {
+ base.Errorf("go: %s@%s: parsing go.mod: missing module line", mod.Path, mod.Version)
+ return nil, ErrRequire
+ }
+ if mpath := f.Module.Mod.Path; mpath != origPath && mpath != mod.Path {
+ base.Errorf("go: %s@%s: parsing go.mod: unexpected module path %q", mod.Path, mod.Version, mpath)
+ return nil, ErrRequire
+ }
+ if f.Go != nil {
+ r.versions.LoadOrStore(mod, f.Go.Version)
+ }
+
+ return r.modFileToList(f), nil
+}
+
+// ErrRequire is the sentinel error returned when Require encounters problems.
+// It prints the problems directly to standard error, so that multiple errors
+// can be displayed easily.
+var ErrRequire = errors.New("error loading module requirements")
+
+func (*mvsReqs) Max(v1, v2 string) string {
+ if v1 != "" && semver.Compare(v1, v2) == -1 {
+ return v2
+ }
+ return v1
+}
+
+// Upgrade is a no-op, here to implement mvs.Reqs.
+// The upgrade logic for go get -u is in ../modget/get.go.
+func (*mvsReqs) Upgrade(m module.Version) (module.Version, error) {
+ return m, nil
+}
+
+func versions(path string) ([]string, error) {
+ // Note: modfetch.Lookup and repo.Versions are cached,
+ // so there's no need for us to add extra caching here.
+ repo, err := modfetch.Lookup(path)
+ if err != nil {
+ return nil, err
+ }
+ return repo.Versions("")
+}
+
+// Previous returns the tagged version of m.Path immediately prior to
+// m.Version, or version "none" if no prior version is tagged.
+func (*mvsReqs) Previous(m module.Version) (module.Version, error) {
+ list, err := versions(m.Path)
+ if err != nil {
+ return module.Version{}, err
+ }
+ i := sort.Search(len(list), func(i int) bool { return semver.Compare(list[i], m.Version) >= 0 })
+ if i > 0 {
+ return module.Version{Path: m.Path, Version: list[i-1]}, nil
+ }
+ return module.Version{Path: m.Path, Version: "none"}, nil
+}
+
+// next returns the next version of m.Path after m.Version.
+// It is only used by the exclusion processing in the Required method,
+// not called directly by MVS.
+func (*mvsReqs) next(m module.Version) (module.Version, error) {
+ list, err := versions(m.Path)
+ if err != nil {
+ return module.Version{}, err
+ }
+ i := sort.Search(len(list), func(i int) bool { return semver.Compare(list[i], m.Version) > 0 })
+ if i < len(list) {
+ return module.Version{Path: m.Path, Version: list[i]}, nil
+ }
+ return module.Version{Path: m.Path, Version: "none"}, nil
+}
+
+func fetch(mod module.Version) (dir string, isLocal bool, err error) {
+ if mod == Target {
+ return ModRoot, true, nil
+ }
+ if r := Replacement(mod); r.Path != "" {
+ if r.Version == "" {
+ dir = r.Path
+ if !filepath.IsAbs(dir) {
+ dir = filepath.Join(ModRoot, dir)
+ }
+ return dir, true, nil
+ }
+ mod = r
+ }
+
+ dir, err = modfetch.Download(mod)
+ return dir, false, err
+}
diff --git a/libgo/go/cmd/go/internal/modload/query.go b/libgo/go/cmd/go/internal/modload/query.go
new file mode 100644
index 00000000000..3b550f1db7f
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modload/query.go
@@ -0,0 +1,249 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modload
+
+import (
+ "cmd/go/internal/modfetch"
+ "cmd/go/internal/modfetch/codehost"
+ "cmd/go/internal/module"
+ "cmd/go/internal/semver"
+ "fmt"
+ pathpkg "path"
+ "strings"
+)
+
+// Query looks up a revision of a given module given a version query string.
+// The module must be a complete module path.
+// The version must take one of the following forms:
+//
+// - the literal string "latest", denoting the latest available, allowed tagged version,
+// with non-prereleases preferred over prereleases.
+// If there are no tagged versions in the repo, latest returns the most recent commit.
+// - v1, denoting the latest available tagged version v1.x.x.
+// - v1.2, denoting the latest available tagged version v1.2.x.
+// - v1.2.3, a semantic version string denoting that tagged version.
+// - <v1.2.3, <=v1.2.3, >v1.2.3, >=v1.2.3,
+// denoting the version closest to the target and satisfying the given operator,
+// with non-prereleases preferred over prereleases.
+// - a repository commit identifier, denoting that commit.
+//
+// If the allowed function is non-nil, Query excludes any versions for which allowed returns false.
+//
+// If path is the path of the main module and the query is "latest",
+// Query returns Target.Version as the version.
+func Query(path, query string, allowed func(module.Version) bool) (*modfetch.RevInfo, error) {
+ if allowed == nil {
+ allowed = func(module.Version) bool { return true }
+ }
+
+ // Parse query to detect parse errors (and possibly handle query)
+ // before any network I/O.
+ badVersion := func(v string) (*modfetch.RevInfo, error) {
+ return nil, fmt.Errorf("invalid semantic version %q in range %q", v, query)
+ }
+ var ok func(module.Version) bool
+ var prefix string
+ var preferOlder bool
+ switch {
+ case query == "latest":
+ ok = allowed
+
+ case strings.HasPrefix(query, "<="):
+ v := query[len("<="):]
+ if !semver.IsValid(v) {
+ return badVersion(v)
+ }
+ if isSemverPrefix(v) {
+ // Refuse to say whether <=v1.2 allows v1.2.3 (remember, @v1.2 might mean v1.2.3).
+ return nil, fmt.Errorf("ambiguous semantic version %q in range %q", v, query)
+ }
+ ok = func(m module.Version) bool {
+ return semver.Compare(m.Version, v) <= 0 && allowed(m)
+ }
+
+ case strings.HasPrefix(query, "<"):
+ v := query[len("<"):]
+ if !semver.IsValid(v) {
+ return badVersion(v)
+ }
+ ok = func(m module.Version) bool {
+ return semver.Compare(m.Version, v) < 0 && allowed(m)
+ }
+
+ case strings.HasPrefix(query, ">="):
+ v := query[len(">="):]
+ if !semver.IsValid(v) {
+ return badVersion(v)
+ }
+ ok = func(m module.Version) bool {
+ return semver.Compare(m.Version, v) >= 0 && allowed(m)
+ }
+ preferOlder = true
+
+ case strings.HasPrefix(query, ">"):
+ v := query[len(">"):]
+ if !semver.IsValid(v) {
+ return badVersion(v)
+ }
+ if isSemverPrefix(v) {
+ // Refuse to say whether >v1.2 allows v1.2.3 (remember, @v1.2 might mean v1.2.3).
+ return nil, fmt.Errorf("ambiguous semantic version %q in range %q", v, query)
+ }
+ ok = func(m module.Version) bool {
+ return semver.Compare(m.Version, v) > 0 && allowed(m)
+ }
+ preferOlder = true
+
+ case semver.IsValid(query) && isSemverPrefix(query):
+ ok = func(m module.Version) bool {
+ return matchSemverPrefix(query, m.Version) && allowed(m)
+ }
+ prefix = query + "."
+
+ case semver.IsValid(query):
+ vers := module.CanonicalVersion(query)
+ if !allowed(module.Version{Path: path, Version: vers}) {
+ return nil, fmt.Errorf("%s@%s excluded", path, vers)
+ }
+ return modfetch.Stat(path, vers)
+
+ default:
+ // Direct lookup of semantic version or commit identifier.
+ info, err := modfetch.Stat(path, query)
+ if err != nil {
+ return nil, err
+ }
+ if !allowed(module.Version{Path: path, Version: info.Version}) {
+ return nil, fmt.Errorf("%s@%s excluded", path, info.Version)
+ }
+ return info, nil
+ }
+
+ if path == Target.Path {
+ if query != "latest" {
+ return nil, fmt.Errorf("can't query specific version (%q) for the main module (%s)", query, path)
+ }
+ if !allowed(Target) {
+ return nil, fmt.Errorf("internal error: main module version is not allowed")
+ }
+ return &modfetch.RevInfo{Version: Target.Version}, nil
+ }
+
+ // Load versions and execute query.
+ repo, err := modfetch.Lookup(path)
+ if err != nil {
+ return nil, err
+ }
+ versions, err := repo.Versions(prefix)
+ if err != nil {
+ return nil, err
+ }
+
+ if preferOlder {
+ for _, v := range versions {
+ if semver.Prerelease(v) == "" && ok(module.Version{Path: path, Version: v}) {
+ return repo.Stat(v)
+ }
+ }
+ for _, v := range versions {
+ if semver.Prerelease(v) != "" && ok(module.Version{Path: path, Version: v}) {
+ return repo.Stat(v)
+ }
+ }
+ } else {
+ for i := len(versions) - 1; i >= 0; i-- {
+ v := versions[i]
+ if semver.Prerelease(v) == "" && ok(module.Version{Path: path, Version: v}) {
+ return repo.Stat(v)
+ }
+ }
+ for i := len(versions) - 1; i >= 0; i-- {
+ v := versions[i]
+ if semver.Prerelease(v) != "" && ok(module.Version{Path: path, Version: v}) {
+ return repo.Stat(v)
+ }
+ }
+ }
+
+ if query == "latest" {
+ // Special case for "latest": if no tags match, use latest commit in repo,
+ // provided it is not excluded.
+ if info, err := repo.Latest(); err == nil && allowed(module.Version{Path: path, Version: info.Version}) {
+ return info, nil
+ }
+ }
+
+ return nil, fmt.Errorf("no matching versions for query %q", query)
+}
+
+// isSemverPrefix reports whether v is a semantic version prefix: v1 or v1.2 (not v1.2.3).
+// The caller is assumed to have checked that semver.IsValid(v) is true.
+func isSemverPrefix(v string) bool {
+ dots := 0
+ for i := 0; i < len(v); i++ {
+ switch v[i] {
+ case '-', '+':
+ return false
+ case '.':
+ dots++
+ if dots >= 2 {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// matchSemverPrefix reports whether the shortened semantic version p
+// matches the full-width (non-shortened) semantic version v.
+func matchSemverPrefix(p, v string) bool {
+ return len(v) > len(p) && v[len(p)] == '.' && v[:len(p)] == p
+}
+
+// QueryPackage looks up a revision of a module containing path.
+//
+// If multiple modules with revisions matching the query provide the requested
+// package, QueryPackage picks the one with the longest module path.
+//
+// If the path is in the the main module and the query is "latest",
+// QueryPackage returns Target as the version.
+func QueryPackage(path, query string, allowed func(module.Version) bool) (module.Version, *modfetch.RevInfo, error) {
+ if _, ok := dirInModule(path, Target.Path, ModRoot, true); ok {
+ if query != "latest" {
+ return module.Version{}, nil, fmt.Errorf("can't query specific version (%q) for package %s in the main module (%s)", query, path, Target.Path)
+ }
+ if !allowed(Target) {
+ return module.Version{}, nil, fmt.Errorf("internal error: package %s is in the main module (%s), but version is not allowed", path, Target.Path)
+ }
+ return Target, &modfetch.RevInfo{Version: Target.Version}, nil
+ }
+
+ finalErr := errMissing
+ for p := path; p != "."; p = pathpkg.Dir(p) {
+ info, err := Query(p, query, allowed)
+ if err != nil {
+ if _, ok := err.(*codehost.VCSError); ok {
+ // A VCSError means we know where to find the code,
+ // we just can't. Abort search.
+ return module.Version{}, nil, err
+ }
+ if finalErr == errMissing {
+ finalErr = err
+ }
+ continue
+ }
+ m := module.Version{Path: p, Version: info.Version}
+ root, isLocal, err := fetch(m)
+ if err != nil {
+ return module.Version{}, nil, err
+ }
+ _, ok := dirInModule(path, m.Path, root, isLocal)
+ if ok {
+ return m, info, nil
+ }
+ }
+
+ return module.Version{}, nil, finalErr
+}
diff --git a/libgo/go/cmd/go/internal/modload/query_test.go b/libgo/go/cmd/go/internal/modload/query_test.go
new file mode 100644
index 00000000000..7f3ffabef74
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modload/query_test.go
@@ -0,0 +1,151 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modload
+
+import (
+ "internal/testenv"
+ "io/ioutil"
+ "log"
+ "os"
+ "path"
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "cmd/go/internal/modfetch"
+ "cmd/go/internal/modfetch/codehost"
+ "cmd/go/internal/module"
+)
+
+func TestMain(m *testing.M) {
+ os.Exit(testMain(m))
+}
+
+func testMain(m *testing.M) int {
+ dir, err := ioutil.TempDir("", "modload-test-")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+ modfetch.PkgMod = filepath.Join(dir, "pkg/mod")
+ codehost.WorkRoot = filepath.Join(dir, "codework")
+ return m.Run()
+}
+
+var (
+ queryRepo = "vcs-test.golang.org/git/querytest.git"
+ queryRepoV2 = queryRepo + "/v2"
+ queryRepoV3 = queryRepo + "/v3"
+
+ // Empty version list (no semver tags), not actually empty.
+ emptyRepo = "vcs-test.golang.org/git/emptytest.git"
+)
+
+var queryTests = []struct {
+ path string
+ query string
+ allow string
+ vers string
+ err string
+}{
+ /*
+ git init
+ echo module vcs-test.golang.org/git/querytest.git >go.mod
+ git add go.mod
+ git commit -m v1 go.mod
+ git tag start
+ for i in v0.0.0-pre1 v0.0.0 v0.0.1 v0.0.2 v0.0.3 v0.1.0 v0.1.1 v0.1.2 v0.3.0 v1.0.0 v1.1.0 v1.9.0 v1.9.9 v1.9.10-pre1; do
+ echo before $i >status
+ git add status
+ git commit -m "before $i" status
+ echo at $i >status
+ git commit -m "at $i" status
+ git tag $i
+ done
+ git tag favorite v0.0.3
+
+ git branch v2 start
+ git checkout v2
+ echo module vcs-test.golang.org/git/querytest.git/v2 >go.mod
+ git commit -m v2 go.mod
+ for i in v2.0.0 v2.1.0 v2.2.0 v2.5.5; do
+ echo before $i >status
+ git add status
+ git commit -m "before $i" status
+ echo at $i >status
+ git commit -m "at $i" status
+ git tag $i
+ done
+ echo after v2.5.5 >status
+ git commit -m 'after v2.5.5' status
+ git checkout master
+ zip -r ../querytest.zip
+ gsutil cp ../querytest.zip gs://vcs-test/git/querytest.zip
+ curl 'https://vcs-test.golang.org/git/querytest?go-get=1'
+ */
+ {path: queryRepo, query: "<v0.0.0", vers: "v0.0.0-pre1"},
+ {path: queryRepo, query: "<v0.0.0-pre1", err: `no matching versions for query "<v0.0.0-pre1"`},
+ {path: queryRepo, query: "<=v0.0.0", vers: "v0.0.0"},
+ {path: queryRepo, query: ">v0.0.0", vers: "v0.0.1"},
+ {path: queryRepo, query: ">=v0.0.0", vers: "v0.0.0"},
+ {path: queryRepo, query: "v0.0.1", vers: "v0.0.1"},
+ {path: queryRepo, query: "v0.0.1+foo", vers: "v0.0.1"},
+ {path: queryRepo, query: "v0.0.99", err: `unknown revision v0.0.99`},
+ {path: queryRepo, query: "v0", vers: "v0.3.0"},
+ {path: queryRepo, query: "v0.1", vers: "v0.1.2"},
+ {path: queryRepo, query: "v0.2", err: `no matching versions for query "v0.2"`},
+ {path: queryRepo, query: "v0.0", vers: "v0.0.3"},
+ {path: queryRepo, query: "latest", vers: "v1.9.9"},
+ {path: queryRepo, query: "latest", allow: "NOMATCH", err: `no matching versions for query "latest"`},
+ {path: queryRepo, query: ">v1.9.9", vers: "v1.9.10-pre1"},
+ {path: queryRepo, query: ">v1.10.0", err: `no matching versions for query ">v1.10.0"`},
+ {path: queryRepo, query: ">=v1.10.0", err: `no matching versions for query ">=v1.10.0"`},
+ {path: queryRepo, query: "6cf84eb", vers: "v0.0.2-0.20180704023347-6cf84ebaea54"},
+ {path: queryRepo, query: "start", vers: "v0.0.0-20180704023101-5e9e31667ddf"},
+ {path: queryRepo, query: "7a1b6bf", vers: "v0.1.0"},
+
+ {path: queryRepoV2, query: "<v0.0.0", err: `no matching versions for query "<v0.0.0"`},
+ {path: queryRepoV2, query: "<=v0.0.0", err: `no matching versions for query "<=v0.0.0"`},
+ {path: queryRepoV2, query: ">v0.0.0", vers: "v2.0.0"},
+ {path: queryRepoV2, query: ">=v0.0.0", vers: "v2.0.0"},
+ {path: queryRepoV2, query: "v0.0.1+foo", vers: "v2.0.0-20180704023347-179bc86b1be3"},
+ {path: queryRepoV2, query: "latest", vers: "v2.5.5"},
+
+ {path: queryRepoV3, query: "latest", vers: "v3.0.0-20180704024501-e0cf3de987e6"},
+
+ {path: emptyRepo, query: "latest", vers: "v0.0.0-20180704023549-7bb914627242"},
+ {path: emptyRepo, query: ">v0.0.0", err: `no matching versions for query ">v0.0.0"`},
+ {path: emptyRepo, query: "<v10.0.0", err: `no matching versions for query "<v10.0.0"`},
+}
+
+func TestQuery(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ for _, tt := range queryTests {
+ allow := tt.allow
+ if allow == "" {
+ allow = "*"
+ }
+ allowed := func(m module.Version) bool {
+ ok, _ := path.Match(allow, m.Version)
+ return ok
+ }
+ t.Run(strings.Replace(tt.path, "/", "_", -1)+"/"+tt.query+"/"+allow, func(t *testing.T) {
+ info, err := Query(tt.path, tt.query, allowed)
+ if tt.err != "" {
+ if err != nil && err.Error() == tt.err {
+ return
+ }
+ t.Fatalf("Query(%q, %q, %v): %v, want error %q", tt.path, tt.query, allow, err, tt.err)
+ }
+ if err != nil {
+ t.Fatalf("Query(%q, %q, %v): %v", tt.path, tt.query, allow, err)
+ }
+ if info.Version != tt.vers {
+ t.Errorf("Query(%q, %q, %v) = %v, want %v", tt.path, tt.query, allow, info.Version, tt.vers)
+ }
+ })
+ }
+}
diff --git a/libgo/go/cmd/go/internal/modload/search.go b/libgo/go/cmd/go/internal/modload/search.go
new file mode 100644
index 00000000000..24825cc35d8
--- /dev/null
+++ b/libgo/go/cmd/go/internal/modload/search.go
@@ -0,0 +1,134 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package modload
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "cmd/go/internal/base"
+ "cmd/go/internal/cfg"
+ "cmd/go/internal/imports"
+ "cmd/go/internal/module"
+ "cmd/go/internal/search"
+)
+
+// matchPackages returns a list of packages in the list of modules
+// matching the pattern. Package loading assumes the given set of tags.
+func matchPackages(pattern string, tags map[string]bool, useStd bool, modules []module.Version) []string {
+ match := func(string) bool { return true }
+ treeCanMatch := func(string) bool { return true }
+ if !search.IsMetaPackage(pattern) {
+ match = search.MatchPattern(pattern)
+ treeCanMatch = search.TreeCanMatchPattern(pattern)
+ }
+
+ have := map[string]bool{
+ "builtin": true, // ignore pseudo-package that exists only for documentation
+ }
+ if !cfg.BuildContext.CgoEnabled {
+ have["runtime/cgo"] = true // ignore during walk
+ }
+ var pkgs []string
+
+ walkPkgs := func(root, importPathRoot string) {
+ root = filepath.Clean(root)
+ var cmd string
+ if root == cfg.GOROOTsrc {
+ cmd = filepath.Join(root, "cmd")
+ }
+ filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
+ if err != nil {
+ return nil
+ }
+
+ // Don't use GOROOT/src but do walk down into it.
+ if path == root && importPathRoot == "" {
+ return nil
+ }
+
+ // GOROOT/src/cmd makes use of GOROOT/src/cmd/vendor,
+ // which module mode can't deal with. Eventually we'll stop using
+ // that vendor directory, and then we can remove this exclusion.
+ // golang.org/issue/26924.
+ if path == cmd {
+ return filepath.SkipDir
+ }
+
+ want := true
+ // Avoid .foo, _foo, and testdata directory trees.
+ _, elem := filepath.Split(path)
+ if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
+ want = false
+ }
+
+ name := importPathRoot + filepath.ToSlash(path[len(root):])
+ if importPathRoot == "" {
+ name = name[1:] // cut leading slash
+ }
+ if !treeCanMatch(name) {
+ want = false
+ }
+
+ if !fi.IsDir() {
+ if fi.Mode()&os.ModeSymlink != 0 && want {
+ if target, err := os.Stat(path); err == nil && target.IsDir() {
+ fmt.Fprintf(os.Stderr, "warning: ignoring symlink %s\n", path)
+ }
+ }
+ return nil
+ }
+
+ if !want {
+ return filepath.SkipDir
+ }
+ if path != root {
+ if _, err := os.Stat(filepath.Join(path, "go.mod")); err == nil {
+ return filepath.SkipDir
+ }
+ }
+
+ if !have[name] {
+ have[name] = true
+ if match(name) {
+ if _, _, err := scanDir(path, tags); err != imports.ErrNoGo {
+ pkgs = append(pkgs, name)
+ }
+ }
+ }
+
+ if elem == "vendor" {
+ return filepath.SkipDir
+ }
+ return nil
+ })
+ }
+
+ if useStd {
+ walkPkgs(cfg.GOROOTsrc, "")
+ }
+
+ for _, mod := range modules {
+ if !treeCanMatch(mod.Path) {
+ continue
+ }
+ var root string
+ if mod.Version == "" {
+ root = ModRoot
+ } else {
+ var err error
+ root, _, err = fetch(mod)
+ if err != nil {
+ base.Errorf("go: %v", err)
+ continue
+ }
+ }
+ walkPkgs(root, mod.Path)
+ }
+
+ return pkgs
+}
diff --git a/libgo/go/cmd/go/internal/module/module.go b/libgo/go/cmd/go/internal/module/module.go
new file mode 100644
index 00000000000..1dbb0f5cb79
--- /dev/null
+++ b/libgo/go/cmd/go/internal/module/module.go
@@ -0,0 +1,540 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package module defines the module.Version type
+// along with support code.
+package module
+
+// IMPORTANT NOTE
+//
+// This file essentially defines the set of valid import paths for the go command.
+// There are many subtle considerations, including Unicode ambiguity,
+// security, network, and file system representations.
+//
+// This file also defines the set of valid module path and version combinations,
+// another topic with many subtle considerations.
+//
+// Changes to the semantics in this file require approval from rsc.
+
+import (
+ "fmt"
+ "sort"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+
+ "cmd/go/internal/semver"
+)
+
+// A Version is defined by a module path and version pair.
+type Version struct {
+ Path string
+
+ // Version is usually a semantic version in canonical form.
+ // There are two exceptions to this general rule.
+ // First, the top-level target of a build has no specific version
+ // and uses Version = "".
+ // Second, during MVS calculations the version "none" is used
+ // to represent the decision to take no version of a given module.
+ Version string `json:",omitempty"`
+}
+
+// Check checks that a given module path, version pair is valid.
+// In addition to the path being a valid module path
+// and the version being a valid semantic version,
+// the two must correspond.
+// For example, the path "yaml/v2" only corresponds to
+// semantic versions beginning with "v2.".
+func Check(path, version string) error {
+ if err := CheckPath(path); err != nil {
+ return err
+ }
+ if !semver.IsValid(version) {
+ return fmt.Errorf("malformed semantic version %v", version)
+ }
+ _, pathMajor, _ := SplitPathVersion(path)
+ if !MatchPathMajor(version, pathMajor) {
+ if pathMajor == "" {
+ pathMajor = "v0 or v1"
+ }
+ if pathMajor[0] == '.' { // .v1
+ pathMajor = pathMajor[1:]
+ }
+ return fmt.Errorf("mismatched module path %v and version %v (want %v)", path, version, pathMajor)
+ }
+ return nil
+}
+
+// firstPathOK reports whether r can appear in the first element of a module path.
+// The first element of the path must be an LDH domain name, at least for now.
+// To avoid case ambiguity, the domain name must be entirely lower case.
+func firstPathOK(r rune) bool {
+ return r == '-' || r == '.' ||
+ '0' <= r && r <= '9' ||
+ 'a' <= r && r <= 'z'
+}
+
+// pathOK reports whether r can appear in an import path element.
+// Paths can be ASCII letters, ASCII digits, and limited ASCII punctuation: + - . _ and ~.
+// This matches what "go get" has historically recognized in import paths.
+// TODO(rsc): We would like to allow Unicode letters, but that requires additional
+// care in the safe encoding (see note below).
+func pathOK(r rune) bool {
+ if r < utf8.RuneSelf {
+ return r == '+' || r == '-' || r == '.' || r == '_' || r == '~' ||
+ '0' <= r && r <= '9' ||
+ 'A' <= r && r <= 'Z' ||
+ 'a' <= r && r <= 'z'
+ }
+ return false
+}
+
+// fileNameOK reports whether r can appear in a file name.
+// For now we allow all Unicode letters but otherwise limit to pathOK plus a few more punctuation characters.
+// If we expand the set of allowed characters here, we have to
+// work harder at detecting potential case-folding and normalization collisions.
+// See note about "safe encoding" below.
+func fileNameOK(r rune) bool {
+ if r < utf8.RuneSelf {
+ // Entire set of ASCII punctuation, from which we remove characters:
+ // ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~
+ // We disallow some shell special characters: " ' * < > ? ` |
+ // (Note that some of those are disallowed by the Windows file system as well.)
+ // We also disallow path separators / : and \ (fileNameOK is only called on path element characters).
+ // We allow spaces (U+0020) in file names.
+ const allowed = "!#$%&()+,-.=@[]^_{}~ "
+ if '0' <= r && r <= '9' || 'A' <= r && r <= 'Z' || 'a' <= r && r <= 'z' {
+ return true
+ }
+ for i := 0; i < len(allowed); i++ {
+ if rune(allowed[i]) == r {
+ return true
+ }
+ }
+ return false
+ }
+ // It may be OK to add more ASCII punctuation here, but only carefully.
+ // For example Windows disallows < > \, and macOS disallows :, so we must not allow those.
+ return unicode.IsLetter(r)
+}
+
+// CheckPath checks that a module path is valid.
+func CheckPath(path string) error {
+ if err := checkPath(path, false); err != nil {
+ return fmt.Errorf("malformed module path %q: %v", path, err)
+ }
+ i := strings.Index(path, "/")
+ if i < 0 {
+ i = len(path)
+ }
+ if i == 0 {
+ return fmt.Errorf("malformed module path %q: leading slash", path)
+ }
+ if !strings.Contains(path[:i], ".") {
+ return fmt.Errorf("malformed module path %q: missing dot in first path element", path)
+ }
+ if path[0] == '-' {
+ return fmt.Errorf("malformed module path %q: leading dash in first path element", path)
+ }
+ for _, r := range path[:i] {
+ if !firstPathOK(r) {
+ return fmt.Errorf("malformed module path %q: invalid char %q in first path element", path, r)
+ }
+ }
+ if _, _, ok := SplitPathVersion(path); !ok {
+ return fmt.Errorf("malformed module path %q: invalid version", path)
+ }
+ return nil
+}
+
+// CheckImportPath checks that an import path is valid.
+func CheckImportPath(path string) error {
+ if err := checkPath(path, false); err != nil {
+ return fmt.Errorf("malformed import path %q: %v", path, err)
+ }
+ return nil
+}
+
+// checkPath checks that a general path is valid.
+// It returns an error describing why but not mentioning path.
+// Because these checks apply to both module paths and import paths,
+// the caller is expected to add the "malformed ___ path %q: " prefix.
+// fileName indicates whether the final element of the path is a file name
+// (as opposed to a directory name).
+func checkPath(path string, fileName bool) error {
+ if !utf8.ValidString(path) {
+ return fmt.Errorf("invalid UTF-8")
+ }
+ if path == "" {
+ return fmt.Errorf("empty string")
+ }
+ if strings.Contains(path, "..") {
+ return fmt.Errorf("double dot")
+ }
+ if strings.Contains(path, "//") {
+ return fmt.Errorf("double slash")
+ }
+ if path[len(path)-1] == '/' {
+ return fmt.Errorf("trailing slash")
+ }
+ elemStart := 0
+ for i, r := range path {
+ if r == '/' {
+ if err := checkElem(path[elemStart:i], fileName); err != nil {
+ return err
+ }
+ elemStart = i + 1
+ }
+ }
+ if err := checkElem(path[elemStart:], fileName); err != nil {
+ return err
+ }
+ return nil
+}
+
+// checkElem checks whether an individual path element is valid.
+// fileName indicates whether the element is a file name (not a directory name).
+func checkElem(elem string, fileName bool) error {
+ if elem == "" {
+ return fmt.Errorf("empty path element")
+ }
+ if strings.Count(elem, ".") == len(elem) {
+ return fmt.Errorf("invalid path element %q", elem)
+ }
+ if elem[0] == '.' && !fileName {
+ return fmt.Errorf("leading dot in path element")
+ }
+ if elem[len(elem)-1] == '.' {
+ return fmt.Errorf("trailing dot in path element")
+ }
+ charOK := pathOK
+ if fileName {
+ charOK = fileNameOK
+ }
+ for _, r := range elem {
+ if !charOK(r) {
+ return fmt.Errorf("invalid char %q", r)
+ }
+ }
+
+ // Windows disallows a bunch of path elements, sadly.
+ // See https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file
+ short := elem
+ if i := strings.Index(short, "."); i >= 0 {
+ short = short[:i]
+ }
+ for _, bad := range badWindowsNames {
+ if strings.EqualFold(bad, short) {
+ return fmt.Errorf("disallowed path element %q", elem)
+ }
+ }
+ return nil
+}
+
+// CheckFilePath checks whether a slash-separated file path is valid.
+func CheckFilePath(path string) error {
+ if err := checkPath(path, true); err != nil {
+ return fmt.Errorf("malformed file path %q: %v", path, err)
+ }
+ return nil
+}
+
+// badWindowsNames are the reserved file path elements on Windows.
+// See https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file
+var badWindowsNames = []string{
+ "CON",
+ "PRN",
+ "AUX",
+ "NUL",
+ "COM1",
+ "COM2",
+ "COM3",
+ "COM4",
+ "COM5",
+ "COM6",
+ "COM7",
+ "COM8",
+ "COM9",
+ "LPT1",
+ "LPT2",
+ "LPT3",
+ "LPT4",
+ "LPT5",
+ "LPT6",
+ "LPT7",
+ "LPT8",
+ "LPT9",
+}
+
+// SplitPathVersion returns prefix and major version such that prefix+pathMajor == path
+// and version is either empty or "/vN" for N >= 2.
+// As a special case, gopkg.in paths are recognized directly;
+// they require ".vN" instead of "/vN", and for all N, not just N >= 2.
+func SplitPathVersion(path string) (prefix, pathMajor string, ok bool) {
+ if strings.HasPrefix(path, "gopkg.in/") {
+ return splitGopkgIn(path)
+ }
+
+ i := len(path)
+ dot := false
+ for i > 0 && ('0' <= path[i-1] && path[i-1] <= '9' || path[i-1] == '.') {
+ if path[i-1] == '.' {
+ dot = true
+ }
+ i--
+ }
+ if i <= 1 || path[i-1] != 'v' || path[i-2] != '/' {
+ return path, "", true
+ }
+ prefix, pathMajor = path[:i-2], path[i-2:]
+ if dot || len(pathMajor) <= 2 || pathMajor[2] == '0' || pathMajor == "/v1" {
+ return path, "", false
+ }
+ return prefix, pathMajor, true
+}
+
+// splitGopkgIn is like SplitPathVersion but only for gopkg.in paths.
+func splitGopkgIn(path string) (prefix, pathMajor string, ok bool) {
+ if !strings.HasPrefix(path, "gopkg.in/") {
+ return path, "", false
+ }
+ i := len(path)
+ if strings.HasSuffix(path, "-unstable") {
+ i -= len("-unstable")
+ }
+ for i > 0 && ('0' <= path[i-1] && path[i-1] <= '9') {
+ i--
+ }
+ if i <= 1 || path[i-1] != 'v' || path[i-2] != '.' {
+ // All gopkg.in paths must end in vN for some N.
+ return path, "", false
+ }
+ prefix, pathMajor = path[:i-2], path[i-2:]
+ if len(pathMajor) <= 2 || pathMajor[2] == '0' && pathMajor != ".v0" {
+ return path, "", false
+ }
+ return prefix, pathMajor, true
+}
+
+// MatchPathMajor reports whether the semantic version v
+// matches the path major version pathMajor.
+func MatchPathMajor(v, pathMajor string) bool {
+ if strings.HasPrefix(pathMajor, ".v") && strings.HasSuffix(pathMajor, "-unstable") {
+ pathMajor = strings.TrimSuffix(pathMajor, "-unstable")
+ }
+ if strings.HasPrefix(v, "v0.0.0-") && pathMajor == ".v1" {
+ // Allow old bug in pseudo-versions that generated v0.0.0- pseudoversion for gopkg .v1.
+ // For example, gopkg.in/yaml.v2@v2.2.1's go.mod requires gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405.
+ return true
+ }
+ m := semver.Major(v)
+ if pathMajor == "" {
+ return m == "v0" || m == "v1" || semver.Build(v) == "+incompatible"
+ }
+ return (pathMajor[0] == '/' || pathMajor[0] == '.') && m == pathMajor[1:]
+}
+
+// CanonicalVersion returns the canonical form of the version string v.
+// It is the same as semver.Canonical(v) except that it preserves the special build suffix "+incompatible".
+func CanonicalVersion(v string) string {
+ cv := semver.Canonical(v)
+ if semver.Build(v) == "+incompatible" {
+ cv += "+incompatible"
+ }
+ return cv
+}
+
+// Sort sorts the list by Path, breaking ties by comparing Versions.
+func Sort(list []Version) {
+ sort.Slice(list, func(i, j int) bool {
+ mi := list[i]
+ mj := list[j]
+ if mi.Path != mj.Path {
+ return mi.Path < mj.Path
+ }
+ // To help go.sum formatting, allow version/file.
+ // Compare semver prefix by semver rules,
+ // file by string order.
+ vi := mi.Version
+ vj := mj.Version
+ var fi, fj string
+ if k := strings.Index(vi, "/"); k >= 0 {
+ vi, fi = vi[:k], vi[k:]
+ }
+ if k := strings.Index(vj, "/"); k >= 0 {
+ vj, fj = vj[:k], vj[k:]
+ }
+ if vi != vj {
+ return semver.Compare(vi, vj) < 0
+ }
+ return fi < fj
+ })
+}
+
+// Safe encodings
+//
+// Module paths appear as substrings of file system paths
+// (in the download cache) and of web server URLs in the proxy protocol.
+// In general we cannot rely on file systems to be case-sensitive,
+// nor can we rely on web servers, since they read from file systems.
+// That is, we cannot rely on the file system to keep rsc.io/QUOTE
+// and rsc.io/quote separate. Windows and macOS don't.
+// Instead, we must never require two different casings of a file path.
+// Because we want the download cache to match the proxy protocol,
+// and because we want the proxy protocol to be possible to serve
+// from a tree of static files (which might be stored on a case-insensitive
+// file system), the proxy protocol must never require two different casings
+// of a URL path either.
+//
+// One possibility would be to make the safe encoding be the lowercase
+// hexadecimal encoding of the actual path bytes. This would avoid ever
+// needing different casings of a file path, but it would be fairly illegible
+// to most programmers when those paths appeared in the file system
+// (including in file paths in compiler errors and stack traces)
+// in web server logs, and so on. Instead, we want a safe encoding that
+// leaves most paths unaltered.
+//
+// The safe encoding is this:
+// replace every uppercase letter with an exclamation mark
+// followed by the letter's lowercase equivalent.
+//
+// For example,
+// github.com/Azure/azure-sdk-for-go -> github.com/!azure/azure-sdk-for-go.
+// github.com/GoogleCloudPlatform/cloudsql-proxy -> github.com/!google!cloud!platform/cloudsql-proxy
+// github.com/Sirupsen/logrus -> github.com/!sirupsen/logrus.
+//
+// Import paths that avoid upper-case letters are left unchanged.
+// Note that because import paths are ASCII-only and avoid various
+// problematic punctuation (like : < and >), the safe encoding is also ASCII-only
+// and avoids the same problematic punctuation.
+//
+// Import paths have never allowed exclamation marks, so there is no
+// need to define how to encode a literal !.
+//
+// Although paths are disallowed from using Unicode (see pathOK above),
+// the eventual plan is to allow Unicode letters as well, to assume that
+// file systems and URLs are Unicode-safe (storing UTF-8), and apply
+// the !-for-uppercase convention. Note however that not all runes that
+// are different but case-fold equivalent are an upper/lower pair.
+// For example, U+004B ('K'), U+006B ('k'), and U+212A ('K' for Kelvin)
+// are considered to case-fold to each other. When we do add Unicode
+// letters, we must not assume that upper/lower are the only case-equivalent pairs.
+// Perhaps the Kelvin symbol would be disallowed entirely, for example.
+// Or perhaps it would encode as "!!k", or perhaps as "(212A)".
+//
+// Also, it would be nice to allow Unicode marks as well as letters,
+// but marks include combining marks, and then we must deal not
+// only with case folding but also normalization: both U+00E9 ('é')
+// and U+0065 U+0301 ('e' followed by combining acute accent)
+// look the same on the page and are treated by some file systems
+// as the same path. If we do allow Unicode marks in paths, there
+// must be some kind of normalization to allow only one canonical
+// encoding of any character used in an import path.
+
+// EncodePath returns the safe encoding of the given module path.
+// It fails if the module path is invalid.
+func EncodePath(path string) (encoding string, err error) {
+ if err := CheckPath(path); err != nil {
+ return "", err
+ }
+
+ return encodeString(path)
+}
+
+// EncodeVersion returns the safe encoding of the given module version.
+// Versions are allowed to be in non-semver form but must be valid file names
+// and not contain exclamation marks.
+func EncodeVersion(v string) (encoding string, err error) {
+ if err := checkElem(v, true); err != nil || strings.Contains(v, "!") {
+ return "", fmt.Errorf("disallowed version string %q", v)
+ }
+ return encodeString(v)
+}
+
+func encodeString(s string) (encoding string, err error) {
+ haveUpper := false
+ for _, r := range s {
+ if r == '!' || r >= utf8.RuneSelf {
+ // This should be disallowed by CheckPath, but diagnose anyway.
+ // The correctness of the encoding loop below depends on it.
+ return "", fmt.Errorf("internal error: inconsistency in EncodePath")
+ }
+ if 'A' <= r && r <= 'Z' {
+ haveUpper = true
+ }
+ }
+
+ if !haveUpper {
+ return s, nil
+ }
+
+ var buf []byte
+ for _, r := range s {
+ if 'A' <= r && r <= 'Z' {
+ buf = append(buf, '!', byte(r+'a'-'A'))
+ } else {
+ buf = append(buf, byte(r))
+ }
+ }
+ return string(buf), nil
+}
+
+// DecodePath returns the module path of the given safe encoding.
+// It fails if the encoding is invalid or encodes an invalid path.
+func DecodePath(encoding string) (path string, err error) {
+ path, ok := decodeString(encoding)
+ if !ok {
+ return "", fmt.Errorf("invalid module path encoding %q", encoding)
+ }
+ if err := CheckPath(path); err != nil {
+ return "", fmt.Errorf("invalid module path encoding %q: %v", encoding, err)
+ }
+ return path, nil
+}
+
+// DecodeVersion returns the version string for the given safe encoding.
+// It fails if the encoding is invalid or encodes an invalid version.
+// Versions are allowed to be in non-semver form but must be valid file names
+// and not contain exclamation marks.
+func DecodeVersion(encoding string) (v string, err error) {
+ v, ok := decodeString(encoding)
+ if !ok {
+ return "", fmt.Errorf("invalid version encoding %q", encoding)
+ }
+ if err := checkElem(v, true); err != nil {
+ return "", fmt.Errorf("disallowed version string %q", v)
+ }
+ return v, nil
+}
+
+func decodeString(encoding string) (string, bool) {
+ var buf []byte
+
+ bang := false
+ for _, r := range encoding {
+ if r >= utf8.RuneSelf {
+ return "", false
+ }
+ if bang {
+ bang = false
+ if r < 'a' || 'z' < r {
+ return "", false
+ }
+ buf = append(buf, byte(r+'A'-'a'))
+ continue
+ }
+ if r == '!' {
+ bang = true
+ continue
+ }
+ if 'A' <= r && r <= 'Z' {
+ return "", false
+ }
+ buf = append(buf, byte(r))
+ }
+ if bang {
+ return "", false
+ }
+ return string(buf), true
+}
diff --git a/libgo/go/cmd/go/internal/module/module_test.go b/libgo/go/cmd/go/internal/module/module_test.go
new file mode 100644
index 00000000000..f21d620d328
--- /dev/null
+++ b/libgo/go/cmd/go/internal/module/module_test.go
@@ -0,0 +1,318 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package module
+
+import "testing"
+
+var checkTests = []struct {
+ path string
+ version string
+ ok bool
+}{
+ {"rsc.io/quote", "0.1.0", false},
+ {"rsc io/quote", "v1.0.0", false},
+
+ {"github.com/go-yaml/yaml", "v0.8.0", true},
+ {"github.com/go-yaml/yaml", "v1.0.0", true},
+ {"github.com/go-yaml/yaml", "v2.0.0", false},
+ {"github.com/go-yaml/yaml", "v2.1.5", false},
+ {"github.com/go-yaml/yaml", "v3.0.0", false},
+
+ {"github.com/go-yaml/yaml/v2", "v1.0.0", false},
+ {"github.com/go-yaml/yaml/v2", "v2.0.0", true},
+ {"github.com/go-yaml/yaml/v2", "v2.1.5", true},
+ {"github.com/go-yaml/yaml/v2", "v3.0.0", false},
+
+ {"gopkg.in/yaml.v0", "v0.8.0", true},
+ {"gopkg.in/yaml.v0", "v1.0.0", false},
+ {"gopkg.in/yaml.v0", "v2.0.0", false},
+ {"gopkg.in/yaml.v0", "v2.1.5", false},
+ {"gopkg.in/yaml.v0", "v3.0.0", false},
+
+ {"gopkg.in/yaml.v1", "v0.8.0", false},
+ {"gopkg.in/yaml.v1", "v1.0.0", true},
+ {"gopkg.in/yaml.v1", "v2.0.0", false},
+ {"gopkg.in/yaml.v1", "v2.1.5", false},
+ {"gopkg.in/yaml.v1", "v3.0.0", false},
+
+ // For gopkg.in, .v1 means v1 only (not v0).
+ // But early versions of vgo still generated v0 pseudo-versions for it.
+ // Even though now we'd generate those as v1 pseudo-versions,
+ // we accept the old pseudo-versions to avoid breaking existing go.mod files.
+ // For example gopkg.in/yaml.v2@v2.2.1's go.mod requires check.v1 at a v0 pseudo-version.
+ {"gopkg.in/check.v1", "v0.0.0", false},
+ {"gopkg.in/check.v1", "v0.0.0-20160102150405-abcdef123456", true},
+
+ {"gopkg.in/yaml.v2", "v1.0.0", false},
+ {"gopkg.in/yaml.v2", "v2.0.0", true},
+ {"gopkg.in/yaml.v2", "v2.1.5", true},
+ {"gopkg.in/yaml.v2", "v3.0.0", false},
+
+ {"rsc.io/quote", "v17.0.0", false},
+ {"rsc.io/quote", "v17.0.0+incompatible", true},
+}
+
+func TestCheck(t *testing.T) {
+ for _, tt := range checkTests {
+ err := Check(tt.path, tt.version)
+ if tt.ok && err != nil {
+ t.Errorf("Check(%q, %q) = %v, wanted nil error", tt.path, tt.version, err)
+ } else if !tt.ok && err == nil {
+ t.Errorf("Check(%q, %q) succeeded, wanted error", tt.path, tt.version)
+ }
+ }
+}
+
+var checkPathTests = []struct {
+ path string
+ ok bool
+ importOK bool
+ fileOK bool
+}{
+ {"x.y/z", true, true, true},
+ {"x.y", true, true, true},
+
+ {"", false, false, false},
+ {"x.y/\xFFz", false, false, false},
+ {"/x.y/z", false, false, false},
+ {"x./z", false, false, false},
+ {".x/z", false, false, true},
+ {"-x/z", false, true, true},
+ {"x..y/z", false, false, false},
+ {"x.y/z/../../w", false, false, false},
+ {"x.y//z", false, false, false},
+ {"x.y/z//w", false, false, false},
+ {"x.y/z/", false, false, false},
+
+ {"x.y/z/v0", false, true, true},
+ {"x.y/z/v1", false, true, true},
+ {"x.y/z/v2", true, true, true},
+ {"x.y/z/v2.0", false, true, true},
+ {"X.y/z", false, true, true},
+
+ {"!x.y/z", false, false, true},
+ {"_x.y/z", false, true, true},
+ {"x.y!/z", false, false, true},
+ {"x.y\"/z", false, false, false},
+ {"x.y#/z", false, false, true},
+ {"x.y$/z", false, false, true},
+ {"x.y%/z", false, false, true},
+ {"x.y&/z", false, false, true},
+ {"x.y'/z", false, false, false},
+ {"x.y(/z", false, false, true},
+ {"x.y)/z", false, false, true},
+ {"x.y*/z", false, false, false},
+ {"x.y+/z", false, true, true},
+ {"x.y,/z", false, false, true},
+ {"x.y-/z", true, true, true},
+ {"x.y./zt", false, false, false},
+ {"x.y:/z", false, false, false},
+ {"x.y;/z", false, false, false},
+ {"x.y</z", false, false, false},
+ {"x.y=/z", false, false, true},
+ {"x.y>/z", false, false, false},
+ {"x.y?/z", false, false, false},
+ {"x.y@/z", false, false, true},
+ {"x.y[/z", false, false, true},
+ {"x.y\\/z", false, false, false},
+ {"x.y]/z", false, false, true},
+ {"x.y^/z", false, false, true},
+ {"x.y_/z", false, true, true},
+ {"x.y`/z", false, false, false},
+ {"x.y{/z", false, false, true},
+ {"x.y}/z", false, false, true},
+ {"x.y~/z", false, true, true},
+ {"x.y/z!", false, false, true},
+ {"x.y/z\"", false, false, false},
+ {"x.y/z#", false, false, true},
+ {"x.y/z$", false, false, true},
+ {"x.y/z%", false, false, true},
+ {"x.y/z&", false, false, true},
+ {"x.y/z'", false, false, false},
+ {"x.y/z(", false, false, true},
+ {"x.y/z)", false, false, true},
+ {"x.y/z*", false, false, false},
+ {"x.y/z+", true, true, true},
+ {"x.y/z,", false, false, true},
+ {"x.y/z-", true, true, true},
+ {"x.y/z.t", true, true, true},
+ {"x.y/z/t", true, true, true},
+ {"x.y/z:", false, false, false},
+ {"x.y/z;", false, false, false},
+ {"x.y/z<", false, false, false},
+ {"x.y/z=", false, false, true},
+ {"x.y/z>", false, false, false},
+ {"x.y/z?", false, false, false},
+ {"x.y/z@", false, false, true},
+ {"x.y/z[", false, false, true},
+ {"x.y/z\\", false, false, false},
+ {"x.y/z]", false, false, true},
+ {"x.y/z^", false, false, true},
+ {"x.y/z_", true, true, true},
+ {"x.y/z`", false, false, false},
+ {"x.y/z{", false, false, true},
+ {"x.y/z}", false, false, true},
+ {"x.y/z~", true, true, true},
+ {"x.y/x.foo", true, true, true},
+ {"x.y/aux.foo", false, false, false},
+ {"x.y/prn", false, false, false},
+ {"x.y/prn2", true, true, true},
+ {"x.y/com", true, true, true},
+ {"x.y/com1", false, false, false},
+ {"x.y/com1.txt", false, false, false},
+ {"x.y/calm1", true, true, true},
+ {"github.com/!123/logrus", false, false, true},
+
+ // TODO: CL 41822 allowed Unicode letters in old "go get"
+ // without due consideration of the implications, and only on github.com (!).
+ // For now, we disallow non-ASCII characters in module mode,
+ // in both module paths and general import paths,
+ // until we can get the implications right.
+ // When we do, we'll enable them everywhere, not just for GitHub.
+ {"github.com/user/unicode/испытание", false, false, true},
+
+ {"../x", false, false, false},
+ {"./y", false, false, false},
+ {"x:y", false, false, false},
+ {`\temp\foo`, false, false, false},
+ {".gitignore", false, false, true},
+ {".github/ISSUE_TEMPLATE", false, false, true},
+ {"x☺y", false, false, false},
+}
+
+func TestCheckPath(t *testing.T) {
+ for _, tt := range checkPathTests {
+ err := CheckPath(tt.path)
+ if tt.ok && err != nil {
+ t.Errorf("CheckPath(%q) = %v, wanted nil error", tt.path, err)
+ } else if !tt.ok && err == nil {
+ t.Errorf("CheckPath(%q) succeeded, wanted error", tt.path)
+ }
+
+ err = CheckImportPath(tt.path)
+ if tt.importOK && err != nil {
+ t.Errorf("CheckImportPath(%q) = %v, wanted nil error", tt.path, err)
+ } else if !tt.importOK && err == nil {
+ t.Errorf("CheckImportPath(%q) succeeded, wanted error", tt.path)
+ }
+
+ err = CheckFilePath(tt.path)
+ if tt.fileOK && err != nil {
+ t.Errorf("CheckFilePath(%q) = %v, wanted nil error", tt.path, err)
+ } else if !tt.fileOK && err == nil {
+ t.Errorf("CheckFilePath(%q) succeeded, wanted error", tt.path)
+ }
+ }
+}
+
+var splitPathVersionTests = []struct {
+ pathPrefix string
+ version string
+}{
+ {"x.y/z", ""},
+ {"x.y/z", "/v2"},
+ {"x.y/z", "/v3"},
+ {"gopkg.in/yaml", ".v0"},
+ {"gopkg.in/yaml", ".v1"},
+ {"gopkg.in/yaml", ".v2"},
+ {"gopkg.in/yaml", ".v3"},
+}
+
+func TestSplitPathVersion(t *testing.T) {
+ for _, tt := range splitPathVersionTests {
+ pathPrefix, version, ok := SplitPathVersion(tt.pathPrefix + tt.version)
+ if pathPrefix != tt.pathPrefix || version != tt.version || !ok {
+ t.Errorf("SplitPathVersion(%q) = %q, %q, %v, want %q, %q, true", tt.pathPrefix+tt.version, pathPrefix, version, ok, tt.pathPrefix, tt.version)
+ }
+ }
+
+ for _, tt := range checkPathTests {
+ pathPrefix, version, ok := SplitPathVersion(tt.path)
+ if pathPrefix+version != tt.path {
+ t.Errorf("SplitPathVersion(%q) = %q, %q, %v, doesn't add to input", tt.path, pathPrefix, version, ok)
+ }
+ }
+}
+
+var encodeTests = []struct {
+ path string
+ enc string // empty means same as path
+}{
+ {path: "ascii.com/abcdefghijklmnopqrstuvwxyz.-+/~_0123456789"},
+ {path: "github.com/GoogleCloudPlatform/omega", enc: "github.com/!google!cloud!platform/omega"},
+}
+
+func TestEncodePath(t *testing.T) {
+ // Check invalid paths.
+ for _, tt := range checkPathTests {
+ if !tt.ok {
+ _, err := EncodePath(tt.path)
+ if err == nil {
+ t.Errorf("EncodePath(%q): succeeded, want error (invalid path)", tt.path)
+ }
+ }
+ }
+
+ // Check encodings.
+ for _, tt := range encodeTests {
+ enc, err := EncodePath(tt.path)
+ if err != nil {
+ t.Errorf("EncodePath(%q): unexpected error: %v", tt.path, err)
+ continue
+ }
+ want := tt.enc
+ if want == "" {
+ want = tt.path
+ }
+ if enc != want {
+ t.Errorf("EncodePath(%q) = %q, want %q", tt.path, enc, want)
+ }
+ }
+}
+
+var badDecode = []string{
+ "github.com/GoogleCloudPlatform/omega",
+ "github.com/!google!cloud!platform!/omega",
+ "github.com/!0google!cloud!platform/omega",
+ "github.com/!_google!cloud!platform/omega",
+ "github.com/!!google!cloud!platform/omega",
+ "",
+}
+
+func TestDecodePath(t *testing.T) {
+ // Check invalid decodings.
+ for _, bad := range badDecode {
+ _, err := DecodePath(bad)
+ if err == nil {
+ t.Errorf("DecodePath(%q): succeeded, want error (invalid decoding)", bad)
+ }
+ }
+
+ // Check invalid paths (or maybe decodings).
+ for _, tt := range checkPathTests {
+ if !tt.ok {
+ path, err := DecodePath(tt.path)
+ if err == nil {
+ t.Errorf("DecodePath(%q) = %q, want error (invalid path)", tt.path, path)
+ }
+ }
+ }
+
+ // Check encodings.
+ for _, tt := range encodeTests {
+ enc := tt.enc
+ if enc == "" {
+ enc = tt.path
+ }
+ path, err := DecodePath(enc)
+ if err != nil {
+ t.Errorf("DecodePath(%q): unexpected error: %v", enc, err)
+ continue
+ }
+ if path != tt.path {
+ t.Errorf("DecodePath(%q) = %q, want %q", enc, path, tt.path)
+ }
+ }
+}
diff --git a/libgo/go/cmd/go/internal/mvs/mvs.go b/libgo/go/cmd/go/internal/mvs/mvs.go
new file mode 100644
index 00000000000..8ec9162dabc
--- /dev/null
+++ b/libgo/go/cmd/go/internal/mvs/mvs.go
@@ -0,0 +1,368 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package mvs implements Minimal Version Selection.
+// See https://research.swtch.com/vgo-mvs.
+package mvs
+
+import (
+ "fmt"
+ "sort"
+ "sync"
+
+ "cmd/go/internal/base"
+ "cmd/go/internal/module"
+ "cmd/go/internal/par"
+)
+
+// A Reqs is the requirement graph on which Minimal Version Selection (MVS) operates.
+//
+// The version strings are opaque except for the special version "none"
+// (see the documentation for module.Version). In particular, MVS does not
+// assume that the version strings are semantic versions; instead, the Max method
+// gives access to the comparison operation.
+//
+// It must be safe to call methods on a Reqs from multiple goroutines simultaneously.
+// Because a Reqs may read the underlying graph from the network on demand,
+// the MVS algorithms parallelize the traversal to overlap network delays.
+type Reqs interface {
+ // Required returns the module versions explicitly required by m itself.
+ // The caller must not modify the returned list.
+ Required(m module.Version) ([]module.Version, error)
+
+ // Max returns the maximum of v1 and v2 (it returns either v1 or v2).
+ //
+ // For all versions v, Max(v, "none") must be v,
+ // and for the tanget passed as the first argument to MVS functions,
+ // Max(target, v) must be target.
+ //
+ // Note that v1 < v2 can be written Max(v1, v2) != v1
+ // and similarly v1 <= v2 can be written Max(v1, v2) == v2.
+ Max(v1, v2 string) string
+
+ // Upgrade returns the upgraded version of m,
+ // for use during an UpgradeAll operation.
+ // If m should be kept as is, Upgrade returns m.
+ // If m is not yet used in the build, then m.Version will be "none".
+ // More typically, m.Version will be the version required
+ // by some other module in the build.
+ //
+ // If no module version is available for the given path,
+ // Upgrade returns a non-nil error.
+ // TODO(rsc): Upgrade must be able to return errors,
+ // but should "no latest version" just return m instead?
+ Upgrade(m module.Version) (module.Version, error)
+
+ // Previous returns the version of m.Path immediately prior to m.Version,
+ // or "none" if no such version is known.
+ Previous(m module.Version) (module.Version, error)
+}
+
+type MissingModuleError struct {
+ Module module.Version
+}
+
+func (e *MissingModuleError) Error() string {
+ return fmt.Sprintf("missing module: %v", e.Module)
+}
+
+// BuildList returns the build list for the target module.
+func BuildList(target module.Version, reqs Reqs) ([]module.Version, error) {
+ return buildList(target, reqs, nil)
+}
+
+func buildList(target module.Version, reqs Reqs, upgrade func(module.Version) module.Version) ([]module.Version, error) {
+ // Explore work graph in parallel in case reqs.Required
+ // does high-latency network operations.
+ var work par.Work
+ work.Add(target)
+ var (
+ mu sync.Mutex
+ min = map[string]string{target.Path: target.Version}
+ firstErr error
+ )
+ work.Do(10, func(item interface{}) {
+ m := item.(module.Version)
+ required, err := reqs.Required(m)
+
+ mu.Lock()
+ if err != nil && firstErr == nil {
+ firstErr = err
+ }
+ if firstErr != nil {
+ mu.Unlock()
+ return
+ }
+ if v, ok := min[m.Path]; !ok || reqs.Max(v, m.Version) != v {
+ min[m.Path] = m.Version
+ }
+ mu.Unlock()
+
+ for _, r := range required {
+ if r.Path == "" {
+ base.Errorf("Required(%v) returned zero module in list", m)
+ continue
+ }
+ work.Add(r)
+ }
+
+ if upgrade != nil {
+ u := upgrade(m)
+ if u.Path == "" {
+ base.Errorf("Upgrade(%v) returned zero module", m)
+ return
+ }
+ work.Add(u)
+ }
+ })
+
+ if firstErr != nil {
+ return nil, firstErr
+ }
+ if v := min[target.Path]; v != target.Version {
+ panic(fmt.Sprintf("mistake: chose version %q instead of target %+v", v, target)) // TODO: Don't panic.
+ }
+
+ list := []module.Version{target}
+ listed := map[string]bool{target.Path: true}
+ for i := 0; i < len(list); i++ {
+ m := list[i]
+ required, err := reqs.Required(m)
+ if err != nil {
+ return nil, err
+ }
+ for _, r := range required {
+ v := min[r.Path]
+ if r.Path != target.Path && reqs.Max(v, r.Version) != v {
+ panic(fmt.Sprintf("mistake: version %q does not satisfy requirement %+v", v, r)) // TODO: Don't panic.
+ }
+ if !listed[r.Path] {
+ list = append(list, module.Version{Path: r.Path, Version: v})
+ listed[r.Path] = true
+ }
+ }
+ }
+
+ tail := list[1:]
+ sort.Slice(tail, func(i, j int) bool {
+ return tail[i].Path < tail[j].Path
+ })
+ return list, nil
+}
+
+// Req returns the minimal requirement list for the target module
+// that results in the given build list, with the constraint that all
+// module paths listed in base must appear in the returned list.
+func Req(target module.Version, list []module.Version, base []string, reqs Reqs) ([]module.Version, error) {
+ // Note: Not running in parallel because we assume
+ // that list came from a previous operation that paged
+ // in all the requirements, so there's no I/O to overlap now.
+
+ // Compute postorder, cache requirements.
+ var postorder []module.Version
+ reqCache := map[module.Version][]module.Version{}
+ reqCache[target] = nil
+ var walk func(module.Version) error
+ walk = func(m module.Version) error {
+ _, ok := reqCache[m]
+ if ok {
+ return nil
+ }
+ required, err := reqs.Required(m)
+ if err != nil {
+ return err
+ }
+ reqCache[m] = required
+ for _, m1 := range required {
+ if err := walk(m1); err != nil {
+ return err
+ }
+ }
+ postorder = append(postorder, m)
+ return nil
+ }
+ for _, m := range list {
+ if err := walk(m); err != nil {
+ return nil, err
+ }
+ }
+
+ // Walk modules in reverse post-order, only adding those not implied already.
+ have := map[string]string{}
+ walk = func(m module.Version) error {
+ if v, ok := have[m.Path]; ok && reqs.Max(m.Version, v) == v {
+ return nil
+ }
+ have[m.Path] = m.Version
+ for _, m1 := range reqCache[m] {
+ walk(m1)
+ }
+ return nil
+ }
+ max := map[string]string{}
+ for _, m := range list {
+ if v, ok := max[m.Path]; ok {
+ max[m.Path] = reqs.Max(m.Version, v)
+ } else {
+ max[m.Path] = m.Version
+ }
+ }
+ // First walk the base modules that must be listed.
+ var min []module.Version
+ for _, path := range base {
+ m := module.Version{Path: path, Version: max[path]}
+ min = append(min, m)
+ walk(m)
+ }
+ // Now the reverse postorder to bring in anything else.
+ for i := len(postorder) - 1; i >= 0; i-- {
+ m := postorder[i]
+ if max[m.Path] != m.Version {
+ // Older version.
+ continue
+ }
+ if have[m.Path] != m.Version {
+ min = append(min, m)
+ walk(m)
+ }
+ }
+ sort.Slice(min, func(i, j int) bool {
+ return min[i].Path < min[j].Path
+ })
+ return min, nil
+}
+
+// UpgradeAll returns a build list for the target module
+// in which every module is upgraded to its latest version.
+func UpgradeAll(target module.Version, reqs Reqs) ([]module.Version, error) {
+ return buildList(target, reqs, func(m module.Version) module.Version {
+ if m.Path == target.Path {
+ return target
+ }
+
+ latest, err := reqs.Upgrade(m)
+ if err != nil {
+ panic(err) // TODO
+ }
+ m.Version = latest.Version
+ return m
+ })
+}
+
+// Upgrade returns a build list for the target module
+// in which the given additional modules are upgraded.
+func Upgrade(target module.Version, reqs Reqs, upgrade ...module.Version) ([]module.Version, error) {
+ list, err := reqs.Required(target)
+ if err != nil {
+ panic(err) // TODO
+ }
+ // TODO: Maybe if an error is given,
+ // rerun with BuildList(upgrade[0], reqs) etc
+ // to find which ones are the buggy ones.
+ list = append([]module.Version(nil), list...)
+ list = append(list, upgrade...)
+ return BuildList(target, &override{target, list, reqs})
+}
+
+// Downgrade returns a build list for the target module
+// in which the given additional modules are downgraded.
+//
+// The versions to be downgraded may be unreachable from reqs.Latest and
+// reqs.Previous, but the methods of reqs must otherwise handle such versions
+// correctly.
+func Downgrade(target module.Version, reqs Reqs, downgrade ...module.Version) ([]module.Version, error) {
+ list, err := reqs.Required(target)
+ if err != nil {
+ panic(err) // TODO
+ }
+ max := make(map[string]string)
+ for _, r := range list {
+ max[r.Path] = r.Version
+ }
+ for _, d := range downgrade {
+ if v, ok := max[d.Path]; !ok || reqs.Max(v, d.Version) != d.Version {
+ max[d.Path] = d.Version
+ }
+ }
+
+ var (
+ added = make(map[module.Version]bool)
+ rdeps = make(map[module.Version][]module.Version)
+ excluded = make(map[module.Version]bool)
+ )
+ var exclude func(module.Version)
+ exclude = func(m module.Version) {
+ if excluded[m] {
+ return
+ }
+ excluded[m] = true
+ for _, p := range rdeps[m] {
+ exclude(p)
+ }
+ }
+ var add func(module.Version)
+ add = func(m module.Version) {
+ if added[m] {
+ return
+ }
+ added[m] = true
+ if v, ok := max[m.Path]; ok && reqs.Max(m.Version, v) != v {
+ exclude(m)
+ return
+ }
+ list, err := reqs.Required(m)
+ if err != nil {
+ panic(err) // TODO
+ }
+ for _, r := range list {
+ add(r)
+ if excluded[r] {
+ exclude(m)
+ return
+ }
+ rdeps[r] = append(rdeps[r], m)
+ }
+ }
+
+ var out []module.Version
+ out = append(out, target)
+List:
+ for _, r := range list {
+ add(r)
+ for excluded[r] {
+ p, err := reqs.Previous(r)
+ if err != nil {
+ return nil, err // TODO
+ }
+ // If the target version is a pseudo-version, it may not be
+ // included when iterating over prior versions using reqs.Previous.
+ // Insert it into the right place in the iteration.
+ // If v is excluded, p should be returned again by reqs.Previous on the next iteration.
+ if v := max[r.Path]; reqs.Max(v, r.Version) != v && reqs.Max(p.Version, v) != p.Version {
+ p.Version = v
+ }
+ if p.Version == "none" {
+ continue List
+ }
+ add(p)
+ r = p
+ }
+ out = append(out, r)
+ }
+
+ return out, nil
+}
+
+type override struct {
+ target module.Version
+ list []module.Version
+ Reqs
+}
+
+func (r *override) Required(m module.Version) ([]module.Version, error) {
+ if m == r.target {
+ return r.list, nil
+ }
+ return r.Reqs.Required(m)
+}
diff --git a/libgo/go/cmd/go/internal/mvs/mvs_test.go b/libgo/go/cmd/go/internal/mvs/mvs_test.go
new file mode 100644
index 00000000000..2a27dfb2889
--- /dev/null
+++ b/libgo/go/cmd/go/internal/mvs/mvs_test.go
@@ -0,0 +1,473 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mvs
+
+import (
+ "reflect"
+ "strings"
+ "testing"
+
+ "cmd/go/internal/module"
+)
+
+var tests = `
+# Scenario from blog.
+name: blog
+A: B1 C2
+B1: D3
+C1: D2
+C2: D4
+C3: D5
+C4: G1
+D2: E1
+D3: E2
+D4: E2 F1
+D5: E2
+G1: C4
+A2: B1 C4 D4
+build A: A B1 C2 D4 E2 F1
+upgrade* A: A B1 C4 D5 E2 G1
+upgrade A C4: A B1 C4 D4 E2 F1 G1
+downgrade A2 D2: A2 C4 D2
+
+name: trim
+A: B1 C2
+B1: D3
+C2: B2
+B2:
+build A: A B2 C2
+
+# Cross-dependency between D and E.
+# No matter how it arises, should get result of merging all build lists via max,
+# which leads to including both D2 and E2.
+
+name: cross1
+A: B C
+B: D1
+C: D2
+D1: E2
+D2: E1
+build A: A B C D2 E2
+
+name: cross1V
+A: B2 C D2 E1
+B1:
+B2: D1
+C: D2
+D1: E2
+D2: E1
+build A: A B2 C D2 E2
+
+name: cross1U
+A: B1 C
+B1:
+B2: D1
+C: D2
+D1: E2
+D2: E1
+build A: A B1 C D2 E1
+upgrade A B2: A B2 C D2 E2
+
+name: cross1R
+A: B C
+B: D2
+C: D1
+D1: E2
+D2: E1
+build A: A B C D2 E2
+
+name: cross1X
+A: B C
+B: D1 E2
+C: D2
+D1: E2
+D2: E1
+build A: A B C D2 E2
+
+name: cross2
+A: B D2
+B: D1
+D1: E2
+D2: E1
+build A: A B D2 E2
+
+name: cross2X
+A: B D2
+B: D1 E2
+C: D2
+D1: E2
+D2: E1
+build A: A B D2 E2
+
+name: cross3
+A: B D2 E1
+B: D1
+D1: E2
+D2: E1
+build A: A B D2 E2
+
+name: cross3X
+A: B D2 E1
+B: D1 E2
+D1: E2
+D2: E1
+build A: A B D2 E2
+
+# Should not get E2 here, because B has been updated
+# not to depend on D1 anymore.
+name: cross4
+A1: B1 D2
+A2: B2 D2
+B1: D1
+B2: D2
+D1: E2
+D2: E1
+build A1: A1 B1 D2 E2
+build A2: A2 B2 D2 E1
+
+# But the upgrade from A1 preserves the E2 dep explicitly.
+upgrade A1 B2: A1 B2 D2 E2
+upgradereq A1 B2: B2 E2
+
+name: cross5
+A: D1
+D1: E2
+D2: E1
+build A: A D1 E2
+upgrade* A: A D2 E2
+upgrade A D2: A D2 E2
+upgradereq A D2: D2 E2
+
+name: cross6
+A: D2
+D1: E2
+D2: E1
+build A: A D2 E1
+upgrade* A: A D2 E2
+upgrade A E2: A D2 E2
+
+name: cross7
+A: B C
+B: D1
+C: E1
+D1: E2
+E1: D2
+build A: A B C D2 E2
+
+# Upgrade from B1 to B2 should drop the transitive dep on D.
+name: drop
+A: B1 C1
+B1: D1
+B2:
+C2:
+D2:
+build A: A B1 C1 D1
+upgrade* A: A B2 C2
+
+name: simplify
+A: B1 C1
+B1: C2
+C1: D1
+C2:
+build A: A B1 C2
+
+name: up1
+A: B1 C1
+B1:
+B2:
+B3:
+B4:
+B5.hidden:
+C2:
+C3:
+build A: A B1 C1
+upgrade* A: A B4 C3
+
+name: up2
+A: B5.hidden C1
+B1:
+B2:
+B3:
+B4:
+B5.hidden:
+C2:
+C3:
+build A: A B5.hidden C1
+upgrade* A: A B5.hidden C3
+
+name: down1
+A: B2
+B1: C1
+B2: C2
+build A: A B2 C2
+downgrade A C1: A B1
+
+name: down2
+A: B2 E2
+B1:
+B2: C2 F2
+C1:
+D1:
+C2: D2 E2
+D2: B2
+E2: D2
+E1:
+F1:
+downgrade A F1: A B1 E1
+
+name: down3
+A:
+
+# golang.org/issue/25542.
+name: noprev1
+A: B4 C2
+B2.hidden:
+C2:
+downgrade A B2.hidden: A B2.hidden C2
+
+name: noprev2
+A: B4 C2
+B2.hidden:
+B1:
+C2:
+downgrade A B2.hidden: A B2.hidden C2
+
+name: noprev3
+A: B4 C2
+B3:
+B2.hidden:
+C2:
+downgrade A B2.hidden: A B2.hidden C2
+
+# Cycles involving the target.
+
+# The target must be the newest version of itself.
+name: cycle1
+A: B1
+B1: A1
+B2: A2
+B3: A3
+build A: A B1
+upgrade A B2: A B2
+upgrade* A: A B3
+
+# Requirements of older versions of the target
+# must not be carried over.
+name: cycle2
+A: B1
+A1: C1
+A2: D1
+B1: A1
+B2: A2
+C1: A2
+C2:
+D2:
+build A: A B1
+upgrade* A: A B2
+
+# Requirement minimization.
+
+name: req1
+A: B1 C1 D1 E1 F1
+B1: C1 E1 F1
+req A: B1 D1
+req A C: B1 C1 D1
+
+name: req2
+A: G1 H1
+G1: H1
+H1: G1
+req A: G1
+req A G: G1
+req A H: H1
+`
+
+func Test(t *testing.T) {
+ var (
+ name string
+ reqs reqsMap
+ fns []func(*testing.T)
+ )
+ flush := func() {
+ if name != "" {
+ t.Run(name, func(t *testing.T) {
+ for _, fn := range fns {
+ fn(t)
+ }
+ })
+ }
+ }
+ m := func(s string) module.Version {
+ return module.Version{Path: s[:1], Version: s[1:]}
+ }
+ ms := func(list []string) []module.Version {
+ var mlist []module.Version
+ for _, s := range list {
+ mlist = append(mlist, m(s))
+ }
+ return mlist
+ }
+ checkList := func(t *testing.T, desc string, list []module.Version, err error, val string) {
+ if err != nil {
+ t.Fatalf("%s: %v", desc, err)
+ }
+ vs := ms(strings.Fields(val))
+ if !reflect.DeepEqual(list, vs) {
+ t.Errorf("%s = %v, want %v", desc, list, vs)
+ }
+ }
+
+ for _, line := range strings.Split(tests, "\n") {
+ line = strings.TrimSpace(line)
+ if strings.HasPrefix(line, "#") || line == "" {
+ continue
+ }
+ i := strings.Index(line, ":")
+ if i < 0 {
+ t.Fatalf("missing colon: %q", line)
+ }
+ key := strings.TrimSpace(line[:i])
+ val := strings.TrimSpace(line[i+1:])
+ if key == "" {
+ t.Fatalf("missing key: %q", line)
+ }
+ kf := strings.Fields(key)
+ switch kf[0] {
+ case "name":
+ if len(kf) != 1 {
+ t.Fatalf("name takes no arguments: %q", line)
+ }
+ flush()
+ reqs = make(reqsMap)
+ fns = nil
+ name = val
+ continue
+ case "build":
+ if len(kf) != 2 {
+ t.Fatalf("build takes one argument: %q", line)
+ }
+ fns = append(fns, func(t *testing.T) {
+ list, err := BuildList(m(kf[1]), reqs)
+ checkList(t, key, list, err, val)
+ })
+ continue
+ case "upgrade*":
+ if len(kf) != 2 {
+ t.Fatalf("upgrade* takes one argument: %q", line)
+ }
+ fns = append(fns, func(t *testing.T) {
+ list, err := UpgradeAll(m(kf[1]), reqs)
+ checkList(t, key, list, err, val)
+ })
+ continue
+ case "upgradereq":
+ if len(kf) < 2 {
+ t.Fatalf("upgrade takes at least one argument: %q", line)
+ }
+ fns = append(fns, func(t *testing.T) {
+ list, err := Upgrade(m(kf[1]), reqs, ms(kf[2:])...)
+ if err == nil {
+ list, err = Req(m(kf[1]), list, nil, reqs)
+ }
+ checkList(t, key, list, err, val)
+ })
+ continue
+ case "upgrade":
+ if len(kf) < 2 {
+ t.Fatalf("upgrade takes at least one argument: %q", line)
+ }
+ fns = append(fns, func(t *testing.T) {
+ list, err := Upgrade(m(kf[1]), reqs, ms(kf[2:])...)
+ checkList(t, key, list, err, val)
+ })
+ continue
+ case "downgrade":
+ if len(kf) < 2 {
+ t.Fatalf("downgrade takes at least one argument: %q", line)
+ }
+ fns = append(fns, func(t *testing.T) {
+ list, err := Downgrade(m(kf[1]), reqs, ms(kf[1:])...)
+ checkList(t, key, list, err, val)
+ })
+ continue
+ case "req":
+ if len(kf) < 2 {
+ t.Fatalf("req takes at least one argument: %q", line)
+ }
+ fns = append(fns, func(t *testing.T) {
+ list, err := BuildList(m(kf[1]), reqs)
+ if err != nil {
+ t.Fatal(err)
+ }
+ list, err = Req(m(kf[1]), list, kf[2:], reqs)
+ checkList(t, key, list, err, val)
+ })
+ continue
+ }
+ if len(kf) == 1 && 'A' <= key[0] && key[0] <= 'Z' {
+ var rs []module.Version
+ for _, f := range strings.Fields(val) {
+ r := m(f)
+ if reqs[r] == nil {
+ reqs[r] = []module.Version{}
+ }
+ rs = append(rs, r)
+ }
+ reqs[m(key)] = rs
+ continue
+ }
+ t.Fatalf("bad line: %q", line)
+ }
+ flush()
+}
+
+type reqsMap map[module.Version][]module.Version
+
+func (r reqsMap) Max(v1, v2 string) string {
+ if v1 == "none" || v2 == "" {
+ return v2
+ }
+ if v2 == "none" || v1 == "" {
+ return v1
+ }
+ if v1 < v2 {
+ return v2
+ }
+ return v1
+}
+
+func (r reqsMap) Upgrade(m module.Version) (module.Version, error) {
+ var u module.Version
+ for k := range r {
+ if k.Path == m.Path && u.Version < k.Version && !strings.HasSuffix(k.Version, ".hidden") {
+ u = k
+ }
+ }
+ if u.Path == "" {
+ return module.Version{}, &MissingModuleError{module.Version{Path: m.Path, Version: ""}}
+ }
+ return u, nil
+}
+
+func (r reqsMap) Previous(m module.Version) (module.Version, error) {
+ var p module.Version
+ for k := range r {
+ if k.Path == m.Path && p.Version < k.Version && k.Version < m.Version && !strings.HasSuffix(k.Version, ".hidden") {
+ p = k
+ }
+ }
+ if p.Path == "" {
+ return module.Version{Path: m.Path, Version: "none"}, nil
+ }
+ return p, nil
+}
+
+func (r reqsMap) Required(m module.Version) ([]module.Version, error) {
+ rr, ok := r[m]
+ if !ok {
+ return nil, &MissingModuleError{m}
+ }
+ return rr, nil
+}
diff --git a/libgo/go/cmd/go/internal/par/work.go b/libgo/go/cmd/go/internal/par/work.go
new file mode 100644
index 00000000000..a568c86f60b
--- /dev/null
+++ b/libgo/go/cmd/go/internal/par/work.go
@@ -0,0 +1,149 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package par implements parallel execution helpers.
+package par
+
+import (
+ "math/rand"
+ "sync"
+ "sync/atomic"
+)
+
+// Work manages a set of work items to be executed in parallel, at most once each.
+// The items in the set must all be valid map keys.
+type Work struct {
+ f func(interface{}) // function to run for each item
+ running int // total number of runners
+
+ mu sync.Mutex
+ added map[interface{}]bool // items added to set
+ todo []interface{} // items yet to be run
+ wait sync.Cond // wait when todo is empty
+ waiting int // number of runners waiting for todo
+}
+
+func (w *Work) init() {
+ if w.added == nil {
+ w.added = make(map[interface{}]bool)
+ }
+}
+
+// Add adds item to the work set, if it hasn't already been added.
+func (w *Work) Add(item interface{}) {
+ w.mu.Lock()
+ w.init()
+ if !w.added[item] {
+ w.added[item] = true
+ w.todo = append(w.todo, item)
+ if w.waiting > 0 {
+ w.wait.Signal()
+ }
+ }
+ w.mu.Unlock()
+}
+
+// Do runs f in parallel on items from the work set,
+// with at most n invocations of f running at a time.
+// It returns when everything added to the work set has been processed.
+// At least one item should have been added to the work set
+// before calling Do (or else Do returns immediately),
+// but it is allowed for f(item) to add new items to the set.
+// Do should only be used once on a given Work.
+func (w *Work) Do(n int, f func(item interface{})) {
+ if n < 1 {
+ panic("par.Work.Do: n < 1")
+ }
+ if w.running >= 1 {
+ panic("par.Work.Do: already called Do")
+ }
+
+ w.running = n
+ w.f = f
+ w.wait.L = &w.mu
+
+ for i := 0; i < n-1; i++ {
+ go w.runner()
+ }
+ w.runner()
+}
+
+// runner executes work in w until both nothing is left to do
+// and all the runners are waiting for work.
+// (Then all the runners return.)
+func (w *Work) runner() {
+ for {
+ // Wait for something to do.
+ w.mu.Lock()
+ for len(w.todo) == 0 {
+ w.waiting++
+ if w.waiting == w.running {
+ // All done.
+ w.wait.Broadcast()
+ w.mu.Unlock()
+ return
+ }
+ w.wait.Wait()
+ w.waiting--
+ }
+
+ // Pick something to do at random,
+ // to eliminate pathological contention
+ // in case items added at about the same time
+ // are most likely to contend.
+ i := rand.Intn(len(w.todo))
+ item := w.todo[i]
+ w.todo[i] = w.todo[len(w.todo)-1]
+ w.todo = w.todo[:len(w.todo)-1]
+ w.mu.Unlock()
+
+ w.f(item)
+ }
+}
+
+// Cache runs an action once per key and caches the result.
+type Cache struct {
+ m sync.Map
+}
+
+type cacheEntry struct {
+ done uint32
+ mu sync.Mutex
+ result interface{}
+}
+
+// Do calls the function f if and only if Do is being called for the first time with this key.
+// No call to Do with a given key returns until the one call to f returns.
+// Do returns the value returned by the one call to f.
+func (c *Cache) Do(key interface{}, f func() interface{}) interface{} {
+ entryIface, ok := c.m.Load(key)
+ if !ok {
+ entryIface, _ = c.m.LoadOrStore(key, new(cacheEntry))
+ }
+ e := entryIface.(*cacheEntry)
+ if atomic.LoadUint32(&e.done) == 0 {
+ e.mu.Lock()
+ if atomic.LoadUint32(&e.done) == 0 {
+ e.result = f()
+ atomic.StoreUint32(&e.done, 1)
+ }
+ e.mu.Unlock()
+ }
+ return e.result
+}
+
+// Get returns the cached result associated with key.
+// It returns nil if there is no such result.
+// If the result for key is being computed, Get does not wait for the computation to finish.
+func (c *Cache) Get(key interface{}) interface{} {
+ entryIface, ok := c.m.Load(key)
+ if !ok {
+ return nil
+ }
+ e := entryIface.(*cacheEntry)
+ if atomic.LoadUint32(&e.done) == 0 {
+ return nil
+ }
+ return e.result
+}
diff --git a/libgo/go/cmd/go/internal/par/work_test.go b/libgo/go/cmd/go/internal/par/work_test.go
new file mode 100644
index 00000000000..f104bc4106f
--- /dev/null
+++ b/libgo/go/cmd/go/internal/par/work_test.go
@@ -0,0 +1,77 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package par
+
+import (
+ "sync/atomic"
+ "testing"
+ "time"
+)
+
+func TestWork(t *testing.T) {
+ var w Work
+
+ const N = 10000
+ n := int32(0)
+ w.Add(N)
+ w.Do(100, func(x interface{}) {
+ atomic.AddInt32(&n, 1)
+ i := x.(int)
+ if i >= 2 {
+ w.Add(i - 1)
+ w.Add(i - 2)
+ }
+ w.Add(i >> 1)
+ w.Add((i >> 1) ^ 1)
+ })
+ if n != N+1 {
+ t.Fatalf("ran %d items, expected %d", n, N+1)
+ }
+}
+
+func TestWorkParallel(t *testing.T) {
+ for tries := 0; tries < 10; tries++ {
+ var w Work
+ const N = 100
+ for i := 0; i < N; i++ {
+ w.Add(i)
+ }
+ start := time.Now()
+ var n int32
+ w.Do(N, func(x interface{}) {
+ time.Sleep(1 * time.Millisecond)
+ atomic.AddInt32(&n, +1)
+ })
+ if n != N {
+ t.Fatalf("par.Work.Do did not do all the work")
+ }
+ if time.Since(start) < N/2*time.Millisecond {
+ return
+ }
+ }
+ t.Fatalf("par.Work.Do does not seem to be parallel")
+}
+
+func TestCache(t *testing.T) {
+ var cache Cache
+
+ n := 1
+ v := cache.Do(1, func() interface{} { n++; return n })
+ if v != 2 {
+ t.Fatalf("cache.Do(1) did not run f")
+ }
+ v = cache.Do(1, func() interface{} { n++; return n })
+ if v != 2 {
+ t.Fatalf("cache.Do(1) ran f again!")
+ }
+ v = cache.Do(2, func() interface{} { n++; return n })
+ if v != 3 {
+ t.Fatalf("cache.Do(2) did not run f")
+ }
+ v = cache.Do(1, func() interface{} { n++; return n })
+ if v != 2 {
+ t.Fatalf("cache.Do(1) did not returned saved value from original cache.Do(1)")
+ }
+}
diff --git a/libgo/go/cmd/go/internal/run/run.go b/libgo/go/cmd/go/internal/run/run.go
index ce24748f4e3..303e6842e7b 100644
--- a/libgo/go/cmd/go/internal/run/run.go
+++ b/libgo/go/cmd/go/internal/run/run.go
@@ -18,11 +18,13 @@ import (
)
var CmdRun = &base.Command{
- UsageLine: "run [build flags] [-exec xprog] gofiles... [arguments...]",
+ UsageLine: "go run [build flags] [-exec xprog] package [arguments...]",
Short: "compile and run Go program",
Long: `
-Run compiles and runs the main package comprising the named Go source files.
-A Go source file is defined to be a file ending in a literal ".go" suffix.
+Run compiles and runs the named main Go package.
+Typically the package is specified as a list of .go source files,
+but it may also be an import path, file system path, or pattern
+matching a single known package, as in 'go run .' or 'go run my/cmd'.
By default, 'go run' runs the compiled binary directly: 'a.out arguments...'.
If the -exec flag is given, 'go run' invokes the binary using xprog:
@@ -34,7 +36,10 @@ for example 'go_nacl_386_exec a.out arguments...'. This allows execution of
cross-compiled programs when a simulator or other execution method is
available.
+The exit status of Run is not the exit status of the compiled binary.
+
For more about build flags, see 'go help build'.
+For more about specifying packages, see 'go help packages'.
See also: go build.
`,
@@ -60,18 +65,33 @@ func runRun(cmd *base.Command, args []string) {
for i < len(args) && strings.HasSuffix(args[i], ".go") {
i++
}
- files, cmdArgs := args[:i], args[i:]
- if len(files) == 0 {
- base.Fatalf("go run: no go files listed")
- }
- for _, file := range files {
- if strings.HasSuffix(file, "_test.go") {
- // GoFilesPackage is going to assign this to TestGoFiles.
- // Reject since it won't be part of the build.
- base.Fatalf("go run: cannot run *_test.go files (%s)", file)
+ var p *load.Package
+ if i > 0 {
+ files := args[:i]
+ for _, file := range files {
+ if strings.HasSuffix(file, "_test.go") {
+ // GoFilesPackage is going to assign this to TestGoFiles.
+ // Reject since it won't be part of the build.
+ base.Fatalf("go run: cannot run *_test.go files (%s)", file)
+ }
+ }
+ p = load.GoFilesPackage(files)
+ } else if len(args) > 0 && !strings.HasPrefix(args[0], "-") {
+ pkgs := load.PackagesAndErrors(args[:1])
+ if len(pkgs) > 1 {
+ var names []string
+ for _, p := range pkgs {
+ names = append(names, p.ImportPath)
+ }
+ base.Fatalf("go run: pattern %s matches multiple packages:\n\t%s", args[0], strings.Join(names, "\n\t"))
}
+ p = pkgs[0]
+ i++
+ } else {
+ base.Fatalf("go run: no go files listed")
}
- p := load.GoFilesPackage(files)
+ cmdArgs := args[i:]
+
if p.Error != nil {
base.Fatalf("%s", p.Error)
}
diff --git a/libgo/go/cmd/go/internal/search/search.go b/libgo/go/cmd/go/internal/search/search.go
new file mode 100644
index 00000000000..60ae73696bb
--- /dev/null
+++ b/libgo/go/cmd/go/internal/search/search.go
@@ -0,0 +1,505 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package search
+
+import (
+ "cmd/go/internal/base"
+ "cmd/go/internal/cfg"
+ "fmt"
+ "go/build"
+ "log"
+ "os"
+ "path"
+ "path/filepath"
+ "regexp"
+ "strings"
+)
+
+// A Match represents the result of matching a single package pattern.
+type Match struct {
+ Pattern string // the pattern itself
+ Literal bool // whether it is a literal (no wildcards)
+ Pkgs []string // matching packages (dirs or import paths)
+}
+
+// MatchPackages returns all the packages that can be found
+// under the $GOPATH directories and $GOROOT matching pattern.
+// The pattern is either "all" (all packages), "std" (standard packages),
+// "cmd" (standard commands), or a path including "...".
+func MatchPackages(pattern string) *Match {
+ m := &Match{
+ Pattern: pattern,
+ Literal: false,
+ }
+ match := func(string) bool { return true }
+ treeCanMatch := func(string) bool { return true }
+ if !IsMetaPackage(pattern) {
+ match = MatchPattern(pattern)
+ treeCanMatch = TreeCanMatchPattern(pattern)
+ }
+
+ have := map[string]bool{
+ "builtin": true, // ignore pseudo-package that exists only for documentation
+ }
+ if !cfg.BuildContext.CgoEnabled {
+ have["runtime/cgo"] = true // ignore during walk
+ }
+
+ for _, src := range cfg.BuildContext.SrcDirs() {
+ if (pattern == "std" || pattern == "cmd") && src != cfg.GOROOTsrc {
+ continue
+ }
+ src = filepath.Clean(src) + string(filepath.Separator)
+ root := src
+ if pattern == "cmd" {
+ root += "cmd" + string(filepath.Separator)
+ }
+ filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
+ if err != nil || path == src {
+ return nil
+ }
+
+ want := true
+ // Avoid .foo, _foo, and testdata directory trees.
+ _, elem := filepath.Split(path)
+ if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
+ want = false
+ }
+
+ name := filepath.ToSlash(path[len(src):])
+ if pattern == "std" && (!IsStandardImportPath(name) || name == "cmd") {
+ // The name "std" is only the standard library.
+ // If the name is cmd, it's the root of the command tree.
+ want = false
+ }
+ if !treeCanMatch(name) {
+ want = false
+ }
+
+ if !fi.IsDir() {
+ if fi.Mode()&os.ModeSymlink != 0 && want {
+ if target, err := os.Stat(path); err == nil && target.IsDir() {
+ fmt.Fprintf(os.Stderr, "warning: ignoring symlink %s\n", path)
+ }
+ }
+ return nil
+ }
+ if !want {
+ return filepath.SkipDir
+ }
+
+ if have[name] {
+ return nil
+ }
+ have[name] = true
+ if !match(name) {
+ return nil
+ }
+ pkg, err := cfg.BuildContext.ImportDir(path, 0)
+ if err != nil {
+ if _, noGo := err.(*build.NoGoError); noGo {
+ return nil
+ }
+ }
+
+ // If we are expanding "cmd", skip main
+ // packages under cmd/vendor. At least as of
+ // March, 2017, there is one there for the
+ // vendored pprof tool.
+ if pattern == "cmd" && strings.HasPrefix(pkg.ImportPath, "cmd/vendor") && pkg.Name == "main" {
+ return nil
+ }
+
+ m.Pkgs = append(m.Pkgs, name)
+ return nil
+ })
+ }
+ return m
+}
+
+var modRoot string
+
+func SetModRoot(dir string) {
+ modRoot = dir
+}
+
+// MatchPackagesInFS is like allPackages but is passed a pattern
+// beginning ./ or ../, meaning it should scan the tree rooted
+// at the given directory. There are ... in the pattern too.
+// (See go help packages for pattern syntax.)
+func MatchPackagesInFS(pattern string) *Match {
+ m := &Match{
+ Pattern: pattern,
+ Literal: false,
+ }
+
+ // Find directory to begin the scan.
+ // Could be smarter but this one optimization
+ // is enough for now, since ... is usually at the
+ // end of a path.
+ i := strings.Index(pattern, "...")
+ dir, _ := path.Split(pattern[:i])
+
+ // pattern begins with ./ or ../.
+ // path.Clean will discard the ./ but not the ../.
+ // We need to preserve the ./ for pattern matching
+ // and in the returned import paths.
+ prefix := ""
+ if strings.HasPrefix(pattern, "./") {
+ prefix = "./"
+ }
+ match := MatchPattern(pattern)
+
+ if modRoot != "" {
+ abs, err := filepath.Abs(dir)
+ if err != nil {
+ base.Fatalf("go: %v", err)
+ }
+ if !hasFilepathPrefix(abs, modRoot) {
+ base.Fatalf("go: pattern %s refers to dir %s, outside module root %s", pattern, abs, modRoot)
+ return nil
+ }
+ }
+
+ filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
+ if err != nil || !fi.IsDir() {
+ return nil
+ }
+ top := false
+ if path == dir {
+ // filepath.Walk starts at dir and recurses. For the recursive case,
+ // the path is the result of filepath.Join, which calls filepath.Clean.
+ // The initial case is not Cleaned, though, so we do this explicitly.
+ //
+ // This converts a path like "./io/" to "io". Without this step, running
+ // "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io
+ // package, because prepending the prefix "./" to the unclean path would
+ // result in "././io", and match("././io") returns false.
+ top = true
+ path = filepath.Clean(path)
+ }
+
+ // Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..".
+ _, elem := filepath.Split(path)
+ dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".."
+ if dot || strings.HasPrefix(elem, "_") || elem == "testdata" {
+ return filepath.SkipDir
+ }
+
+ if !top && cfg.ModulesEnabled {
+ // Ignore other modules found in subdirectories.
+ if _, err := os.Stat(filepath.Join(path, "go.mod")); err == nil {
+ return filepath.SkipDir
+ }
+ }
+
+ name := prefix + filepath.ToSlash(path)
+ if !match(name) {
+ return nil
+ }
+
+ // We keep the directory if we can import it, or if we can't import it
+ // due to invalid Go source files. This means that directories containing
+ // parse errors will be built (and fail) instead of being silently skipped
+ // as not matching the pattern. Go 1.5 and earlier skipped, but that
+ // behavior means people miss serious mistakes.
+ // See golang.org/issue/11407.
+ if p, err := cfg.BuildContext.ImportDir(path, 0); err != nil && (p == nil || len(p.InvalidGoFiles) == 0) {
+ if _, noGo := err.(*build.NoGoError); !noGo {
+ log.Print(err)
+ }
+ return nil
+ }
+ m.Pkgs = append(m.Pkgs, name)
+ return nil
+ })
+ return m
+}
+
+// TreeCanMatchPattern(pattern)(name) reports whether
+// name or children of name can possibly match pattern.
+// Pattern is the same limited glob accepted by matchPattern.
+func TreeCanMatchPattern(pattern string) func(name string) bool {
+ wildCard := false
+ if i := strings.Index(pattern, "..."); i >= 0 {
+ wildCard = true
+ pattern = pattern[:i]
+ }
+ return func(name string) bool {
+ return len(name) <= len(pattern) && hasPathPrefix(pattern, name) ||
+ wildCard && strings.HasPrefix(name, pattern)
+ }
+}
+
+// MatchPattern(pattern)(name) reports whether
+// name matches pattern. Pattern is a limited glob
+// pattern in which '...' means 'any string' and there
+// is no other special syntax.
+// Unfortunately, there are two special cases. Quoting "go help packages":
+//
+// First, /... at the end of the pattern can match an empty string,
+// so that net/... matches both net and packages in its subdirectories, like net/http.
+// Second, any slash-separted pattern element containing a wildcard never
+// participates in a match of the "vendor" element in the path of a vendored
+// package, so that ./... does not match packages in subdirectories of
+// ./vendor or ./mycode/vendor, but ./vendor/... and ./mycode/vendor/... do.
+// Note, however, that a directory named vendor that itself contains code
+// is not a vendored package: cmd/vendor would be a command named vendor,
+// and the pattern cmd/... matches it.
+func MatchPattern(pattern string) func(name string) bool {
+ // Convert pattern to regular expression.
+ // The strategy for the trailing /... is to nest it in an explicit ? expression.
+ // The strategy for the vendor exclusion is to change the unmatchable
+ // vendor strings to a disallowed code point (vendorChar) and to use
+ // "(anything but that codepoint)*" as the implementation of the ... wildcard.
+ // This is a bit complicated but the obvious alternative,
+ // namely a hand-written search like in most shell glob matchers,
+ // is too easy to make accidentally exponential.
+ // Using package regexp guarantees linear-time matching.
+
+ const vendorChar = "\x00"
+
+ if strings.Contains(pattern, vendorChar) {
+ return func(name string) bool { return false }
+ }
+
+ re := regexp.QuoteMeta(pattern)
+ re = replaceVendor(re, vendorChar)
+ switch {
+ case strings.HasSuffix(re, `/`+vendorChar+`/\.\.\.`):
+ re = strings.TrimSuffix(re, `/`+vendorChar+`/\.\.\.`) + `(/vendor|/` + vendorChar + `/\.\.\.)`
+ case re == vendorChar+`/\.\.\.`:
+ re = `(/vendor|/` + vendorChar + `/\.\.\.)`
+ case strings.HasSuffix(re, `/\.\.\.`):
+ re = strings.TrimSuffix(re, `/\.\.\.`) + `(/\.\.\.)?`
+ }
+ re = strings.Replace(re, `\.\.\.`, `[^`+vendorChar+`]*`, -1)
+
+ reg := regexp.MustCompile(`^` + re + `$`)
+
+ return func(name string) bool {
+ if strings.Contains(name, vendorChar) {
+ return false
+ }
+ return reg.MatchString(replaceVendor(name, vendorChar))
+ }
+}
+
+// replaceVendor returns the result of replacing
+// non-trailing vendor path elements in x with repl.
+func replaceVendor(x, repl string) string {
+ if !strings.Contains(x, "vendor") {
+ return x
+ }
+ elem := strings.Split(x, "/")
+ for i := 0; i < len(elem)-1; i++ {
+ if elem[i] == "vendor" {
+ elem[i] = repl
+ }
+ }
+ return strings.Join(elem, "/")
+}
+
+// WarnUnmatched warns about patterns that didn't match any packages.
+func WarnUnmatched(matches []*Match) {
+ for _, m := range matches {
+ if len(m.Pkgs) == 0 {
+ fmt.Fprintf(os.Stderr, "go: warning: %q matched no packages\n", m.Pattern)
+ }
+ }
+}
+
+// ImportPaths returns the matching paths to use for the given command line.
+// It calls ImportPathsQuiet and then WarnUnmatched.
+func ImportPaths(patterns []string) []*Match {
+ matches := ImportPathsQuiet(patterns)
+ WarnUnmatched(matches)
+ return matches
+}
+
+// ImportPathsQuiet is like ImportPaths but does not warn about patterns with no matches.
+func ImportPathsQuiet(patterns []string) []*Match {
+ var out []*Match
+ for _, a := range CleanPatterns(patterns) {
+ if IsMetaPackage(a) {
+ out = append(out, MatchPackages(a))
+ continue
+ }
+ if strings.Contains(a, "...") {
+ if build.IsLocalImport(a) {
+ out = append(out, MatchPackagesInFS(a))
+ } else {
+ out = append(out, MatchPackages(a))
+ }
+ continue
+ }
+ out = append(out, &Match{Pattern: a, Literal: true, Pkgs: []string{a}})
+ }
+ return out
+}
+
+// CleanPatterns returns the patterns to use for the given
+// command line. It canonicalizes the patterns but does not
+// evaluate any matches.
+func CleanPatterns(patterns []string) []string {
+ if len(patterns) == 0 {
+ return []string{"."}
+ }
+ var out []string
+ for _, a := range patterns {
+ // Arguments are supposed to be import paths, but
+ // as a courtesy to Windows developers, rewrite \ to /
+ // in command-line arguments. Handles .\... and so on.
+ if filepath.Separator == '\\' {
+ a = strings.Replace(a, `\`, `/`, -1)
+ }
+
+ // Put argument in canonical form, but preserve leading ./.
+ if strings.HasPrefix(a, "./") {
+ a = "./" + path.Clean(a)
+ if a == "./." {
+ a = "."
+ }
+ } else {
+ a = path.Clean(a)
+ }
+ out = append(out, a)
+ }
+ return out
+}
+
+// IsMetaPackage checks if name is a reserved package name that expands to multiple packages.
+func IsMetaPackage(name string) bool {
+ return name == "std" || name == "cmd" || name == "all"
+}
+
+// hasPathPrefix reports whether the path s begins with the
+// elements in prefix.
+func hasPathPrefix(s, prefix string) bool {
+ switch {
+ default:
+ return false
+ case len(s) == len(prefix):
+ return s == prefix
+ case len(s) > len(prefix):
+ if prefix != "" && prefix[len(prefix)-1] == '/' {
+ return strings.HasPrefix(s, prefix)
+ }
+ return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
+ }
+}
+
+// hasFilepathPrefix reports whether the path s begins with the
+// elements in prefix.
+func hasFilepathPrefix(s, prefix string) bool {
+ switch {
+ default:
+ return false
+ case len(s) == len(prefix):
+ return s == prefix
+ case len(s) > len(prefix):
+ if prefix != "" && prefix[len(prefix)-1] == filepath.Separator {
+ return strings.HasPrefix(s, prefix)
+ }
+ return s[len(prefix)] == filepath.Separator && s[:len(prefix)] == prefix
+ }
+}
+
+// IsStandardImportPath reports whether $GOROOT/src/path should be considered
+// part of the standard distribution. For historical reasons we allow people to add
+// their own code to $GOROOT instead of using $GOPATH, but we assume that
+// code will start with a domain name (dot in the first element).
+//
+// Note that this function is meant to evaluate whether a directory found in GOROOT
+// should be treated as part of the standard library. It should not be used to decide
+// that a directory found in GOPATH should be rejected: directories in GOPATH
+// need not have dots in the first element, and they just take their chances
+// with future collisions in the standard library.
+func IsStandardImportPath(path string) bool {
+ i := strings.Index(path, "/")
+ if i < 0 {
+ i = len(path)
+ }
+ elem := path[:i]
+ return !strings.Contains(elem, ".")
+}
+
+// IsRelativePath reports whether pattern should be interpreted as a directory
+// path relative to the current directory, as opposed to a pattern matching
+// import paths.
+func IsRelativePath(pattern string) bool {
+ return strings.HasPrefix(pattern, "./") || strings.HasPrefix(pattern, "../") || pattern == "." || pattern == ".."
+}
+
+// InDir checks whether path is in the file tree rooted at dir.
+// If so, InDir returns an equivalent path relative to dir.
+// If not, InDir returns an empty string.
+// InDir makes some effort to succeed even in the presence of symbolic links.
+// TODO(rsc): Replace internal/test.inDir with a call to this function for Go 1.12.
+func InDir(path, dir string) string {
+ if rel := inDirLex(path, dir); rel != "" {
+ return rel
+ }
+ xpath, err := filepath.EvalSymlinks(path)
+ if err != nil || xpath == path {
+ xpath = ""
+ } else {
+ if rel := inDirLex(xpath, dir); rel != "" {
+ return rel
+ }
+ }
+
+ xdir, err := filepath.EvalSymlinks(dir)
+ if err == nil && xdir != dir {
+ if rel := inDirLex(path, xdir); rel != "" {
+ return rel
+ }
+ if xpath != "" {
+ if rel := inDirLex(xpath, xdir); rel != "" {
+ return rel
+ }
+ }
+ }
+ return ""
+}
+
+// inDirLex is like inDir but only checks the lexical form of the file names.
+// It does not consider symbolic links.
+// TODO(rsc): This is a copy of str.HasFilePathPrefix, modified to
+// return the suffix. Most uses of str.HasFilePathPrefix should probably
+// be calling InDir instead.
+func inDirLex(path, dir string) string {
+ pv := strings.ToUpper(filepath.VolumeName(path))
+ dv := strings.ToUpper(filepath.VolumeName(dir))
+ path = path[len(pv):]
+ dir = dir[len(dv):]
+ switch {
+ default:
+ return ""
+ case pv != dv:
+ return ""
+ case len(path) == len(dir):
+ if path == dir {
+ return "."
+ }
+ return ""
+ case dir == "":
+ return path
+ case len(path) > len(dir):
+ if dir[len(dir)-1] == filepath.Separator {
+ if path[:len(dir)] == dir {
+ return path[len(dir):]
+ }
+ return ""
+ }
+ if path[len(dir)] == filepath.Separator && path[:len(dir)] == dir {
+ if len(path) == len(dir)+1 {
+ return "."
+ }
+ return path[len(dir)+1:]
+ }
+ return ""
+ }
+}
diff --git a/libgo/go/cmd/go/internal/load/match_test.go b/libgo/go/cmd/go/internal/search/search_test.go
index b8d67dac742..0bef765fa45 100644
--- a/libgo/go/cmd/go/internal/load/match_test.go
+++ b/libgo/go/cmd/go/internal/search/search_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package load
+package search
import (
"strings"
@@ -65,8 +65,8 @@ var matchPatternTests = `
`
func TestMatchPattern(t *testing.T) {
- testPatterns(t, "matchPattern", matchPatternTests, func(pattern, name string) bool {
- return matchPattern(pattern)(name)
+ testPatterns(t, "MatchPattern", matchPatternTests, func(pattern, name string) bool {
+ return MatchPattern(pattern)(name)
})
}
@@ -106,8 +106,8 @@ var treeCanMatchPatternTests = `
`
func TestTreeCanMatchPattern(t *testing.T) {
- testPatterns(t, "treeCanMatchPattern", treeCanMatchPatternTests, func(pattern, name string) bool {
- return treeCanMatchPattern(pattern)(name)
+ testPatterns(t, "TreeCanMatchPattern", treeCanMatchPatternTests, func(pattern, name string) bool {
+ return TreeCanMatchPattern(pattern)(name)
})
}
diff --git a/libgo/go/cmd/go/internal/semver/semver.go b/libgo/go/cmd/go/internal/semver/semver.go
new file mode 100644
index 00000000000..4af7118e55d
--- /dev/null
+++ b/libgo/go/cmd/go/internal/semver/semver.go
@@ -0,0 +1,388 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package semver implements comparison of semantic version strings.
+// In this package, semantic version strings must begin with a leading "v",
+// as in "v1.0.0".
+//
+// The general form of a semantic version string accepted by this package is
+//
+// vMAJOR[.MINOR[.PATCH[-PRERELEASE][+BUILD]]]
+//
+// where square brackets indicate optional parts of the syntax;
+// MAJOR, MINOR, and PATCH are decimal integers without extra leading zeros;
+// PRERELEASE and BUILD are each a series of non-empty dot-separated identifiers
+// using only alphanumeric characters and hyphens; and
+// all-numeric PRERELEASE identifiers must not have leading zeros.
+//
+// This package follows Semantic Versioning 2.0.0 (see semver.org)
+// with two exceptions. First, it requires the "v" prefix. Second, it recognizes
+// vMAJOR and vMAJOR.MINOR (with no prerelease or build suffixes)
+// as shorthands for vMAJOR.0.0 and vMAJOR.MINOR.0.
+package semver
+
+// parsed returns the parsed form of a semantic version string.
+type parsed struct {
+ major string
+ minor string
+ patch string
+ short string
+ prerelease string
+ build string
+ err string
+}
+
+// IsValid reports whether v is a valid semantic version string.
+func IsValid(v string) bool {
+ _, ok := parse(v)
+ return ok
+}
+
+// Canonical returns the canonical formatting of the semantic version v.
+// It fills in any missing .MINOR or .PATCH and discards build metadata.
+// Two semantic versions compare equal only if their canonical formattings
+// are identical strings.
+// The canonical invalid semantic version is the empty string.
+func Canonical(v string) string {
+ p, ok := parse(v)
+ if !ok {
+ return ""
+ }
+ if p.build != "" {
+ return v[:len(v)-len(p.build)]
+ }
+ if p.short != "" {
+ return v + p.short
+ }
+ return v
+}
+
+// Major returns the major version prefix of the semantic version v.
+// For example, Major("v2.1.0") == "v2".
+// If v is an invalid semantic version string, Major returns the empty string.
+func Major(v string) string {
+ pv, ok := parse(v)
+ if !ok {
+ return ""
+ }
+ return v[:1+len(pv.major)]
+}
+
+// MajorMinor returns the major.minor version prefix of the semantic version v.
+// For example, MajorMinor("v2.1.0") == "v2.1".
+// If v is an invalid semantic version string, MajorMinor returns the empty string.
+func MajorMinor(v string) string {
+ pv, ok := parse(v)
+ if !ok {
+ return ""
+ }
+ i := 1 + len(pv.major)
+ if j := i + 1 + len(pv.minor); j <= len(v) && v[i] == '.' && v[i+1:j] == pv.minor {
+ return v[:j]
+ }
+ return v[:i] + "." + pv.minor
+}
+
+// Prerelease returns the prerelease suffix of the semantic version v.
+// For example, Prerelease("v2.1.0-pre+meta") == "-pre".
+// If v is an invalid semantic version string, Prerelease returns the empty string.
+func Prerelease(v string) string {
+ pv, ok := parse(v)
+ if !ok {
+ return ""
+ }
+ return pv.prerelease
+}
+
+// Build returns the build suffix of the semantic version v.
+// For example, Build("v2.1.0+meta") == "+meta".
+// If v is an invalid semantic version string, Build returns the empty string.
+func Build(v string) string {
+ pv, ok := parse(v)
+ if !ok {
+ return ""
+ }
+ return pv.build
+}
+
+// Compare returns an integer comparing two versions according to
+// according to semantic version precedence.
+// The result will be 0 if v == w, -1 if v < w, or +1 if v > w.
+//
+// An invalid semantic version string is considered less than a valid one.
+// All invalid semantic version strings compare equal to each other.
+func Compare(v, w string) int {
+ pv, ok1 := parse(v)
+ pw, ok2 := parse(w)
+ if !ok1 && !ok2 {
+ return 0
+ }
+ if !ok1 {
+ return -1
+ }
+ if !ok2 {
+ return +1
+ }
+ if c := compareInt(pv.major, pw.major); c != 0 {
+ return c
+ }
+ if c := compareInt(pv.minor, pw.minor); c != 0 {
+ return c
+ }
+ if c := compareInt(pv.patch, pw.patch); c != 0 {
+ return c
+ }
+ return comparePrerelease(pv.prerelease, pw.prerelease)
+}
+
+// Max canonicalizes its arguments and then returns the version string
+// that compares greater.
+func Max(v, w string) string {
+ v = Canonical(v)
+ w = Canonical(w)
+ if Compare(v, w) > 0 {
+ return v
+ }
+ return w
+}
+
+func parse(v string) (p parsed, ok bool) {
+ if v == "" || v[0] != 'v' {
+ p.err = "missing v prefix"
+ return
+ }
+ p.major, v, ok = parseInt(v[1:])
+ if !ok {
+ p.err = "bad major version"
+ return
+ }
+ if v == "" {
+ p.minor = "0"
+ p.patch = "0"
+ p.short = ".0.0"
+ return
+ }
+ if v[0] != '.' {
+ p.err = "bad minor prefix"
+ ok = false
+ return
+ }
+ p.minor, v, ok = parseInt(v[1:])
+ if !ok {
+ p.err = "bad minor version"
+ return
+ }
+ if v == "" {
+ p.patch = "0"
+ p.short = ".0"
+ return
+ }
+ if v[0] != '.' {
+ p.err = "bad patch prefix"
+ ok = false
+ return
+ }
+ p.patch, v, ok = parseInt(v[1:])
+ if !ok {
+ p.err = "bad patch version"
+ return
+ }
+ if len(v) > 0 && v[0] == '-' {
+ p.prerelease, v, ok = parsePrerelease(v)
+ if !ok {
+ p.err = "bad prerelease"
+ return
+ }
+ }
+ if len(v) > 0 && v[0] == '+' {
+ p.build, v, ok = parseBuild(v)
+ if !ok {
+ p.err = "bad build"
+ return
+ }
+ }
+ if v != "" {
+ p.err = "junk on end"
+ ok = false
+ return
+ }
+ ok = true
+ return
+}
+
+func parseInt(v string) (t, rest string, ok bool) {
+ if v == "" {
+ return
+ }
+ if v[0] < '0' || '9' < v[0] {
+ return
+ }
+ i := 1
+ for i < len(v) && '0' <= v[i] && v[i] <= '9' {
+ i++
+ }
+ if v[0] == '0' && i != 1 {
+ return
+ }
+ return v[:i], v[i:], true
+}
+
+func parsePrerelease(v string) (t, rest string, ok bool) {
+ // "A pre-release version MAY be denoted by appending a hyphen and
+ // a series of dot separated identifiers immediately following the patch version.
+ // Identifiers MUST comprise only ASCII alphanumerics and hyphen [0-9A-Za-z-].
+ // Identifiers MUST NOT be empty. Numeric identifiers MUST NOT include leading zeroes."
+ if v == "" || v[0] != '-' {
+ return
+ }
+ i := 1
+ start := 1
+ for i < len(v) && v[i] != '+' {
+ if !isIdentChar(v[i]) && v[i] != '.' {
+ return
+ }
+ if v[i] == '.' {
+ if start == i || isBadNum(v[start:i]) {
+ return
+ }
+ start = i + 1
+ }
+ i++
+ }
+ if start == i || isBadNum(v[start:i]) {
+ return
+ }
+ return v[:i], v[i:], true
+}
+
+func parseBuild(v string) (t, rest string, ok bool) {
+ if v == "" || v[0] != '+' {
+ return
+ }
+ i := 1
+ start := 1
+ for i < len(v) {
+ if !isIdentChar(v[i]) {
+ return
+ }
+ if v[i] == '.' {
+ if start == i {
+ return
+ }
+ start = i + 1
+ }
+ i++
+ }
+ if start == i {
+ return
+ }
+ return v[:i], v[i:], true
+}
+
+func isIdentChar(c byte) bool {
+ return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '-'
+}
+
+func isBadNum(v string) bool {
+ i := 0
+ for i < len(v) && '0' <= v[i] && v[i] <= '9' {
+ i++
+ }
+ return i == len(v) && i > 1 && v[0] == '0'
+}
+
+func isNum(v string) bool {
+ i := 0
+ for i < len(v) && '0' <= v[i] && v[i] <= '9' {
+ i++
+ }
+ return i == len(v)
+}
+
+func compareInt(x, y string) int {
+ if x == y {
+ return 0
+ }
+ if len(x) < len(y) {
+ return -1
+ }
+ if len(x) > len(y) {
+ return +1
+ }
+ if x < y {
+ return -1
+ } else {
+ return +1
+ }
+}
+
+func comparePrerelease(x, y string) int {
+ // "When major, minor, and patch are equal, a pre-release version has
+ // lower precedence than a normal version.
+ // Example: 1.0.0-alpha < 1.0.0.
+ // Precedence for two pre-release versions with the same major, minor,
+ // and patch version MUST be determined by comparing each dot separated
+ // identifier from left to right until a difference is found as follows:
+ // identifiers consisting of only digits are compared numerically and
+ // identifiers with letters or hyphens are compared lexically in ASCII
+ // sort order. Numeric identifiers always have lower precedence than
+ // non-numeric identifiers. A larger set of pre-release fields has a
+ // higher precedence than a smaller set, if all of the preceding
+ // identifiers are equal.
+ // Example: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta <
+ // 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0."
+ if x == y {
+ return 0
+ }
+ if x == "" {
+ return +1
+ }
+ if y == "" {
+ return -1
+ }
+ for x != "" && y != "" {
+ x = x[1:] // skip - or .
+ y = y[1:] // skip - or .
+ var dx, dy string
+ dx, x = nextIdent(x)
+ dy, y = nextIdent(y)
+ if dx != dy {
+ ix := isNum(dx)
+ iy := isNum(dy)
+ if ix != iy {
+ if ix {
+ return -1
+ } else {
+ return +1
+ }
+ }
+ if ix {
+ if len(dx) < len(dy) {
+ return -1
+ }
+ if len(dx) > len(dy) {
+ return +1
+ }
+ }
+ if dx < dy {
+ return -1
+ } else {
+ return +1
+ }
+ }
+ }
+ if x == "" {
+ return -1
+ } else {
+ return +1
+ }
+}
+
+func nextIdent(x string) (dx, rest string) {
+ i := 0
+ for i < len(x) && x[i] != '.' {
+ i++
+ }
+ return x[:i], x[i:]
+}
diff --git a/libgo/go/cmd/go/internal/semver/semver_test.go b/libgo/go/cmd/go/internal/semver/semver_test.go
new file mode 100644
index 00000000000..96b64a58075
--- /dev/null
+++ b/libgo/go/cmd/go/internal/semver/semver_test.go
@@ -0,0 +1,182 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package semver
+
+import (
+ "strings"
+ "testing"
+)
+
+var tests = []struct {
+ in string
+ out string
+}{
+ {"bad", ""},
+ {"v1-alpha.beta.gamma", ""},
+ {"v1-pre", ""},
+ {"v1+meta", ""},
+ {"v1-pre+meta", ""},
+ {"v1.2-pre", ""},
+ {"v1.2+meta", ""},
+ {"v1.2-pre+meta", ""},
+ {"v1.0.0-alpha", "v1.0.0-alpha"},
+ {"v1.0.0-alpha.1", "v1.0.0-alpha.1"},
+ {"v1.0.0-alpha.beta", "v1.0.0-alpha.beta"},
+ {"v1.0.0-beta", "v1.0.0-beta"},
+ {"v1.0.0-beta.2", "v1.0.0-beta.2"},
+ {"v1.0.0-beta.11", "v1.0.0-beta.11"},
+ {"v1.0.0-rc.1", "v1.0.0-rc.1"},
+ {"v1", "v1.0.0"},
+ {"v1.0", "v1.0.0"},
+ {"v1.0.0", "v1.0.0"},
+ {"v1.2", "v1.2.0"},
+ {"v1.2.0", "v1.2.0"},
+ {"v1.2.3-456", "v1.2.3-456"},
+ {"v1.2.3-456.789", "v1.2.3-456.789"},
+ {"v1.2.3-456-789", "v1.2.3-456-789"},
+ {"v1.2.3-456a", "v1.2.3-456a"},
+ {"v1.2.3-pre", "v1.2.3-pre"},
+ {"v1.2.3-pre+meta", "v1.2.3-pre"},
+ {"v1.2.3-pre.1", "v1.2.3-pre.1"},
+ {"v1.2.3-zzz", "v1.2.3-zzz"},
+ {"v1.2.3", "v1.2.3"},
+ {"v1.2.3+meta", "v1.2.3"},
+ {"v1.2.3+meta-pre", "v1.2.3"},
+}
+
+func TestIsValid(t *testing.T) {
+ for _, tt := range tests {
+ ok := IsValid(tt.in)
+ if ok != (tt.out != "") {
+ t.Errorf("IsValid(%q) = %v, want %v", tt.in, ok, !ok)
+ }
+ }
+}
+
+func TestCanonical(t *testing.T) {
+ for _, tt := range tests {
+ out := Canonical(tt.in)
+ if out != tt.out {
+ t.Errorf("Canonical(%q) = %q, want %q", tt.in, out, tt.out)
+ }
+ }
+}
+
+func TestMajor(t *testing.T) {
+ for _, tt := range tests {
+ out := Major(tt.in)
+ want := ""
+ if i := strings.Index(tt.out, "."); i >= 0 {
+ want = tt.out[:i]
+ }
+ if out != want {
+ t.Errorf("Major(%q) = %q, want %q", tt.in, out, want)
+ }
+ }
+}
+
+func TestMajorMinor(t *testing.T) {
+ for _, tt := range tests {
+ out := MajorMinor(tt.in)
+ var want string
+ if tt.out != "" {
+ want = tt.in
+ if i := strings.Index(want, "+"); i >= 0 {
+ want = want[:i]
+ }
+ if i := strings.Index(want, "-"); i >= 0 {
+ want = want[:i]
+ }
+ switch strings.Count(want, ".") {
+ case 0:
+ want += ".0"
+ case 1:
+ // ok
+ case 2:
+ want = want[:strings.LastIndex(want, ".")]
+ }
+ }
+ if out != want {
+ t.Errorf("MajorMinor(%q) = %q, want %q", tt.in, out, want)
+ }
+ }
+}
+
+func TestPrerelease(t *testing.T) {
+ for _, tt := range tests {
+ pre := Prerelease(tt.in)
+ var want string
+ if tt.out != "" {
+ if i := strings.Index(tt.out, "-"); i >= 0 {
+ want = tt.out[i:]
+ }
+ }
+ if pre != want {
+ t.Errorf("Prerelease(%q) = %q, want %q", tt.in, pre, want)
+ }
+ }
+}
+
+func TestBuild(t *testing.T) {
+ for _, tt := range tests {
+ build := Build(tt.in)
+ var want string
+ if tt.out != "" {
+ if i := strings.Index(tt.in, "+"); i >= 0 {
+ want = tt.in[i:]
+ }
+ }
+ if build != want {
+ t.Errorf("Build(%q) = %q, want %q", tt.in, build, want)
+ }
+ }
+}
+
+func TestCompare(t *testing.T) {
+ for i, ti := range tests {
+ for j, tj := range tests {
+ cmp := Compare(ti.in, tj.in)
+ var want int
+ if ti.out == tj.out {
+ want = 0
+ } else if i < j {
+ want = -1
+ } else {
+ want = +1
+ }
+ if cmp != want {
+ t.Errorf("Compare(%q, %q) = %d, want %d", ti.in, tj.in, cmp, want)
+ }
+ }
+ }
+}
+
+func TestMax(t *testing.T) {
+ for i, ti := range tests {
+ for j, tj := range tests {
+ max := Max(ti.in, tj.in)
+ want := Canonical(ti.in)
+ if i < j {
+ want = Canonical(tj.in)
+ }
+ if max != want {
+ t.Errorf("Max(%q, %q) = %q, want %q", ti.in, tj.in, max, want)
+ }
+ }
+ }
+}
+
+var (
+ v1 = "v1.0.0+metadata-dash"
+ v2 = "v1.0.0+metadata-dash1"
+)
+
+func BenchmarkCompare(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ if Compare(v1, v2) != 0 {
+ b.Fatalf("bad compare")
+ }
+ }
+}
diff --git a/libgo/go/cmd/go/internal/str/path.go b/libgo/go/cmd/go/internal/str/path.go
index 84ca9d581e9..a9b4d759a6b 100644
--- a/libgo/go/cmd/go/internal/str/path.go
+++ b/libgo/go/cmd/go/internal/str/path.go
@@ -9,8 +9,25 @@ import (
"strings"
)
-// HasFilePathPrefix reports whether the filesystem path s begins with the
-// elements in prefix.
+// HasPath reports whether the slash-separated path s
+// begins with the elements in prefix.
+func HasPathPrefix(s, prefix string) bool {
+ if len(s) == len(prefix) {
+ return s == prefix
+ }
+ if prefix == "" {
+ return true
+ }
+ if len(s) > len(prefix) {
+ if prefix[len(prefix)-1] == '/' || s[len(prefix)] == '/' {
+ return s[:len(prefix)] == prefix
+ }
+ }
+ return false
+}
+
+// HasFilePathPrefix reports whether the filesystem path s
+// begins with the elements in prefix.
func HasFilePathPrefix(s, prefix string) bool {
sv := strings.ToUpper(filepath.VolumeName(s))
pv := strings.ToUpper(filepath.VolumeName(prefix))
@@ -23,8 +40,10 @@ func HasFilePathPrefix(s, prefix string) bool {
return false
case len(s) == len(prefix):
return s == prefix
+ case prefix == "":
+ return true
case len(s) > len(prefix):
- if prefix != "" && prefix[len(prefix)-1] == filepath.Separator {
+ if prefix[len(prefix)-1] == filepath.Separator {
return strings.HasPrefix(s, prefix)
}
return s[len(prefix)] == filepath.Separator && s[:len(prefix)] == prefix
diff --git a/libgo/go/cmd/go/internal/test/cover.go b/libgo/go/cmd/go/internal/test/cover.go
index 12538b46564..9841791552d 100644
--- a/libgo/go/cmd/go/internal/test/cover.go
+++ b/libgo/go/cmd/go/internal/test/cover.go
@@ -23,7 +23,7 @@ var coverMerge struct {
// Using this function clears the profile in case it existed from a previous run,
// or in case it doesn't exist and the test is going to fail to create it (or not run).
func initCoverProfile() {
- if testCoverProfile == "" {
+ if testCoverProfile == "" || testC {
return
}
if !filepath.IsAbs(testCoverProfile) && testOutputDir != "" {
diff --git a/libgo/go/cmd/go/internal/test/test.go b/libgo/go/cmd/go/internal/test/test.go
index 5adb7df7c48..a089f1b134a 100644
--- a/libgo/go/cmd/go/internal/test/test.go
+++ b/libgo/go/cmd/go/internal/test/test.go
@@ -9,11 +9,7 @@ import (
"crypto/sha256"
"errors"
"fmt"
- "go/ast"
"go/build"
- "go/doc"
- "go/parser"
- "go/token"
"io"
"io/ioutil"
"os"
@@ -25,15 +21,13 @@ import (
"strconv"
"strings"
"sync"
- "text/template"
"time"
- "unicode"
- "unicode/utf8"
"cmd/go/internal/base"
"cmd/go/internal/cache"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
+ "cmd/go/internal/modload"
"cmd/go/internal/str"
"cmd/go/internal/work"
"cmd/internal/test2json"
@@ -44,7 +38,7 @@ func init() {
CmdTest.Run = runTest
}
-const testUsage = "test [build/test flags] [packages] [build/test flags & test binary flags]"
+const testUsage = "go test [build/test flags] [packages] [build/test flags & test binary flags]"
var CmdTest = &base.Command{
CustomFlags: true,
@@ -76,9 +70,12 @@ to hold ancillary data needed by the tests.
As part of building a test binary, go test runs go vet on the package
and its test source files to identify significant problems. If go vet
-finds any problems, go test reports those and does not run the test binary.
-Only a high-confidence subset of the default go vet checks are used.
-To disable the running of go vet, use the -vet=off flag.
+finds any problems, go test reports those and does not run the test
+binary. Only a high-confidence subset of the default go vet checks are
+used. That subset is: 'atomic', 'bool', 'buildtags', 'nilfunc', and
+'printf'. You can see the documentation for these and other vet tests
+via "go doc cmd/vet". To disable the running of go vet, use the
+-vet=off flag.
All test output and summary lines are printed to the go command's
standard output, even if the test printed them to its own standard
@@ -172,7 +169,7 @@ flags are also accessible by 'go test'.
// Usage prints the usage message for 'go test -h' and exits.
func Usage() {
- os.Stderr.WriteString(testUsage + "\n\n" +
+ os.Stderr.WriteString("usage: " + testUsage + "\n\n" +
strings.TrimSpace(testFlag1) + "\n\n\t" +
strings.TrimSpace(testFlag2) + "\n")
os.Exit(2)
@@ -328,14 +325,13 @@ profile the tests during execution:
Writes test binary as -c would.
-memprofile mem.out
- Write a memory profile to the file after all tests have passed.
+ Write an allocation profile to the file after all tests have passed.
Writes test binary as -c would.
-memprofilerate n
- Enable more precise (and expensive) memory profiles by setting
- runtime.MemProfileRate. See 'go doc runtime.MemProfileRate'.
- To profile all memory allocations, use -test.memprofilerate=1
- and pass --alloc_space flag to the pprof tool.
+ Enable more precise (and expensive) memory allocation profiles by
+ setting runtime.MemProfileRate. See 'go doc runtime.MemProfileRate'.
+ To profile all memory allocations, use -test.memprofilerate=1.
-mutexprofile mutex.out
Write a mutex contention profile to the specified file
@@ -385,6 +381,12 @@ flag not known to the go test command. Continuing the example above,
the package list would have to appear before -myflag, but could appear
on either side of -v.
+When 'go test' runs in package list mode, 'go test' caches successful
+package test results to avoid unnecessary repeated running of tests. To
+disable test caching, use any test flag or argument other than the
+cacheable flags. The idiomatic way to disable test caching explicitly
+is to use -count=1.
+
To keep an argument for a test binary from being interpreted as a
known flag or a package name, use -args (see 'go help test') which
passes the remainder of the command line through to the test binary
@@ -499,13 +501,6 @@ var (
testCacheExpire time.Time // ignore cached test results before this time
)
-var testMainDeps = []string{
- // Dependencies for testmain.
- "os",
- "testing",
- "testing/internal/testdeps",
-}
-
// testVetFlags is the list of flags to pass to vet when invoked automatically during go test.
var testVetFlags = []string{
// TODO(rsc): Decide which tests are enabled by default.
@@ -533,6 +528,8 @@ var testVetFlags = []string{
}
func runTest(cmd *base.Command, args []string) {
+ modload.LoadTests = true
+
pkgArgs, testArgs = testFlags(args)
work.FindExecCmd() // initialize cached result
@@ -597,7 +594,7 @@ func runTest(cmd *base.Command, args []string) {
cfg.BuildV = testV
deps := make(map[string]bool)
- for _, dep := range testMainDeps {
+ for _, dep := range load.TestMainDeps {
deps[dep] = true
}
@@ -656,7 +653,7 @@ func runTest(cmd *base.Command, args []string) {
}
// Select for coverage all dependencies matching the testCoverPaths patterns.
- for _, p := range load.PackageList(pkgs) {
+ for _, p := range load.GetTestPackageList(pkgs) {
haveMatch := false
for i := range testCoverPaths {
if match[i](p) {
@@ -704,7 +701,7 @@ func runTest(cmd *base.Command, args []string) {
coverFiles = append(coverFiles, p.GoFiles...)
coverFiles = append(coverFiles, p.CgoFiles...)
coverFiles = append(coverFiles, p.TestGoFiles...)
- p.Internal.CoverVars = declareCoverVars(p.ImportPath, coverFiles...)
+ p.Internal.CoverVars = declareCoverVars(p, coverFiles...)
if testCover && testCoverMode == "atomic" {
ensureImport(p, "sync/atomic")
}
@@ -721,16 +718,13 @@ func runTest(cmd *base.Command, args []string) {
buildTest, runTest, printTest, err := builderTest(&b, p)
if err != nil {
str := err.Error()
- if strings.HasPrefix(str, "\n") {
- str = str[1:]
- }
- failed := fmt.Sprintf("FAIL\t%s [setup failed]\n", p.ImportPath)
-
+ str = strings.TrimPrefix(str, "\n")
if p.ImportPath != "" {
- base.Errorf("# %s\n%s\n%s", p.ImportPath, str, failed)
+ base.Errorf("# %s\n%s", p.ImportPath, str)
} else {
- base.Errorf("%s\n%s", str, failed)
+ base.Errorf("%s", str)
}
+ fmt.Printf("FAIL\t%s [setup failed]\n", p.ImportPath)
continue
}
builds = append(builds, buildTest)
@@ -798,14 +792,20 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
}
// Build Package structs describing:
+ // pmain - pkg.test binary
// ptest - package + test files
// pxtest - package of external test files
- // pmain - pkg.test binary
- var ptest, pxtest, pmain *load.Package
-
- localCover := testCover && testCoverPaths == nil
-
- ptest, pxtest, err = load.GetTestPackagesFor(p, localCover || p.Name == "main")
+ var cover *load.TestCover
+ if testCover {
+ cover = &load.TestCover{
+ Mode: testCoverMode,
+ Local: testCover && testCoverPaths == nil,
+ Pkgs: testCoverPkgs,
+ Paths: testCoverPaths,
+ DeclVars: declareCoverVars,
+ }
+ }
+ pmain, ptest, pxtest, err := load.GetTestPackagesFor(p, cover)
if err != nil {
return nil, nil, nil, err
}
@@ -822,116 +822,18 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
}
testBinary := elem + ".test"
- // Should we apply coverage analysis locally,
- // only for this package and only for this test?
- // Yes, if -cover is on but -coverpkg has not specified
- // a list of packages for global coverage.
- if localCover {
- ptest.Internal.CoverMode = testCoverMode
- var coverFiles []string
- coverFiles = append(coverFiles, ptest.GoFiles...)
- coverFiles = append(coverFiles, ptest.CgoFiles...)
- ptest.Internal.CoverVars = declareCoverVars(ptest.ImportPath, coverFiles...)
- }
-
testDir := b.NewObjdir()
if err := b.Mkdir(testDir); err != nil {
return nil, nil, nil, err
}
- // Action for building pkg.test.
- pmain = &load.Package{
- PackagePublic: load.PackagePublic{
- Name: "main",
- Dir: testDir,
- GoFiles: []string{"_testmain.go"},
- ImportPath: p.ImportPath + " (testmain)",
- Root: p.Root,
- },
- Internal: load.PackageInternal{
- Build: &build.Package{Name: "main"},
- OmitDebug: !testC && !testNeedBinary,
-
- Asmflags: p.Internal.Asmflags,
- Gcflags: p.Internal.Gcflags,
- Ldflags: p.Internal.Ldflags,
- Gccgoflags: p.Internal.Gccgoflags,
- },
- }
-
- // The generated main also imports testing, regexp, and os.
- // Also the linker introduces implicit dependencies reported by LinkerDeps.
- var stk load.ImportStack
- stk.Push("testmain")
- deps := testMainDeps // cap==len, so safe for append
- for _, d := range load.LinkerDeps(p) {
- deps = append(deps, d)
- }
- for _, dep := range deps {
- if dep == ptest.ImportPath {
- pmain.Internal.Imports = append(pmain.Internal.Imports, ptest)
- } else {
- p1 := load.LoadImport(dep, "", nil, &stk, nil, 0)
- if p1.Error != nil {
- return nil, nil, nil, p1.Error
- }
- pmain.Internal.Imports = append(pmain.Internal.Imports, p1)
- }
- }
-
- if testCoverPkgs != nil {
- // Add imports, but avoid duplicates.
- seen := map[*load.Package]bool{p: true, ptest: true}
- for _, p1 := range pmain.Internal.Imports {
- seen[p1] = true
- }
- for _, p1 := range testCoverPkgs {
- if !seen[p1] {
- seen[p1] = true
- pmain.Internal.Imports = append(pmain.Internal.Imports, p1)
- }
- }
- }
-
- // Do initial scan for metadata needed for writing _testmain.go
- // Use that metadata to update the list of imports for package main.
- // The list of imports is used by recompileForTest and by the loop
- // afterward that gathers t.Cover information.
- t, err := loadTestFuncs(ptest)
- if err != nil {
- return nil, nil, nil, err
- }
- if len(ptest.GoFiles)+len(ptest.CgoFiles) > 0 {
- pmain.Internal.Imports = append(pmain.Internal.Imports, ptest)
- t.ImportTest = true
- }
- if pxtest != nil {
- pmain.Internal.Imports = append(pmain.Internal.Imports, pxtest)
- t.ImportXtest = true
- }
-
- if ptest != p {
- // We have made modifications to the package p being tested
- // and are rebuilding p (as ptest).
- // Arrange to rebuild all packages q such that
- // the test depends on q and q depends on p.
- // This makes sure that q sees the modifications to p.
- // Strictly speaking, the rebuild is only necessary if the
- // modifications to p change its export metadata, but
- // determining that is a bit tricky, so we rebuild always.
- recompileForTest(pmain, p, ptest, pxtest)
- }
-
- for _, cp := range pmain.Internal.Imports {
- if len(cp.Internal.CoverVars) > 0 {
- t.Cover = append(t.Cover, coverInfo{cp, cp.Internal.CoverVars})
- }
- }
+ pmain.Dir = testDir
+ pmain.Internal.OmitDebug = !testC && !testNeedBinary
if !cfg.BuildN {
// writeTestmain writes _testmain.go,
// using the test description gathered in t.
- if err := writeTestmain(testDir+"_testmain.go", t); err != nil {
+ if err := ioutil.WriteFile(testDir+"_testmain.go", *pmain.Internal.TestmainGo, 0666); err != nil {
return nil, nil, nil, err
}
}
@@ -993,8 +895,10 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
}
runAction = installAction // make sure runAction != nil even if not running test
}
+ var vetRunAction *work.Action
if testC {
printAction = &work.Action{Mode: "test print (nop)", Package: p, Deps: []*work.Action{runAction}} // nop
+ vetRunAction = printAction
} else {
// run test
c := new(runCache)
@@ -1007,12 +911,7 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
TryCache: c.tryCache,
Objdir: testDir,
}
- if len(ptest.GoFiles)+len(ptest.CgoFiles) > 0 {
- addTestVet(b, ptest, runAction, installAction)
- }
- if pxtest != nil {
- addTestVet(b, pxtest, runAction, installAction)
- }
+ vetRunAction = runAction
cleanAction = &work.Action{
Mode: "test clean",
Func: builderCleanTest,
@@ -1029,6 +928,14 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
IgnoreFail: true, // print even if test failed
}
}
+
+ if len(ptest.GoFiles)+len(ptest.CgoFiles) > 0 {
+ addTestVet(b, ptest, vetRunAction, installAction)
+ }
+ if pxtest != nil {
+ addTestVet(b, pxtest, vetRunAction, installAction)
+ }
+
if installAction != nil {
if runAction != installAction {
installAction.Deps = append(installAction.Deps, runAction)
@@ -1057,44 +964,6 @@ func addTestVet(b *work.Builder, p *load.Package, runAction, installAction *work
}
}
-func recompileForTest(pmain, preal, ptest, pxtest *load.Package) {
- // The "test copy" of preal is ptest.
- // For each package that depends on preal, make a "test copy"
- // that depends on ptest. And so on, up the dependency tree.
- testCopy := map[*load.Package]*load.Package{preal: ptest}
- for _, p := range load.PackageList([]*load.Package{pmain}) {
- if p == preal {
- continue
- }
- // Copy on write.
- didSplit := p == pmain || p == pxtest
- split := func() {
- if didSplit {
- return
- }
- didSplit = true
- if testCopy[p] != nil {
- panic("recompileForTest loop")
- }
- p1 := new(load.Package)
- testCopy[p] = p1
- *p1 = *p
- p1.Internal.Imports = make([]*load.Package, len(p.Internal.Imports))
- copy(p1.Internal.Imports, p.Internal.Imports)
- p = p1
- p.Target = ""
- }
-
- // Update p.Internal.Imports to use test copies.
- for i, imp := range p.Internal.Imports {
- if p1 := testCopy[imp]; p1 != nil && p1 != imp {
- split()
- p.Internal.Imports[i] = p1
- }
- }
- }
-}
-
// isTestFile reports whether the source file is a set of tests and should therefore
// be excluded from coverage analysis.
func isTestFile(file string) bool {
@@ -1104,7 +973,7 @@ func isTestFile(file string) bool {
// declareCoverVars attaches the required cover variables names
// to the files, to be used when annotating the files.
-func declareCoverVars(importPath string, files ...string) map[string]*load.CoverVar {
+func declareCoverVars(p *load.Package, files ...string) map[string]*load.CoverVar {
coverVars := make(map[string]*load.CoverVar)
coverIndex := 0
// We create the cover counters as new top-level variables in the package.
@@ -1113,14 +982,25 @@ func declareCoverVars(importPath string, files ...string) map[string]*load.Cover
// so we append 12 hex digits from the SHA-256 of the import path.
// The point is only to avoid accidents, not to defeat users determined to
// break things.
- sum := sha256.Sum256([]byte(importPath))
+ sum := sha256.Sum256([]byte(p.ImportPath))
h := fmt.Sprintf("%x", sum[:6])
for _, file := range files {
if isTestFile(file) {
continue
}
+ // For a package that is "local" (imported via ./ import or command line, outside GOPATH),
+ // we record the full path to the file name.
+ // Otherwise we record the import path, then a forward slash, then the file name.
+ // This makes profiles within GOPATH file system-independent.
+ // These names appear in the cmd/cover HTML interface.
+ var longFile string
+ if p.Internal.Local {
+ longFile = filepath.Join(p.Dir, file)
+ } else {
+ longFile = path.Join(p.ImportPath, file)
+ }
coverVars[file] = &load.CoverVar{
- File: filepath.Join(importPath, file),
+ File: longFile,
Var: fmt.Sprintf("GoCover_%d_%x", coverIndex, h),
}
coverIndex++
@@ -1538,7 +1418,7 @@ func computeTestInputsID(a *work.Action, testlog []byte) (cache.ActionID, error)
fmt.Fprintf(h, "env %s %x\n", name, hashGetenv(name))
case "chdir":
pwd = name // always absolute
- fmt.Fprintf(h, "cbdir %s %x\n", name, hashStat(name))
+ fmt.Fprintf(h, "chdir %s %x\n", name, hashStat(name))
case "stat":
if !filepath.IsAbs(name) {
name = filepath.Join(pwd, name)
@@ -1746,310 +1626,3 @@ func builderNoTest(b *work.Builder, a *work.Action) error {
fmt.Fprintf(stdout, "? \t%s\t[no test files]\n", a.Package.ImportPath)
return nil
}
-
-// isTestFunc tells whether fn has the type of a testing function. arg
-// specifies the parameter type we look for: B, M or T.
-func isTestFunc(fn *ast.FuncDecl, arg string) bool {
- if fn.Type.Results != nil && len(fn.Type.Results.List) > 0 ||
- fn.Type.Params.List == nil ||
- len(fn.Type.Params.List) != 1 ||
- len(fn.Type.Params.List[0].Names) > 1 {
- return false
- }
- ptr, ok := fn.Type.Params.List[0].Type.(*ast.StarExpr)
- if !ok {
- return false
- }
- // We can't easily check that the type is *testing.M
- // because we don't know how testing has been imported,
- // but at least check that it's *M or *something.M.
- // Same applies for B and T.
- if name, ok := ptr.X.(*ast.Ident); ok && name.Name == arg {
- return true
- }
- if sel, ok := ptr.X.(*ast.SelectorExpr); ok && sel.Sel.Name == arg {
- return true
- }
- return false
-}
-
-// isTest tells whether name looks like a test (or benchmark, according to prefix).
-// It is a Test (say) if there is a character after Test that is not a lower-case letter.
-// We don't want TesticularCancer.
-func isTest(name, prefix string) bool {
- if !strings.HasPrefix(name, prefix) {
- return false
- }
- if len(name) == len(prefix) { // "Test" is ok
- return true
- }
- rune, _ := utf8.DecodeRuneInString(name[len(prefix):])
- return !unicode.IsLower(rune)
-}
-
-type coverInfo struct {
- Package *load.Package
- Vars map[string]*load.CoverVar
-}
-
-// loadTestFuncs returns the testFuncs describing the tests that will be run.
-func loadTestFuncs(ptest *load.Package) (*testFuncs, error) {
- t := &testFuncs{
- Package: ptest,
- }
- for _, file := range ptest.TestGoFiles {
- if err := t.load(filepath.Join(ptest.Dir, file), "_test", &t.ImportTest, &t.NeedTest); err != nil {
- return nil, err
- }
- }
- for _, file := range ptest.XTestGoFiles {
- if err := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.ImportXtest, &t.NeedXtest); err != nil {
- return nil, err
- }
- }
- return t, nil
-}
-
-// writeTestmain writes the _testmain.go file for t to the file named out.
-func writeTestmain(out string, t *testFuncs) error {
- f, err := os.Create(out)
- if err != nil {
- return err
- }
- defer f.Close()
-
- if err := testmainTmpl.Execute(f, t); err != nil {
- return err
- }
-
- return nil
-}
-
-type testFuncs struct {
- Tests []testFunc
- Benchmarks []testFunc
- Examples []testFunc
- TestMain *testFunc
- Package *load.Package
- ImportTest bool
- NeedTest bool
- ImportXtest bool
- NeedXtest bool
- Cover []coverInfo
-}
-
-func (t *testFuncs) CoverMode() string {
- return testCoverMode
-}
-
-func (t *testFuncs) CoverEnabled() bool {
- return testCover
-}
-
-// ImportPath returns the import path of the package being tested, if it is within GOPATH.
-// This is printed by the testing package when running benchmarks.
-func (t *testFuncs) ImportPath() string {
- pkg := t.Package.ImportPath
- if strings.HasPrefix(pkg, "_/") {
- return ""
- }
- if pkg == "command-line-arguments" {
- return ""
- }
- return pkg
-}
-
-// Covered returns a string describing which packages are being tested for coverage.
-// If the covered package is the same as the tested package, it returns the empty string.
-// Otherwise it is a comma-separated human-readable list of packages beginning with
-// " in", ready for use in the coverage message.
-func (t *testFuncs) Covered() string {
- if testCoverPaths == nil {
- return ""
- }
- return " in " + strings.Join(testCoverPaths, ", ")
-}
-
-// Tested returns the name of the package being tested.
-func (t *testFuncs) Tested() string {
- return t.Package.Name
-}
-
-type testFunc struct {
- Package string // imported package name (_test or _xtest)
- Name string // function name
- Output string // output, for examples
- Unordered bool // output is allowed to be unordered.
-}
-
-var testFileSet = token.NewFileSet()
-
-func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {
- f, err := parser.ParseFile(testFileSet, filename, nil, parser.ParseComments)
- if err != nil {
- return base.ExpandScanner(err)
- }
- for _, d := range f.Decls {
- n, ok := d.(*ast.FuncDecl)
- if !ok {
- continue
- }
- if n.Recv != nil {
- continue
- }
- name := n.Name.String()
- switch {
- case name == "TestMain":
- if isTestFunc(n, "T") {
- t.Tests = append(t.Tests, testFunc{pkg, name, "", false})
- *doImport, *seen = true, true
- continue
- }
- err := checkTestFunc(n, "M")
- if err != nil {
- return err
- }
- if t.TestMain != nil {
- return errors.New("multiple definitions of TestMain")
- }
- t.TestMain = &testFunc{pkg, name, "", false}
- *doImport, *seen = true, true
- case isTest(name, "Test"):
- err := checkTestFunc(n, "T")
- if err != nil {
- return err
- }
- t.Tests = append(t.Tests, testFunc{pkg, name, "", false})
- *doImport, *seen = true, true
- case isTest(name, "Benchmark"):
- err := checkTestFunc(n, "B")
- if err != nil {
- return err
- }
- t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, "", false})
- *doImport, *seen = true, true
- }
- }
- ex := doc.Examples(f)
- sort.Slice(ex, func(i, j int) bool { return ex[i].Order < ex[j].Order })
- for _, e := range ex {
- *doImport = true // import test file whether executed or not
- if e.Output == "" && !e.EmptyOutput {
- // Don't run examples with no output.
- continue
- }
- t.Examples = append(t.Examples, testFunc{pkg, "Example" + e.Name, e.Output, e.Unordered})
- *seen = true
- }
- return nil
-}
-
-func checkTestFunc(fn *ast.FuncDecl, arg string) error {
- if !isTestFunc(fn, arg) {
- name := fn.Name.String()
- pos := testFileSet.Position(fn.Pos())
- return fmt.Errorf("%s: wrong signature for %s, must be: func %s(%s *testing.%s)", pos, name, name, strings.ToLower(arg), arg)
- }
- return nil
-}
-
-var testmainTmpl = template.Must(template.New("main").Parse(`
-package main
-
-import (
-{{if not .TestMain}}
- "os"
-{{end}}
- "testing"
- "testing/internal/testdeps"
-
-{{if .ImportTest}}
- {{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}}
-{{end}}
-{{if .ImportXtest}}
- {{if .NeedXtest}}_xtest{{else}}_{{end}} {{.Package.ImportPath | printf "%s_test" | printf "%q"}}
-{{end}}
-{{range $i, $p := .Cover}}
- _cover{{$i}} {{$p.Package.ImportPath | printf "%q"}}
-{{end}}
-)
-
-var tests = []testing.InternalTest{
-{{range .Tests}}
- {"{{.Name}}", {{.Package}}.{{.Name}}},
-{{end}}
-}
-
-var benchmarks = []testing.InternalBenchmark{
-{{range .Benchmarks}}
- {"{{.Name}}", {{.Package}}.{{.Name}}},
-{{end}}
-}
-
-var examples = []testing.InternalExample{
-{{range .Examples}}
- {"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}, {{.Unordered}}},
-{{end}}
-}
-
-func init() {
- testdeps.ImportPath = {{.ImportPath | printf "%q"}}
-}
-
-{{if .CoverEnabled}}
-
-// Only updated by init functions, so no need for atomicity.
-var (
- coverCounters = make(map[string][]uint32)
- coverBlocks = make(map[string][]testing.CoverBlock)
-)
-
-func init() {
- {{range $i, $p := .Cover}}
- {{range $file, $cover := $p.Vars}}
- coverRegisterFile({{printf "%q" $cover.File}}, _cover{{$i}}.{{$cover.Var}}.Count[:], _cover{{$i}}.{{$cover.Var}}.Pos[:], _cover{{$i}}.{{$cover.Var}}.NumStmt[:])
- {{end}}
- {{end}}
-}
-
-func coverRegisterFile(fileName string, counter []uint32, pos []uint32, numStmts []uint16) {
- if 3*len(counter) != len(pos) || len(counter) != len(numStmts) {
- panic("coverage: mismatched sizes")
- }
- if coverCounters[fileName] != nil {
- // Already registered.
- return
- }
- coverCounters[fileName] = counter
- block := make([]testing.CoverBlock, len(counter))
- for i := range counter {
- block[i] = testing.CoverBlock{
- Line0: pos[3*i+0],
- Col0: uint16(pos[3*i+2]),
- Line1: pos[3*i+1],
- Col1: uint16(pos[3*i+2]>>16),
- Stmts: numStmts[i],
- }
- }
- coverBlocks[fileName] = block
-}
-{{end}}
-
-func main() {
-{{if .CoverEnabled}}
- testing.RegisterCover(testing.Cover{
- Mode: {{printf "%q" .CoverMode}},
- Counters: coverCounters,
- Blocks: coverBlocks,
- CoveredPackages: {{printf "%q" .Covered}},
- })
-{{end}}
- m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, examples)
-{{with .TestMain}}
- {{.Package}}.{{.Name}}(m)
-{{else}}
- os.Exit(m.Run())
-{{end}}
-}
-
-`))
diff --git a/libgo/go/cmd/go/internal/test/testflag.go b/libgo/go/cmd/go/internal/test/testflag.go
index 8a686b71255..73f8c69d9e1 100644
--- a/libgo/go/cmd/go/internal/test/testflag.go
+++ b/libgo/go/cmd/go/internal/test/testflag.go
@@ -63,6 +63,7 @@ var testFlagDefn = []*cmdflag.Defn{
// add build flags to testFlagDefn
func init() {
+ cmdflag.AddKnownFlags("test", testFlagDefn)
var cmd base.Command
work.AddBuildFlags(&cmd)
cmd.Flag.VisitAll(func(f *flag.Flag) {
@@ -87,6 +88,7 @@ func init() {
// go test fmt -custom-flag-for-fmt-test
// go test -x math
func testFlags(args []string) (packageNames, passToTest []string) {
+ args = str.StringList(cmdflag.FindGOFLAGS(testFlagDefn), args)
inPkg := false
var explicitArgs []string
for i := 0; i < len(args); i++ {
diff --git a/libgo/go/cmd/go/internal/tool/tool.go b/libgo/go/cmd/go/internal/tool/tool.go
index 4c7d0897e05..edcf93513d8 100644
--- a/libgo/go/cmd/go/internal/tool/tool.go
+++ b/libgo/go/cmd/go/internal/tool/tool.go
@@ -18,7 +18,7 @@ import (
var CmdTool = &base.Command{
Run: runTool,
- UsageLine: "tool [-n] command [args...]",
+ UsageLine: "go tool [-n] command [args...]",
Short: "run specified go tool",
Long: `
Tool runs the go tool command identified by the arguments.
diff --git a/libgo/go/cmd/go/internal/txtar/archive.go b/libgo/go/cmd/go/internal/txtar/archive.go
new file mode 100644
index 00000000000..c384f33bdf8
--- /dev/null
+++ b/libgo/go/cmd/go/internal/txtar/archive.go
@@ -0,0 +1,140 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package txtar implements a trivial text-based file archive format.
+//
+// The goals for the format are:
+//
+// - be trivial enough to create and edit by hand.
+// - be able to store trees of text files describing go command test cases.
+// - diff nicely in git history and code reviews.
+//
+// Non-goals include being a completely general archive format,
+// storing binary data, storing file modes, storing special files like
+// symbolic links, and so on.
+//
+// Txtar format
+//
+// A txtar archive is zero or more comment lines and then a sequence of file entries.
+// Each file entry begins with a file marker line of the form "-- FILENAME --"
+// and is followed by zero or more file content lines making up the file data.
+// The comment or file content ends at the next file marker line.
+// The file marker line must begin with the three-byte sequence "-- "
+// and end with the three-byte sequence " --", but the enclosed
+// file name can be surrounding by additional white space,
+// all of which is stripped.
+//
+// If the txtar file is missing a trailing newline on the final line,
+// parsers should consider a final newline to be present anyway.
+//
+// There are no possible syntax errors in a txtar archive.
+package txtar
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "strings"
+)
+
+// An Archive is a collection of files.
+type Archive struct {
+ Comment []byte
+ Files []File
+}
+
+// A File is a single file in an archive.
+type File struct {
+ Name string // name of file ("foo/bar.txt")
+ Data []byte // text content of file
+}
+
+// Format returns the serialized form of an Archive.
+// It is assumed that the Archive data structure is well-formed:
+// a.Comment and all a.File[i].Data contain no file marker lines,
+// and all a.File[i].Name is non-empty.
+func Format(a *Archive) []byte {
+ var buf bytes.Buffer
+ buf.Write(fixNL(a.Comment))
+ for _, f := range a.Files {
+ fmt.Fprintf(&buf, "-- %s --\n", f.Name)
+ buf.Write(fixNL(f.Data))
+ }
+ return buf.Bytes()
+}
+
+// ParseFile parses the named file as an archive.
+func ParseFile(file string) (*Archive, error) {
+ data, err := ioutil.ReadFile(file)
+ if err != nil {
+ return nil, err
+ }
+ return Parse(data), nil
+}
+
+// Parse parses the serialized form of an Archive.
+// The returned Archive holds slices of data.
+func Parse(data []byte) *Archive {
+ a := new(Archive)
+ var name string
+ a.Comment, name, data = findFileMarker(data)
+ for name != "" {
+ f := File{name, nil}
+ f.Data, name, data = findFileMarker(data)
+ a.Files = append(a.Files, f)
+ }
+ return a
+}
+
+var (
+ newlineMarker = []byte("\n-- ")
+ marker = []byte("-- ")
+ markerEnd = []byte(" --")
+)
+
+// findFileMarker finds the next file marker in data,
+// extracts the file name, and returns the data before the marker,
+// the file name, and the data after the marker.
+// If there is no next marker, findFileMarker returns before = fixNL(data), name = "", after = nil.
+func findFileMarker(data []byte) (before []byte, name string, after []byte) {
+ var i int
+ for {
+ if name, after = isMarker(data[i:]); name != "" {
+ return data[:i], name, after
+ }
+ j := bytes.Index(data[i:], newlineMarker)
+ if j < 0 {
+ return fixNL(data), "", nil
+ }
+ i += j + 1 // positioned at start of new possible marker
+ }
+}
+
+// isMarker checks whether data begins with a file marker line.
+// If so, it returns the name from the line and the data after the line.
+// Otherwise it returns name == "" with an unspecified after.
+func isMarker(data []byte) (name string, after []byte) {
+ if !bytes.HasPrefix(data, marker) {
+ return "", nil
+ }
+ if i := bytes.IndexByte(data, '\n'); i >= 0 {
+ data, after = data[:i], data[i+1:]
+ }
+ if !bytes.HasSuffix(data, markerEnd) {
+ return "", nil
+ }
+ return strings.TrimSpace(string(data[len(marker) : len(data)-len(markerEnd)])), after
+}
+
+// If data is empty or ends in \n, fixNL returns data.
+// Otherwise fixNL returns a new slice consisting of data with a final \n added.
+func fixNL(data []byte) []byte {
+ if len(data) == 0 || data[len(data)-1] == '\n' {
+ return data
+ }
+ d := make([]byte, len(data)+1)
+ copy(d, data)
+ d[len(data)] = '\n'
+ return d
+}
diff --git a/libgo/go/cmd/go/internal/txtar/archive_test.go b/libgo/go/cmd/go/internal/txtar/archive_test.go
new file mode 100644
index 00000000000..3f734f67625
--- /dev/null
+++ b/libgo/go/cmd/go/internal/txtar/archive_test.go
@@ -0,0 +1,67 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package txtar
+
+import (
+ "bytes"
+ "fmt"
+ "reflect"
+ "testing"
+)
+
+var tests = []struct {
+ name string
+ text string
+ parsed *Archive
+}{
+ {
+ name: "basic",
+ text: `comment1
+comment2
+-- file1 --
+File 1 text.
+-- foo ---
+More file 1 text.
+-- file 2 --
+File 2 text.
+-- empty --
+-- noNL --
+hello world`,
+ parsed: &Archive{
+ Comment: []byte("comment1\ncomment2\n"),
+ Files: []File{
+ {"file1", []byte("File 1 text.\n-- foo ---\nMore file 1 text.\n")},
+ {"file 2", []byte("File 2 text.\n")},
+ {"empty", []byte{}},
+ {"noNL", []byte("hello world\n")},
+ },
+ },
+ },
+}
+
+func Test(t *testing.T) {
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ a := Parse([]byte(tt.text))
+ if !reflect.DeepEqual(a, tt.parsed) {
+ t.Fatalf("Parse: wrong output:\nhave:\n%s\nwant:\n%s", shortArchive(a), shortArchive(tt.parsed))
+ }
+ text := Format(a)
+ a = Parse(text)
+ if !reflect.DeepEqual(a, tt.parsed) {
+ t.Fatalf("Parse after Format: wrong output:\nhave:\n%s\nwant:\n%s", shortArchive(a), shortArchive(tt.parsed))
+ }
+ })
+ }
+}
+
+func shortArchive(a *Archive) string {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "comment: %q\n", a.Comment)
+ for _, f := range a.Files {
+ fmt.Fprintf(&buf, "file %q: %q\n", f.Name, f.Data)
+ }
+ return buf.String()
+}
diff --git a/libgo/go/cmd/go/internal/version/version.go b/libgo/go/cmd/go/internal/version/version.go
index c3f7d73ff1d..9344a28dc36 100644
--- a/libgo/go/cmd/go/internal/version/version.go
+++ b/libgo/go/cmd/go/internal/version/version.go
@@ -14,7 +14,7 @@ import (
var CmdVersion = &base.Command{
Run: runVersion,
- UsageLine: "version",
+ UsageLine: "go version",
Short: "print Go version",
Long: `Version prints the Go version, as reported by runtime.Version.`,
}
diff --git a/libgo/go/cmd/go/internal/vet/vet.go b/libgo/go/cmd/go/internal/vet/vet.go
index a737ebd669f..ea85fb8d5c9 100644
--- a/libgo/go/cmd/go/internal/vet/vet.go
+++ b/libgo/go/cmd/go/internal/vet/vet.go
@@ -8,6 +8,7 @@ package vet
import (
"cmd/go/internal/base"
"cmd/go/internal/load"
+ "cmd/go/internal/modload"
"cmd/go/internal/work"
"path/filepath"
)
@@ -15,7 +16,7 @@ import (
var CmdVet = &base.Command{
Run: runVet,
CustomFlags: true,
- UsageLine: "vet [-n] [-x] [build flags] [vet flags] [packages]",
+ UsageLine: "go vet [-n] [-x] [build flags] [vet flags] [packages]",
Short: "report likely mistakes in packages",
Long: `
Vet runs the Go vet command on the packages named by the import paths.
@@ -35,6 +36,8 @@ See also: go fmt, go fix.
}
func runVet(cmd *base.Command, args []string) {
+ modload.LoadTests = true
+
vetFlags, pkgArgs := vetFlags(args)
work.BuildInit()
@@ -57,7 +60,7 @@ func runVet(cmd *base.Command, args []string) {
root := &work.Action{Mode: "go vet"}
for _, p := range pkgs {
- ptest, pxtest, err := load.GetTestPackagesFor(p, false)
+ _, ptest, pxtest, err := load.GetTestPackagesFor(p, nil)
if err != nil {
base.Errorf("%v", err)
continue
diff --git a/libgo/go/cmd/go/internal/vet/vetflag.go b/libgo/go/cmd/go/internal/vet/vetflag.go
index 03770ea920e..50eac425ec3 100644
--- a/libgo/go/cmd/go/internal/vet/vetflag.go
+++ b/libgo/go/cmd/go/internal/vet/vetflag.go
@@ -12,6 +12,7 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/cmdflag"
+ "cmd/go/internal/str"
"cmd/go/internal/work"
)
@@ -26,39 +27,40 @@ var vetFlagDefn = []*cmdflag.Defn{
// to vet. We handle them in vetFlags.
// local.
- {Name: "all", BoolVar: new(bool)},
- {Name: "asmdecl", BoolVar: new(bool)},
- {Name: "assign", BoolVar: new(bool)},
- {Name: "atomic", BoolVar: new(bool)},
- {Name: "bool", BoolVar: new(bool)},
- {Name: "buildtags", BoolVar: new(bool)},
- {Name: "cgocall", BoolVar: new(bool)},
- {Name: "composites", BoolVar: new(bool)},
- {Name: "copylocks", BoolVar: new(bool)},
- {Name: "httpresponse", BoolVar: new(bool)},
- {Name: "lostcancel", BoolVar: new(bool)},
- {Name: "methods", BoolVar: new(bool)},
- {Name: "nilfunc", BoolVar: new(bool)},
- {Name: "printf", BoolVar: new(bool)},
- {Name: "printfuncs"},
- {Name: "rangeloops", BoolVar: new(bool)},
- {Name: "shadow", BoolVar: new(bool)},
- {Name: "shadowstrict", BoolVar: new(bool)},
- {Name: "shift", BoolVar: new(bool)},
- {Name: "source", BoolVar: new(bool)},
- {Name: "structtags", BoolVar: new(bool)},
- {Name: "tests", BoolVar: new(bool)},
- {Name: "unreachable", BoolVar: new(bool)},
- {Name: "unsafeptr", BoolVar: new(bool)},
- {Name: "unusedfuncs"},
- {Name: "unusedresult", BoolVar: new(bool)},
- {Name: "unusedstringmethods"},
+ {Name: "all", BoolVar: new(bool), PassToTest: true},
+ {Name: "asmdecl", BoolVar: new(bool), PassToTest: true},
+ {Name: "assign", BoolVar: new(bool), PassToTest: true},
+ {Name: "atomic", BoolVar: new(bool), PassToTest: true},
+ {Name: "bool", BoolVar: new(bool), PassToTest: true},
+ {Name: "buildtags", BoolVar: new(bool), PassToTest: true},
+ {Name: "cgocall", BoolVar: new(bool), PassToTest: true},
+ {Name: "composites", BoolVar: new(bool), PassToTest: true},
+ {Name: "copylocks", BoolVar: new(bool), PassToTest: true},
+ {Name: "httpresponse", BoolVar: new(bool), PassToTest: true},
+ {Name: "lostcancel", BoolVar: new(bool), PassToTest: true},
+ {Name: "methods", BoolVar: new(bool), PassToTest: true},
+ {Name: "nilfunc", BoolVar: new(bool), PassToTest: true},
+ {Name: "printf", BoolVar: new(bool), PassToTest: true},
+ {Name: "printfuncs", PassToTest: true},
+ {Name: "rangeloops", BoolVar: new(bool), PassToTest: true},
+ {Name: "shadow", BoolVar: new(bool), PassToTest: true},
+ {Name: "shadowstrict", BoolVar: new(bool), PassToTest: true},
+ {Name: "shift", BoolVar: new(bool), PassToTest: true},
+ {Name: "source", BoolVar: new(bool), PassToTest: true},
+ {Name: "structtags", BoolVar: new(bool), PassToTest: true},
+ {Name: "tests", BoolVar: new(bool), PassToTest: true},
+ {Name: "unreachable", BoolVar: new(bool), PassToTest: true},
+ {Name: "unsafeptr", BoolVar: new(bool), PassToTest: true},
+ {Name: "unusedfuncs", PassToTest: true},
+ {Name: "unusedresult", BoolVar: new(bool), PassToTest: true},
+ {Name: "unusedstringmethods", PassToTest: true},
}
var vetTool string
// add build flags to vetFlagDefn.
func init() {
+ cmdflag.AddKnownFlags("vet", vetFlagDefn)
var cmd base.Command
work.AddBuildFlags(&cmd)
cmd.Flag.StringVar(&vetTool, "vettool", "", "path to vet tool binary") // for cmd/vet tests; undocumented for now
@@ -73,6 +75,7 @@ func init() {
// vetFlags processes the command line, splitting it at the first non-flag
// into the list of flags and list of packages.
func vetFlags(args []string) (passToVet, packageNames []string) {
+ args = str.StringList(cmdflag.FindGOFLAGS(vetFlagDefn), args)
for i := 0; i < len(args); i++ {
if !strings.HasPrefix(args[i], "-") {
return args[:i], args[i:]
@@ -88,9 +91,17 @@ func vetFlags(args []string) (passToVet, packageNames []string) {
if err := f.Value.Set(value); err != nil {
base.Fatalf("invalid flag argument for -%s: %v", f.Name, err)
}
- switch f.Name {
- // Flags known to the build but not to vet, so must be dropped.
- case "x", "n", "vettool", "compiler":
+ keep := f.PassToTest
+ if !keep {
+ // A build flag, probably one we don't want to pass to vet.
+ // Can whitelist.
+ switch f.Name {
+ case "tags", "v":
+ keep = true
+ }
+ }
+ if !keep {
+ // Flags known to the build but not to vet, so must be dropped.
if extraWord {
args = append(args[:i], args[i+2:]...)
extraWord = false
diff --git a/libgo/go/cmd/go/internal/web2/web.go b/libgo/go/cmd/go/internal/web2/web.go
new file mode 100644
index 00000000000..f3900379e17
--- /dev/null
+++ b/libgo/go/cmd/go/internal/web2/web.go
@@ -0,0 +1,297 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package web2
+
+import (
+ "bytes"
+ "cmd/go/internal/base"
+ "encoding/json"
+ "flag"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "os"
+ "path/filepath"
+ "runtime"
+ "runtime/debug"
+ "strings"
+ "sync"
+)
+
+var TraceGET = false
+var webstack = false
+
+func init() {
+ flag.BoolVar(&TraceGET, "webtrace", TraceGET, "trace GET requests")
+ flag.BoolVar(&webstack, "webstack", webstack, "print stack for GET requests")
+}
+
+type netrcLine struct {
+ machine string
+ login string
+ password string
+}
+
+var netrcOnce sync.Once
+var netrc []netrcLine
+
+func parseNetrc(data string) []netrcLine {
+ var nrc []netrcLine
+ var l netrcLine
+ for _, line := range strings.Split(data, "\n") {
+ f := strings.Fields(line)
+ for i := 0; i < len(f)-1; i += 2 {
+ switch f[i] {
+ case "machine":
+ l.machine = f[i+1]
+ case "login":
+ l.login = f[i+1]
+ case "password":
+ l.password = f[i+1]
+ }
+ }
+ if l.machine != "" && l.login != "" && l.password != "" {
+ nrc = append(nrc, l)
+ l = netrcLine{}
+ }
+ }
+ return nrc
+}
+
+func havePassword(machine string) bool {
+ netrcOnce.Do(readNetrc)
+ for _, line := range netrc {
+ if line.machine == machine {
+ return true
+ }
+ }
+ return false
+}
+
+func netrcPath() string {
+ switch runtime.GOOS {
+ case "windows":
+ return filepath.Join(os.Getenv("USERPROFILE"), "_netrc")
+ case "plan9":
+ return filepath.Join(os.Getenv("home"), ".netrc")
+ default:
+ return filepath.Join(os.Getenv("HOME"), ".netrc")
+ }
+}
+
+func readNetrc() {
+ data, err := ioutil.ReadFile(netrcPath())
+ if err != nil {
+ return
+ }
+ netrc = parseNetrc(string(data))
+}
+
+type getState struct {
+ req *http.Request
+ resp *http.Response
+ body io.ReadCloser
+ non200ok bool
+}
+
+type Option interface {
+ option(*getState) error
+}
+
+func Non200OK() Option {
+ return optionFunc(func(g *getState) error {
+ g.non200ok = true
+ return nil
+ })
+}
+
+type optionFunc func(*getState) error
+
+func (f optionFunc) option(g *getState) error {
+ return f(g)
+}
+
+func DecodeJSON(dst interface{}) Option {
+ return optionFunc(func(g *getState) error {
+ if g.resp != nil {
+ return json.NewDecoder(g.body).Decode(dst)
+ }
+ return nil
+ })
+}
+
+func ReadAllBody(body *[]byte) Option {
+ return optionFunc(func(g *getState) error {
+ if g.resp != nil {
+ var err error
+ *body, err = ioutil.ReadAll(g.body)
+ return err
+ }
+ return nil
+ })
+}
+
+func Body(body *io.ReadCloser) Option {
+ return optionFunc(func(g *getState) error {
+ if g.resp != nil {
+ *body = g.body
+ g.body = nil
+ }
+ return nil
+ })
+}
+
+func Header(hdr *http.Header) Option {
+ return optionFunc(func(g *getState) error {
+ if g.resp != nil {
+ *hdr = CopyHeader(g.resp.Header)
+ }
+ return nil
+ })
+}
+
+func CopyHeader(hdr http.Header) http.Header {
+ if hdr == nil {
+ return nil
+ }
+ h2 := make(http.Header)
+ for k, v := range hdr {
+ v2 := make([]string, len(v))
+ copy(v2, v)
+ h2[k] = v2
+ }
+ return h2
+}
+
+var cache struct {
+ mu sync.Mutex
+ byURL map[string]*cacheEntry
+}
+
+type cacheEntry struct {
+ mu sync.Mutex
+ resp *http.Response
+ body []byte
+}
+
+var httpDo = http.DefaultClient.Do
+
+func SetHTTPDoForTesting(do func(*http.Request) (*http.Response, error)) {
+ if do == nil {
+ do = http.DefaultClient.Do
+ }
+ httpDo = do
+}
+
+func Get(url string, options ...Option) error {
+ if TraceGET || webstack {
+ println("GET", url)
+ if webstack {
+ println(string(debug.Stack()))
+ }
+ }
+
+ req, err := http.NewRequest("GET", url, nil)
+ if err != nil {
+ return err
+ }
+
+ netrcOnce.Do(readNetrc)
+ for _, l := range netrc {
+ if l.machine == req.URL.Host {
+ req.SetBasicAuth(l.login, l.password)
+ break
+ }
+ }
+
+ g := &getState{req: req}
+ for _, o := range options {
+ if err := o.option(g); err != nil {
+ return err
+ }
+ }
+
+ cache.mu.Lock()
+ e := cache.byURL[url]
+ if e == nil {
+ e = new(cacheEntry)
+ if !strings.HasPrefix(url, "file:") {
+ if cache.byURL == nil {
+ cache.byURL = make(map[string]*cacheEntry)
+ }
+ cache.byURL[url] = e
+ }
+ }
+ cache.mu.Unlock()
+
+ e.mu.Lock()
+ if strings.HasPrefix(url, "file:") {
+ body, err := ioutil.ReadFile(req.URL.Path)
+ if err != nil {
+ e.mu.Unlock()
+ return err
+ }
+ e.body = body
+ e.resp = &http.Response{
+ StatusCode: 200,
+ }
+ } else if e.resp == nil {
+ resp, err := httpDo(req)
+ if err != nil {
+ e.mu.Unlock()
+ return err
+ }
+ e.resp = resp
+ // TODO: Spool to temp file.
+ body, err := ioutil.ReadAll(resp.Body)
+ resp.Body.Close()
+ resp.Body = nil
+ if err != nil {
+ e.mu.Unlock()
+ return err
+ }
+ e.body = body
+ }
+ g.resp = e.resp
+ g.body = ioutil.NopCloser(bytes.NewReader(e.body))
+ e.mu.Unlock()
+
+ defer func() {
+ if g.body != nil {
+ g.body.Close()
+ }
+ }()
+
+ if g.resp.StatusCode == 403 && req.URL.Host == "api.github.com" && !havePassword("api.github.com") {
+ base.Errorf("%s", githubMessage)
+ }
+ if !g.non200ok && g.resp.StatusCode != 200 {
+ return fmt.Errorf("unexpected status (%s): %v", url, g.resp.Status)
+ }
+
+ for _, o := range options {
+ if err := o.option(g); err != nil {
+ return err
+ }
+ }
+ return err
+}
+
+var githubMessage = `go: 403 response from api.github.com
+
+GitHub applies fairly small rate limits to unauthenticated users, and
+you appear to be hitting them. To authenticate, please visit
+https://github.com/settings/tokens and click "Generate New Token" to
+create a Personal Access Token. The token only needs "public_repo"
+scope, but you can add "repo" if you want to access private
+repositories too.
+
+Add the token to your $HOME/.netrc (%USERPROFILE%\_netrc on Windows):
+
+ machine api.github.com login YOU password TOKEN
+
+Sorry for the interruption.
+`
diff --git a/libgo/go/cmd/go/internal/web2/web_test.go b/libgo/go/cmd/go/internal/web2/web_test.go
new file mode 100644
index 00000000000..c6f6b1eff4d
--- /dev/null
+++ b/libgo/go/cmd/go/internal/web2/web_test.go
@@ -0,0 +1,35 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package web2
+
+import (
+ "reflect"
+ "testing"
+)
+
+var testNetrc = `
+machine api.github.com
+ login user
+ password pwd
+
+machine incomlete.host
+ login justlogin
+
+machine test.host
+login user2
+password pwd2
+`
+
+func TestReadNetrc(t *testing.T) {
+ lines := parseNetrc(testNetrc)
+ want := []netrcLine{
+ {"api.github.com", "user", "pwd"},
+ {"test.host", "user2", "pwd2"},
+ }
+
+ if !reflect.DeepEqual(lines, want) {
+ t.Errorf("parseNetrc:\nhave %q\nwant %q", lines, want)
+ }
+}
diff --git a/libgo/go/cmd/go/internal/webtest/test.go b/libgo/go/cmd/go/internal/webtest/test.go
new file mode 100644
index 00000000000..94b20a33ffc
--- /dev/null
+++ b/libgo/go/cmd/go/internal/webtest/test.go
@@ -0,0 +1,314 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package webtest
+
+import (
+ "bufio"
+ "bytes"
+ "encoding/hex"
+ "flag"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "os"
+ "sort"
+ "strconv"
+ "strings"
+ "sync"
+ "unicode/utf8"
+
+ web "cmd/go/internal/web2"
+)
+
+var mode = flag.String("webtest", "replay", "set webtest `mode` - record, replay, bypass")
+
+func Hook() {
+ if *mode == "bypass" {
+ return
+ }
+ web.SetHTTPDoForTesting(Do)
+}
+
+func Unhook() {
+ web.SetHTTPDoForTesting(nil)
+}
+
+func Print() {
+ web.SetHTTPDoForTesting(DoPrint)
+}
+
+var responses struct {
+ mu sync.Mutex
+ byURL map[string]*respEntry
+}
+
+type respEntry struct {
+ status string
+ code int
+ hdr http.Header
+ body []byte
+}
+
+func Serve(url string, status string, hdr http.Header, body []byte) {
+ if status == "" {
+ status = "200 OK"
+ }
+ code, err := strconv.Atoi(strings.Fields(status)[0])
+ if err != nil {
+ panic("bad Serve status - " + status + " - " + err.Error())
+ }
+
+ responses.mu.Lock()
+ defer responses.mu.Unlock()
+
+ if responses.byURL == nil {
+ responses.byURL = make(map[string]*respEntry)
+ }
+ responses.byURL[url] = &respEntry{status: status, code: code, hdr: web.CopyHeader(hdr), body: body}
+}
+
+func Do(req *http.Request) (*http.Response, error) {
+ if req.Method != "GET" {
+ return nil, fmt.Errorf("bad method - must be GET")
+ }
+
+ responses.mu.Lock()
+ e := responses.byURL[req.URL.String()]
+ responses.mu.Unlock()
+
+ if e == nil {
+ if *mode == "record" {
+ loaded.mu.Lock()
+ if len(loaded.did) != 1 {
+ loaded.mu.Unlock()
+ return nil, fmt.Errorf("cannot use -webtest=record with multiple loaded response files")
+ }
+ var file string
+ for file = range loaded.did {
+ break
+ }
+ loaded.mu.Unlock()
+ return doSave(file, req)
+ }
+ e = &respEntry{code: 599, status: "599 unexpected request (no canned response)"}
+ }
+ resp := &http.Response{
+ Status: e.status,
+ StatusCode: e.code,
+ Header: web.CopyHeader(e.hdr),
+ Body: ioutil.NopCloser(bytes.NewReader(e.body)),
+ }
+ return resp, nil
+}
+
+func DoPrint(req *http.Request) (*http.Response, error) {
+ return doSave("", req)
+}
+
+func doSave(file string, req *http.Request) (*http.Response, error) {
+ resp, err := http.DefaultClient.Do(req)
+ if err != nil {
+ return nil, err
+ }
+ data, err := ioutil.ReadAll(resp.Body)
+ resp.Body.Close()
+ if err != nil {
+ return nil, err
+ }
+ resp.Body = ioutil.NopCloser(bytes.NewReader(data))
+
+ var f *os.File
+ if file == "" {
+ f = os.Stderr
+ } else {
+ f, err = os.OpenFile(file, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer f.Close()
+ }
+
+ fmt.Fprintf(f, "GET %s\n", req.URL.String())
+ fmt.Fprintf(f, "%s\n", resp.Status)
+ var keys []string
+ for k := range resp.Header {
+ keys = append(keys, k)
+ }
+ sort.Strings(keys)
+ for _, k := range keys {
+ if k == "Set-Cookie" {
+ continue
+ }
+ for _, v := range resp.Header[k] {
+ fmt.Fprintf(f, "%s: %s\n", k, v)
+ }
+ }
+ fmt.Fprintf(f, "\n")
+ if utf8.Valid(data) && !bytes.Contains(data, []byte("\nGET")) && !isHexDump(data) {
+ fmt.Fprintf(f, "%s\n\n", data)
+ } else {
+ fmt.Fprintf(f, "%s\n", hex.Dump(data))
+ }
+ return resp, err
+}
+
+var loaded struct {
+ mu sync.Mutex
+ did map[string]bool
+}
+
+func LoadOnce(file string) {
+ loaded.mu.Lock()
+ if loaded.did[file] {
+ loaded.mu.Unlock()
+ return
+ }
+ if loaded.did == nil {
+ loaded.did = make(map[string]bool)
+ }
+ loaded.did[file] = true
+ loaded.mu.Unlock()
+
+ f, err := os.Open(file)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer f.Close()
+
+ b := bufio.NewReader(f)
+ var ungetLine string
+ nextLine := func() string {
+ if ungetLine != "" {
+ l := ungetLine
+ ungetLine = ""
+ return l
+ }
+ line, err := b.ReadString('\n')
+ if err != nil {
+ if err == io.EOF {
+ return ""
+ }
+ log.Fatalf("%s: unexpected read error: %v", file, err)
+ }
+ return line
+ }
+
+ for {
+ line := nextLine()
+ if line == "" { // EOF
+ break
+ }
+ line = strings.TrimSpace(line)
+ if strings.HasPrefix(line, "#") || line == "" {
+ continue
+ }
+ if !strings.HasPrefix(line, "GET ") {
+ log.Fatalf("%s: malformed GET line: %s", file, line)
+ }
+ url := line[len("GET "):]
+ status := nextLine()
+ if _, err := strconv.Atoi(strings.Fields(status)[0]); err != nil {
+ log.Fatalf("%s: malformed status line (after GET %s): %s", file, url, status)
+ }
+ hdr := make(http.Header)
+ for {
+ kv := strings.TrimSpace(nextLine())
+ if kv == "" {
+ break
+ }
+ i := strings.Index(kv, ":")
+ if i < 0 {
+ log.Fatalf("%s: malformed header line (after GET %s): %s", file, url, kv)
+ }
+ k, v := kv[:i], strings.TrimSpace(kv[i+1:])
+ hdr[k] = append(hdr[k], v)
+ }
+
+ var body []byte
+ Body:
+ for n := 0; ; n++ {
+ line := nextLine()
+ if n == 0 && isHexDump([]byte(line)) {
+ ungetLine = line
+ b, err := parseHexDump(nextLine)
+ if err != nil {
+ log.Fatalf("%s: malformed hex dump (after GET %s): %v", file, url, err)
+ }
+ body = b
+ break
+ }
+ if line == "" { // EOF
+ for i := 0; i < 2; i++ {
+ if len(body) > 0 && body[len(body)-1] == '\n' {
+ body = body[:len(body)-1]
+ }
+ }
+ break
+ }
+ body = append(body, line...)
+ for line == "\n" {
+ line = nextLine()
+ if strings.HasPrefix(line, "GET ") {
+ ungetLine = line
+ body = body[:len(body)-1]
+ if len(body) > 0 {
+ body = body[:len(body)-1]
+ }
+ break Body
+ }
+ body = append(body, line...)
+ }
+ }
+
+ Serve(url, status, hdr, body)
+ }
+}
+
+func isHexDump(data []byte) bool {
+ return bytes.HasPrefix(data, []byte("00000000 ")) || bytes.HasPrefix(data, []byte("0000000 "))
+}
+
+// parseHexDump parses the hex dump in text, which should be the
+// output of "hexdump -C" or Plan 9's "xd -b" or Go's hex.Dump
+// and returns the original data used to produce the dump.
+// It is meant to enable storing golden binary files as text, so that
+// changes to the golden files can be seen during code reviews.
+func parseHexDump(nextLine func() string) ([]byte, error) {
+ var out []byte
+ for {
+ line := nextLine()
+ if line == "" || line == "\n" {
+ break
+ }
+ if i := strings.Index(line, "|"); i >= 0 { // remove text dump
+ line = line[:i]
+ }
+ f := strings.Fields(line)
+ if len(f) > 1+16 {
+ return nil, fmt.Errorf("parsing hex dump: too many fields on line %q", line)
+ }
+ if len(f) == 0 || len(f) == 1 && f[0] == "*" { // all zeros block omitted
+ continue
+ }
+ addr64, err := strconv.ParseUint(f[0], 16, 0)
+ if err != nil {
+ return nil, fmt.Errorf("parsing hex dump: invalid address %q", f[0])
+ }
+ addr := int(addr64)
+ if len(out) < addr {
+ out = append(out, make([]byte, addr-len(out))...)
+ }
+ for _, x := range f[1:] {
+ val, err := strconv.ParseUint(x, 16, 8)
+ if err != nil {
+ return nil, fmt.Errorf("parsing hexdump: invalid hex byte %q", x)
+ }
+ out = append(out, byte(val))
+ }
+ }
+ return out, nil
+}
diff --git a/libgo/go/cmd/go/internal/work/action.go b/libgo/go/cmd/go/internal/work/action.go
index 803a6bd4611..82cf228fa44 100644
--- a/libgo/go/cmd/go/internal/work/action.go
+++ b/libgo/go/cmd/go/internal/work/action.go
@@ -37,7 +37,10 @@ type Builder struct {
flagCache map[[2]string]bool // a cache of supported compiler flags
Print func(args ...interface{}) (int, error)
- ComputeStaleOnly bool // compute staleness for go list; no actual build
+ IsCmdList bool // running as part of go list; set p.Stale and additional fields below
+ NeedError bool // list needs p.Error
+ NeedExport bool // list needs p.Export
+ NeedCompiledGoFiles bool // list needs p.CompiledGoFIles
objdirSeq int // counter for NewObjdir
pkgSeq int
@@ -80,9 +83,10 @@ type Action struct {
actionID cache.ActionID // cache ID of action input
buildID string // build ID of action output
- needVet bool // Mode=="build": need to fill in vet config
- vetCfg *vetConfig // vet config
- output []byte // output redirect buffer (nil means use b.Print)
+ VetxOnly bool // Mode=="vet": only being called to supply info about dependencies
+ needVet bool // Mode=="build": need to fill in vet config
+ vetCfg *vetConfig // vet config
+ output []byte // output redirect buffer (nil means use b.Print)
// Execution state.
pending int // number of deps yet to complete
@@ -139,6 +143,7 @@ type actionJSON struct {
Priority int `json:",omitempty"`
Failed bool `json:",omitempty"`
Built string `json:",omitempty"`
+ VetxOnly bool `json:",omitempty"`
}
// cacheKey is the key for the action cache.
@@ -178,6 +183,7 @@ func actionGraphJSON(a *Action) string {
Failed: a.Failed,
Priority: a.priority,
Built: a.built,
+ VetxOnly: a.VetxOnly,
}
if a.Package != nil {
// TODO(rsc): Make this a unique key for a.Package somehow.
@@ -208,7 +214,6 @@ const (
)
func (b *Builder) Init() {
- var err error
b.Print = func(a ...interface{}) (int, error) {
return fmt.Fprint(os.Stderr, a...)
}
@@ -220,10 +225,19 @@ func (b *Builder) Init() {
if cfg.BuildN {
b.WorkDir = "$WORK"
} else {
- b.WorkDir, err = ioutil.TempDir(os.Getenv("GOTMPDIR"), "go-build")
+ tmp, err := ioutil.TempDir(os.Getenv("GOTMPDIR"), "go-build")
if err != nil {
- base.Fatalf("%s", err)
+ base.Fatalf("go: creating work dir: %v", err)
}
+ if !filepath.IsAbs(tmp) {
+ abs, err := filepath.Abs(tmp)
+ if err != nil {
+ os.RemoveAll(tmp)
+ base.Fatalf("go: creating work dir: %v", err)
+ }
+ tmp = abs
+ }
+ b.WorkDir = tmp
if cfg.BuildX || cfg.BuildWork {
fmt.Fprintf(os.Stderr, "WORK=%s\n", b.WorkDir)
}
@@ -322,8 +336,8 @@ func (b *Builder) AutoAction(mode, depMode BuildMode, p *load.Package) *Action {
// depMode is the action (build or install) to use when building dependencies.
// To turn package main into an executable, call b.Link instead.
func (b *Builder) CompileAction(mode, depMode BuildMode, p *load.Package) *Action {
- if mode != ModeBuild && p.Internal.Local && p.Target == "" {
- // Imported via local path. No permanent target.
+ if mode != ModeBuild && (p.Internal.Local || p.Module != nil) && p.Target == "" {
+ // Imported via local path or using modules. No permanent target.
mode = ModeBuild
}
if mode != ModeBuild && p.Name == "main" {
@@ -340,8 +354,10 @@ func (b *Builder) CompileAction(mode, depMode BuildMode, p *load.Package) *Actio
Objdir: b.NewObjdir(),
}
- for _, p1 := range p.Internal.Imports {
- a.Deps = append(a.Deps, b.CompileAction(depMode, depMode, p1))
+ if p.Error == nil || !p.Error.IsImportCycle {
+ for _, p1 := range p.Internal.Imports {
+ a.Deps = append(a.Deps, b.CompileAction(depMode, depMode, p1))
+ }
}
if p.Standard {
@@ -379,6 +395,12 @@ func (b *Builder) CompileAction(mode, depMode BuildMode, p *load.Package) *Actio
// If the caller may be causing p to be installed, it is up to the caller
// to make sure that the install depends on (runs after) vet.
func (b *Builder) VetAction(mode, depMode BuildMode, p *load.Package) *Action {
+ a := b.vetAction(mode, depMode, p)
+ a.VetxOnly = false
+ return a
+}
+
+func (b *Builder) vetAction(mode, depMode BuildMode, p *load.Package) *Action {
// Construct vet action.
a := b.cacheAction("vet", p, func() *Action {
a1 := b.CompileAction(mode, depMode, p)
@@ -390,19 +412,34 @@ func (b *Builder) VetAction(mode, depMode BuildMode, p *load.Package) *Action {
stk.Pop()
aFmt := b.CompileAction(ModeBuild, depMode, p1)
+ var deps []*Action
+ if a1.buggyInstall {
+ // (*Builder).vet expects deps[0] to be the package
+ // and deps[1] to be "fmt". If we see buggyInstall
+ // here then a1 is an install of a shared library,
+ // and the real package is a1.Deps[0].
+ deps = []*Action{a1.Deps[0], aFmt, a1}
+ } else {
+ deps = []*Action{a1, aFmt}
+ }
+ for _, p1 := range load.PackageList(p.Internal.Imports) {
+ deps = append(deps, b.vetAction(mode, depMode, p1))
+ }
+
a := &Action{
- Mode: "vet",
- Package: p,
- Deps: []*Action{a1, aFmt},
- Objdir: a1.Objdir,
+ Mode: "vet",
+ Package: p,
+ Deps: deps,
+ Objdir: a1.Objdir,
+ VetxOnly: true,
+ IgnoreFail: true, // it's OK if vet of dependencies "fails" (reports problems)
}
if a1.Func == nil {
// Built-in packages like unsafe.
return a
}
- a1.needVet = true
+ deps[0].needVet = true
a.Func = (*Builder).vet
-
return a
})
return a
diff --git a/libgo/go/cmd/go/internal/work/build.go b/libgo/go/cmd/go/internal/work/build.go
index 25dfe58d4bf..ed41ce5d073 100644
--- a/libgo/go/cmd/go/internal/work/build.go
+++ b/libgo/go/cmd/go/internal/work/build.go
@@ -18,10 +18,11 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
+ "cmd/go/internal/search"
)
var CmdBuild = &base.Command{
- UsageLine: "build [-o output] [-i] [build flags] [packages]",
+ UsageLine: "go build [-o output] [-i] [build flags] [packages]",
Short: "compile packages and dependencies",
Long: `
Build compiles the packages named by the import paths,
@@ -65,7 +66,7 @@ and test commands:
Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.
-msan
enable interoperation with memory sanitizer.
- Supported only on linux/amd64,
+ Supported only on linux/amd64, linux/arm64
and only with Clang/LLVM as the host C compiler.
-v
print the names of packages as they are compiled.
@@ -97,6 +98,9 @@ and test commands:
-linkshared
link against shared libraries previously created with
-buildmode=shared.
+ -mod mode
+ module download mode to use: readonly, release, or vendor.
+ See 'go help modules' for more.
-pkgdir dir
install and load all packages from dir instead of the usual locations.
For example, when building with a non-standard configuration,
@@ -217,6 +221,7 @@ func AddBuildFlags(cmd *base.Command) {
cmd.Flag.StringVar(&cfg.BuildBuildmode, "buildmode", "default", "")
cmd.Flag.Var(&load.BuildGcflags, "gcflags", "")
cmd.Flag.Var(&load.BuildGccgoflags, "gccgoflags", "")
+ cmd.Flag.StringVar(&cfg.BuildMod, "mod", "", "")
cmd.Flag.StringVar(&cfg.BuildContext.InstallSuffix, "installsuffix", "", "")
cmd.Flag.Var(&load.BuildLdflags, "ldflags", "")
cmd.Flag.BoolVar(&cfg.BuildLinkshared, "linkshared", false, "")
@@ -284,11 +289,6 @@ func runBuild(cmd *base.Command, args []string) {
cfg.BuildO += cfg.ExeSuffix
}
- // Special case -o /dev/null by not writing at all.
- if cfg.BuildO == os.DevNull {
- cfg.BuildO = ""
- }
-
// sanity check some often mis-used options
switch cfg.BuildContext.Compiler {
case "gccgo":
@@ -309,7 +309,12 @@ func runBuild(cmd *base.Command, args []string) {
depMode = ModeInstall
}
- pkgs = pkgsFilter(load.Packages(args))
+ pkgs = omitTestOnly(pkgsFilter(load.Packages(args)))
+
+ // Special case -o /dev/null by not writing at all.
+ if cfg.BuildO == os.DevNull {
+ cfg.BuildO = ""
+ }
if cfg.BuildO != "" {
if len(pkgs) > 1 {
@@ -337,7 +342,7 @@ func runBuild(cmd *base.Command, args []string) {
}
var CmdInstall = &base.Command{
- UsageLine: "install [-i] [build flags] [packages]",
+ UsageLine: "go install [-i] [build flags] [packages]",
Short: "compile and install packages and dependencies",
Long: `
Install compiles and installs the packages named by the import paths.
@@ -376,7 +381,7 @@ func libname(args []string, pkgs []*load.Package) (string, error) {
}
var haveNonMeta bool
for _, arg := range args {
- if load.IsMetaPackage(arg) {
+ if search.IsMetaPackage(arg) {
appendName(arg)
} else {
haveNonMeta = true
@@ -409,19 +414,44 @@ func libname(args []string, pkgs []*load.Package) (string, error) {
func runInstall(cmd *base.Command, args []string) {
BuildInit()
- InstallPackages(args, false)
+ InstallPackages(args, load.PackagesForBuild(args))
}
-func InstallPackages(args []string, forGet bool) {
+// omitTestOnly returns pkgs with test-only packages removed.
+func omitTestOnly(pkgs []*load.Package) []*load.Package {
+ var list []*load.Package
+ for _, p := range pkgs {
+ if len(p.GoFiles)+len(p.CgoFiles) == 0 && !p.Internal.CmdlinePkgLiteral {
+ // Package has no source files,
+ // perhaps due to build tags or perhaps due to only having *_test.go files.
+ // Also, it is only being processed as the result of a wildcard match
+ // like ./..., not because it was listed as a literal path on the command line.
+ // Ignore it.
+ continue
+ }
+ list = append(list, p)
+ }
+ return list
+}
+
+func InstallPackages(patterns []string, pkgs []*load.Package) {
if cfg.GOBIN != "" && !filepath.IsAbs(cfg.GOBIN) {
base.Fatalf("cannot install, GOBIN must be an absolute path")
}
- pkgs := pkgsFilter(load.PackagesForBuild(args))
-
+ pkgs = omitTestOnly(pkgsFilter(pkgs))
for _, p := range pkgs {
- if p.Target == "" && (!p.Standard || p.ImportPath != "unsafe") {
+ if p.Target == "" {
switch {
+ case p.Standard && p.ImportPath == "unsafe":
+ // unsafe is a built-in package, has no target
+ case p.Name != "main" && p.Internal.Local && p.ConflictDir == "":
+ // Non-executables outside GOPATH need not have a target:
+ // we can use the cache to hold the built package archive for use in future builds.
+ // The ones inside GOPATH should have a target (in GOPATH/pkg)
+ // or else something is wrong and worth reporting (like a ConflictDir).
+ case p.Name != "main" && p.Module != nil:
+ // Non-executables have no target (except the cache) when building with modules.
case p.Internal.GobinSubdir:
base.Errorf("go %s: cannot install cross-compiled binaries when GOBIN is set", cfg.CmdName)
case p.Internal.CmdlineFiles:
@@ -445,11 +475,6 @@ func InstallPackages(args []string, forGet bool) {
a := &Action{Mode: "go install"}
var tools []*Action
for _, p := range pkgs {
- // During 'go get', don't attempt (and fail) to install packages with only tests.
- // TODO(rsc): It's not clear why 'go get' should be different from 'go install' here. See #20760.
- if forGet && len(p.GoFiles)+len(p.CgoFiles) == 0 && len(p.TestGoFiles)+len(p.XTestGoFiles) > 0 {
- continue
- }
// If p is a tool, delay the installation until the end of the build.
// This avoids installing assemblers/compilers that are being executed
// by other steps in the build.
@@ -475,7 +500,7 @@ func InstallPackages(args []string, forGet bool) {
// tools above did not apply, and a is just a simple Action
// with a list of Deps, one per package named in pkgs,
// the same as in runBuild.
- a = b.buildmodeShared(ModeInstall, ModeInstall, args, pkgs, a)
+ a = b.buildmodeShared(ModeInstall, ModeInstall, patterns, pkgs, a)
}
b.Do(a)
@@ -490,7 +515,7 @@ func InstallPackages(args []string, forGet bool) {
// One way to view this behavior is that it is as if 'go install' first
// runs 'go build' and the moves the generated file to the install dir.
// See issue 9645.
- if len(args) == 0 && len(pkgs) == 1 && pkgs[0].Name == "main" {
+ if len(patterns) == 0 && len(pkgs) == 1 && pkgs[0].Name == "main" {
// Compute file 'go build' would have created.
// If it exists and is an executable file, remove it.
_, targ := filepath.Split(pkgs[0].ImportPath)
diff --git a/libgo/go/cmd/go/internal/work/build_test.go b/libgo/go/cmd/go/internal/work/build_test.go
index 3f5ba37c641..010e17ee480 100644
--- a/libgo/go/cmd/go/internal/work/build_test.go
+++ b/libgo/go/cmd/go/internal/work/build_test.go
@@ -42,15 +42,60 @@ func TestSplitPkgConfigOutput(t *testing.T) {
}{
{[]byte(`-r:foo -L/usr/white\ space/lib -lfoo\ bar -lbar\ baz`), []string{"-r:foo", "-L/usr/white space/lib", "-lfoo bar", "-lbar baz"}},
{[]byte(`-lextra\ fun\ arg\\`), []string{`-lextra fun arg\`}},
- {[]byte(`broken flag\`), []string{"broken", "flag"}},
{[]byte("\textra whitespace\r\n"), []string{"extra", "whitespace"}},
{[]byte(" \r\n "), nil},
+ {[]byte(`"-r:foo" "-L/usr/white space/lib" "-lfoo bar" "-lbar baz"`), []string{"-r:foo", "-L/usr/white space/lib", "-lfoo bar", "-lbar baz"}},
+ {[]byte(`"-lextra fun arg\\"`), []string{`-lextra fun arg\`}},
+ {[]byte(`" \r\n\ "`), []string{` \r\n\ `}},
+ {[]byte(`""`), nil},
+ {[]byte(``), nil},
+ {[]byte(`"\\"`), []string{`\`}},
+ {[]byte(`"\x"`), []string{`\x`}},
+ {[]byte(`"\\x"`), []string{`\x`}},
+ {[]byte(`'\\'`), []string{`\`}},
+ {[]byte(`'\x'`), []string{`\x`}},
+ {[]byte(`"\\x"`), []string{`\x`}},
+ {[]byte(`-fPIC -I/test/include/foo -DQUOTED='"/test/share/doc"'`), []string{"-fPIC", "-I/test/include/foo", `-DQUOTED="/test/share/doc"`}},
+ {[]byte(`-fPIC -I/test/include/foo -DQUOTED="/test/share/doc"`), []string{"-fPIC", "-I/test/include/foo", "-DQUOTED=/test/share/doc"}},
+ {[]byte(`-fPIC -I/test/include/foo -DQUOTED=\"/test/share/doc\"`), []string{"-fPIC", "-I/test/include/foo", `-DQUOTED="/test/share/doc"`}},
+ {[]byte(`-fPIC -I/test/include/foo -DQUOTED='/test/share/doc'`), []string{"-fPIC", "-I/test/include/foo", "-DQUOTED=/test/share/doc"}},
+ {[]byte(`-DQUOTED='/te\st/share/d\oc'`), []string{`-DQUOTED=/te\st/share/d\oc`}},
+ {[]byte(`-Dhello=10 -Dworld=+32 -DDEFINED_FROM_PKG_CONFIG=hello\ world`), []string{"-Dhello=10", "-Dworld=+32", "-DDEFINED_FROM_PKG_CONFIG=hello world"}},
+ {[]byte(`"broken\"" \\\a "a"`), []string{"broken\"", "\\a", "a"}},
} {
- got := splitPkgConfigOutput(test.in)
+ got, err := splitPkgConfigOutput(test.in)
+ if err != nil {
+ t.Errorf("splitPkgConfigOutput on %v failed with error %v", test.in, err)
+ continue
+ }
+ if !reflect.DeepEqual(got, test.want) {
+ t.Errorf("splitPkgConfigOutput(%v) = %v; want %v", test.in, got, test.want)
+ }
+ }
+
+ for _, test := range []struct {
+ in []byte
+ want []string
+ }{
+ // broken quotation
+ {[]byte(`" \r\n `), nil},
+ {[]byte(`"-r:foo" "-L/usr/white space/lib "-lfoo bar" "-lbar baz"`), nil},
+ {[]byte(`"-lextra fun arg\\`), nil},
+ // broken char escaping
+ {[]byte(`broken flag\`), nil},
+ {[]byte(`extra broken flag \`), nil},
+ {[]byte(`\`), nil},
+ {[]byte(`"broken\"" "extra" \`), nil},
+ } {
+ got, err := splitPkgConfigOutput(test.in)
+ if err == nil {
+ t.Errorf("splitPkgConfigOutput(%v) = %v; haven't failed with error as expected.", test.in, got)
+ }
if !reflect.DeepEqual(got, test.want) {
t.Errorf("splitPkgConfigOutput(%v) = %v; want %v", test.in, got, test.want)
}
}
+
}
func TestSharedLibName(t *testing.T) {
@@ -220,7 +265,7 @@ func TestRespectSetgidDir(t *testing.T) {
defer pkgfile.Close()
dirGIDFile := filepath.Join(setgiddir, "setgid")
- if err := b.moveOrCopyFile(nil, dirGIDFile, pkgfile.Name(), 0666, true); err != nil {
+ if err := b.moveOrCopyFile(dirGIDFile, pkgfile.Name(), 0666, true); err != nil {
t.Fatalf("moveOrCopyFile: %v", err)
}
diff --git a/libgo/go/cmd/go/internal/work/buildid.go b/libgo/go/cmd/go/internal/work/buildid.go
index c7c07ed0186..fb57e912802 100644
--- a/libgo/go/cmd/go/internal/work/buildid.go
+++ b/libgo/go/cmd/go/internal/work/buildid.go
@@ -18,6 +18,7 @@ import (
"cmd/go/internal/load"
"cmd/go/internal/str"
"cmd/internal/buildid"
+ "cmd/internal/objabi"
)
// Build IDs
@@ -174,20 +175,29 @@ func (b *Builder) toolID(name string) string {
return id
}
- cmdline := str.StringList(cfg.BuildToolexec, base.Tool(name), "-V=full")
+ path := base.Tool(name)
+ desc := "go tool " + name
+
+ // Special case: undocumented -vettool overrides usual vet, for testing vet.
+ if name == "vet" && VetTool != "" {
+ path = VetTool
+ desc = VetTool
+ }
+
+ cmdline := str.StringList(cfg.BuildToolexec, path, "-V=full")
cmd := exec.Command(cmdline[0], cmdline[1:]...)
cmd.Env = base.EnvForDir(cmd.Dir, os.Environ())
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
- base.Fatalf("go tool %s: %v\n%s%s", name, err, stdout.Bytes(), stderr.Bytes())
+ base.Fatalf("%s: %v\n%s%s", desc, err, stdout.Bytes(), stderr.Bytes())
}
line := stdout.String()
f := strings.Fields(line)
- if len(f) < 3 || f[0] != name || f[1] != "version" || f[2] == "devel" && !strings.HasPrefix(f[len(f)-1], "buildID=") {
- base.Fatalf("go tool %s -V=full: unexpected output:\n\t%s", name, line)
+ if len(f) < 3 || f[0] != name && path != VetTool || f[1] != "version" || f[2] == "devel" && !strings.HasPrefix(f[len(f)-1], "buildID=") {
+ base.Fatalf("%s -V=full: unexpected output:\n\t%s", desc, line)
}
if f[2] == "devel" {
// On the development branch, use the content ID part of the build ID.
@@ -197,6 +207,11 @@ func (b *Builder) toolID(name string) string {
id = f[2]
}
+ // For the compiler, add any experiments.
+ if name == "compile" {
+ id += " " + objabi.Expstring()
+ }
+
b.id.Lock()
b.toolIDCache[name] = id
b.id.Unlock()
@@ -301,11 +316,7 @@ func assemblerIsGas() bool {
if err == nil {
cmd := exec.Command(strings.TrimSpace(string(assembler)), "--version")
out, err := cmd.Output()
- if err == nil && strings.Contains(string(out), "GNU") {
- return true
- } else {
- return false
- }
+ return err == nil && strings.Contains(string(out), "GNU")
} else {
return false
}
@@ -480,7 +491,7 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID
// already up-to-date, then to avoid a rebuild, report the package
// as up-to-date as well. See "Build IDs" comment above.
// TODO(rsc): Rewrite this code to use a TryCache func on the link action.
- if target != "" && !cfg.BuildA && a.Mode == "build" && len(a.triggers) == 1 && a.triggers[0].Mode == "link" {
+ if target != "" && !cfg.BuildA && !b.NeedExport && a.Mode == "build" && len(a.triggers) == 1 && a.triggers[0].Mode == "link" {
buildID, err := buildid.ReadFile(target)
if err == nil {
id := strings.Split(buildID, buildIDSeparator)
@@ -499,6 +510,14 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID
a.buildID = id[1] + buildIDSeparator + id[2]
linkID := hashToString(b.linkActionID(a.triggers[0]))
if id[0] == linkID {
+ // Best effort attempt to display output from the compile and link steps.
+ // If it doesn't work, it doesn't work: reusing the cached binary is more
+ // important than reprinting diagnostic information.
+ if c := cache.Default(); c != nil {
+ showStdout(b, c, a.actionID, "stdout") // compile output
+ showStdout(b, c, a.actionID, "link-stdout") // link output
+ }
+
// Poison a.Target to catch uses later in the build.
a.Target = "DO NOT USE - main build pseudo-cache Target"
a.built = "DO NOT USE - main build pseudo-cache built"
@@ -516,13 +535,22 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID
// We avoid the nested build ID problem in the previous special case
// by recording the test results in the cache under the action ID half.
if !cfg.BuildA && len(a.triggers) == 1 && a.triggers[0].TryCache != nil && a.triggers[0].TryCache(b, a.triggers[0]) {
+ // Best effort attempt to display output from the compile and link steps.
+ // If it doesn't work, it doesn't work: reusing the test result is more
+ // important than reprinting diagnostic information.
+ if c := cache.Default(); c != nil {
+ showStdout(b, c, a.Deps[0].actionID, "stdout") // compile output
+ showStdout(b, c, a.Deps[0].actionID, "link-stdout") // link output
+ }
+
+ // Poison a.Target to catch uses later in the build.
a.Target = "DO NOT USE - pseudo-cache Target"
a.built = "DO NOT USE - pseudo-cache built"
return true
}
- if b.ComputeStaleOnly {
- // Invoked during go list only to compute and record staleness.
+ if b.IsCmdList {
+ // Invoked during go list to compute and record staleness.
if p := a.Package; p != nil && !p.Stale {
p.Stale = true
if cfg.BuildA {
@@ -554,22 +582,9 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID
// but we're still happy to use results from the build artifact cache.
if c := cache.Default(); c != nil {
if !cfg.BuildA {
- entry, err := c.Get(actionHash)
- if err == nil {
- file := c.OutputFile(entry.OutputID)
- info, err1 := os.Stat(file)
- buildID, err2 := buildid.ReadFile(file)
- if err1 == nil && err2 == nil && info.Size() == entry.Size {
- stdout, stdoutEntry, err := c.GetBytes(cache.Subkey(a.actionID, "stdout"))
- if err == nil {
- if len(stdout) > 0 {
- if cfg.BuildX || cfg.BuildN {
- b.Showcmd("", "%s # internal", joinUnambiguously(str.StringList("cat", c.OutputFile(stdoutEntry.OutputID))))
- }
- if !cfg.BuildN {
- b.Print(string(stdout))
- }
- }
+ if file, _, err := c.GetFile(actionHash); err == nil {
+ if buildID, err := buildid.ReadFile(file); err == nil {
+ if err := showStdout(b, c, a.actionID, "stdout"); err == nil {
a.built = file
a.Target = "DO NOT USE - using cache"
a.buildID = buildID
@@ -587,11 +602,24 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID
a.output = []byte{}
}
- if b.ComputeStaleOnly {
- return true
+ return false
+}
+
+func showStdout(b *Builder, c *cache.Cache, actionID cache.ActionID, key string) error {
+ stdout, stdoutEntry, err := c.GetBytes(cache.Subkey(actionID, key))
+ if err != nil {
+ return err
}
- return false
+ if len(stdout) > 0 {
+ if cfg.BuildX || cfg.BuildN {
+ b.Showcmd("", "%s # internal", joinUnambiguously(str.StringList("cat", c.OutputFile(stdoutEntry.OutputID))))
+ }
+ if !cfg.BuildN {
+ b.Print(string(stdout))
+ }
+ }
+ return nil
}
// flushOutput flushes the output being queued in a.
@@ -618,6 +646,26 @@ func (b *Builder) updateBuildID(a *Action, target string, rewrite bool) error {
}
}
+ // Cache output from compile/link, even if we don't do the rest.
+ if c := cache.Default(); c != nil {
+ switch a.Mode {
+ case "build":
+ c.PutBytes(cache.Subkey(a.actionID, "stdout"), a.output)
+ case "link":
+ // Even though we don't cache the binary, cache the linker text output.
+ // We might notice that an installed binary is up-to-date but still
+ // want to pretend to have run the linker.
+ // Store it under the main package's action ID
+ // to make it easier to find when that's all we have.
+ for _, a1 := range a.Deps {
+ if p1 := a1.Package; p1 != nil && p1.Name == "main" {
+ c.PutBytes(cache.Subkey(a1.actionID, "link-stdout"), a.output)
+ break
+ }
+ }
+ }
+ }
+
// Find occurrences of old ID and compute new content-based ID.
r, err := os.Open(target)
if err != nil {
@@ -675,11 +723,16 @@ func (b *Builder) updateBuildID(a *Action, target string, rewrite bool) error {
panic("internal error: a.output not set")
}
outputID, _, err := c.Put(a.actionID, r)
+ r.Close()
if err == nil && cfg.BuildX {
b.Showcmd("", "%s # internal", joinUnambiguously(str.StringList("cp", target, c.OutputFile(outputID))))
}
- c.PutBytes(cache.Subkey(a.actionID, "stdout"), a.output)
- r.Close()
+ if b.NeedExport {
+ if err != nil {
+ return err
+ }
+ a.Package.Export = c.OutputFile(outputID)
+ }
}
}
diff --git a/libgo/go/cmd/go/internal/work/exec.go b/libgo/go/cmd/go/internal/work/exec.go
index 5994dbc702f..84870e52ccc 100644
--- a/libgo/go/cmd/go/internal/work/exec.go
+++ b/libgo/go/cmd/go/internal/work/exec.go
@@ -14,6 +14,7 @@ import (
"io"
"io/ioutil"
"log"
+ "math/rand"
"os"
"os/exec"
"path/filepath"
@@ -53,7 +54,7 @@ func actionList(root *Action) []*Action {
// do runs the action graph rooted at root.
func (b *Builder) Do(root *Action) {
- if c := cache.Default(); c != nil && !b.ComputeStaleOnly {
+ if c := cache.Default(); c != nil && !b.IsCmdList {
// If we're doing real work, take time at the end to trim the cache.
defer c.Trim()
}
@@ -195,10 +196,13 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID {
fmt.Fprintf(h, "goos %s goarch %s\n", cfg.Goos, cfg.Goarch)
fmt.Fprintf(h, "import %q\n", p.ImportPath)
fmt.Fprintf(h, "omitdebug %v standard %v local %v prefix %q\n", p.Internal.OmitDebug, p.Standard, p.Internal.Local, p.Internal.LocalPrefix)
+ if p.Internal.ForceLibrary {
+ fmt.Fprintf(h, "forcelibrary\n")
+ }
if len(p.CgoFiles)+len(p.SwigFiles) > 0 {
fmt.Fprintf(h, "cgo %q\n", b.toolID("cgo"))
- cppflags, cflags, cxxflags, fflags, _, _ := b.CFlags(p)
- fmt.Fprintf(h, "CC=%q %q %q\n", b.ccExe(), cppflags, cflags)
+ cppflags, cflags, cxxflags, fflags, ldflags, _ := b.CFlags(p)
+ fmt.Fprintf(h, "CC=%q %q %q %q\n", b.ccExe(), cppflags, cflags, ldflags)
if len(p.CXXFiles)+len(p.SwigFiles) > 0 {
fmt.Fprintf(h, "CXX=%q %q\n", b.cxxExe(), cxxflags)
}
@@ -295,40 +299,93 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID {
return h.Sum()
}
+// needCgoHdr reports whether the actions triggered by this one
+// expect to be able to access the cgo-generated header file.
+func (b *Builder) needCgoHdr(a *Action) bool {
+ // If this build triggers a header install, run cgo to get the header.
+ if !b.IsCmdList && (a.Package.UsesCgo() || a.Package.UsesSwig()) && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared") {
+ for _, t1 := range a.triggers {
+ if t1.Mode == "install header" {
+ return true
+ }
+ }
+ for _, t1 := range a.triggers {
+ for _, t2 := range t1.triggers {
+ if t2.Mode == "install header" {
+ return true
+ }
+ }
+ }
+ }
+ return false
+}
+
+// allowedVersion reports whether the version v is an allowed version of go
+// (one that we can compile).
+// v is known to be of the form "1.23".
+func allowedVersion(v string) bool {
+ // Special case: no requirement.
+ if v == "" {
+ return true
+ }
+ // Special case "1.0" means "go1", which is OK.
+ if v == "1.0" {
+ return true
+ }
+ // Otherwise look through release tags of form "go1.23" for one that matches.
+ for _, tag := range cfg.BuildContext.ReleaseTags {
+ if strings.HasPrefix(tag, "go") && tag[2:] == v {
+ return true
+ }
+ }
+ return false
+}
+
+const (
+ needBuild uint32 = 1 << iota
+ needCgoHdr
+ needVet
+ needCompiledGoFiles
+ needStale
+)
+
// build is the action for building a single package.
// Note that any new influence on this logic must be reported in b.buildActionID above as well.
func (b *Builder) build(a *Action) (err error) {
p := a.Package
+
+ bit := func(x uint32, b bool) uint32 {
+ if b {
+ return x
+ }
+ return 0
+ }
+
cached := false
+ need := bit(needBuild, !b.IsCmdList || b.NeedExport) |
+ bit(needCgoHdr, b.needCgoHdr(a)) |
+ bit(needVet, a.needVet) |
+ bit(needCompiledGoFiles, b.NeedCompiledGoFiles)
+
if !p.BinaryOnly {
if b.useCache(a, p, b.buildActionID(a), p.Target) {
- // If this build triggers a header install, run cgo to get the header.
- // TODO(rsc): Once we can cache multiple file outputs from an action,
- // the header should be cached, and then this awful test can be deleted.
- // Need to look for install header actions depending on this action,
- // or depending on a link that depends on this action.
- needHeader := false
- if (a.Package.UsesCgo() || a.Package.UsesSwig()) && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared") {
- for _, t1 := range a.triggers {
- if t1.Mode == "install header" {
- needHeader = true
- goto CheckedHeader
- }
- }
- for _, t1 := range a.triggers {
- for _, t2 := range t1.triggers {
- if t2.Mode == "install header" {
- needHeader = true
- goto CheckedHeader
- }
- }
- }
+ // We found the main output in the cache.
+ // If we don't need any other outputs, we can stop.
+ need &^= needBuild
+ if b.NeedExport {
+ p.Export = a.built
}
- CheckedHeader:
- if b.ComputeStaleOnly || !a.needVet && !needHeader {
- return nil
+ if need&needCompiledGoFiles != 0 && b.loadCachedGoFiles(a) {
+ need &^= needCompiledGoFiles
}
+ // Otherwise, we need to write files to a.Objdir (needVet, needCgoHdr).
+ // Remember that we might have them in cache
+ // and check again after we create a.Objdir.
cached = true
+ a.output = []byte{} // start saving output in case we miss any cache results
+ }
+ if need == 0 {
+ return nil
}
defer b.flushOutput(a)
}
@@ -337,6 +394,9 @@ func (b *Builder) build(a *Action) (err error) {
if err != nil && err != errPrintedOutput {
err = fmt.Errorf("go build %s: %v", a.Package.ImportPath, err)
}
+ if err != nil && b.IsCmdList && b.NeedError && p.Error == nil {
+ p.Error = &load.PackageError{Err: err.Error()}
+ }
}()
if cfg.BuildN {
// In -n mode, print a banner between packages.
@@ -356,17 +416,24 @@ func (b *Builder) build(a *Action) (err error) {
if err == nil {
a.built = a.Package.Target
a.Target = a.Package.Target
+ if b.NeedExport {
+ a.Package.Export = a.Package.Target
+ }
a.buildID = b.fileHash(a.Package.Target)
a.Package.Stale = false
a.Package.StaleReason = "binary-only package"
return nil
}
- if b.ComputeStaleOnly {
- a.Package.Stale = true
- a.Package.StaleReason = "missing or invalid binary-only package"
+ a.Package.Stale = true
+ a.Package.StaleReason = "missing or invalid binary-only package"
+ if b.IsCmdList {
return nil
}
- return fmt.Errorf("missing or invalid binary-only package")
+ return fmt.Errorf("missing or invalid binary-only package; expected file %q", a.Package.Target)
+ }
+
+ if p.Module != nil && !allowedVersion(p.Module.GoVersion) {
+ return fmt.Errorf("module requires Go %s", p.Module.GoVersion)
}
if err := b.Mkdir(a.Objdir); err != nil {
@@ -374,6 +441,23 @@ func (b *Builder) build(a *Action) (err error) {
}
objdir := a.Objdir
+ if cached {
+ if need&needCgoHdr != 0 && b.loadCachedCgoHdr(a) {
+ need &^= needCgoHdr
+ }
+
+ // Load cached vet config, but only if that's all we have left
+ // (need == needVet, not testing just the one bit).
+ // If we are going to do a full build anyway,
+ // we're going to regenerate the files below anyway.
+ if need == needVet && b.loadCachedVet(a) {
+ need &^= needVet
+ }
+ if need == 0 {
+ return nil
+ }
+ }
+
// make target directory
dir, _ := filepath.Split(a.Target)
if dir != "" {
@@ -382,13 +466,12 @@ func (b *Builder) build(a *Action) (err error) {
}
}
- var gofiles, cgofiles, cfiles, sfiles, cxxfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string
-
- gofiles = append(gofiles, a.Package.GoFiles...)
- cgofiles = append(cgofiles, a.Package.CgoFiles...)
- cfiles = append(cfiles, a.Package.CFiles...)
- sfiles = append(sfiles, a.Package.SFiles...)
- cxxfiles = append(cxxfiles, a.Package.CXXFiles...)
+ gofiles := str.StringList(a.Package.GoFiles)
+ cgofiles := str.StringList(a.Package.CgoFiles)
+ cfiles := str.StringList(a.Package.CFiles)
+ sfiles := str.StringList(a.Package.SFiles)
+ cxxfiles := str.StringList(a.Package.CXXFiles)
+ var objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string
if a.Package.UsesCgo() || a.Package.UsesSwig() {
if pcCFLAGS, pcLDFLAGS, err = b.getPkgConfigFlags(a.Package); err != nil {
@@ -432,7 +515,7 @@ func (b *Builder) build(a *Action) (err error) {
// Not covering this file.
continue
}
- if err := b.cover(a, coverFile, sourceFile, 0666, cover.Var); err != nil {
+ if err := b.cover(a, coverFile, sourceFile, cover.Var); err != nil {
return err
}
if i < len(gofiles) {
@@ -488,10 +571,16 @@ func (b *Builder) build(a *Action) (err error) {
}
cgoObjects = append(cgoObjects, outObj...)
gofiles = append(gofiles, outGo...)
+
+ switch cfg.BuildBuildmode {
+ case "c-archive", "c-shared":
+ b.cacheCgoHdr(a)
+ }
}
- if cached && !a.needVet {
- return nil
- }
+ b.cacheGofiles(a, gofiles)
+
+ // Running cgo generated the cgo header.
+ need &^= needCgoHdr
// Sanity check only, since Package.load already checked as well.
if len(gofiles) == 0 {
@@ -499,26 +588,19 @@ func (b *Builder) build(a *Action) (err error) {
}
// Prepare Go vet config if needed.
- var vcfg *vetConfig
- if a.needVet {
- // Pass list of absolute paths to vet,
- // so that vet's error messages will use absolute paths,
- // so that we can reformat them relative to the directory
- // in which the go command is invoked.
- vcfg = &vetConfig{
- Compiler: cfg.BuildToolchainName,
- Dir: a.Package.Dir,
- GoFiles: mkAbsFiles(a.Package.Dir, gofiles),
- ImportPath: a.Package.ImportPath,
- ImportMap: make(map[string]string),
- PackageFile: make(map[string]string),
- Standard: make(map[string]bool),
- }
- a.vetCfg = vcfg
- for i, raw := range a.Package.Internal.RawImports {
- final := a.Package.Imports[i]
- vcfg.ImportMap[raw] = final
+ if need&needVet != 0 {
+ buildVetConfig(a, gofiles)
+ need &^= needVet
+ }
+ if need&needCompiledGoFiles != 0 {
+ if !b.loadCachedGoFiles(a) {
+ return fmt.Errorf("failed to cache compiled Go files")
}
+ need &^= needCompiledGoFiles
+ }
+ if need == 0 {
+ // Nothing left to do.
+ return nil
}
// Prepare Go import config.
@@ -529,24 +611,12 @@ func (b *Builder) build(a *Action) (err error) {
// except when it doesn't.
var icfg bytes.Buffer
fmt.Fprintf(&icfg, "# import config\n")
-
for i, raw := range a.Package.Internal.RawImports {
final := a.Package.Imports[i]
if final != raw {
fmt.Fprintf(&icfg, "importmap %s=%s\n", raw, final)
}
}
-
- // Compute the list of mapped imports in the vet config
- // so that we can add any missing mappings below.
- var vcfgMapped map[string]bool
- if vcfg != nil {
- vcfgMapped = make(map[string]bool)
- for _, p := range vcfg.ImportMap {
- vcfgMapped[p] = true
- }
- }
-
for _, a1 := range a.Deps {
p1 := a1.Package
if p1 == nil || p1.ImportPath == "" {
@@ -555,33 +625,20 @@ func (b *Builder) build(a *Action) (err error) {
if a1.built != "" {
fmt.Fprintf(&icfg, "packagefile %s=%s\n", p1.ImportPath, a1.built)
}
- if vcfg != nil {
- // Add import mapping if needed
- // (for imports like "runtime/cgo" that appear only in generated code).
- if !vcfgMapped[p1.ImportPath] {
- vcfg.ImportMap[p1.ImportPath] = p1.ImportPath
- }
- if a1.built != "" {
- vcfg.PackageFile[p1.ImportPath] = a1.built
- }
- if p1.Standard {
- vcfg.Standard[p1.ImportPath] = true
- }
- }
}
- if cached {
- // The cached package file is OK, so we don't need to run the compile.
- // We've only going through the motions to prepare the vet configuration,
- // which is now complete.
- return nil
+ if p.Internal.BuildInfo != "" && cfg.ModulesEnabled {
+ if err := b.writeFile(objdir+"_gomod_.go", load.ModInfoProg(p.Internal.BuildInfo)); err != nil {
+ return err
+ }
+ gofiles = append(gofiles, objdir+"_gomod_.go")
}
// Compile Go.
objpkg := objdir + "_pkg_.a"
ofile, out, err := BuildToolchain.gc(b, a, objpkg, icfg.Bytes(), len(sfiles) > 0, gofiles)
if len(out) > 0 {
- b.showOutput(a, a.Package.Dir, a.Package.ImportPath, b.processOutput(out))
+ b.showOutput(a, a.Package.Dir, a.Package.Desc(), b.processOutput(out))
if err != nil {
return errPrintedOutput
}
@@ -604,17 +661,17 @@ func (b *Builder) build(a *Action) (err error) {
switch {
case strings.HasSuffix(name, _goos_goarch):
targ := file[:len(name)-len(_goos_goarch)] + "_GOOS_GOARCH." + ext
- if err := b.copyFile(a, objdir+targ, filepath.Join(a.Package.Dir, file), 0666, true); err != nil {
+ if err := b.copyFile(objdir+targ, filepath.Join(a.Package.Dir, file), 0666, true); err != nil {
return err
}
case strings.HasSuffix(name, _goarch):
targ := file[:len(name)-len(_goarch)] + "_GOARCH." + ext
- if err := b.copyFile(a, objdir+targ, filepath.Join(a.Package.Dir, file), 0666, true); err != nil {
+ if err := b.copyFile(objdir+targ, filepath.Join(a.Package.Dir, file), 0666, true); err != nil {
return err
}
case strings.HasSuffix(name, _goos):
targ := file[:len(name)-len(_goos)] + "_GOOS." + ext
- if err := b.copyFile(a, objdir+targ, filepath.Join(a.Package.Dir, file), 0666, true); err != nil {
+ if err := b.copyFile(objdir+targ, filepath.Join(a.Package.Dir, file), 0666, true); err != nil {
return err
}
}
@@ -638,7 +695,7 @@ func (b *Builder) build(a *Action) (err error) {
}
// For gccgo on ELF systems, we write the build ID as an assembler file.
- // This lets us set the the SHF_EXCLUDE flag.
+ // This lets us set the SHF_EXCLUDE flag.
// This is read by readGccgoArchive in cmd/internal/buildid/buildid.go.
if a.buildID != "" && cfg.BuildToolchainName == "gccgo" {
switch cfg.Goos {
@@ -695,16 +752,189 @@ func (b *Builder) build(a *Action) (err error) {
return nil
}
+func (b *Builder) cacheObjdirFile(a *Action, c *cache.Cache, name string) error {
+ f, err := os.Open(a.Objdir + name)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ _, _, err = c.Put(cache.Subkey(a.actionID, name), f)
+ return err
+}
+
+func (b *Builder) findCachedObjdirFile(a *Action, c *cache.Cache, name string) (string, error) {
+ file, _, err := c.GetFile(cache.Subkey(a.actionID, name))
+ if err != nil {
+ return "", err
+ }
+ return file, nil
+}
+
+func (b *Builder) loadCachedObjdirFile(a *Action, c *cache.Cache, name string) error {
+ cached, err := b.findCachedObjdirFile(a, c, name)
+ if err != nil {
+ return err
+ }
+ return b.copyFile(a.Objdir+name, cached, 0666, true)
+}
+
+func (b *Builder) cacheCgoHdr(a *Action) {
+ c := cache.Default()
+ if c == nil {
+ return
+ }
+ b.cacheObjdirFile(a, c, "_cgo_install.h")
+}
+
+func (b *Builder) loadCachedCgoHdr(a *Action) bool {
+ c := cache.Default()
+ if c == nil {
+ return false
+ }
+ err := b.loadCachedObjdirFile(a, c, "_cgo_install.h")
+ return err == nil
+}
+
+func (b *Builder) cacheGofiles(a *Action, gofiles []string) {
+ c := cache.Default()
+ if c == nil {
+ return
+ }
+ var buf bytes.Buffer
+ for _, file := range gofiles {
+ if !strings.HasPrefix(file, a.Objdir) {
+ // not generated
+ buf.WriteString("./")
+ buf.WriteString(file)
+ buf.WriteString("\n")
+ continue
+ }
+ name := file[len(a.Objdir):]
+ buf.WriteString(name)
+ buf.WriteString("\n")
+ if err := b.cacheObjdirFile(a, c, name); err != nil {
+ return
+ }
+ }
+ c.PutBytes(cache.Subkey(a.actionID, "gofiles"), buf.Bytes())
+}
+
+func (b *Builder) loadCachedVet(a *Action) bool {
+ c := cache.Default()
+ if c == nil {
+ return false
+ }
+ list, _, err := c.GetBytes(cache.Subkey(a.actionID, "gofiles"))
+ if err != nil {
+ return false
+ }
+ var gofiles []string
+ for _, name := range strings.Split(string(list), "\n") {
+ if name == "" { // end of list
+ continue
+ }
+ if strings.HasPrefix(name, "./") {
+ gofiles = append(gofiles, name[2:])
+ continue
+ }
+ if err := b.loadCachedObjdirFile(a, c, name); err != nil {
+ return false
+ }
+ gofiles = append(gofiles, a.Objdir+name)
+ }
+ buildVetConfig(a, gofiles)
+ return true
+}
+
+func (b *Builder) loadCachedGoFiles(a *Action) bool {
+ c := cache.Default()
+ if c == nil {
+ return false
+ }
+ list, _, err := c.GetBytes(cache.Subkey(a.actionID, "gofiles"))
+ if err != nil {
+ return false
+ }
+ var files []string
+ for _, name := range strings.Split(string(list), "\n") {
+ if name == "" { // end of list
+ continue
+ }
+ if strings.HasPrefix(name, "./") {
+ files = append(files, name[len("./"):])
+ continue
+ }
+ file, err := b.findCachedObjdirFile(a, c, name)
+ if err != nil {
+ return false
+ }
+ files = append(files, file)
+ }
+ a.Package.CompiledGoFiles = files
+ return true
+}
+
+// vetConfig is the configuration passed to vet describing a single package.
type vetConfig struct {
- Compiler string
- Dir string
- GoFiles []string
- ImportMap map[string]string
- PackageFile map[string]string
- Standard map[string]bool
- ImportPath string
+ Compiler string // compiler name (gc, gccgo)
+ Dir string // directory containing package
+ ImportPath string // canonical import path ("package path")
+ GoFiles []string // absolute paths to package source files
+
+ ImportMap map[string]string // map import path in source code to package path
+ PackageFile map[string]string // map package path to .a file with export data
+ Standard map[string]bool // map package path to whether it's in the standard library
+ PackageVetx map[string]string // map package path to vetx data from earlier vet run
+ VetxOnly bool // only compute vetx data; don't report detected problems
+ VetxOutput string // write vetx data to this output file
+
+ SucceedOnTypecheckFailure bool // awful hack; see #18395 and below
+}
+
+func buildVetConfig(a *Action, gofiles []string) {
+ // Pass list of absolute paths to vet,
+ // so that vet's error messages will use absolute paths,
+ // so that we can reformat them relative to the directory
+ // in which the go command is invoked.
+ vcfg := &vetConfig{
+ Compiler: cfg.BuildToolchainName,
+ Dir: a.Package.Dir,
+ GoFiles: mkAbsFiles(a.Package.Dir, gofiles),
+ ImportPath: a.Package.ImportPath,
+ ImportMap: make(map[string]string),
+ PackageFile: make(map[string]string),
+ Standard: make(map[string]bool),
+ }
+ a.vetCfg = vcfg
+ for i, raw := range a.Package.Internal.RawImports {
+ final := a.Package.Imports[i]
+ vcfg.ImportMap[raw] = final
+ }
- SucceedOnTypecheckFailure bool
+ // Compute the list of mapped imports in the vet config
+ // so that we can add any missing mappings below.
+ vcfgMapped := make(map[string]bool)
+ for _, p := range vcfg.ImportMap {
+ vcfgMapped[p] = true
+ }
+
+ for _, a1 := range a.Deps {
+ p1 := a1.Package
+ if p1 == nil || p1.ImportPath == "" {
+ continue
+ }
+ // Add import mapping if needed
+ // (for imports like "runtime/cgo" that appear only in generated code).
+ if !vcfgMapped[p1.ImportPath] {
+ vcfg.ImportMap[p1.ImportPath] = p1.ImportPath
+ }
+ if a1.built != "" {
+ vcfg.PackageFile[p1.ImportPath] = a1.built
+ }
+ if p1.Standard {
+ vcfg.Standard[p1.ImportPath] = true
+ }
+ }
}
// VetTool is the path to an alternate vet tool binary.
@@ -719,13 +949,51 @@ func (b *Builder) vet(a *Action) error {
// a.Deps[0] is the build of the package being vetted.
// a.Deps[1] is the build of the "fmt" package.
+ a.Failed = false // vet of dependency may have failed but we can still succeed
+
+ if a.Deps[0].Failed {
+ // The build of the package has failed. Skip vet check.
+ // Vet could return export data for non-typecheck errors,
+ // but we ignore it because the package cannot be compiled.
+ return nil
+ }
+
vcfg := a.Deps[0].vetCfg
if vcfg == nil {
// Vet config should only be missing if the build failed.
- if !a.Deps[0].Failed {
- return fmt.Errorf("vet config not found")
+ return fmt.Errorf("vet config not found")
+ }
+
+ vcfg.VetxOnly = a.VetxOnly
+ vcfg.VetxOutput = a.Objdir + "vet.out"
+ vcfg.PackageVetx = make(map[string]string)
+
+ h := cache.NewHash("vet " + a.Package.ImportPath)
+ fmt.Fprintf(h, "vet %q\n", b.toolID("vet"))
+
+ // Note: We could decide that vet should compute export data for
+ // all analyses, in which case we don't need to include the flags here.
+ // But that would mean that if an analysis causes problems like
+ // unexpected crashes there would be no way to turn it off.
+ // It seems better to let the flags disable export analysis too.
+ fmt.Fprintf(h, "vetflags %q\n", VetFlags)
+
+ fmt.Fprintf(h, "pkg %q\n", a.Deps[0].actionID)
+ for _, a1 := range a.Deps {
+ if a1.Mode == "vet" && a1.built != "" {
+ fmt.Fprintf(h, "vetout %q %s\n", a1.Package.ImportPath, b.fileHash(a1.built))
+ vcfg.PackageVetx[a1.Package.ImportPath] = a1.built
+ }
+ }
+ key := cache.ActionID(h.Sum())
+
+ if vcfg.VetxOnly {
+ if c := cache.Default(); c != nil && !cfg.BuildA {
+ if file, _, err := c.GetFile(key); err == nil {
+ a.built = file
+ return nil
+ }
}
- return nil
}
if vcfg.ImportMap["fmt"] == "" {
@@ -742,7 +1010,9 @@ func (b *Builder) vet(a *Action) error {
// so at least for now assume the bug is in vet.
// We know of at least #18395.
// TODO(rsc,gri): Try to remove this for Go 1.11.
- vcfg.SucceedOnTypecheckFailure = cfg.CmdName == "test"
+ //
+ // Disabled 2018-04-20. Let's see if we can do without it.
+ // vcfg.SucceedOnTypecheckFailure = cfg.CmdName == "test"
js, err := json.MarshalIndent(vcfg, "", "\t")
if err != nil {
@@ -753,7 +1023,7 @@ func (b *Builder) vet(a *Action) error {
return err
}
- var env []string
+ env := b.cCompilerEnv()
if cfg.BuildToolchainName == "gccgo" {
env = append(env, "GCCGO="+BuildToolchain.compiler())
}
@@ -763,7 +1033,18 @@ func (b *Builder) vet(a *Action) error {
if tool == "" {
tool = base.Tool("vet")
}
- return b.run(a, p.Dir, p.ImportPath, env, cfg.BuildToolexec, tool, VetFlags, a.Objdir+"vet.cfg")
+ runErr := b.run(a, p.Dir, p.ImportPath, env, cfg.BuildToolexec, tool, VetFlags, a.Objdir+"vet.cfg")
+
+ // If vet wrote export data, save it for input to future vets.
+ if f, err := os.Open(vcfg.VetxOutput); err == nil {
+ a.built = vcfg.VetxOutput
+ if c := cache.Default(); c != nil {
+ c.Put(key, f)
+ }
+ f.Close()
+ }
+
+ return runErr
}
// linkActionID computes the action ID for a link action.
@@ -849,7 +1130,7 @@ func (b *Builder) printLinkerConfig(h io.Writer, p *load.Package) {
// link is the action for linking a single command.
// Note that any new influence on this logic must be reported in b.linkActionID above as well.
func (b *Builder) link(a *Action) (err error) {
- if b.useCache(a, a.Package, b.linkActionID(a), a.Package.Target) {
+ if b.useCache(a, a.Package, b.linkActionID(a), a.Package.Target) || b.IsCmdList {
return nil
}
defer b.flushOutput(a)
@@ -886,11 +1167,11 @@ func (b *Builder) link(a *Action) (err error) {
// We still call updateBuildID to update a.buildID, which is important
// for test result caching, but passing rewrite=false (final arg)
// means we don't actually rewrite the binary, nor store the
- // result into the cache.
- // Not calling updateBuildID means we also don't insert these
- // binaries into the build object cache. That's probably a net win:
+ // result into the cache. That's probably a net win:
// less cache space wasted on large binaries we are not likely to
// need again. (On the other hand it does make repeated go test slower.)
+ // It also makes repeated go run slower, which is a win in itself:
+ // we don't want people to treat go run like a scripting environment.
if err := b.updateBuildID(a, a.Target, !a.Package.Internal.OmitDebug); err != nil {
return err
}
@@ -922,36 +1203,64 @@ func (b *Builder) PkgconfigCmd() string {
}
// splitPkgConfigOutput parses the pkg-config output into a slice of
-// flags. pkg-config always uses \ to escape special characters.
-func splitPkgConfigOutput(out []byte) []string {
+// flags. This implements the algorithm from pkgconf/libpkgconf/argvsplit.c.
+func splitPkgConfigOutput(out []byte) ([]string, error) {
if len(out) == 0 {
- return nil
+ return nil, nil
}
var flags []string
- flag := make([]byte, len(out))
- r, w := 0, 0
- for r < len(out) {
- switch out[r] {
- case ' ', '\t', '\r', '\n':
- if w > 0 {
- flags = append(flags, string(flag[:w]))
+ flag := make([]byte, 0, len(out))
+ escaped := false
+ quote := byte(0)
+
+ for _, c := range out {
+ if escaped {
+ if quote != 0 {
+ switch c {
+ case '$', '`', '"', '\\':
+ default:
+ flag = append(flag, '\\')
+ }
+ flag = append(flag, c)
+ } else {
+ flag = append(flag, c)
}
- w = 0
- case '\\':
- r++
- fallthrough
- default:
- if r < len(out) {
- flag[w] = out[r]
- w++
+ escaped = false
+ } else if quote != 0 {
+ if c == quote {
+ quote = 0
+ } else {
+ switch c {
+ case '\\':
+ escaped = true
+ default:
+ flag = append(flag, c)
+ }
+ }
+ } else if strings.IndexByte(" \t\n\v\f\r", c) < 0 {
+ switch c {
+ case '\\':
+ escaped = true
+ case '\'', '"':
+ quote = c
+ default:
+ flag = append(flag, c)
}
+ } else if len(flag) != 0 {
+ flags = append(flags, string(flag))
+ flag = flag[:0]
}
- r++
}
- if w > 0 {
- flags = append(flags, string(flag[:w]))
+ if escaped {
+ return nil, errors.New("broken character escaping in pkgconf output ")
+ }
+ if quote != 0 {
+ return nil, errors.New("unterminated quoted string in pkgconf output ")
+ } else if len(flag) != 0 {
+ flags = append(flags, string(flag))
}
- return flags
+
+ return flags, nil
}
// Calls pkg-config if needed and returns the cflags/ldflags needed to build the package.
@@ -976,21 +1285,24 @@ func (b *Builder) getPkgConfigFlags(p *load.Package) (cflags, ldflags []string,
}
}
var out []byte
- out, err = b.runOut(p.Dir, p.ImportPath, nil, b.PkgconfigCmd(), "--cflags", pcflags, "--", pkgs)
+ out, err = b.runOut(p.Dir, nil, b.PkgconfigCmd(), "--cflags", pcflags, "--", pkgs)
if err != nil {
- b.showOutput(nil, p.Dir, b.PkgconfigCmd()+" --cflags "+strings.Join(pcflags, " ")+strings.Join(pkgs, " "), string(out))
+ b.showOutput(nil, p.Dir, b.PkgconfigCmd()+" --cflags "+strings.Join(pcflags, " ")+" -- "+strings.Join(pkgs, " "), string(out))
b.Print(err.Error() + "\n")
return nil, nil, errPrintedOutput
}
if len(out) > 0 {
- cflags = splitPkgConfigOutput(out)
+ cflags, err = splitPkgConfigOutput(out)
+ if err != nil {
+ return nil, nil, err
+ }
if err := checkCompilerFlags("CFLAGS", "pkg-config --cflags", cflags); err != nil {
return nil, nil, err
}
}
- out, err = b.runOut(p.Dir, p.ImportPath, nil, b.PkgconfigCmd(), "--libs", pcflags, "--", pkgs)
+ out, err = b.runOut(p.Dir, nil, b.PkgconfigCmd(), "--libs", pcflags, "--", pkgs)
if err != nil {
- b.showOutput(nil, p.Dir, b.PkgconfigCmd()+" --libs "+strings.Join(pcflags, " ")+strings.Join(pkgs, " "), string(out))
+ b.showOutput(nil, p.Dir, b.PkgconfigCmd()+" --libs "+strings.Join(pcflags, " ")+" -- "+strings.Join(pkgs, " "), string(out))
b.Print(err.Error() + "\n")
return nil, nil, errPrintedOutput
}
@@ -1051,7 +1363,7 @@ func (b *Builder) linkSharedActionID(a *Action) cache.ActionID {
}
func (b *Builder) linkShared(a *Action) (err error) {
- if b.useCache(a, nil, b.linkSharedActionID(a), a.Target) {
+ if b.useCache(a, nil, b.linkSharedActionID(a), a.Target) || b.IsCmdList {
return nil
}
defer b.flushOutput(a)
@@ -1096,7 +1408,9 @@ func BuildInstallFunc(b *Builder, a *Action) (err error) {
// so the built target is not in the a1.Objdir tree that b.cleanup(a1) removes.
if a1.built == a.Target {
a.built = a.Target
- b.cleanup(a1)
+ if !a.buggyInstall {
+ b.cleanup(a1)
+ }
// Whether we're smart enough to avoid a complete rebuild
// depends on exactly what the staleness and rebuild algorithms
// are, as well as potentially the state of the Go build cache.
@@ -1115,13 +1429,17 @@ func BuildInstallFunc(b *Builder, a *Action) (err error) {
// We want to hide that awful detail as much as possible, so don't
// advertise it by touching the mtimes (usually the libraries are up
// to date).
- if !a.buggyInstall && !b.ComputeStaleOnly {
+ if !a.buggyInstall && !b.IsCmdList {
now := time.Now()
os.Chtimes(a.Target, now, now)
}
return nil
}
- if b.ComputeStaleOnly {
+
+ // If we're building for go list -export,
+ // never install anything; just keep the cache reference.
+ if b.IsCmdList {
+ a.built = a1.built
return nil
}
@@ -1146,9 +1464,11 @@ func BuildInstallFunc(b *Builder, a *Action) (err error) {
}
}
- defer b.cleanup(a1)
+ if !a.buggyInstall {
+ defer b.cleanup(a1)
+ }
- return b.moveOrCopyFile(a, a.Target, a1.built, perm, false)
+ return b.moveOrCopyFile(a.Target, a1.built, perm, false)
}
// cleanup removes a's object dir to keep the amount of
@@ -1158,14 +1478,18 @@ func BuildInstallFunc(b *Builder, a *Action) (err error) {
func (b *Builder) cleanup(a *Action) {
if !cfg.BuildWork {
if cfg.BuildX {
- b.Showcmd("", "rm -r %s", a.Objdir)
+ // Don't say we are removing the directory if
+ // we never created it.
+ if _, err := os.Stat(a.Objdir); err == nil || cfg.BuildN {
+ b.Showcmd("", "rm -r %s", a.Objdir)
+ }
}
os.RemoveAll(a.Objdir)
}
}
// moveOrCopyFile is like 'mv src dst' or 'cp src dst'.
-func (b *Builder) moveOrCopyFile(a *Action, dst, src string, perm os.FileMode, force bool) error {
+func (b *Builder) moveOrCopyFile(dst, src string, perm os.FileMode, force bool) error {
if cfg.BuildN {
b.Showcmd("", "mv %s %s", src, dst)
return nil
@@ -1176,7 +1500,7 @@ func (b *Builder) moveOrCopyFile(a *Action, dst, src string, perm os.FileMode, f
// If the source is in the build cache, we need to copy it.
if strings.HasPrefix(src, cache.DefaultDir()) {
- return b.copyFile(a, dst, src, perm, force)
+ return b.copyFile(dst, src, perm, force)
}
// On Windows, always copy the file, so that we respect the NTFS
@@ -1184,7 +1508,7 @@ func (b *Builder) moveOrCopyFile(a *Action, dst, src string, perm os.FileMode, f
// What matters here is not cfg.Goos (the system we are building
// for) but runtime.GOOS (the system we are building on).
if runtime.GOOS == "windows" {
- return b.copyFile(a, dst, src, perm, force)
+ return b.copyFile(dst, src, perm, force)
}
// If the destination directory has the group sticky bit set,
@@ -1192,7 +1516,7 @@ func (b *Builder) moveOrCopyFile(a *Action, dst, src string, perm os.FileMode, f
// https://golang.org/issue/18878
if fi, err := os.Stat(filepath.Dir(dst)); err == nil {
if fi.IsDir() && (fi.Mode()&os.ModeSetgid) != 0 {
- return b.copyFile(a, dst, src, perm, force)
+ return b.copyFile(dst, src, perm, force)
}
}
@@ -1222,11 +1546,11 @@ func (b *Builder) moveOrCopyFile(a *Action, dst, src string, perm os.FileMode, f
}
}
- return b.copyFile(a, dst, src, perm, force)
+ return b.copyFile(dst, src, perm, force)
}
// copyFile is like 'cp src dst'.
-func (b *Builder) copyFile(a *Action, dst, src string, perm os.FileMode, force bool) error {
+func (b *Builder) copyFile(dst, src string, perm os.FileMode, force bool) error {
if cfg.BuildN || cfg.BuildX {
b.Showcmd("", "cp %s %s", src, dst)
if cfg.BuildN {
@@ -1317,12 +1641,12 @@ func (b *Builder) installHeader(a *Action) error {
}
}
- return b.moveOrCopyFile(a, a.Target, src, 0666, true)
+ return b.moveOrCopyFile(a.Target, src, 0666, true)
}
// cover runs, in effect,
// go tool cover -mode=b.coverMode -var="varName" -o dst.go src.go
-func (b *Builder) cover(a *Action, dst, src string, perm os.FileMode, varName string) error {
+func (b *Builder) cover(a *Action, dst, src string, varName string) error {
return b.run(a, a.Objdir, "cover "+a.Package.ImportPath, nil,
cfg.BuildToolexec,
base.Tool("cover"),
@@ -1344,6 +1668,7 @@ var objectMagic = [][]byte{
{0x00, 0x00, 0x01, 0xEB}, // Plan 9 i386
{0x00, 0x00, 0x8a, 0x97}, // Plan 9 amd64
{0x00, 0x00, 0x06, 0x47}, // Plan 9 arm
+ {0x00, 0x61, 0x73, 0x6D}, // WASM
{0x01, 0xDF}, // XCOFF32
{0x01, 0xF7}, // XCOFF64
}
@@ -1389,11 +1714,11 @@ func mayberemovefile(s string) {
func (b *Builder) fmtcmd(dir string, format string, args ...interface{}) string {
cmd := fmt.Sprintf(format, args...)
if dir != "" && dir != "/" {
- to := "."
+ dot := " ."
if dir[len(dir)-1] == filepath.Separator {
- to += string(filepath.Separator)
+ dot += string(filepath.Separator)
}
- cmd = strings.Replace(" "+cmd, " "+dir, " "+to, -1)[1:]
+ cmd = strings.Replace(" "+cmd, " "+dir, dot, -1)[1:]
if b.scriptDir != dir {
b.scriptDir = dir
cmd = "cd " + dir + "\n" + cmd
@@ -1472,7 +1797,7 @@ var cgoTypeSigRe = regexp.MustCompile(`\b_C2?(type|func|var|macro)_\B`)
// If the command fails, run prints information about the failure
// and returns a non-nil error.
func (b *Builder) run(a *Action, dir string, desc string, env []string, cmdargs ...interface{}) error {
- out, err := b.runOut(dir, desc, env, cmdargs...)
+ out, err := b.runOut(dir, env, cmdargs...)
if len(out) > 0 {
if desc == "" {
desc = b.fmtcmd(dir, "%s", strings.Join(str.StringList(cmdargs...), " "))
@@ -1504,7 +1829,7 @@ func (b *Builder) processOutput(out []byte) string {
// runOut runs the command given by cmdline in the directory dir.
// It returns the command output and any errors that occurred.
-func (b *Builder) runOut(dir string, desc string, env []string, cmdargs ...interface{}) ([]byte, error) {
+func (b *Builder) runOut(dir string, env []string, cmdargs ...interface{}) ([]byte, error) {
cmdline := str.StringList(cmdargs...)
for _, arg := range cmdline {
@@ -1540,6 +1865,8 @@ func (b *Builder) runOut(dir string, desc string, env []string, cmdargs ...inter
cmd := exec.Command(cmdline[0], cmdline[1:]...)
cmd.Stdout = &buf
cmd.Stderr = &buf
+ cleanup := passLongArgsInResponseFiles(cmd)
+ defer cleanup()
cmd.Dir = dir
cmd.Env = base.MergeEnvLists(env, base.EnvForDir(cmd.Dir, os.Environ()))
err := cmd.Run()
@@ -1576,6 +1903,13 @@ func joinUnambiguously(a []string) string {
return buf.String()
}
+// cCompilerEnv returns environment variables to set when running the
+// C compiler. This is needed to disable escape codes in clang error
+// messages that confuse tools like cgo.
+func (b *Builder) cCompilerEnv() []string {
+ return []string{"TERM=dumb"}
+}
+
// mkdir makes the named directory.
func (b *Builder) Mkdir(dir string) error {
// Make Mkdir(a.Objdir) a no-op instead of an error when a.Objdir == "".
@@ -1723,7 +2057,7 @@ func (b *Builder) ccompile(a *Action, p *load.Package, outfile string, flags []s
if !filepath.IsAbs(outfile) {
outfile = filepath.Join(p.Dir, outfile)
}
- output, err := b.runOut(filepath.Dir(file), desc, nil, compiler, flags, "-o", outfile, "-c", filepath.Base(file))
+ output, err := b.runOut(filepath.Dir(file), b.cCompilerEnv(), compiler, flags, "-o", outfile, "-c", filepath.Base(file))
if len(output) > 0 {
// On FreeBSD 11, when we pass -g to clang 3.8 it
// invokes its internal assembler with -dwarf-version=2.
@@ -1763,7 +2097,7 @@ func (b *Builder) gccld(p *load.Package, objdir, out string, flags []string, obj
} else {
cmd = b.GccCmd(p.Dir, objdir)
}
- return b.run(nil, p.Dir, p.ImportPath, nil, cmd, "-o", out, objs, flags)
+ return b.run(nil, p.Dir, p.ImportPath, b.cCompilerEnv(), cmd, "-o", out, objs, flags)
}
// Grab these before main helpfully overwrites them.
@@ -2068,7 +2402,7 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo
// along to the host linker. At this point in the code, cgoLDFLAGS
// consists of the original $CGO_LDFLAGS (unchecked) and all the
// flags put together from source code (checked).
- var cgoenv []string
+ cgoenv := b.cCompilerEnv()
if len(cgoLDFLAGS) > 0 {
flags := make([]string, len(cgoLDFLAGS))
for i, f := range cgoLDFLAGS {
@@ -2195,7 +2529,15 @@ func (b *Builder) dynimport(a *Action, p *load.Package, objdir, importGo, cgoExe
// we need to use -pie for Linux/ARM to get accurate imported sym
ldflags := cgoLDFLAGS
if (cfg.Goarch == "arm" && cfg.Goos == "linux") || cfg.Goos == "android" {
- ldflags = append(ldflags, "-pie")
+ // -static -pie doesn't make sense, and causes link errors.
+ // Issue 26197.
+ n := make([]string, 0, len(ldflags))
+ for _, flag := range ldflags {
+ if flag != "-static" {
+ n = append(n, flag)
+ }
+ }
+ ldflags = append(n, "-pie")
}
if err := b.gccld(p, objdir, dynobj, ldflags, linkobj); err != nil {
return err
@@ -2206,7 +2548,7 @@ func (b *Builder) dynimport(a *Action, p *load.Package, objdir, importGo, cgoExe
if p.Standard && p.ImportPath == "runtime/cgo" {
cgoflags = []string{"-dynlinker"} // record path to dynamic linker
}
- return b.run(a, p.Dir, p.ImportPath, nil, cfg.BuildToolexec, cgoExe, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags)
+ return b.run(a, p.Dir, p.ImportPath, b.cCompilerEnv(), cfg.BuildToolexec, cgoExe, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags)
}
// Run SWIG on all SWIG input files.
@@ -2256,7 +2598,7 @@ var (
)
func (b *Builder) swigDoVersionCheck() error {
- out, err := b.runOut("", "", nil, "swig", "-version")
+ out, err := b.runOut("", nil, "swig", "-version")
if err != nil {
return err
}
@@ -2411,19 +2753,19 @@ func (b *Builder) swigOne(a *Action, p *load.Package, file, objdir string, pcCFL
args = append(args, "-c++")
}
- out, err := b.runOut(p.Dir, p.ImportPath, nil, "swig", args, file)
+ out, err := b.runOut(p.Dir, nil, "swig", args, file)
if err != nil {
if len(out) > 0 {
if bytes.Contains(out, []byte("-intgosize")) || bytes.Contains(out, []byte("-cgo")) {
return "", "", errors.New("must have SWIG version >= 3.0.6")
}
- b.showOutput(a, p.Dir, p.ImportPath, b.processOutput(out)) // swig error
+ b.showOutput(a, p.Dir, p.Desc(), b.processOutput(out)) // swig error
return "", "", errPrintedOutput
}
return "", "", err
}
if len(out) > 0 {
- b.showOutput(a, p.Dir, p.ImportPath, b.processOutput(out)) // swig warning
+ b.showOutput(a, p.Dir, p.Desc(), b.processOutput(out)) // swig warning
}
// If the input was x.swig, the output is x.go in the objdir.
@@ -2473,3 +2815,78 @@ func mkAbsFiles(dir string, files []string) []string {
}
return abs
}
+
+// passLongArgsInResponseFiles modifies cmd on Windows such that, for
+// certain programs, long arguments are passed in "response files", a
+// file on disk with the arguments, with one arg per line. An actual
+// argument starting with '@' means that the rest of the argument is
+// a filename of arguments to expand.
+//
+// See Issue 18468.
+func passLongArgsInResponseFiles(cmd *exec.Cmd) (cleanup func()) {
+ cleanup = func() {} // no cleanup by default
+
+ var argLen int
+ for _, arg := range cmd.Args {
+ argLen += len(arg)
+ }
+
+ // If we're not approaching 32KB of args, just pass args normally.
+ // (use 30KB instead to be conservative; not sure how accounting is done)
+ if !useResponseFile(cmd.Path, argLen) {
+ return
+ }
+
+ tf, err := ioutil.TempFile("", "args")
+ if err != nil {
+ log.Fatalf("error writing long arguments to response file: %v", err)
+ }
+ cleanup = func() { os.Remove(tf.Name()) }
+ var buf bytes.Buffer
+ for _, arg := range cmd.Args[1:] {
+ fmt.Fprintf(&buf, "%s\n", arg)
+ }
+ if _, err := tf.Write(buf.Bytes()); err != nil {
+ tf.Close()
+ cleanup()
+ log.Fatalf("error writing long arguments to response file: %v", err)
+ }
+ if err := tf.Close(); err != nil {
+ cleanup()
+ log.Fatalf("error writing long arguments to response file: %v", err)
+ }
+ cmd.Args = []string{cmd.Args[0], "@" + tf.Name()}
+ return cleanup
+}
+
+func useResponseFile(path string, argLen int) bool {
+ // Unless we're on Windows, don't use response files.
+ if runtime.GOOS != "windows" {
+ return false
+ }
+
+ // Unless the program uses objabi.Flagparse, which understands
+ // response files, don't use response files.
+ // TODO: do we need more commands? asm? cgo? For now, no.
+ prog := strings.TrimSuffix(filepath.Base(path), ".exe")
+ switch prog {
+ case "compile", "link":
+ default:
+ return false
+ }
+
+ // Windows has a limit of 32 KB arguments. To be conservative and not
+ // worry about whether that includes spaces or not, just use 30 KB.
+ if argLen > (30 << 10) {
+ return true
+ }
+
+ // On the Go build system, use response files about 10% of the
+ // time, just to excercise this codepath.
+ isBuilder := os.Getenv("GO_BUILDER_NAME") != ""
+ if isBuilder && rand.Intn(10) == 0 {
+ return true
+ }
+
+ return false
+}
diff --git a/libgo/go/cmd/go/internal/work/gc.go b/libgo/go/cmd/go/internal/work/gc.go
index 71b5337939e..6e5333ccbc4 100644
--- a/libgo/go/cmd/go/internal/work/gc.go
+++ b/libgo/go/cmd/go/internal/work/gc.go
@@ -57,9 +57,14 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg []byte, a
gcargs = append(gcargs, "-std")
}
compilingRuntime := p.Standard && (p.ImportPath == "runtime" || strings.HasPrefix(p.ImportPath, "runtime/internal"))
+ // The runtime package imports a couple of general internal packages.
+ if p.Standard && (p.ImportPath == "internal/cpu" || p.ImportPath == "internal/bytealg") {
+ compilingRuntime = true
+ }
if compilingRuntime {
- // runtime compiles with a special gc flag to emit
- // additional reflect type data.
+ // runtime compiles with a special gc flag to check for
+ // memory allocations that are invalid in the runtime package,
+ // and to implement some special compiler pragmas.
gcargs = append(gcargs, "-+")
}
@@ -70,7 +75,7 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg []byte, a
extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.FFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles)
if p.Standard {
switch p.ImportPath {
- case "bytes", "internal/poll", "net", "os", "runtime/pprof", "sync", "syscall", "time":
+ case "bytes", "internal/poll", "net", "os", "runtime/pprof", "runtime/trace", "sync", "syscall", "time":
extFiles++
}
}
@@ -84,7 +89,7 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg []byte, a
gcargs = append(gcargs, "-buildid", a.buildID)
}
platform := cfg.Goos + "/" + cfg.Goarch
- if p.Internal.OmitDebug || platform == "nacl/amd64p32" || platform == "darwin/arm" || platform == "darwin/arm64" || cfg.Goos == "plan9" {
+ if p.Internal.OmitDebug || platform == "nacl/amd64p32" || cfg.Goos == "plan9" || cfg.Goarch == "wasm" {
gcargs = append(gcargs, "-dwarf=false")
}
if strings.HasPrefix(runtimeVersion, "go1") && !strings.Contains(os.Args[0], "go_bootstrap") {
@@ -128,7 +133,7 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg []byte, a
args = append(args, mkAbs(p.Dir, f))
}
- output, err = b.runOut(p.Dir, p.ImportPath, nil, args...)
+ output, err = b.runOut(p.Dir, nil, args...)
return ofile, output, err
}
@@ -228,6 +233,11 @@ func (gcToolchain) asm(b *Builder, a *Action, sfiles []string) ([]string, error)
args = append(args, "-D", "GOMIPS_"+cfg.GOMIPS)
}
+ if cfg.Goarch == "mips64" || cfg.Goarch == "mips64le" {
+ // Define GOMIPS64_value from cfg.GOMIPS64.
+ args = append(args, "-D", "GOMIPS64_"+cfg.GOMIPS64)
+ }
+
var ofiles []string
for _, sfile := range sfiles {
ofile := a.Objdir + sfile[:len(sfile)-len(".s")] + ".o"
@@ -289,14 +299,14 @@ func (gcToolchain) pack(b *Builder, a *Action, afile string, ofiles []string) er
if cfg.BuildN {
return nil
}
- if err := packInternal(b, absAfile, absOfiles); err != nil {
- b.showOutput(a, p.Dir, p.ImportPath, err.Error()+"\n")
+ if err := packInternal(absAfile, absOfiles); err != nil {
+ b.showOutput(a, p.Dir, p.Desc(), err.Error()+"\n")
return errPrintedOutput
}
return nil
}
-func packInternal(b *Builder, afile string, ofiles []string) error {
+func packInternal(afile string, ofiles []string) error {
dst, err := os.OpenFile(afile, os.O_WRONLY|os.O_APPEND, 0)
if err != nil {
return err
diff --git a/libgo/go/cmd/go/internal/work/gccgo.go b/libgo/go/cmd/go/internal/work/gccgo.go
index e8dab191478..7255748b5c3 100644
--- a/libgo/go/cmd/go/internal/work/gccgo.go
+++ b/libgo/go/cmd/go/internal/work/gccgo.go
@@ -87,7 +87,7 @@ func (tools gccgoToolchain) gc(b *Builder, a *Action, archive string, importcfg
args = append(args, mkAbs(p.Dir, f))
}
- output, err = b.runOut(p.Dir, p.ImportPath, nil, args)
+ output, err = b.runOut(p.Dir, nil, args)
return ofile, output, err
}
@@ -270,7 +270,7 @@ func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string
readAndRemoveCgoFlags := func(archive string) (string, error) {
newID++
newArchive := root.Objdir + fmt.Sprintf("_pkg%d_.a", newID)
- if err := b.copyFile(root, newArchive, archive, 0666, false); err != nil {
+ if err := b.copyFile(newArchive, archive, 0666, false); err != nil {
return "", err
}
if cfg.BuildN {
diff --git a/libgo/go/cmd/go/internal/work/init.go b/libgo/go/cmd/go/internal/work/init.go
index c2beb3be6e7..de0cd4282b3 100644
--- a/libgo/go/cmd/go/internal/work/init.go
+++ b/libgo/go/cmd/go/internal/work/init.go
@@ -9,13 +9,16 @@ package work
import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
+ "cmd/go/internal/load"
"flag"
"fmt"
"os"
"path/filepath"
+ "strings"
)
func BuildInit() {
+ load.ModInit()
instrumentInit()
buildModeInit()
@@ -39,15 +42,20 @@ func instrumentInit() {
fmt.Fprintf(os.Stderr, "go %s: may not use -race and -msan simultaneously\n", flag.Args()[0])
os.Exit(2)
}
- if cfg.BuildMSan && (cfg.Goos != "linux" || cfg.Goarch != "amd64") {
+ if cfg.BuildMSan && (cfg.Goos != "linux" || cfg.Goarch != "amd64" && cfg.Goarch != "arm64") {
fmt.Fprintf(os.Stderr, "-msan is not supported on %s/%s\n", cfg.Goos, cfg.Goarch)
os.Exit(2)
}
- if cfg.Goarch != "amd64" || cfg.Goos != "linux" && cfg.Goos != "freebsd" && cfg.Goos != "darwin" && cfg.Goos != "windows" {
- fmt.Fprintf(os.Stderr, "go %s: -race and -msan are only supported on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0])
- os.Exit(2)
+ if cfg.BuildRace {
+ platform := cfg.Goos + "/" + cfg.Goarch
+ switch platform {
+ default:
+ fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, linux/ppc64le, freebsd/amd64, netbsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0])
+ os.Exit(2)
+ case "linux/amd64", "linux/ppc64le", "freebsd/amd64", "netbsd/amd64", "darwin/amd64", "windows/amd64":
+ // race supported on these platforms
+ }
}
-
mode := "race"
if cfg.BuildMSan {
mode = "msan"
@@ -83,6 +91,9 @@ func buildModeInit() {
default:
switch cfg.Goos {
case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
+ if platform == "linux/ppc64" {
+ base.Fatalf("-buildmode=c-archive not supported on %s\n", platform)
+ }
// Use -shared so that the result is
// suitable for inclusion in a PIE or
// shared library.
@@ -101,7 +112,8 @@ func buildModeInit() {
} else {
switch platform {
case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/ppc64le", "linux/s390x",
- "android/amd64", "android/arm", "android/arm64", "android/386":
+ "android/amd64", "android/arm", "android/arm64", "android/386",
+ "freebsd/amd64":
codegenArg = "-shared"
case "darwin/amd64", "darwin/386":
case "windows/amd64", "windows/386":
@@ -144,7 +156,8 @@ func buildModeInit() {
} else {
switch platform {
case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x",
- "android/amd64", "android/arm", "android/arm64", "android/386":
+ "android/amd64", "android/arm", "android/arm64", "android/386",
+ "freebsd/amd64":
codegenArg = "-shared"
case "darwin/amd64":
codegenArg = "-shared"
@@ -220,4 +233,31 @@ func buildModeInit() {
cfg.BuildContext.InstallSuffix += codegenArg[1:]
}
}
+
+ switch cfg.BuildMod {
+ case "":
+ // ok
+ case "readonly", "vendor":
+ if load.ModLookup == nil && !inGOFLAGS("-mod") {
+ base.Fatalf("build flag -mod=%s only valid when using modules", cfg.BuildMod)
+ }
+ default:
+ base.Fatalf("-mod=%s not supported (can be '', 'readonly', or 'vendor')", cfg.BuildMod)
+ }
+}
+
+func inGOFLAGS(flag string) bool {
+ for _, goflag := range base.GOFLAGS() {
+ name := goflag
+ if strings.HasPrefix(name, "--") {
+ name = name[1:]
+ }
+ if i := strings.Index(name, "="); i >= 0 {
+ name = name[:i]
+ }
+ if name == flag {
+ return true
+ }
+ }
+ return false
}
diff --git a/libgo/go/cmd/go/internal/work/security.go b/libgo/go/cmd/go/internal/work/security.go
index 1b82af9c97c..d5d126123a4 100644
--- a/libgo/go/cmd/go/internal/work/security.go
+++ b/libgo/go/cmd/go/internal/work/security.go
@@ -112,6 +112,7 @@ var validCompilerFlags = []*regexp.Regexp{
re(`--sysroot=([^@\-].*)`),
re(`-w`),
re(`-x([^@\-].*)`),
+ re(`-v`),
}
var validCompilerFlagsWithNextArg = []string{
@@ -135,6 +136,7 @@ var validLinkerFlags = []*regexp.Regexp{
re(`-f(no-)?(pic|PIC|pie|PIE)`),
re(`-f(no-)?openmp(-simd)?`),
re(`-fsanitize=([^@\-].*)`),
+ re(`-flat_namespace`),
re(`-g([^@\-].*)?`),
re(`-headerpad_max_install_names`),
re(`-m(abi|arch|cpu|fpu|tune)=([^@\-].*)`),
@@ -150,6 +152,7 @@ var validLinkerFlags = []*regexp.Regexp{
re(`-shared`),
re(`-?-static([-a-z0-9+]*)`),
re(`-?-stdlib=([^@\-].*)`),
+ re(`-v`),
// Note that any wildcards in -Wl need to exclude comma,
// since -Wl splits its argument at commas and passes
diff --git a/libgo/go/cmd/go/internal/work/security_test.go b/libgo/go/cmd/go/internal/work/security_test.go
index c3a61b8e70b..d23b6eadff5 100644
--- a/libgo/go/cmd/go/internal/work/security_test.go
+++ b/libgo/go/cmd/go/internal/work/security_test.go
@@ -58,6 +58,7 @@ var goodCompilerFlags = [][]string{
{"-I", "世界"},
{"-framework", "Chocolate"},
{"-x", "c"},
+ {"-v"},
}
var badCompilerFlags = [][]string{
@@ -136,6 +137,7 @@ var goodLinkerFlags = [][]string{
{"-l", "世界"},
{"-L", "framework"},
{"-framework", "Chocolate"},
+ {"-v"},
{"-Wl,-framework", "-Wl,Chocolate"},
{"-Wl,-framework,Chocolate"},
{"-Wl,-unresolved-symbols=ignore-all"},
diff --git a/libgo/go/cmd/go/main.go b/libgo/go/cmd/go/main.go
index 7558e087673..14b435295ec 100644
--- a/libgo/go/cmd/go/main.go
+++ b/libgo/go/cmd/go/main.go
@@ -27,6 +27,10 @@ import (
"cmd/go/internal/get"
"cmd/go/internal/help"
"cmd/go/internal/list"
+ "cmd/go/internal/modcmd"
+ "cmd/go/internal/modfetch"
+ "cmd/go/internal/modget"
+ "cmd/go/internal/modload"
"cmd/go/internal/run"
"cmd/go/internal/test"
"cmd/go/internal/tool"
@@ -36,31 +40,37 @@ import (
)
func init() {
- base.Commands = []*base.Command{
+ base.Go.Commands = []*base.Command{
+ bug.CmdBug,
work.CmdBuild,
clean.CmdClean,
doc.CmdDoc,
envcmd.CmdEnv,
- bug.CmdBug,
fix.CmdFix,
fmtcmd.CmdFmt,
generate.CmdGenerate,
get.CmdGet,
work.CmdInstall,
list.CmdList,
+ modcmd.CmdMod,
run.CmdRun,
test.CmdTest,
tool.CmdTool,
version.CmdVersion,
vet.CmdVet,
- help.HelpC,
help.HelpBuildmode,
+ help.HelpC,
help.HelpCache,
+ help.HelpEnvironment,
help.HelpFileType,
+ modload.HelpGoMod,
help.HelpGopath,
- help.HelpEnvironment,
+ get.HelpGopathGet,
+ modfetch.HelpGoproxy,
help.HelpImportPath,
+ modload.HelpModules,
+ modget.HelpModuleGet,
help.HelpPackages,
test.HelpTestflag,
test.HelpTestfunc,
@@ -78,6 +88,11 @@ func main() {
base.Usage()
}
+ if modload.MustUseModules {
+ // If running with modules force-enabled, change get now to change help message.
+ *get.CmdGet = *modget.CmdGet
+ }
+
cfg.CmdName = args[0] // for error messages
if args[0] == "help" {
help.Help(args[1:])
@@ -118,6 +133,46 @@ func main() {
os.Exit(2)
}
+ // TODO(rsc): Remove all these helper prints in Go 1.12.
+ switch args[0] {
+ case "mod":
+ if len(args) >= 2 {
+ flag := args[1]
+ if strings.HasPrefix(flag, "--") {
+ flag = flag[1:]
+ }
+ if i := strings.Index(flag, "="); i >= 0 {
+ flag = flag[:i]
+ }
+ switch flag {
+ case "-sync":
+ fmt.Fprintf(os.Stderr, "go: go mod -sync is now go mod tidy\n")
+ os.Exit(2)
+ case "-init", "-fix", "-graph", "-vendor", "-verify":
+ fmt.Fprintf(os.Stderr, "go: go mod %s is now go mod %s\n", flag, flag[1:])
+ os.Exit(2)
+ case "-fmt", "-json", "-module", "-require", "-droprequire", "-replace", "-dropreplace", "-exclude", "-dropexclude":
+ fmt.Fprintf(os.Stderr, "go: go mod %s is now go mod edit %s\n", flag, flag)
+ os.Exit(2)
+ }
+ }
+ case "vendor":
+ fmt.Fprintf(os.Stderr, "go: vgo vendor is now go mod vendor\n")
+ os.Exit(2)
+ case "verify":
+ fmt.Fprintf(os.Stderr, "go: vgo verify is now go mod verify\n")
+ os.Exit(2)
+ }
+
+ if args[0] == "get" {
+ // Replace get with module-aware get if appropriate.
+ // Note that if MustUseModules is true, this happened already above,
+ // but no harm in doing it again.
+ if modload.Init(); modload.Enabled() {
+ *get.CmdGet = *modget.CmdGet
+ }
+ }
+
// Set environment (GOOS, GOARCH, etc) explicitly.
// In theory all the commands we invoke should have
// the same default computation of these as we do,
@@ -131,12 +186,36 @@ func main() {
}
}
- for _, cmd := range base.Commands {
- if cmd.Name() == args[0] && cmd.Runnable() {
+BigCmdLoop:
+ for bigCmd := base.Go; ; {
+ for _, cmd := range bigCmd.Commands {
+ if cmd.Name() != args[0] {
+ continue
+ }
+ if len(cmd.Commands) > 0 {
+ bigCmd = cmd
+ args = args[1:]
+ if len(args) == 0 {
+ help.PrintUsage(os.Stderr, bigCmd)
+ base.SetExitStatus(2)
+ base.Exit()
+ }
+ if args[0] == "help" {
+ // Accept 'go mod help' and 'go mod help foo' for 'go help mod' and 'go help mod foo'.
+ help.Help(append(strings.Split(cfg.CmdName, " "), args[1:]...))
+ return
+ }
+ cfg.CmdName += " " + args[0]
+ continue BigCmdLoop
+ }
+ if !cmd.Runnable() {
+ continue
+ }
cmd.Flag.Usage = func() { cmd.Usage() }
if cmd.CustomFlags {
args = args[1:]
} else {
+ base.SetFromGOFLAGS(cmd.Flag)
cmd.Flag.Parse(args[1:])
args = cmd.Flag.Args()
}
@@ -144,11 +223,14 @@ func main() {
base.Exit()
return
}
+ helpArg := ""
+ if i := strings.LastIndex(cfg.CmdName, " "); i >= 0 {
+ helpArg = " " + cfg.CmdName[:i]
+ }
+ fmt.Fprintf(os.Stderr, "go %s: unknown command\nRun 'go help%s' for usage.\n", cfg.CmdName, helpArg)
+ base.SetExitStatus(2)
+ base.Exit()
}
-
- fmt.Fprintf(os.Stderr, "go: unknown subcommand %q\nRun 'go help' for usage.\n", args[0])
- base.SetExitStatus(2)
- base.Exit()
}
func init() {
@@ -160,6 +242,6 @@ func mainUsage() {
if len(os.Args) > 1 && os.Args[1] == "test" {
test.Usage()
}
- help.PrintUsage(os.Stderr)
+ help.PrintUsage(os.Stderr, base.Go)
os.Exit(2)
}
diff --git a/libgo/go/cmd/go/proxy_test.go b/libgo/go/cmd/go/proxy_test.go
new file mode 100644
index 00000000000..212e5aa08f7
--- /dev/null
+++ b/libgo/go/cmd/go/proxy_test.go
@@ -0,0 +1,272 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main_test
+
+import (
+ "archive/zip"
+ "bytes"
+ "encoding/json"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "net"
+ "net/http"
+ "os"
+ "path/filepath"
+ "strings"
+ "sync"
+ "testing"
+
+ "cmd/go/internal/modfetch"
+ "cmd/go/internal/modfetch/codehost"
+ "cmd/go/internal/module"
+ "cmd/go/internal/par"
+ "cmd/go/internal/semver"
+ "cmd/go/internal/txtar"
+)
+
+var (
+ proxyAddr = flag.String("proxy", "", "run proxy on this network address instead of running any tests")
+ proxyURL string
+)
+
+var proxyOnce sync.Once
+
+// StartProxy starts the Go module proxy running on *proxyAddr (like "localhost:1234")
+// and sets proxyURL to the GOPROXY setting to use to access the proxy.
+// Subsequent calls are no-ops.
+//
+// The proxy serves from testdata/mod. See testdata/mod/README.
+func StartProxy() {
+ proxyOnce.Do(func() {
+ fmt.Fprintf(os.Stderr, "go test proxy starting\n")
+ readModList()
+ addr := *proxyAddr
+ if addr == "" {
+ addr = "localhost:0"
+ }
+ l, err := net.Listen("tcp", addr)
+ if err != nil {
+ log.Fatal(err)
+ }
+ *proxyAddr = l.Addr().String()
+ proxyURL = "http://" + *proxyAddr + "/mod"
+ fmt.Fprintf(os.Stderr, "go test proxy running at GOPROXY=%s\n", proxyURL)
+ go func() {
+ log.Fatalf("go proxy: http.Serve: %v", http.Serve(l, http.HandlerFunc(proxyHandler)))
+ }()
+ })
+}
+
+var modList []module.Version
+
+func readModList() {
+ infos, err := ioutil.ReadDir("testdata/mod")
+ if err != nil {
+ log.Fatal(err)
+ }
+ for _, info := range infos {
+ name := info.Name()
+ if !strings.HasSuffix(name, ".txt") {
+ continue
+ }
+ name = strings.TrimSuffix(name, ".txt")
+ i := strings.LastIndex(name, "_v")
+ if i < 0 {
+ continue
+ }
+ encPath := strings.Replace(name[:i], "_", "/", -1)
+ path, err := module.DecodePath(encPath)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "go proxy_test: %v\n", err)
+ continue
+ }
+ encVers := name[i+1:]
+ vers, err := module.DecodeVersion(encVers)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "go proxy_test: %v\n", err)
+ continue
+ }
+ modList = append(modList, module.Version{Path: path, Version: vers})
+ }
+}
+
+var zipCache par.Cache
+
+// proxyHandler serves the Go module proxy protocol.
+// See the proxy section of https://research.swtch.com/vgo-module.
+func proxyHandler(w http.ResponseWriter, r *http.Request) {
+ if !strings.HasPrefix(r.URL.Path, "/mod/") {
+ http.NotFound(w, r)
+ return
+ }
+ path := strings.TrimPrefix(r.URL.Path, "/mod/")
+ i := strings.Index(path, "/@v/")
+ if i < 0 {
+ http.NotFound(w, r)
+ return
+ }
+ enc, file := path[:i], path[i+len("/@v/"):]
+ path, err := module.DecodePath(enc)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "go proxy_test: %v\n", err)
+ http.NotFound(w, r)
+ return
+ }
+ if file == "list" {
+ n := 0
+ for _, m := range modList {
+ if m.Path == path && !modfetch.IsPseudoVersion(m.Version) {
+ if err := module.Check(m.Path, m.Version); err == nil {
+ fmt.Fprintf(w, "%s\n", m.Version)
+ n++
+ }
+ }
+ }
+ if n == 0 {
+ http.NotFound(w, r)
+ }
+ return
+ }
+
+ i = strings.LastIndex(file, ".")
+ if i < 0 {
+ http.NotFound(w, r)
+ return
+ }
+ encVers, ext := file[:i], file[i+1:]
+ vers, err := module.DecodeVersion(encVers)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "go proxy_test: %v\n", err)
+ http.NotFound(w, r)
+ return
+ }
+
+ if codehost.AllHex(vers) {
+ var best string
+ // Convert commit hash (only) to known version.
+ // Use latest version in semver priority, to match similar logic
+ // in the repo-based module server (see modfetch.(*codeRepo).convert).
+ for _, m := range modList {
+ if m.Path == path && semver.Compare(best, m.Version) < 0 {
+ var hash string
+ if modfetch.IsPseudoVersion(m.Version) {
+ hash = m.Version[strings.LastIndex(m.Version, "-")+1:]
+ } else {
+ hash = findHash(m)
+ }
+ if strings.HasPrefix(hash, vers) || strings.HasPrefix(vers, hash) {
+ best = m.Version
+ }
+ }
+ }
+ if best != "" {
+ vers = best
+ }
+ }
+
+ a := readArchive(path, vers)
+ if a == nil {
+ fmt.Fprintf(os.Stderr, "go proxy: no archive %s %s\n", path, vers)
+ http.Error(w, "cannot load archive", 500)
+ return
+ }
+
+ switch ext {
+ case "info", "mod":
+ want := "." + ext
+ for _, f := range a.Files {
+ if f.Name == want {
+ w.Write(f.Data)
+ return
+ }
+ }
+
+ case "zip":
+ type cached struct {
+ zip []byte
+ err error
+ }
+ c := zipCache.Do(a, func() interface{} {
+ var buf bytes.Buffer
+ z := zip.NewWriter(&buf)
+ for _, f := range a.Files {
+ if strings.HasPrefix(f.Name, ".") {
+ continue
+ }
+ zf, err := z.Create(path + "@" + vers + "/" + f.Name)
+ if err != nil {
+ return cached{nil, err}
+ }
+ if _, err := zf.Write(f.Data); err != nil {
+ return cached{nil, err}
+ }
+ }
+ if err := z.Close(); err != nil {
+ return cached{nil, err}
+ }
+ return cached{buf.Bytes(), nil}
+ }).(cached)
+
+ if c.err != nil {
+ fmt.Fprintf(os.Stderr, "go proxy: %v\n", c.err)
+ http.Error(w, c.err.Error(), 500)
+ return
+ }
+ w.Write(c.zip)
+ return
+
+ }
+ http.NotFound(w, r)
+}
+
+func findHash(m module.Version) string {
+ a := readArchive(m.Path, m.Version)
+ if a == nil {
+ return ""
+ }
+ var data []byte
+ for _, f := range a.Files {
+ if f.Name == ".info" {
+ data = f.Data
+ break
+ }
+ }
+ var info struct{ Short string }
+ json.Unmarshal(data, &info)
+ return info.Short
+}
+
+var archiveCache par.Cache
+
+var cmdGoDir, _ = os.Getwd()
+
+func readArchive(path, vers string) *txtar.Archive {
+ enc, err := module.EncodePath(path)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "go proxy: %v\n", err)
+ return nil
+ }
+ encVers, err := module.EncodeVersion(vers)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "go proxy: %v\n", err)
+ return nil
+ }
+
+ prefix := strings.Replace(enc, "/", "_", -1)
+ name := filepath.Join(cmdGoDir, "testdata/mod", prefix+"_"+encVers+".txt")
+ a := archiveCache.Do(name, func() interface{} {
+ a, err := txtar.ParseFile(name)
+ if err != nil {
+ if testing.Verbose() || !os.IsNotExist(err) {
+ fmt.Fprintf(os.Stderr, "go proxy: %v\n", err)
+ }
+ a = nil
+ }
+ return a
+ }).(*txtar.Archive)
+ return a
+}
diff --git a/libgo/go/cmd/go/script_test.go b/libgo/go/cmd/go/script_test.go
new file mode 100644
index 00000000000..02cb17b0452
--- /dev/null
+++ b/libgo/go/cmd/go/script_test.go
@@ -0,0 +1,905 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Script-driven tests.
+// See testdata/script/README for an overview.
+
+package main_test
+
+import (
+ "bytes"
+ "fmt"
+ "internal/testenv"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "strconv"
+ "strings"
+ "testing"
+ "time"
+
+ "cmd/go/internal/imports"
+ "cmd/go/internal/par"
+ "cmd/go/internal/txtar"
+)
+
+// TestScript runs the tests in testdata/script/*.txt.
+func TestScript(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+ if skipExternal {
+ t.Skipf("skipping external tests on %s/%s", runtime.GOOS, runtime.GOARCH)
+ }
+
+ files, err := filepath.Glob("testdata/script/*.txt")
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, file := range files {
+ file := file
+ name := strings.TrimSuffix(filepath.Base(file), ".txt")
+ t.Run(name, func(t *testing.T) {
+ t.Parallel()
+ ts := &testScript{t: t, name: name, file: file}
+ ts.setup()
+ if !*testWork {
+ defer removeAll(ts.workdir)
+ }
+ ts.run()
+ })
+ }
+}
+
+// A testScript holds execution state for a single test script.
+type testScript struct {
+ t *testing.T
+ workdir string // temporary work dir ($WORK)
+ log bytes.Buffer // test execution log (printed at end of test)
+ mark int // offset of next log truncation
+ cd string // current directory during test execution; initially $WORK/gopath/src
+ name string // short name of test ("foo")
+ file string // full file name ("testdata/script/foo.txt")
+ lineno int // line number currently executing
+ line string // line currently executing
+ env []string // environment list (for os/exec)
+ envMap map[string]string // environment mapping (matches env)
+ stdout string // standard output from last 'go' command; for 'stdout' command
+ stderr string // standard error from last 'go' command; for 'stderr' command
+ stopped bool // test wants to stop early
+ start time.Time // time phase started
+}
+
+var extraEnvKeys = []string{
+ "SYSTEMROOT", // must be preserved on Windows to find DLLs; golang.org/issue/25210
+ "LD_LIBRARY_PATH", // must be preserved on Unix systems to find shared libraries
+
+ // For gccgo testing.
+ "GO_TESTING_GOTOOLS",
+ "GCCGOTOOLDIR",
+}
+
+// setup sets up the test execution temporary directory and environment.
+func (ts *testScript) setup() {
+ StartProxy()
+ ts.workdir = filepath.Join(testTmpDir, "script-"+ts.name)
+ ts.check(os.MkdirAll(filepath.Join(ts.workdir, "tmp"), 0777))
+ ts.check(os.MkdirAll(filepath.Join(ts.workdir, "gopath/src"), 0777))
+ ts.cd = filepath.Join(ts.workdir, "gopath/src")
+ ts.env = []string{
+ "WORK=" + ts.workdir, // must be first for ts.abbrev
+ "PATH=" + testBin + string(filepath.ListSeparator) + os.Getenv("PATH"),
+ homeEnvName() + "=/no-home",
+ "CCACHE_DISABLE=1", // ccache breaks with non-existent HOME
+ "GOARCH=" + runtime.GOARCH,
+ "GOCACHE=" + testGOCACHE,
+ "GOOS=" + runtime.GOOS,
+ "GOPATH=" + filepath.Join(ts.workdir, "gopath"),
+ "GOPROXY=" + proxyURL,
+ "GOROOT=" + testGOROOT,
+ tempEnvName() + "=" + filepath.Join(ts.workdir, "tmp"),
+ "devnull=" + os.DevNull,
+ ":=" + string(os.PathListSeparator),
+ }
+
+ if runtime.GOOS == "plan9" {
+ ts.env = append(ts.env, "path="+testBin+string(filepath.ListSeparator)+os.Getenv("path"))
+ }
+
+ if runtime.GOOS == "windows" {
+ ts.env = append(ts.env, "exe=.exe")
+ } else {
+ ts.env = append(ts.env, "exe=")
+ }
+ for _, key := range extraEnvKeys {
+ if val := os.Getenv(key); val != "" {
+ ts.env = append(ts.env, key+"="+val)
+ }
+ }
+
+ ts.envMap = make(map[string]string)
+ for _, kv := range ts.env {
+ if i := strings.Index(kv, "="); i >= 0 {
+ ts.envMap[kv[:i]] = kv[i+1:]
+ }
+ }
+}
+
+var execCache par.Cache
+
+// run runs the test script.
+func (ts *testScript) run() {
+ // Truncate log at end of last phase marker,
+ // discarding details of successful phase.
+ rewind := func() {
+ if !testing.Verbose() {
+ ts.log.Truncate(ts.mark)
+ }
+ }
+
+ // Insert elapsed time for phase at end of phase marker
+ markTime := func() {
+ if ts.mark > 0 && !ts.start.IsZero() {
+ afterMark := append([]byte{}, ts.log.Bytes()[ts.mark:]...)
+ ts.log.Truncate(ts.mark - 1) // cut \n and afterMark
+ fmt.Fprintf(&ts.log, " (%.3fs)\n", time.Since(ts.start).Seconds())
+ ts.log.Write(afterMark)
+ }
+ ts.start = time.Time{}
+ }
+
+ defer func() {
+ markTime()
+ // Flush testScript log to testing.T log.
+ ts.t.Log("\n" + ts.abbrev(ts.log.String()))
+ }()
+
+ // Unpack archive.
+ a, err := txtar.ParseFile(ts.file)
+ ts.check(err)
+ for _, f := range a.Files {
+ name := ts.mkabs(ts.expand(f.Name))
+ ts.check(os.MkdirAll(filepath.Dir(name), 0777))
+ ts.check(ioutil.WriteFile(name, f.Data, 0666))
+ }
+
+ // With -v or -testwork, start log with full environment.
+ if *testWork || testing.Verbose() {
+ // Display environment.
+ ts.cmdEnv(false, nil)
+ fmt.Fprintf(&ts.log, "\n")
+ ts.mark = ts.log.Len()
+ }
+
+ // Run script.
+ // See testdata/script/README for documentation of script form.
+ script := string(a.Comment)
+Script:
+ for script != "" {
+ // Extract next line.
+ ts.lineno++
+ var line string
+ if i := strings.Index(script, "\n"); i >= 0 {
+ line, script = script[:i], script[i+1:]
+ } else {
+ line, script = script, ""
+ }
+
+ // # is a comment indicating the start of new phase.
+ if strings.HasPrefix(line, "#") {
+ // If there was a previous phase, it succeeded,
+ // so rewind the log to delete its details (unless -v is in use).
+ // If nothing has happened at all since the mark,
+ // rewinding is a no-op and adding elapsed time
+ // for doing nothing is meaningless, so don't.
+ if ts.log.Len() > ts.mark {
+ rewind()
+ markTime()
+ }
+ // Print phase heading and mark start of phase output.
+ fmt.Fprintf(&ts.log, "%s\n", line)
+ ts.mark = ts.log.Len()
+ ts.start = time.Now()
+ continue
+ }
+
+ // Parse input line. Ignore blanks entirely.
+ args := ts.parse(line)
+ if len(args) == 0 {
+ continue
+ }
+
+ // Echo command to log.
+ fmt.Fprintf(&ts.log, "> %s\n", line)
+
+ // Command prefix [cond] means only run this command if cond is satisfied.
+ for strings.HasPrefix(args[0], "[") && strings.HasSuffix(args[0], "]") {
+ cond := args[0]
+ cond = cond[1 : len(cond)-1]
+ cond = strings.TrimSpace(cond)
+ args = args[1:]
+ if len(args) == 0 {
+ ts.fatalf("missing command after condition")
+ }
+ want := true
+ if strings.HasPrefix(cond, "!") {
+ want = false
+ cond = strings.TrimSpace(cond[1:])
+ }
+ // Known conds are: $GOOS, $GOARCH, runtime.Compiler, and 'short' (for testing.Short).
+ //
+ // NOTE: If you make changes here, update testdata/script/README too!
+ //
+ ok := false
+ switch cond {
+ case runtime.GOOS, runtime.GOARCH, runtime.Compiler:
+ ok = true
+ case "short":
+ ok = testing.Short()
+ case "cgo":
+ ok = canCgo
+ case "msan":
+ ok = canMSan
+ case "race":
+ ok = canRace
+ case "net":
+ ok = testenv.HasExternalNetwork()
+ case "link":
+ ok = testenv.HasLink()
+ case "symlink":
+ ok = testenv.HasSymlink()
+ default:
+ if strings.HasPrefix(cond, "exec:") {
+ prog := cond[len("exec:"):]
+ ok = execCache.Do(prog, func() interface{} {
+ _, err := exec.LookPath(prog)
+ return err == nil
+ }).(bool)
+ break
+ }
+ if !imports.KnownArch[cond] && !imports.KnownOS[cond] && cond != "gc" && cond != "gccgo" {
+ ts.fatalf("unknown condition %q", cond)
+ }
+ }
+ if ok != want {
+ // Don't run rest of line.
+ continue Script
+ }
+ }
+
+ // Command prefix ! means negate the expectations about this command:
+ // go command should fail, match should not be found, etc.
+ neg := false
+ if args[0] == "!" {
+ neg = true
+ args = args[1:]
+ if len(args) == 0 {
+ ts.fatalf("! on line by itself")
+ }
+ }
+
+ // Run command.
+ cmd := scriptCmds[args[0]]
+ if cmd == nil {
+ ts.fatalf("unknown command %q", args[0])
+ }
+ cmd(ts, neg, args[1:])
+
+ // Command can ask script to stop early.
+ if ts.stopped {
+ return
+ }
+ }
+
+ // Final phase ended.
+ rewind()
+ markTime()
+ fmt.Fprintf(&ts.log, "PASS\n")
+}
+
+// scriptCmds are the script command implementations.
+// Keep list and the implementations below sorted by name.
+//
+// NOTE: If you make changes here, update testdata/script/README too!
+//
+var scriptCmds = map[string]func(*testScript, bool, []string){
+ "addcrlf": (*testScript).cmdAddcrlf,
+ "cd": (*testScript).cmdCd,
+ "cmp": (*testScript).cmdCmp,
+ "cp": (*testScript).cmdCp,
+ "env": (*testScript).cmdEnv,
+ "exec": (*testScript).cmdExec,
+ "exists": (*testScript).cmdExists,
+ "go": (*testScript).cmdGo,
+ "grep": (*testScript).cmdGrep,
+ "mkdir": (*testScript).cmdMkdir,
+ "rm": (*testScript).cmdRm,
+ "skip": (*testScript).cmdSkip,
+ "stale": (*testScript).cmdStale,
+ "stderr": (*testScript).cmdStderr,
+ "stdout": (*testScript).cmdStdout,
+ "stop": (*testScript).cmdStop,
+ "symlink": (*testScript).cmdSymlink,
+}
+
+// addcrlf adds CRLF line endings to the named files.
+func (ts *testScript) cmdAddcrlf(neg bool, args []string) {
+ if len(args) == 0 {
+ ts.fatalf("usage: addcrlf file...")
+ }
+
+ for _, file := range args {
+ file = ts.mkabs(file)
+ data, err := ioutil.ReadFile(file)
+ ts.check(err)
+ ts.check(ioutil.WriteFile(file, bytes.Replace(data, []byte("\n"), []byte("\r\n"), -1), 0666))
+ }
+}
+
+// cd changes to a different directory.
+func (ts *testScript) cmdCd(neg bool, args []string) {
+ if neg {
+ ts.fatalf("unsupported: ! cd")
+ }
+ if len(args) != 1 {
+ ts.fatalf("usage: cd dir")
+ }
+
+ dir := args[0]
+ if !filepath.IsAbs(dir) {
+ dir = filepath.Join(ts.cd, dir)
+ }
+ info, err := os.Stat(dir)
+ if os.IsNotExist(err) {
+ ts.fatalf("directory %s does not exist", dir)
+ }
+ ts.check(err)
+ if !info.IsDir() {
+ ts.fatalf("%s is not a directory", dir)
+ }
+ ts.cd = dir
+ fmt.Fprintf(&ts.log, "%s\n", ts.cd)
+}
+
+// cmp compares two files.
+func (ts *testScript) cmdCmp(neg bool, args []string) {
+ if neg {
+ // It would be strange to say "this file can have any content except this precise byte sequence".
+ ts.fatalf("unsupported: ! cmp")
+ }
+ if len(args) != 2 {
+ ts.fatalf("usage: cmp file1 file2")
+ }
+
+ name1, name2 := args[0], args[1]
+ var text1, text2 string
+ if name1 == "stdout" {
+ text1 = ts.stdout
+ } else if name1 == "stderr" {
+ text1 = ts.stderr
+ } else {
+ data, err := ioutil.ReadFile(ts.mkabs(name1))
+ ts.check(err)
+ text1 = string(data)
+ }
+
+ data, err := ioutil.ReadFile(ts.mkabs(name2))
+ ts.check(err)
+ text2 = string(data)
+
+ if text1 == text2 {
+ return
+ }
+
+ fmt.Fprintf(&ts.log, "[diff -%s +%s]\n%s\n", name1, name2, diff(text1, text2))
+ ts.fatalf("%s and %s differ", name1, name2)
+}
+
+// cp copies files, maybe eventually directories.
+func (ts *testScript) cmdCp(neg bool, args []string) {
+ if neg {
+ ts.fatalf("unsupported: ! cp")
+ }
+ if len(args) < 2 {
+ ts.fatalf("usage: cp src... dst")
+ }
+
+ dst := ts.mkabs(args[len(args)-1])
+ info, err := os.Stat(dst)
+ dstDir := err == nil && info.IsDir()
+ if len(args) > 2 && !dstDir {
+ ts.fatalf("cp: destination %s is not a directory", dst)
+ }
+
+ for _, arg := range args[:len(args)-1] {
+ src := ts.mkabs(arg)
+ info, err := os.Stat(src)
+ ts.check(err)
+ data, err := ioutil.ReadFile(src)
+ ts.check(err)
+ targ := dst
+ if dstDir {
+ targ = filepath.Join(dst, filepath.Base(src))
+ }
+ ts.check(ioutil.WriteFile(targ, data, info.Mode()&0777))
+ }
+}
+
+// env displays or adds to the environment.
+func (ts *testScript) cmdEnv(neg bool, args []string) {
+ if neg {
+ ts.fatalf("unsupported: ! env")
+ }
+ if len(args) == 0 {
+ printed := make(map[string]bool) // env list can have duplicates; only print effective value (from envMap) once
+ for _, kv := range ts.env {
+ k := kv[:strings.Index(kv, "=")]
+ if !printed[k] {
+ fmt.Fprintf(&ts.log, "%s=%s\n", k, ts.envMap[k])
+ }
+ }
+ return
+ }
+ for _, env := range args {
+ i := strings.Index(env, "=")
+ if i < 0 {
+ // Display value instead of setting it.
+ fmt.Fprintf(&ts.log, "%s=%s\n", env, ts.envMap[env])
+ continue
+ }
+ ts.env = append(ts.env, env)
+ ts.envMap[env[:i]] = env[i+1:]
+ }
+}
+
+// exec runs the given command.
+func (ts *testScript) cmdExec(neg bool, args []string) {
+ if len(args) < 1 {
+ ts.fatalf("usage: exec program [args...]")
+ }
+ var err error
+ ts.stdout, ts.stderr, err = ts.exec(args[0], args[1:]...)
+ if ts.stdout != "" {
+ fmt.Fprintf(&ts.log, "[stdout]\n%s", ts.stdout)
+ }
+ if ts.stderr != "" {
+ fmt.Fprintf(&ts.log, "[stderr]\n%s", ts.stderr)
+ }
+ if err != nil {
+ fmt.Fprintf(&ts.log, "[%v]\n", err)
+ if !neg {
+ ts.fatalf("unexpected command failure")
+ }
+ } else {
+ if neg {
+ ts.fatalf("unexpected command success")
+ }
+ }
+}
+
+// exists checks that the list of files exists.
+func (ts *testScript) cmdExists(neg bool, args []string) {
+ var readonly bool
+ if len(args) > 0 && args[0] == "-readonly" {
+ readonly = true
+ args = args[1:]
+ }
+ if len(args) == 0 {
+ ts.fatalf("usage: exists [-readonly] file...")
+ }
+
+ for _, file := range args {
+ file = ts.mkabs(file)
+ info, err := os.Stat(file)
+ if err == nil && neg {
+ what := "file"
+ if info.IsDir() {
+ what = "directory"
+ }
+ ts.fatalf("%s %s unexpectedly exists", what, file)
+ }
+ if err != nil && !neg {
+ ts.fatalf("%s does not exist", file)
+ }
+ if err == nil && !neg && readonly && info.Mode()&0222 != 0 {
+ ts.fatalf("%s exists but is writable", file)
+ }
+ }
+}
+
+// go runs the go command.
+func (ts *testScript) cmdGo(neg bool, args []string) {
+ ts.cmdExec(neg, append([]string{testGo}, args...))
+}
+
+// mkdir creates directories.
+func (ts *testScript) cmdMkdir(neg bool, args []string) {
+ if neg {
+ ts.fatalf("unsupported: ! mkdir")
+ }
+ if len(args) < 1 {
+ ts.fatalf("usage: mkdir dir...")
+ }
+ for _, arg := range args {
+ ts.check(os.MkdirAll(ts.mkabs(arg), 0777))
+ }
+}
+
+// rm removes files or directories.
+func (ts *testScript) cmdRm(neg bool, args []string) {
+ if neg {
+ ts.fatalf("unsupported: ! rm")
+ }
+ if len(args) < 1 {
+ ts.fatalf("usage: rm file...")
+ }
+ for _, arg := range args {
+ file := ts.mkabs(arg)
+ removeAll(file) // does chmod and then attempts rm
+ ts.check(os.RemoveAll(file)) // report error
+ }
+}
+
+// skip marks the test skipped.
+func (ts *testScript) cmdSkip(neg bool, args []string) {
+ if len(args) > 1 {
+ ts.fatalf("usage: skip [msg]")
+ }
+ if neg {
+ ts.fatalf("unsupported: ! skip")
+ }
+ if len(args) == 1 {
+ ts.t.Skip(args[0])
+ }
+ ts.t.Skip()
+}
+
+// stale checks that the named build targets are stale.
+func (ts *testScript) cmdStale(neg bool, args []string) {
+ if len(args) == 0 {
+ ts.fatalf("usage: stale target...")
+ }
+ tmpl := "{{if .Error}}{{.ImportPath}}: {{.Error.Err}}{else}}"
+ if neg {
+ tmpl += "{{if .Stale}}{{.ImportPath}} is unexpectedly stale{{end}}"
+ } else {
+ tmpl += "{{if not .Stale}}{{.ImportPath}} is unexpectedly NOT stale{{end}}"
+ }
+ tmpl += "{{end}}"
+ goArgs := append([]string{"list", "-e", "-f=" + tmpl}, args...)
+ stdout, stderr, err := ts.exec(testGo, goArgs...)
+ if err != nil {
+ ts.fatalf("go list: %v\n%s%s", err, stdout, stderr)
+ }
+ if stdout != "" {
+ ts.fatalf("%s", stdout)
+ }
+}
+
+// stdout checks that the last go command standard output matches a regexp.
+func (ts *testScript) cmdStdout(neg bool, args []string) {
+ scriptMatch(ts, neg, args, ts.stdout, "stdout")
+}
+
+// stderr checks that the last go command standard output matches a regexp.
+func (ts *testScript) cmdStderr(neg bool, args []string) {
+ scriptMatch(ts, neg, args, ts.stderr, "stderr")
+}
+
+// grep checks that file content matches a regexp.
+// Like stdout/stderr and unlike Unix grep, it accepts Go regexp syntax.
+func (ts *testScript) cmdGrep(neg bool, args []string) {
+ scriptMatch(ts, neg, args, "", "grep")
+}
+
+// scriptMatch implements both stdout and stderr.
+func scriptMatch(ts *testScript, neg bool, args []string, text, name string) {
+ n := 0
+ if len(args) >= 1 && strings.HasPrefix(args[0], "-count=") {
+ if neg {
+ ts.fatalf("cannot use -count= with negated match")
+ }
+ var err error
+ n, err = strconv.Atoi(args[0][len("-count="):])
+ if err != nil {
+ ts.fatalf("bad -count=: %v", err)
+ }
+ if n < 1 {
+ ts.fatalf("bad -count=: must be at least 1")
+ }
+ args = args[1:]
+ }
+
+ extraUsage := ""
+ want := 1
+ if name == "grep" {
+ extraUsage = " file"
+ want = 2
+ }
+ if len(args) != want {
+ ts.fatalf("usage: %s [-count=N] 'pattern' file%s", name, extraUsage)
+ }
+
+ pattern := args[0]
+ re, err := regexp.Compile(`(?m)` + pattern)
+ ts.check(err)
+
+ isGrep := name == "grep"
+ if isGrep {
+ name = args[1] // for error messages
+ data, err := ioutil.ReadFile(ts.mkabs(args[1]))
+ ts.check(err)
+ text = string(data)
+ }
+
+ if neg {
+ if re.MatchString(text) {
+ if isGrep {
+ fmt.Fprintf(&ts.log, "[%s]\n%s\n", name, text)
+ }
+ ts.fatalf("unexpected match for %#q found in %s: %s", pattern, name, re.FindString(text))
+ }
+ } else {
+ if !re.MatchString(text) {
+ if isGrep {
+ fmt.Fprintf(&ts.log, "[%s]\n%s\n", name, text)
+ }
+ ts.fatalf("no match for %#q found in %s", pattern, name)
+ }
+ if n > 0 {
+ count := len(re.FindAllString(text, -1))
+ if count != n {
+ if isGrep {
+ fmt.Fprintf(&ts.log, "[%s]\n%s\n", name, text)
+ }
+ ts.fatalf("have %d matches for %#q, want %d", count, pattern, n)
+ }
+ }
+ }
+}
+
+// stop stops execution of the test (marking it passed).
+func (ts *testScript) cmdStop(neg bool, args []string) {
+ if neg {
+ ts.fatalf("unsupported: ! stop")
+ }
+ if len(args) > 1 {
+ ts.fatalf("usage: stop [msg]")
+ }
+ if len(args) == 1 {
+ fmt.Fprintf(&ts.log, "stop: %s\n", args[0])
+ } else {
+ fmt.Fprintf(&ts.log, "stop\n")
+ }
+ ts.stopped = true
+}
+
+// symlink creates a symbolic link.
+func (ts *testScript) cmdSymlink(neg bool, args []string) {
+ if neg {
+ ts.fatalf("unsupported: ! symlink")
+ }
+ if len(args) != 3 || args[1] != "->" {
+ ts.fatalf("usage: symlink file -> target")
+ }
+ // Note that the link target args[2] is not interpreted with mkabs:
+ // it will be interpreted relative to the directory file is in.
+ ts.check(os.Symlink(args[2], ts.mkabs(args[0])))
+}
+
+// Helpers for command implementations.
+
+// abbrev abbreviates the actual work directory in the string s to the literal string "$WORK".
+func (ts *testScript) abbrev(s string) string {
+ s = strings.Replace(s, ts.workdir, "$WORK", -1)
+ if *testWork {
+ // Expose actual $WORK value in environment dump on first line of work script,
+ // so that the user can find out what directory -testwork left behind.
+ s = "WORK=" + ts.workdir + "\n" + strings.TrimPrefix(s, "WORK=$WORK\n")
+ }
+ return s
+}
+
+// check calls ts.fatalf if err != nil.
+func (ts *testScript) check(err error) {
+ if err != nil {
+ ts.fatalf("%v", err)
+ }
+}
+
+// exec runs the given command line (an actual subprocess, not simulated)
+// in ts.cd with environment ts.env and then returns collected standard output and standard error.
+func (ts *testScript) exec(command string, args ...string) (stdout, stderr string, err error) {
+ cmd := exec.Command(command, args...)
+ cmd.Dir = ts.cd
+ cmd.Env = append(ts.env, "PWD="+ts.cd)
+ var stdoutBuf, stderrBuf strings.Builder
+ cmd.Stdout = &stdoutBuf
+ cmd.Stderr = &stderrBuf
+ err = cmd.Run()
+ return stdoutBuf.String(), stderrBuf.String(), err
+}
+
+// expand applies environment variable expansion to the string s.
+func (ts *testScript) expand(s string) string {
+ return os.Expand(s, func(key string) string { return ts.envMap[key] })
+}
+
+// fatalf aborts the test with the given failure message.
+func (ts *testScript) fatalf(format string, args ...interface{}) {
+ fmt.Fprintf(&ts.log, "FAIL: %s:%d: %s\n", ts.file, ts.lineno, fmt.Sprintf(format, args...))
+ ts.t.FailNow()
+}
+
+// mkabs interprets file relative to the test script's current directory
+// and returns the corresponding absolute path.
+func (ts *testScript) mkabs(file string) string {
+ if filepath.IsAbs(file) {
+ return file
+ }
+ return filepath.Join(ts.cd, file)
+}
+
+// parse parses a single line as a list of space-separated arguments
+// subject to environment variable expansion (but not resplitting).
+// Single quotes around text disable splitting and expansion.
+// To embed a single quote, double it: 'Don''t communicate by sharing memory.'
+func (ts *testScript) parse(line string) []string {
+ ts.line = line
+
+ var (
+ args []string
+ arg string // text of current arg so far (need to add line[start:i])
+ start = -1 // if >= 0, position where current arg text chunk starts
+ quoted = false // currently processing quoted text
+ )
+ for i := 0; ; i++ {
+ if !quoted && (i >= len(line) || line[i] == ' ' || line[i] == '\t' || line[i] == '\r' || line[i] == '#') {
+ // Found arg-separating space.
+ if start >= 0 {
+ arg += ts.expand(line[start:i])
+ args = append(args, arg)
+ start = -1
+ arg = ""
+ }
+ if i >= len(line) || line[i] == '#' {
+ break
+ }
+ continue
+ }
+ if i >= len(line) {
+ ts.fatalf("unterminated quoted argument")
+ }
+ if line[i] == '\'' {
+ if !quoted {
+ // starting a quoted chunk
+ if start >= 0 {
+ arg += ts.expand(line[start:i])
+ }
+ start = i + 1
+ quoted = true
+ continue
+ }
+ // 'foo''bar' means foo'bar, like in rc shell and Pascal.
+ if i+1 < len(line) && line[i+1] == '\'' {
+ arg += line[start:i]
+ start = i + 1
+ i++ // skip over second ' before next iteration
+ continue
+ }
+ // ending a quoted chunk
+ arg += line[start:i]
+ start = i + 1
+ quoted = false
+ continue
+ }
+ // found character worth saving; make sure we're saving
+ if start < 0 {
+ start = i
+ }
+ }
+ return args
+}
+
+// diff returns a formatted diff of the two texts,
+// showing the entire text and the minimum line-level
+// additions and removals to turn text1 into text2.
+// (That is, lines only in text1 appear with a leading -,
+// and lines only in text2 appear with a leading +.)
+func diff(text1, text2 string) string {
+ if text1 != "" && !strings.HasSuffix(text1, "\n") {
+ text1 += "(missing final newline)"
+ }
+ lines1 := strings.Split(text1, "\n")
+ lines1 = lines1[:len(lines1)-1] // remove empty string after final line
+ if text2 != "" && !strings.HasSuffix(text2, "\n") {
+ text2 += "(missing final newline)"
+ }
+ lines2 := strings.Split(text2, "\n")
+ lines2 = lines2[:len(lines2)-1] // remove empty string after final line
+
+ // Naive dynamic programming algorithm for edit distance.
+ // https://en.wikipedia.org/wiki/Wagner–Fischer_algorithm
+ // dist[i][j] = edit distance between lines1[:len(lines1)-i] and lines2[:len(lines2)-j]
+ // (The reversed indices make following the minimum cost path
+ // visit lines in the same order as in the text.)
+ dist := make([][]int, len(lines1)+1)
+ for i := range dist {
+ dist[i] = make([]int, len(lines2)+1)
+ if i == 0 {
+ for j := range dist[0] {
+ dist[0][j] = j
+ }
+ continue
+ }
+ for j := range dist[i] {
+ if j == 0 {
+ dist[i][0] = i
+ continue
+ }
+ cost := dist[i][j-1] + 1
+ if cost > dist[i-1][j]+1 {
+ cost = dist[i-1][j] + 1
+ }
+ if lines1[len(lines1)-i] == lines2[len(lines2)-j] {
+ if cost > dist[i-1][j-1] {
+ cost = dist[i-1][j-1]
+ }
+ }
+ dist[i][j] = cost
+ }
+ }
+
+ var buf strings.Builder
+ i, j := len(lines1), len(lines2)
+ for i > 0 || j > 0 {
+ cost := dist[i][j]
+ if i > 0 && j > 0 && cost == dist[i-1][j-1] && lines1[len(lines1)-i] == lines2[len(lines2)-j] {
+ fmt.Fprintf(&buf, " %s\n", lines1[len(lines1)-i])
+ i--
+ j--
+ } else if i > 0 && cost == dist[i-1][j]+1 {
+ fmt.Fprintf(&buf, "-%s\n", lines1[len(lines1)-i])
+ i--
+ } else {
+ fmt.Fprintf(&buf, "+%s\n", lines2[len(lines2)-j])
+ j--
+ }
+ }
+ return buf.String()
+}
+
+var diffTests = []struct {
+ text1 string
+ text2 string
+ diff string
+}{
+ {"a b c", "a b d e f", "a b -c +d +e +f"},
+ {"", "a b c", "+a +b +c"},
+ {"a b c", "", "-a -b -c"},
+ {"a b c", "d e f", "-a -b -c +d +e +f"},
+ {"a b c d e f", "a b d e f", "a b -c d e f"},
+ {"a b c e f", "a b c d e f", "a b c +d e f"},
+}
+
+func TestDiff(t *testing.T) {
+ for _, tt := range diffTests {
+ // Turn spaces into \n.
+ text1 := strings.Replace(tt.text1, " ", "\n", -1)
+ if text1 != "" {
+ text1 += "\n"
+ }
+ text2 := strings.Replace(tt.text2, " ", "\n", -1)
+ if text2 != "" {
+ text2 += "\n"
+ }
+ out := diff(text1, text2)
+ // Cut final \n, cut spaces, turn remaining \n into spaces.
+ out = strings.Replace(strings.Replace(strings.TrimSuffix(out, "\n"), " ", "", -1), "\n", " ", -1)
+ if out != tt.diff {
+ t.Errorf("diff(%q, %q) = %q, want %q", text1, text2, out, tt.diff)
+ }
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/addmod.go b/libgo/go/cmd/go/testdata/addmod.go
new file mode 100644
index 00000000000..19850af0f37
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/addmod.go
@@ -0,0 +1,154 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+// Addmod adds a module as a txtar archive to the testdata/mod directory.
+//
+// Usage:
+//
+// go run addmod.go path@version...
+//
+// It should only be used for very small modules - we do not want to check
+// very large files into testdata/mod.
+//
+// It is acceptable to edit the archive afterward to remove or shorten files.
+// See mod/README for more information.
+//
+package main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+
+ "../internal/txtar"
+)
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "usage: go run addmod.go path@version...\n")
+ os.Exit(2)
+}
+
+var tmpdir string
+
+func fatalf(format string, args ...interface{}) {
+ os.RemoveAll(tmpdir)
+ log.Fatalf(format, args...)
+}
+
+const goCmd = "vgo"
+
+func main() {
+ flag.Usage = usage
+ flag.Parse()
+ if flag.NArg() == 0 {
+ usage()
+ }
+
+ log.SetPrefix("addmod: ")
+ log.SetFlags(0)
+
+ var err error
+ tmpdir, err = ioutil.TempDir("", "addmod-")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ run := func(command string, args ...string) string {
+ cmd := exec.Command(command, args...)
+ cmd.Dir = tmpdir
+ var stderr bytes.Buffer
+ cmd.Stderr = &stderr
+ out, err := cmd.Output()
+ if err != nil {
+ fatalf("%s %s: %v\n%s", command, strings.Join(args, " "), err, stderr.Bytes())
+ }
+ return string(out)
+ }
+
+ gopath := strings.TrimSpace(run("go", "env", "GOPATH"))
+ if gopath == "" {
+ fatalf("cannot find GOPATH")
+ }
+
+ exitCode := 0
+ for _, arg := range flag.Args() {
+ if err := ioutil.WriteFile(filepath.Join(tmpdir, "go.mod"), []byte("module m\n"), 0666); err != nil {
+ fatalf("%v", err)
+ }
+ run(goCmd, "get", "-d", arg)
+ path := arg
+ if i := strings.Index(path, "@"); i >= 0 {
+ path = path[:i]
+ }
+ out := run(goCmd, "list", "-m", "-f={{.Path}} {{.Version}} {{.Dir}}", path)
+ f := strings.Fields(out)
+ if len(f) != 3 {
+ log.Printf("go list -m %s: unexpected output %q", arg, out)
+ exitCode = 1
+ continue
+ }
+ path, vers, dir := f[0], f[1], f[2]
+ mod, err := ioutil.ReadFile(filepath.Join(gopath, "pkg/mod/cache/download", path, "@v", vers+".mod"))
+ if err != nil {
+ log.Printf("%s: %v", arg, err)
+ exitCode = 1
+ continue
+ }
+ info, err := ioutil.ReadFile(filepath.Join(gopath, "pkg/mod/cache/download", path, "@v", vers+".info"))
+ if err != nil {
+ log.Printf("%s: %v", arg, err)
+ exitCode = 1
+ continue
+ }
+
+ a := new(txtar.Archive)
+ title := arg
+ if !strings.Contains(arg, "@") {
+ title += "@" + vers
+ }
+ a.Comment = []byte(fmt.Sprintf("module %s\n\n", title))
+ a.Files = []txtar.File{
+ {Name: ".mod", Data: mod},
+ {Name: ".info", Data: info},
+ }
+ dir = filepath.Clean(dir)
+ err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
+ if !info.Mode().IsRegular() {
+ return nil
+ }
+ name := info.Name()
+ if name == "go.mod" || strings.HasSuffix(name, ".go") {
+ data, err := ioutil.ReadFile(path)
+ if err != nil {
+ return err
+ }
+ a.Files = append(a.Files, txtar.File{Name: strings.TrimPrefix(path, dir+string(filepath.Separator)), Data: data})
+ }
+ return nil
+ })
+ if err != nil {
+ log.Printf("%s: %v", arg, err)
+ exitCode = 1
+ continue
+ }
+
+ data := txtar.Format(a)
+ target := filepath.Join("mod", strings.Replace(path, "/", "_", -1)+"_"+vers+".txt")
+ if err := ioutil.WriteFile(target, data, 0666); err != nil {
+ log.Printf("%s: %v", arg, err)
+ exitCode = 1
+ continue
+ }
+ }
+ os.RemoveAll(tmpdir)
+ os.Exit(exitCode)
+}
diff --git a/libgo/go/cmd/go/testdata/badmod/go.mod b/libgo/go/cmd/go/testdata/badmod/go.mod
new file mode 100644
index 00000000000..f7f64238700
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/badmod/go.mod
@@ -0,0 +1 @@
+module m
diff --git a/libgo/go/cmd/go/testdata/badmod/x.go b/libgo/go/cmd/go/testdata/badmod/x.go
new file mode 100644
index 00000000000..579fb086eeb
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/badmod/x.go
@@ -0,0 +1,4 @@
+package x
+
+import _ "appengine"
+import _ "nonexistent.rsc.io" // domain does not exist
diff --git a/libgo/go/cmd/go/testdata/importcycle/src/selfimport/selfimport.go b/libgo/go/cmd/go/testdata/importcycle/src/selfimport/selfimport.go
new file mode 100644
index 00000000000..dc63c4b9f29
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/importcycle/src/selfimport/selfimport.go
@@ -0,0 +1,3 @@
+package selfimport
+
+import "selfimport"
diff --git a/libgo/go/cmd/go/testdata/mod/README b/libgo/go/cmd/go/testdata/mod/README
new file mode 100644
index 00000000000..43ddf77eff3
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/README
@@ -0,0 +1,36 @@
+This directory holds Go modules served by a Go module proxy
+that runs on localhost during tests, both to make tests avoid
+requiring specific network servers and also to make them
+significantly faster.
+
+A small go get'able test module can be added here by running
+
+ cd cmd/go/testdata
+ go run addmod.go path@vers
+
+where path and vers are the module path and version to add here.
+
+For interactive experimentation using this set of modules, run:
+
+ cd cmd/go
+ go test -proxy=localhost:1234 &
+ export GOPROXY=http://localhost:1234/mod
+
+and then run go commands as usual.
+
+Modules saved to this directory should be small: a few kilobytes at most.
+It is acceptable to edit the archives created by addmod.go to remove
+or shorten files. It is also acceptable to write module archives by hand:
+they need not be backed by some public git repo.
+
+Each module archive is named path_vers.txt, where slashes in path
+have been replaced with underscores. The archive must contain
+two files ".info" and ".mod", to be served as the info and mod files
+in the proxy protocol (see https://research.swtch.com/vgo-module).
+The remaining files are served as the content of the module zip file.
+The path@vers prefix required of files in the zip file is added
+automatically by the proxy: the files in the archive have names without
+the prefix, like plain "go.mod", "x.go", and so on.
+
+See ../addmod.go and ../savedir.go for tools to generate txtar files,
+although again it is also fine to write them by hand.
diff --git a/libgo/go/cmd/go/testdata/mod/example.com_join_subpkg_v1.0.0.txt b/libgo/go/cmd/go/testdata/mod/example.com_join_subpkg_v1.0.0.txt
new file mode 100644
index 00000000000..1ecfa0b6de9
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/example.com_join_subpkg_v1.0.0.txt
@@ -0,0 +1,9 @@
+Written by hand.
+Test case for package moved into a parent module.
+
+-- .mod --
+module example.com/join/subpkg
+-- .info --
+{"Version": "v1.0.0"}
+-- x.go --
+package subpkg
diff --git a/libgo/go/cmd/go/testdata/mod/example.com_join_subpkg_v1.1.0.txt b/libgo/go/cmd/go/testdata/mod/example.com_join_subpkg_v1.1.0.txt
new file mode 100644
index 00000000000..9eb823adb76
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/example.com_join_subpkg_v1.1.0.txt
@@ -0,0 +1,9 @@
+Written by hand.
+Test case for package moved into a parent module.
+
+-- .mod --
+module example.com/join/subpkg
+
+require example.com/join v1.1.0
+-- .info --
+{"Version": "v1.1.0"}
diff --git a/libgo/go/cmd/go/testdata/mod/example.com_join_v1.0.0.txt b/libgo/go/cmd/go/testdata/mod/example.com_join_v1.0.0.txt
new file mode 100644
index 00000000000..84c68b13b6d
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/example.com_join_v1.0.0.txt
@@ -0,0 +1,7 @@
+Written by hand.
+Test case for package moved into a parent module.
+
+-- .mod --
+module example.com/join
+-- .info --
+{"Version": "v1.0.0"}
diff --git a/libgo/go/cmd/go/testdata/mod/example.com_join_v1.1.0.txt b/libgo/go/cmd/go/testdata/mod/example.com_join_v1.1.0.txt
new file mode 100644
index 00000000000..5f92036d9e7
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/example.com_join_v1.1.0.txt
@@ -0,0 +1,9 @@
+Written by hand.
+Test case for package moved into a parent module.
+
+-- .mod --
+module example.com/join
+-- .info --
+{"Version": "v1.1.0"}
+-- subpkg/x.go --
+package subpkg
diff --git a/libgo/go/cmd/go/testdata/mod/example.com_split_subpkg_v1.1.0.txt b/libgo/go/cmd/go/testdata/mod/example.com_split_subpkg_v1.1.0.txt
new file mode 100644
index 00000000000..b197b663981
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/example.com_split_subpkg_v1.1.0.txt
@@ -0,0 +1,11 @@
+Written by hand.
+Test case for getting a package that has been moved to a different module.
+
+-- .mod --
+module example.com/split/subpkg
+
+require example.com/split v1.1.0
+-- .info --
+{"Version": "v1.1.0"}
+-- x.go --
+package subpkg
diff --git a/libgo/go/cmd/go/testdata/mod/example.com_split_v1.0.0.txt b/libgo/go/cmd/go/testdata/mod/example.com_split_v1.0.0.txt
new file mode 100644
index 00000000000..b706e590d98
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/example.com_split_v1.0.0.txt
@@ -0,0 +1,9 @@
+Written by hand.
+Test case for getting a package that has been moved to a different module.
+
+-- .mod --
+module example.com/split
+-- .info --
+{"Version": "v1.0.0"}
+-- subpkg/x.go --
+package subpkg
diff --git a/libgo/go/cmd/go/testdata/mod/example.com_split_v1.1.0.txt b/libgo/go/cmd/go/testdata/mod/example.com_split_v1.1.0.txt
new file mode 100644
index 00000000000..d38971f9b62
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/example.com_split_v1.1.0.txt
@@ -0,0 +1,9 @@
+Written by hand.
+Test case for getting a package that has been moved to a different module.
+
+-- .mod --
+module example.com/split
+
+require example.com/split/subpkg v1.1.0
+-- .info --
+{"Version": "v1.1.0"}
diff --git a/libgo/go/cmd/go/testdata/mod/example.com_v1.0.0.txt b/libgo/go/cmd/go/testdata/mod/example.com_v1.0.0.txt
new file mode 100644
index 00000000000..263287d9e2c
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/example.com_v1.0.0.txt
@@ -0,0 +1,9 @@
+Written by hand.
+Test case for module at root of domain.
+
+-- .mod --
+module example.com
+-- .info --
+{"Version": "v1.0.0"}
+-- x.go --
+package x
diff --git a/libgo/go/cmd/go/testdata/mod/golang.org_notx_useinternal_v0.1.0.txt b/libgo/go/cmd/go/testdata/mod/golang.org_notx_useinternal_v0.1.0.txt
new file mode 100644
index 00000000000..0420a1a4a0a
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/golang.org_notx_useinternal_v0.1.0.txt
@@ -0,0 +1,13 @@
+written by hand — attempts to use a prohibited internal package
+(https://golang.org/s/go14internal)
+
+-- .mod --
+module golang.org/notx/useinternal
+-- .info --
+{"Version":"v0.1.0","Name":"","Short":"","Time":"2018-07-25T17:24:00Z"}
+-- go.mod --
+module golang.org/notx/useinternal
+-- useinternal.go --
+package useinternal
+
+import _ "golang.org/x/internal/subtle"
diff --git a/libgo/go/cmd/go/testdata/mod/golang.org_x_internal_v0.1.0.txt b/libgo/go/cmd/go/testdata/mod/golang.org_x_internal_v0.1.0.txt
new file mode 100644
index 00000000000..5737e95cf47
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/golang.org_x_internal_v0.1.0.txt
@@ -0,0 +1,43 @@
+written by hand — loosely derived from golang.org/x/crypto/internal/subtle,
+but splitting the internal package across a module boundary
+
+-- .mod --
+module golang.org/x/internal
+-- .info --
+{"Version":"v0.1.0","Name":"","Short":"","Time":"2018-07-25T17:24:00Z"}
+-- go.mod --
+module golang.org/x/internal
+-- subtle/aliasing.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !appengine
+
+// This is a tiny version of golang.org/x/crypto/internal/subtle.
+
+package subtle
+
+import "unsafe"
+
+func AnyOverlap(x, y []byte) bool {
+ return len(x) > 0 && len(y) > 0 &&
+ uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) &&
+ uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1]))
+}
+-- subtle/aliasing_appengine.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build appengine
+
+package subtle
+
+import "reflect"
+
+func AnyOverlap(x, y []byte) bool {
+ return len(x) > 0 && len(y) > 0 &&
+ reflect.ValueOf(&x[0]).Pointer() <= reflect.ValueOf(&y[len(y)-1]).Pointer() &&
+ reflect.ValueOf(&y[0]).Pointer() <= reflect.ValueOf(&x[len(x)-1]).Pointer()
+}
diff --git a/libgo/go/cmd/go/testdata/mod/golang.org_x_text_v0.0.0-20170915032832-14c0d48ead0c.txt b/libgo/go/cmd/go/testdata/mod/golang.org_x_text_v0.0.0-20170915032832-14c0d48ead0c.txt
new file mode 100644
index 00000000000..f4f50cdedb6
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/golang.org_x_text_v0.0.0-20170915032832-14c0d48ead0c.txt
@@ -0,0 +1,47 @@
+written by hand - just enough to compile rsc.io/sampler, rsc.io/quote
+
+-- .mod --
+module golang.org/x/text
+-- .info --
+{"Version":"v0.0.0-20170915032832-14c0d48ead0c","Name":"v0.0.0-20170915032832-14c0d48ead0c","Short":"14c0d48ead0c","Time":"2017-09-15T03:28:32Z"}
+-- go.mod --
+module golang.org/x/text
+-- unused/unused.go --
+package unused
+-- language/lang.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This is a tiny version of golang.org/x/text.
+
+package language
+
+import "strings"
+
+type Tag string
+
+func Make(s string) Tag { return Tag(s) }
+
+func (t Tag) String() string { return string(t) }
+
+func NewMatcher(tags []Tag) Matcher { return &matcher{tags} }
+
+type Matcher interface {
+ Match(...Tag) (Tag, int, int)
+}
+
+type matcher struct {
+ tags []Tag
+}
+
+func (m *matcher) Match(prefs ...Tag) (Tag, int, int) {
+ for _, pref := range prefs {
+ for _, tag := range m.tags {
+ if tag == pref || strings.HasPrefix(string(pref), string(tag+"-")) || strings.HasPrefix(string(tag), string(pref+"-")) {
+ return tag, 0, 0
+ }
+ }
+ }
+ return m.tags[0], 0, 0
+}
diff --git a/libgo/go/cmd/go/testdata/mod/golang.org_x_text_v0.3.0.txt b/libgo/go/cmd/go/testdata/mod/golang.org_x_text_v0.3.0.txt
new file mode 100644
index 00000000000..5561afae8ed
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/golang.org_x_text_v0.3.0.txt
@@ -0,0 +1,47 @@
+written by hand - just enough to compile rsc.io/sampler, rsc.io/quote
+
+-- .mod --
+module golang.org/x/text
+-- .info --
+{"Version":"v0.3.0","Name":"","Short":"","Time":"2017-09-16T03:28:32Z"}
+-- go.mod --
+module golang.org/x/text
+-- unused/unused.go --
+package unused
+-- language/lang.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This is a tiny version of golang.org/x/text.
+
+package language
+
+import "strings"
+
+type Tag string
+
+func Make(s string) Tag { return Tag(s) }
+
+func (t Tag) String() string { return string(t) }
+
+func NewMatcher(tags []Tag) Matcher { return &matcher{tags} }
+
+type Matcher interface {
+ Match(...Tag) (Tag, int, int)
+}
+
+type matcher struct {
+ tags []Tag
+}
+
+func (m *matcher) Match(prefs ...Tag) (Tag, int, int) {
+ for _, pref := range prefs {
+ for _, tag := range m.tags {
+ if tag == pref || strings.HasPrefix(string(pref), string(tag+"-")) || strings.HasPrefix(string(tag), string(pref+"-")) {
+ return tag, 0, 0
+ }
+ }
+ }
+ return m.tags[0], 0, 0
+}
diff --git a/libgo/go/cmd/go/testdata/mod/golang.org_x_useinternal_v0.1.0.txt b/libgo/go/cmd/go/testdata/mod/golang.org_x_useinternal_v0.1.0.txt
new file mode 100644
index 00000000000..3fcba447bef
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/golang.org_x_useinternal_v0.1.0.txt
@@ -0,0 +1,13 @@
+written by hand — uses an internal package from another module
+(https://golang.org/s/go14internal)
+
+-- .mod --
+module golang.org/x/useinternal
+-- .info --
+{"Version":"v0.1.0","Name":"","Short":"","Time":"2018-07-25T17:24:00Z"}
+-- go.mod --
+module golang.org/x/useinternal
+-- useinternal.go --
+package useinternal
+
+import _ "golang.org/x/internal/subtle"
diff --git a/libgo/go/cmd/go/testdata/mod/gopkg.in_dummy.v2-unstable_v2.0.0.txt b/libgo/go/cmd/go/testdata/mod/gopkg.in_dummy.v2-unstable_v2.0.0.txt
new file mode 100644
index 00000000000..f174159fd3f
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/gopkg.in_dummy.v2-unstable_v2.0.0.txt
@@ -0,0 +1,9 @@
+gopkg.in/dummy.v2-unstable v2.0.0
+written by hand
+
+-- .mod --
+module gopkg.in/dummy.v2-unstable
+-- .info --
+{"Version":"v2.0.0"}
+-- dummy.go --
+package dummy
diff --git a/libgo/go/cmd/go/testdata/mod/research.swtch.com_vgo-tour_v1.0.0.txt b/libgo/go/cmd/go/testdata/mod/research.swtch.com_vgo-tour_v1.0.0.txt
new file mode 100644
index 00000000000..0f060dc8e32
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/research.swtch.com_vgo-tour_v1.0.0.txt
@@ -0,0 +1,23 @@
+research.swtch.com/vgo-tour@v1.0.0
+
+-- .mod --
+module "research.swtch.com/vgo-tour"
+-- .info --
+{"Version":"v1.0.0","Name":"84de74b35823c1e49634f2262f1a58cfc951ebae","Short":"84de74b35823","Time":"2018-02-20T00:04:00Z"}
+-- go.mod --
+module "research.swtch.com/vgo-tour"
+-- hello.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "rsc.io/quote"
+)
+
+func main() {
+ fmt.Println(quote.Hello())
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_!c!g!o_v1.0.0.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_!c!g!o_v1.0.0.txt
new file mode 100644
index 00000000000..6276147535b
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_!c!g!o_v1.0.0.txt
@@ -0,0 +1,19 @@
+rsc.io/CGO v1.0.0
+
+-- .mod --
+module rsc.io/CGO
+-- .info --
+{"Version":"v1.0.0","Name":"","Short":"","Time":"2018-08-01T18:23:45Z"}
+-- go.mod --
+module rsc.io/CGO
+-- cgo.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package CGO
+
+// #cgo CFLAGS: -I${SRCDIR}
+import "C"
+
+var V = 0
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_!q!u!o!t!e_v1.5.2.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_!q!u!o!t!e_v1.5.2.txt
new file mode 100644
index 00000000000..21185c39f33
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_!q!u!o!t!e_v1.5.2.txt
@@ -0,0 +1,88 @@
+rsc.io/QUOTE v1.5.2
+
+-- .mod --
+module rsc.io/QUOTE
+
+require rsc.io/quote v1.5.2
+-- .info --
+{"Version":"v1.5.2","Name":"","Short":"","Time":"2018-07-15T16:25:34Z"}
+-- go.mod --
+module rsc.io/QUOTE
+
+require rsc.io/quote v1.5.2
+-- QUOTE/quote.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// PACKAGE QUOTE COLLECTS LOUD SAYINGS.
+package QUOTE
+
+import (
+ "strings"
+
+ "rsc.io/quote"
+)
+
+// HELLO RETURNS A GREETING.
+func HELLO() string {
+ return strings.ToUpper(quote.Hello())
+}
+
+// GLASS RETURNS A USEFUL PHRASE FOR WORLD TRAVELERS.
+func GLASS() string {
+ return strings.ToUpper(quote.GLASS())
+}
+
+// GO RETURNS A GO PROVERB.
+func GO() string {
+ return strings.ToUpper(quote.GO())
+}
+
+// OPT RETURNS AN OPTIMIZATION TRUTH.
+func OPT() string {
+ return strings.ToUpper(quote.OPT())
+}
+-- QUOTE/quote_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package QUOTE
+
+import (
+ "os"
+ "testing"
+)
+
+func init() {
+ os.Setenv("LC_ALL", "en")
+}
+
+func TestHELLO(t *testing.T) {
+ hello := "HELLO, WORLD"
+ if out := HELLO(); out != hello {
+ t.Errorf("HELLO() = %q, want %q", out, hello)
+ }
+}
+
+func TestGLASS(t *testing.T) {
+ glass := "I CAN EAT GLASS AND IT DOESN'T HURT ME."
+ if out := GLASS(); out != glass {
+ t.Errorf("GLASS() = %q, want %q", out, glass)
+ }
+}
+
+func TestGO(t *testing.T) {
+ go1 := "DON'T COMMUNICATE BY SHARING MEMORY, SHARE MEMORY BY COMMUNICATING."
+ if out := GO(); out != go1 {
+ t.Errorf("GO() = %q, want %q", out, go1)
+ }
+}
+
+func TestOPT(t *testing.T) {
+ opt := "IF A PROGRAM IS TOO SLOW, IT MUST HAVE A LOOP."
+ if out := OPT(); out != opt {
+ t.Errorf("OPT() = %q, want %q", out, opt)
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_!q!u!o!t!e_v1.5.3-!p!r!e.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_!q!u!o!t!e_v1.5.3-!p!r!e.txt
new file mode 100644
index 00000000000..54bac2df7bb
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_!q!u!o!t!e_v1.5.3-!p!r!e.txt
@@ -0,0 +1,88 @@
+rsc.io/QUOTE v1.5.3-PRE (sigh)
+
+-- .mod --
+module rsc.io/QUOTE
+
+require rsc.io/quote v1.5.2
+-- .info --
+{"Version":"v1.5.3-PRE","Name":"","Short":"","Time":"2018-07-15T16:25:34Z"}
+-- go.mod --
+module rsc.io/QUOTE
+
+require rsc.io/quote v1.5.2
+-- QUOTE/quote.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// PACKAGE QUOTE COLLECTS LOUD SAYINGS.
+package QUOTE
+
+import (
+ "strings"
+
+ "rsc.io/quote"
+)
+
+// HELLO RETURNS A GREETING.
+func HELLO() string {
+ return strings.ToUpper(quote.Hello())
+}
+
+// GLASS RETURNS A USEFUL PHRASE FOR WORLD TRAVELERS.
+func GLASS() string {
+ return strings.ToUpper(quote.GLASS())
+}
+
+// GO RETURNS A GO PROVERB.
+func GO() string {
+ return strings.ToUpper(quote.GO())
+}
+
+// OPT RETURNS AN OPTIMIZATION TRUTH.
+func OPT() string {
+ return strings.ToUpper(quote.OPT())
+}
+-- QUOTE/quote_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package QUOTE
+
+import (
+ "os"
+ "testing"
+)
+
+func init() {
+ os.Setenv("LC_ALL", "en")
+}
+
+func TestHELLO(t *testing.T) {
+ hello := "HELLO, WORLD"
+ if out := HELLO(); out != hello {
+ t.Errorf("HELLO() = %q, want %q", out, hello)
+ }
+}
+
+func TestGLASS(t *testing.T) {
+ glass := "I CAN EAT GLASS AND IT DOESN'T HURT ME."
+ if out := GLASS(); out != glass {
+ t.Errorf("GLASS() = %q, want %q", out, glass)
+ }
+}
+
+func TestGO(t *testing.T) {
+ go1 := "DON'T COMMUNICATE BY SHARING MEMORY, SHARE MEMORY BY COMMUNICATING."
+ if out := GO(); out != go1 {
+ t.Errorf("GO() = %q, want %q", out, go1)
+ }
+}
+
+func TestOPT(t *testing.T) {
+ opt := "IF A PROGRAM IS TOO SLOW, IT MUST HAVE A LOOP."
+ if out := OPT(); out != opt {
+ t.Errorf("OPT() = %q, want %q", out, opt)
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_badfile1_v1.0.0.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_badfile1_v1.0.0.txt
new file mode 100644
index 00000000000..9d23e7db98c
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_badfile1_v1.0.0.txt
@@ -0,0 +1,14 @@
+rsc.io/badfile1 v1.0.0
+written by hand
+this is part of the badfile test but is a valid zip file.
+
+-- .mod --
+module rsc.io/badfile1
+-- .info --
+{"Version":"v1.0.0"}
+-- go.mod --
+module rsc.io/badfile1
+-- α.go --
+package α
+-- .gitignore --
+-- x/y/z/.gitignore --
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_badfile2_v1.0.0.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_badfile2_v1.0.0.txt
new file mode 100644
index 00000000000..58e1e1c103a
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_badfile2_v1.0.0.txt
@@ -0,0 +1,12 @@
+rsc.io/badfile1 v1.0.0
+written by hand
+
+-- .mod --
+module rsc.io/badfile2
+-- .info --
+{"Version":"v1.0.0"}
+-- go.mod --
+module rsc.io/badfile2
+-- ☺.go --
+package smiley
+
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_badfile3_v1.0.0.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_badfile3_v1.0.0.txt
new file mode 100644
index 00000000000..a008448c5fd
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_badfile3_v1.0.0.txt
@@ -0,0 +1,12 @@
+rsc.io/badfile3 v1.0.0
+written by hand
+
+-- .mod --
+module rsc.io/badfile3
+-- .info --
+{"Version":"v1.0.0"}
+-- go.mod --
+module rsc.io/badfile3
+-- x?y.go --
+package x
+
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_badfile4_v1.0.0.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_badfile4_v1.0.0.txt
new file mode 100644
index 00000000000..e28844dc632
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_badfile4_v1.0.0.txt
@@ -0,0 +1,15 @@
+rsc.io/badfile4 v1.0.0
+written by hand
+
+-- .mod --
+module rsc.io/badfile4
+-- .info --
+{"Version":"v1.0.0"}
+-- go.mod --
+module rsc.io/badfile4
+-- x/Y.go --
+package x
+-- x/y.go --
+package x
+
+
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_badfile5_v1.0.0.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_badfile5_v1.0.0.txt
new file mode 100644
index 00000000000..3c7903a3bc0
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_badfile5_v1.0.0.txt
@@ -0,0 +1,13 @@
+rsc.io/badfile5 v1.0.0
+written by hand
+
+-- .mod --
+module rsc.io/badfile5
+-- .info --
+{"Version":"v1.0.0"}
+-- go.mod --
+module rsc.io/badfile5
+-- x/y/z/w.go --
+package z
+-- x/Y/zz/ww.go --
+package zz
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_badmod_v1.0.0.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_badmod_v1.0.0.txt
new file mode 100644
index 00000000000..993ceb7a0be
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_badmod_v1.0.0.txt
@@ -0,0 +1,11 @@
+rsc.io/badmod v1.0.0
+written by hand
+
+-- .mod --
+module rsc.io/badmod
+hello world
+-- .info --
+{"Version":"v1.0.0"}
+-- x.go --
+package x
+
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_breaker_v1.0.0.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_breaker_v1.0.0.txt
new file mode 100644
index 00000000000..a103e3f8aa1
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_breaker_v1.0.0.txt
@@ -0,0 +1,11 @@
+rsc.io/breaker v1.0.0
+written by hand
+
+-- .mod --
+module rsc.io/breaker
+-- .info --
+{"Version":"v1.0.0"}
+-- breaker.go --
+package breaker
+
+const X = 1
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_breaker_v2.0.0+incompatible.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_breaker_v2.0.0+incompatible.txt
new file mode 100644
index 00000000000..59d8bacf078
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_breaker_v2.0.0+incompatible.txt
@@ -0,0 +1,11 @@
+rsc.io/breaker v2.0.0+incompatible
+written by hand
+
+-- .mod --
+module rsc.io/breaker
+-- .info --
+{"Version":"v2.0.0+incompatible", "Name": "7307b307f4f0dde421900f8e5126fadac1e13aed", "Short": "7307b307f4f0"}
+-- breaker.go --
+package breaker
+
+const XX = 2
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_breaker_v2.0.0.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_breaker_v2.0.0.txt
new file mode 100644
index 00000000000..59d8bacf078
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_breaker_v2.0.0.txt
@@ -0,0 +1,11 @@
+rsc.io/breaker v2.0.0+incompatible
+written by hand
+
+-- .mod --
+module rsc.io/breaker
+-- .info --
+{"Version":"v2.0.0+incompatible", "Name": "7307b307f4f0dde421900f8e5126fadac1e13aed", "Short": "7307b307f4f0"}
+-- breaker.go --
+package breaker
+
+const XX = 2
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_fortune_v1.0.0.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_fortune_v1.0.0.txt
new file mode 100644
index 00000000000..d8a71f3cd93
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_fortune_v1.0.0.txt
@@ -0,0 +1,15 @@
+rsc.io/fortune v1.0.0
+written by hand
+
+-- .mod --
+module rsc.io/fortune
+-- .info --
+{"Version":"v1.0.0"}
+-- fortune.go --
+package main
+
+import "rsc.io/quote"
+
+func main() {
+ println(quote.Hello())
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_fortune_v2_v2.0.0.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_fortune_v2_v2.0.0.txt
new file mode 100644
index 00000000000..cfa91f08a5d
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_fortune_v2_v2.0.0.txt
@@ -0,0 +1,15 @@
+rsc.io/fortune v2.0.0
+written by hand
+
+-- .mod --
+module rsc.io/fortune/v2
+-- .info --
+{"Version":"v2.0.0"}
+-- fortune.go --
+package main
+
+import "rsc.io/quote"
+
+func main() {
+ println(quote.Hello())
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180214005133-e7a685a342c0.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180214005133-e7a685a342c0.txt
new file mode 100644
index 00000000000..8ae173e7aec
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180214005133-e7a685a342c0.txt
@@ -0,0 +1,60 @@
+rsc.io/quote@e7a685a342
+
+-- .mod --
+module "rsc.io/quote"
+-- .info --
+{"Version":"v0.0.0-20180214005133-e7a685a342c0","Name":"e7a685a342c001acc3eb7f5eafa82980480042c7","Short":"e7a685a342c0","Time":"2018-02-14T00:51:33Z"}
+-- go.mod --
+module "rsc.io/quote"
+-- quote.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package quote collects pithy sayings.
+package quote // import "rsc.io/quote"
+
+// Hello returns a greeting.
+func Hello() string {
+ return "Hello, world."
+}
+
+// Glass returns a useful phrase for world travelers.
+func Glass() string {
+ // See http://www.oocities.org/nodotus/hbglass.html.
+ return "I can eat glass and it doesn't hurt me."
+}
+
+// Go returns a Go proverb.
+func Go() string {
+ return "Don't communicate by sharing memory, share memory by communicating."
+}
+-- quote_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package quote
+
+import "testing"
+
+func TestHello(t *testing.T) {
+ hello := "Hello, world."
+ if out := Hello(); out != hello {
+ t.Errorf("Hello() = %q, want %q", out, hello)
+ }
+}
+
+func TestGlass(t *testing.T) {
+ glass := "I can eat glass and it doesn't hurt me."
+ if out := Glass(); out != glass {
+ t.Errorf("Glass() = %q, want %q", out, glass)
+ }
+}
+
+func TestGo(t *testing.T) {
+ go1 := "Don't communicate by sharing memory. Share memory by communicating."
+ if out := Go(); out != go1 {
+ t.Errorf("Go() = %q, want %q", out, go1)
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180214005840-23179ee8a569.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180214005840-23179ee8a569.txt
new file mode 100644
index 00000000000..bc626bac7a4
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180214005840-23179ee8a569.txt
@@ -0,0 +1,86 @@
+rsc.io/quote@v0.0.0-20180214005840-23179ee8a569
+
+-- .mod --
+module "rsc.io/quote"
+
+require "rsc.io/sampler" v1.3.0
+-- .info --
+{"Version":"v0.0.0-20180214005840-23179ee8a569","Name":"23179ee8a569bb05d896ae05c6503ec69a19f99f","Short":"23179ee8a569","Time":"2018-02-14T00:58:40Z"}
+-- go.mod --
+module "rsc.io/quote"
+
+require "rsc.io/sampler" v1.3.0
+-- quote.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package quote collects pithy sayings.
+package quote // import "rsc.io/quote"
+
+import "rsc.io/sampler"
+
+// Hello returns a greeting.
+func Hello() string {
+ return sampler.Hello()
+}
+
+// Glass returns a useful phrase for world travelers.
+func Glass() string {
+ // See http://www.oocities.org/nodotus/hbglass.html.
+ return "I can eat glass and it doesn't hurt me."
+}
+
+// Go returns a Go proverb.
+func Go() string {
+ return "Don't communicate by sharing memory, share memory by communicating."
+}
+
+// Opt returns an optimization truth.
+func Opt() string {
+ // Wisdom from ken.
+ return "If a program is too slow, it must have a loop."
+}
+-- quote_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package quote
+
+import (
+ "os"
+ "testing"
+)
+
+func init() {
+ os.Setenv("LC_ALL", "en")
+}
+
+func TestHello(t *testing.T) {
+ hello := "Hello, world."
+ if out := Hello(); out != hello {
+ t.Errorf("Hello() = %q, want %q", out, hello)
+ }
+}
+
+func TestGlass(t *testing.T) {
+ glass := "I can eat glass and it doesn't hurt me."
+ if out := Glass(); out != glass {
+ t.Errorf("Glass() = %q, want %q", out, glass)
+ }
+}
+
+func TestGo(t *testing.T) {
+ go1 := "Don't communicate by sharing memory, share memory by communicating."
+ if out := Go(); out != go1 {
+ t.Errorf("Go() = %q, want %q", out, go1)
+ }
+}
+
+func TestOpt(t *testing.T) {
+ opt := "If a program is too slow, it must have a loop."
+ if out := Opt(); out != opt {
+ t.Errorf("Opt() = %q, want %q", out, opt)
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180628003336-dd9747d19b04.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180628003336-dd9747d19b04.txt
new file mode 100644
index 00000000000..bbc8097dc3a
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180628003336-dd9747d19b04.txt
@@ -0,0 +1,100 @@
+rsc.io/quote@dd9747d
+
+-- .mod --
+module "rsc.io/quote"
+
+require "rsc.io/sampler" v1.3.0
+-- .info --
+{"Version":"v0.0.0-20180628003336-dd9747d19b04","Name":"dd9747d19b041365fbddf0399ddba6bff5eb1b3e","Short":"dd9747d19b04","Time":"2018-06-28T00:33:36Z"}
+-- buggy/buggy_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package buggy
+
+import "testing"
+
+func Test(t *testing.T) {
+ t.Fatal("buggy!")
+}
+-- go.mod --
+module "rsc.io/quote"
+
+require "rsc.io/sampler" v1.3.0
+-- quote.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package quote collects pithy sayings.
+package quote // import "rsc.io/quote"
+
+import "rsc.io/sampler"
+
+AN EVEN WORSE CHANGE!
+
+// Hello returns a greeting.
+func Hello() string {
+ return sampler.Hello()
+}
+
+// Glass returns a useful phrase for world travelers.
+func Glass() string {
+ // See http://www.oocities.org/nodotus/hbglass.html.
+ return "I can eat glass and it doesn't hurt me."
+}
+
+// Go returns a Go proverb.
+func Go() string {
+ return "Don't communicate by sharing memory, share memory by communicating."
+}
+
+// Opt returns an optimization truth.
+func Opt() string {
+ // Wisdom from ken.
+ return "If a program is too slow, it must have a loop."
+}
+-- quote_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package quote
+
+import (
+ "os"
+ "testing"
+)
+
+func init() {
+ os.Setenv("LC_ALL", "en")
+}
+
+func TestHello(t *testing.T) {
+ hello := "Hello, world."
+ if out := Hello(); out != hello {
+ t.Errorf("Hello() = %q, want %q", out, hello)
+ }
+}
+
+func TestGlass(t *testing.T) {
+ glass := "I can eat glass and it doesn't hurt me."
+ if out := Glass(); out != glass {
+ t.Errorf("Glass() = %q, want %q", out, glass)
+ }
+}
+
+func TestGo(t *testing.T) {
+ go1 := "Don't communicate by sharing memory, share memory by communicating."
+ if out := Go(); out != go1 {
+ t.Errorf("Go() = %q, want %q", out, go1)
+ }
+}
+
+func TestOpt(t *testing.T) {
+ opt := "If a program is too slow, it must have a loop."
+ if out := Opt(); out != opt {
+ t.Errorf("Opt() = %q, want %q", out, opt)
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709153244-fd906ed3b100.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709153244-fd906ed3b100.txt
new file mode 100644
index 00000000000..e461ed4231e
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709153244-fd906ed3b100.txt
@@ -0,0 +1,86 @@
+rsc.io/quote@v2.0.0
+
+-- .mod --
+module "rsc.io/quote"
+
+require "rsc.io/sampler" v1.3.0
+-- .info --
+{"Version":"v0.0.0-20180709153244-fd906ed3b100","Name":"fd906ed3b100e47181ffa9ec36d82294525c9109","Short":"fd906ed3b100","Time":"2018-07-09T15:32:44Z"}
+-- go.mod --
+module "rsc.io/quote"
+
+require "rsc.io/sampler" v1.3.0
+-- quote.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package quote collects pithy sayings.
+package quote // import "rsc.io/quote"
+
+import "rsc.io/sampler"
+
+// Hello returns a greeting.
+func HelloV2() string {
+ return sampler.Hello()
+}
+
+// Glass returns a useful phrase for world travelers.
+func GlassV2() string {
+ // See http://www.oocities.org/nodotus/hbglass.html.
+ return "I can eat glass and it doesn't hurt me."
+}
+
+// Go returns a Go proverb.
+func GoV2() string {
+ return "Don't communicate by sharing memory, share memory by communicating."
+}
+
+// Opt returns an optimization truth.
+func OptV2() string {
+ // Wisdom from ken.
+ return "If a program is too slow, it must have a loop."
+}
+-- quote_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package quote
+
+import (
+ "os"
+ "testing"
+)
+
+func init() {
+ os.Setenv("LC_ALL", "en")
+}
+
+func TestHello(t *testing.T) {
+ hello := "Hello, world."
+ if out := Hello(); out != hello {
+ t.Errorf("Hello() = %q, want %q", out, hello)
+ }
+}
+
+func TestGlass(t *testing.T) {
+ glass := "I can eat glass and it doesn't hurt me."
+ if out := Glass(); out != glass {
+ t.Errorf("Glass() = %q, want %q", out, glass)
+ }
+}
+
+func TestGo(t *testing.T) {
+ go1 := "Don't communicate by sharing memory, share memory by communicating."
+ if out := Go(); out != go1 {
+ t.Errorf("Go() = %q, want %q", out, go1)
+ }
+}
+
+func TestOpt(t *testing.T) {
+ opt := "If a program is too slow, it must have a loop."
+ if out := Opt(); out != opt {
+ t.Errorf("Opt() = %q, want %q", out, opt)
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709160352-0d003b9c4bfa.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709160352-0d003b9c4bfa.txt
new file mode 100644
index 00000000000..c1d511fda71
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709160352-0d003b9c4bfa.txt
@@ -0,0 +1,98 @@
+rsc.io/quote@v0.0.0-20180709160352-0d003b9c4bfa
+
+-- .mod --
+module rsc.io/quote
+
+require rsc.io/sampler v1.3.0
+-- .info --
+{"Version":"v0.0.0-20180709160352-0d003b9c4bfa","Name":"0d003b9c4bfac881641be8eb1598b782a467a97f","Short":"0d003b9c4bfa","Time":"2018-07-09T16:03:52Z"}
+-- buggy/buggy_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package buggy
+
+import "testing"
+
+func Test(t *testing.T) {
+ t.Fatal("buggy!")
+}
+-- go.mod --
+module rsc.io/quote
+
+require rsc.io/sampler v1.3.0
+-- quote.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package quote collects pithy sayings.
+package quote // import "rsc.io/quote"
+
+import "rsc.io/quote/v2"
+
+// Hello returns a greeting.
+func Hello() string {
+ return quote.HelloV2()
+}
+
+// Glass returns a useful phrase for world travelers.
+func Glass() string {
+ // See http://www.oocities.org/nodotus/hbglass.html.
+ return quote.GlassV2()
+}
+
+// Go returns a Go proverb.
+func Go() string {
+ return quote.GoV2()
+}
+
+// Opt returns an optimization truth.
+func Opt() string {
+ // Wisdom from ken.
+ return quote.OptV2()
+}
+-- quote_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package quote
+
+import (
+ "os"
+ "testing"
+)
+
+func init() {
+ os.Setenv("LC_ALL", "en")
+}
+
+func TestHello(t *testing.T) {
+ hello := "Hello, world."
+ if out := Hello(); out != hello {
+ t.Errorf("Hello() = %q, want %q", out, hello)
+ }
+}
+
+func TestGlass(t *testing.T) {
+ glass := "I can eat glass and it doesn't hurt me."
+ if out := Glass(); out != glass {
+ t.Errorf("Glass() = %q, want %q", out, glass)
+ }
+}
+
+func TestGo(t *testing.T) {
+ go1 := "Don't communicate by sharing memory, share memory by communicating."
+ if out := Go(); out != go1 {
+ t.Errorf("Go() = %q, want %q", out, go1)
+ }
+}
+
+func TestOpt(t *testing.T) {
+ opt := "If a program is too slow, it must have a loop."
+ if out := Opt(); out != opt {
+ t.Errorf("Opt() = %q, want %q", out, opt)
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162749-b44a0b17b2d1.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162749-b44a0b17b2d1.txt
new file mode 100644
index 00000000000..f7f794d76dd
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162749-b44a0b17b2d1.txt
@@ -0,0 +1,104 @@
+rsc.io/quote@v0.0.0-20180709162749-b44a0b17b2d1
+
+-- .mod --
+module rsc.io/quote
+
+require (
+ rsc.io/quote/v2 v2.0.1
+ rsc.io/sampler v1.3.0
+)
+-- .info --
+{"Version":"v0.0.0-20180709162749-b44a0b17b2d1","Name":"b44a0b17b2d1fe4c98a8d0e7a68c9bf9e762799a","Short":"b44a0b17b2d1","Time":"2018-07-09T16:27:49Z"}
+-- buggy/buggy_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package buggy
+
+import "testing"
+
+func Test(t *testing.T) {
+ t.Fatal("buggy!")
+}
+-- go.mod --
+module rsc.io/quote
+
+require (
+ rsc.io/quote/v2 v2.0.1
+ rsc.io/sampler v1.3.0
+)
+-- quote.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package quote collects pithy sayings.
+package quote // import "rsc.io/quote"
+
+import "rsc.io/quote/v2"
+
+// Hello returns a greeting.
+func Hello() string {
+ return quote.HelloV2()
+}
+
+// Glass returns a useful phrase for world travelers.
+func Glass() string {
+ // See http://www.oocities.org/nodotus/hbglass.html.
+ return quote.GlassV2()
+}
+
+// Go returns a Go proverb.
+func Go() string {
+ return quote.GoV2()
+}
+
+// Opt returns an optimization truth.
+func Opt() string {
+ // Wisdom from ken.
+ return quote.OptV2()
+}
+-- quote_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package quote
+
+import (
+ "os"
+ "testing"
+)
+
+func init() {
+ os.Setenv("LC_ALL", "en")
+}
+
+func TestHello(t *testing.T) {
+ hello := "Hello, world."
+ if out := Hello(); out != hello {
+ t.Errorf("Hello() = %q, want %q", out, hello)
+ }
+}
+
+func TestGlass(t *testing.T) {
+ glass := "I can eat glass and it doesn't hurt me."
+ if out := Glass(); out != glass {
+ t.Errorf("Glass() = %q, want %q", out, glass)
+ }
+}
+
+func TestGo(t *testing.T) {
+ go1 := "Don't communicate by sharing memory, share memory by communicating."
+ if out := Go(); out != go1 {
+ t.Errorf("Go() = %q, want %q", out, go1)
+ }
+}
+
+func TestOpt(t *testing.T) {
+ opt := "If a program is too slow, it must have a loop."
+ if out := Opt(); out != opt {
+ t.Errorf("Opt() = %q, want %q", out, opt)
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162816-fe488b867524.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162816-fe488b867524.txt
new file mode 100644
index 00000000000..2d5d8b4e72a
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162816-fe488b867524.txt
@@ -0,0 +1,104 @@
+rsc.io/quote@v0.0.0-20180709162816-fe488b867524
+
+-- .mod --
+module rsc.io/quote
+
+require (
+ rsc.io/quote/v2 v2.0.1
+ rsc.io/sampler v1.3.0
+)
+-- .info --
+{"Version":"v0.0.0-20180709162816-fe488b867524","Name":"fe488b867524806e861c3f4f43ae6946a42ca3f1","Short":"fe488b867524","Time":"2018-07-09T16:28:16Z"}
+-- buggy/buggy_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package buggy
+
+import "testing"
+
+func Test(t *testing.T) {
+ t.Fatal("buggy!")
+}
+-- go.mod --
+module rsc.io/quote
+
+require (
+ rsc.io/quote/v2 v2.0.1
+ rsc.io/sampler v1.3.0
+)
+-- quote.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package quote collects pithy sayings.
+package quote // import "rsc.io/quote"
+
+import "rsc.io/quote/v2"
+
+// Hello returns a greeting.
+func Hello() string {
+ return quote.HelloV2()
+}
+
+// Glass returns a useful phrase for world travelers.
+func Glass() string {
+ // See http://www.oocities.org/nodotus/hbglass.html.
+ return quote.GlassV2()
+}
+
+// Go returns a Go proverb.
+func Go() string {
+ return quote.GoV2()
+}
+
+// Opt returns an optimization truth.
+func Opt() string {
+ // Wisdom from ken.
+ return quote.OptV2()
+}
+-- quote_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package quote
+
+import (
+ "os"
+ "testing"
+)
+
+func init() {
+ os.Setenv("LC_ALL", "en")
+}
+
+func TestHello(t *testing.T) {
+ hello := "Hello, world."
+ if out := Hello(); out != hello {
+ t.Errorf("Hello() = %q, want %q", out, hello)
+ }
+}
+
+func TestGlass(t *testing.T) {
+ glass := "I can eat glass and it doesn't hurt me."
+ if out := Glass(); out != glass {
+ t.Errorf("Glass() = %q, want %q", out, glass)
+ }
+}
+
+func TestGo(t *testing.T) {
+ go1 := "Don't communicate by sharing memory, share memory by communicating."
+ if out := Go(); out != go1 {
+ t.Errorf("Go() = %q, want %q", out, go1)
+ }
+}
+
+func TestOpt(t *testing.T) {
+ opt := "If a program is too slow, it must have a loop."
+ if out := Opt(); out != opt {
+ t.Errorf("Opt() = %q, want %q", out, opt)
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162918-a91498bed0a7.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162918-a91498bed0a7.txt
new file mode 100644
index 00000000000..853a8c2a1ac
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162918-a91498bed0a7.txt
@@ -0,0 +1,98 @@
+rsc.io/quote@v0.0.0-20180709162918-a91498bed0a7
+
+-- .mod --
+module rsc.io/quote
+
+require rsc.io/sampler v1.3.0
+-- .info --
+{"Version":"v0.0.0-20180709162918-a91498bed0a7","Name":"a91498bed0a73d4bb9c1fb2597925f7883bc40a7","Short":"a91498bed0a7","Time":"2018-07-09T16:29:18Z"}
+-- buggy/buggy_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package buggy
+
+import "testing"
+
+func Test(t *testing.T) {
+ t.Fatal("buggy!")
+}
+-- go.mod --
+module rsc.io/quote
+
+require rsc.io/sampler v1.3.0
+-- quote.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package quote collects pithy sayings.
+package quote // import "rsc.io/quote"
+
+import "rsc.io/quote/v3"
+
+// Hello returns a greeting.
+func Hello() string {
+ return quote.HelloV3()
+}
+
+// Glass returns a useful phrase for world travelers.
+func Glass() string {
+ // See http://www.oocities.org/nodotus/hbglass.html.
+ return quote.GlassV3()
+}
+
+// Go returns a Go proverb.
+func Go() string {
+ return quote.GoV3()
+}
+
+// Opt returns an optimization truth.
+func Opt() string {
+ // Wisdom from ken.
+ return quote.OptV3()
+}
+-- quote_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package quote
+
+import (
+ "os"
+ "testing"
+)
+
+func init() {
+ os.Setenv("LC_ALL", "en")
+}
+
+func TestHello(t *testing.T) {
+ hello := "Hello, world."
+ if out := Hello(); out != hello {
+ t.Errorf("Hello() = %q, want %q", out, hello)
+ }
+}
+
+func TestGlass(t *testing.T) {
+ glass := "I can eat glass and it doesn't hurt me."
+ if out := Glass(); out != glass {
+ t.Errorf("Glass() = %q, want %q", out, glass)
+ }
+}
+
+func TestGo(t *testing.T) {
+ go1 := "Don't communicate by sharing memory, share memory by communicating."
+ if out := Go(); out != go1 {
+ t.Errorf("Go() = %q, want %q", out, go1)
+ }
+}
+
+func TestOpt(t *testing.T) {
+ opt := "If a program is too slow, it must have a loop."
+ if out := Opt(); out != opt {
+ t.Errorf("Opt() = %q, want %q", out, opt)
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180710144737-5d9f230bcfba.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180710144737-5d9f230bcfba.txt
new file mode 100644
index 00000000000..2ebeac39714
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180710144737-5d9f230bcfba.txt
@@ -0,0 +1,104 @@
+rsc.io/quote@v0.0.0-20180710144737-5d9f230bcfba
+
+-- .mod --
+module rsc.io/quote
+
+require (
+ rsc.io/quote/v3 v3.0.0
+ rsc.io/sampler v1.3.0
+)
+-- .info --
+{"Version":"v0.0.0-20180710144737-5d9f230bcfba","Name":"5d9f230bcfbae514bb6c2215694c2ce7273fc604","Short":"5d9f230bcfba","Time":"2018-07-10T14:47:37Z"}
+-- buggy/buggy_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package buggy
+
+import "testing"
+
+func Test(t *testing.T) {
+ t.Fatal("buggy!")
+}
+-- go.mod --
+module rsc.io/quote
+
+require (
+ rsc.io/quote/v3 v3.0.0
+ rsc.io/sampler v1.3.0
+)
+-- quote.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package quote collects pithy sayings.
+package quote // import "rsc.io/quote"
+
+import "rsc.io/quote/v3"
+
+// Hello returns a greeting.
+func Hello() string {
+ return quote.HelloV3()
+}
+
+// Glass returns a useful phrase for world travelers.
+func Glass() string {
+ // See http://www.oocities.org/nodotus/hbglass.html.
+ return quote.GlassV3()
+}
+
+// Go returns a Go proverb.
+func Go() string {
+ return quote.GoV3()
+}
+
+// Opt returns an optimization truth.
+func Opt() string {
+ // Wisdom from ken.
+ return quote.OptV3()
+}
+-- quote_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package quote
+
+import (
+ "os"
+ "testing"
+)
+
+func init() {
+ os.Setenv("LC_ALL", "en")
+}
+
+func TestHello(t *testing.T) {
+ hello := "Hello, world."
+ if out := Hello(); out != hello {
+ t.Errorf("Hello() = %q, want %q", out, hello)
+ }
+}
+
+func TestGlass(t *testing.T) {
+ glass := "I can eat glass and it doesn't hurt me."
+ if out := Glass(); out != glass {
+ t.Errorf("Glass() = %q, want %q", out, glass)
+ }
+}
+
+func TestGo(t *testing.T) {
+ go1 := "Don't communicate by sharing memory, share memory by communicating."
+ if out := Go(); out != go1 {
+ t.Errorf("Go() = %q, want %q", out, go1)
+ }
+}
+
+func TestOpt(t *testing.T) {
+ opt := "If a program is too slow, it must have a loop."
+ if out := Opt(); out != opt {
+ t.Errorf("Opt() = %q, want %q", out, opt)
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.0.0.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.0.0.txt
new file mode 100644
index 00000000000..9a079374445
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.0.0.txt
@@ -0,0 +1,35 @@
+rsc.io/quote@v1.0.0
+
+-- .mod --
+module "rsc.io/quote"
+-- .info --
+{"Version":"v1.0.0","Name":"f488df80bcdbd3e5bafdc24ad7d1e79e83edd7e6","Short":"f488df80bcdb","Time":"2018-02-14T00:45:20Z"}
+-- go.mod --
+module "rsc.io/quote"
+-- quote.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package quote collects pithy sayings.
+package quote // import "rsc.io/quote"
+
+// Hello returns a greeting.
+func Hello() string {
+ return "Hello, world."
+}
+-- quote_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package quote
+
+import "testing"
+
+func TestHello(t *testing.T) {
+ hello := "Hello, world."
+ if out := Hello(); out != hello {
+ t.Errorf("Hello() = %q, want %q", out, hello)
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.1.0.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.1.0.txt
new file mode 100644
index 00000000000..0c416053901
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.1.0.txt
@@ -0,0 +1,48 @@
+rsc.io/quote@v1.1.0
+
+-- .mod --
+module "rsc.io/quote"
+-- .info --
+{"Version":"v1.1.0","Name":"cfd7145f43f92a8d56b4a3dd603795a3291381a9","Short":"cfd7145f43f9","Time":"2018-02-14T00:46:44Z"}
+-- go.mod --
+module "rsc.io/quote"
+-- quote.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package quote collects pithy sayings.
+package quote // import "rsc.io/quote"
+
+// Hello returns a greeting.
+func Hello() string {
+ return "Hello, world."
+}
+
+// Glass returns a useful phrase for world travelers.
+func Glass() string {
+ // See http://www.oocities.org/nodotus/hbglass.html.
+ return "I can eat glass and it doesn't hurt me."
+}
+-- quote_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package quote
+
+import "testing"
+
+func TestHello(t *testing.T) {
+ hello := "Hello, world."
+ if out := Hello(); out != hello {
+ t.Errorf("Hello() = %q, want %q", out, hello)
+ }
+}
+
+func TestGlass(t *testing.T) {
+ glass := "I can eat glass and it doesn't hurt me."
+ if out := Glass(); out != glass {
+ t.Errorf("Glass() = %q, want %q", out, glass)
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.2.0.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.2.0.txt
new file mode 100644
index 00000000000..e714f0b9137
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.2.0.txt
@@ -0,0 +1,61 @@
+rsc.io/quote@v1.2.0
+
+-- .mod --
+module "rsc.io/quote"
+-- .info --
+{"Version":"v1.2.0","Name":"d8a3de91045c932a1c71e545308fe97571d6d65c","Short":"d8a3de91045c","Time":"2018-02-14T00:47:51Z"}
+-- go.mod --
+module "rsc.io/quote"
+-- quote.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package quote collects pithy sayings.
+package quote // import "rsc.io/quote"
+
+// Hello returns a greeting.
+func Hello() string {
+ return "Hello, world."
+}
+
+// Glass returns a useful phrase for world travelers.
+func Glass() string {
+ // See http://www.oocities.org/nodotus/hbglass.html.
+ return "I can eat glass and it doesn't hurt me."
+}
+
+// Go returns a Go proverb.
+func Go() string {
+ return "Don't communicate by sharing memory, share memory by communicating."
+}
+-- quote_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package quote
+
+import "testing"
+
+func TestHello(t *testing.T) {
+ hello := "Hello, world."
+ if out := Hello(); out != hello {
+ t.Errorf("Hello() = %q, want %q", out, hello)
+ }
+}
+
+func TestGlass(t *testing.T) {
+ glass := "I can eat glass and it doesn't hurt me."
+ if out := Glass(); out != glass {
+ t.Errorf("Glass() = %q, want %q", out, glass)
+ }
+}
+
+// Go returns a Go proverb.
+func TestGo(t *testing.T) {
+ go1 := "Don't communicate by sharing memory. Share memory by communicating."
+ if out := Go(); out != go1 {
+ t.Errorf("Go() = %q, want %q", out, go1)
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.2.1.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.2.1.txt
new file mode 100644
index 00000000000..89d5191d3a0
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.2.1.txt
@@ -0,0 +1,60 @@
+rsc.io/quote@v1.2.1
+
+-- .mod --
+module "rsc.io/quote"
+-- .info --
+{"Version":"v1.2.1","Name":"5c1f03b64ab7aa958798a569a31924655dc41e76","Short":"5c1f03b64ab7","Time":"2018-02-14T00:54:20Z"}
+-- go.mod --
+module "rsc.io/quote"
+-- quote.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package quote collects pithy sayings.
+package quote // import "rsc.io/quote"
+
+// Hello returns a greeting.
+func Hello() string {
+ return "Hello, world."
+}
+
+// Glass returns a useful phrase for world travelers.
+func Glass() string {
+ // See http://www.oocities.org/nodotus/hbglass.html.
+ return "I can eat glass and it doesn't hurt me."
+}
+
+// Go returns a Go proverb.
+func Go() string {
+ return "Don't communicate by sharing memory, share memory by communicating."
+}
+-- quote_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package quote
+
+import "testing"
+
+func TestHello(t *testing.T) {
+ hello := "Hello, world."
+ if out := Hello(); out != hello {
+ t.Errorf("Hello() = %q, want %q", out, hello)
+ }
+}
+
+func TestGlass(t *testing.T) {
+ glass := "I can eat glass and it doesn't hurt me."
+ if out := Glass(); out != glass {
+ t.Errorf("Glass() = %q, want %q", out, glass)
+ }
+}
+
+func TestGo(t *testing.T) {
+ go1 := "Don't communicate by sharing memory, share memory by communicating."
+ if out := Go(); out != go1 {
+ t.Errorf("Go() = %q, want %q", out, go1)
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.3.0.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.3.0.txt
new file mode 100644
index 00000000000..d62766c7d2b
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.3.0.txt
@@ -0,0 +1,73 @@
+rsc.io/quote@v1.3.0
+
+-- .mod --
+module "rsc.io/quote"
+-- .info --
+{"Version":"v1.3.0","Name":"84de74b35823c1e49634f2262f1a58cfc951ebae","Short":"84de74b35823","Time":"2018-02-14T00:54:53Z"}
+-- go.mod --
+module "rsc.io/quote"
+-- quote.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package quote collects pithy sayings.
+package quote // import "rsc.io/quote"
+
+// Hello returns a greeting.
+func Hello() string {
+ return "Hello, world."
+}
+
+// Glass returns a useful phrase for world travelers.
+func Glass() string {
+ // See http://www.oocities.org/nodotus/hbglass.html.
+ return "I can eat glass and it doesn't hurt me."
+}
+
+// Go returns a Go proverb.
+func Go() string {
+ return "Don't communicate by sharing memory, share memory by communicating."
+}
+
+// Opt returns an optimization truth.
+func Opt() string {
+ // Wisdom from ken.
+ return "If a program is too slow, it must have a loop."
+}
+-- quote_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package quote
+
+import "testing"
+
+func TestHello(t *testing.T) {
+ hello := "Hello, world."
+ if out := Hello(); out != hello {
+ t.Errorf("Hello() = %q, want %q", out, hello)
+ }
+}
+
+func TestGlass(t *testing.T) {
+ glass := "I can eat glass and it doesn't hurt me."
+ if out := Glass(); out != glass {
+ t.Errorf("Glass() = %q, want %q", out, glass)
+ }
+}
+
+func TestGo(t *testing.T) {
+ go1 := "Don't communicate by sharing memory, share memory by communicating."
+ if out := Go(); out != go1 {
+ t.Errorf("Go() = %q, want %q", out, go1)
+ }
+}
+
+func TestOpt(t *testing.T) {
+ opt := "If a program is too slow, it must have a loop."
+ if out := Opt(); out != opt {
+ t.Errorf("Opt() = %q, want %q", out, opt)
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.4.0.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.4.0.txt
new file mode 100644
index 00000000000..698ff8de812
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.4.0.txt
@@ -0,0 +1,79 @@
+rsc.io/quote@v1.4.0
+
+-- .mod --
+module "rsc.io/quote"
+
+require "rsc.io/sampler" v1.0.0
+-- .info --
+{"Version":"v1.4.0","Name":"19e8b977bd2f437798c2cc2dcfe8a1c0f169481b","Short":"19e8b977bd2f","Time":"2018-02-14T00:56:05Z"}
+-- go.mod --
+module "rsc.io/quote"
+
+require "rsc.io/sampler" v1.0.0
+-- quote.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package quote collects pithy sayings.
+package quote // import "rsc.io/quote"
+
+import "rsc.io/sampler"
+
+// Hello returns a greeting.
+func Hello() string {
+ return sampler.Hello()
+}
+
+// Glass returns a useful phrase for world travelers.
+func Glass() string {
+ // See http://www.oocities.org/nodotus/hbglass.html.
+ return "I can eat glass and it doesn't hurt me."
+}
+
+// Go returns a Go proverb.
+func Go() string {
+ return "Don't communicate by sharing memory, share memory by communicating."
+}
+
+// Opt returns an optimization truth.
+func Opt() string {
+ // Wisdom from ken.
+ return "If a program is too slow, it must have a loop."
+}
+-- quote_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package quote
+
+import "testing"
+
+func TestHello(t *testing.T) {
+ hello := "Hello, world."
+ if out := Hello(); out != hello {
+ t.Errorf("Hello() = %q, want %q", out, hello)
+ }
+}
+
+func TestGlass(t *testing.T) {
+ glass := "I can eat glass and it doesn't hurt me."
+ if out := Glass(); out != glass {
+ t.Errorf("Glass() = %q, want %q", out, glass)
+ }
+}
+
+func TestGo(t *testing.T) {
+ go1 := "Don't communicate by sharing memory, share memory by communicating."
+ if out := Go(); out != go1 {
+ t.Errorf("Go() = %q, want %q", out, go1)
+ }
+}
+
+func TestOpt(t *testing.T) {
+ opt := "If a program is too slow, it must have a loop."
+ if out := Opt(); out != opt {
+ t.Errorf("Opt() = %q, want %q", out, opt)
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.5.0.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.5.0.txt
new file mode 100644
index 00000000000..e7fcdbccff5
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.5.0.txt
@@ -0,0 +1,79 @@
+rsc.io/quote@v1.5.0
+
+-- .mod --
+module "rsc.io/quote"
+
+require "rsc.io/sampler" v1.3.0
+-- .info --
+{"Version":"v1.5.0","Name":"3ba1e30dc83bd52c990132b9dfb1688a9d22de13","Short":"3ba1e30dc83b","Time":"2018-02-14T00:58:15Z"}
+-- go.mod --
+module "rsc.io/quote"
+
+require "rsc.io/sampler" v1.3.0
+-- quote.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package quote collects pithy sayings.
+package quote // import "rsc.io/quote"
+
+import "rsc.io/sampler"
+
+// Hello returns a greeting.
+func Hello() string {
+ return sampler.Hello()
+}
+
+// Glass returns a useful phrase for world travelers.
+func Glass() string {
+ // See http://www.oocities.org/nodotus/hbglass.html.
+ return "I can eat glass and it doesn't hurt me."
+}
+
+// Go returns a Go proverb.
+func Go() string {
+ return "Don't communicate by sharing memory, share memory by communicating."
+}
+
+// Opt returns an optimization truth.
+func Opt() string {
+ // Wisdom from ken.
+ return "If a program is too slow, it must have a loop."
+}
+-- quote_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package quote
+
+import "testing"
+
+func TestHello(t *testing.T) {
+ hello := "Hello, world."
+ if out := Hello(); out != hello {
+ t.Errorf("Hello() = %q, want %q", out, hello)
+ }
+}
+
+func TestGlass(t *testing.T) {
+ glass := "I can eat glass and it doesn't hurt me."
+ if out := Glass(); out != glass {
+ t.Errorf("Glass() = %q, want %q", out, glass)
+ }
+}
+
+func TestGo(t *testing.T) {
+ go1 := "Don't communicate by sharing memory, share memory by communicating."
+ if out := Go(); out != go1 {
+ t.Errorf("Go() = %q, want %q", out, go1)
+ }
+}
+
+func TestOpt(t *testing.T) {
+ opt := "If a program is too slow, it must have a loop."
+ if out := Opt(); out != opt {
+ t.Errorf("Opt() = %q, want %q", out, opt)
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.5.1.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.5.1.txt
new file mode 100644
index 00000000000..eed051bea04
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.5.1.txt
@@ -0,0 +1,86 @@
+rsc.io/quote@23179ee8a569
+
+-- .mod --
+module "rsc.io/quote"
+
+require "rsc.io/sampler" v1.3.0
+-- .info --
+{"Version":"v1.5.1","Name":"23179ee8a569bb05d896ae05c6503ec69a19f99f","Short":"23179ee8a569","Time":"2018-02-14T00:58:40Z"}
+-- go.mod --
+module "rsc.io/quote"
+
+require "rsc.io/sampler" v1.3.0
+-- quote.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package quote collects pithy sayings.
+package quote // import "rsc.io/quote"
+
+import "rsc.io/sampler"
+
+// Hello returns a greeting.
+func Hello() string {
+ return sampler.Hello()
+}
+
+// Glass returns a useful phrase for world travelers.
+func Glass() string {
+ // See http://www.oocities.org/nodotus/hbglass.html.
+ return "I can eat glass and it doesn't hurt me."
+}
+
+// Go returns a Go proverb.
+func Go() string {
+ return "Don't communicate by sharing memory, share memory by communicating."
+}
+
+// Opt returns an optimization truth.
+func Opt() string {
+ // Wisdom from ken.
+ return "If a program is too slow, it must have a loop."
+}
+-- quote_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package quote
+
+import (
+ "os"
+ "testing"
+)
+
+func init() {
+ os.Setenv("LC_ALL", "en")
+}
+
+func TestHello(t *testing.T) {
+ hello := "Hello, world."
+ if out := Hello(); out != hello {
+ t.Errorf("Hello() = %q, want %q", out, hello)
+ }
+}
+
+func TestGlass(t *testing.T) {
+ glass := "I can eat glass and it doesn't hurt me."
+ if out := Glass(); out != glass {
+ t.Errorf("Glass() = %q, want %q", out, glass)
+ }
+}
+
+func TestGo(t *testing.T) {
+ go1 := "Don't communicate by sharing memory, share memory by communicating."
+ if out := Go(); out != go1 {
+ t.Errorf("Go() = %q, want %q", out, go1)
+ }
+}
+
+func TestOpt(t *testing.T) {
+ opt := "If a program is too slow, it must have a loop."
+ if out := Opt(); out != opt {
+ t.Errorf("Opt() = %q, want %q", out, opt)
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.5.2.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.5.2.txt
new file mode 100644
index 00000000000..8671f6fe772
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.5.2.txt
@@ -0,0 +1,98 @@
+rsc.io/quote@v1.5.2
+
+-- .mod --
+module "rsc.io/quote"
+
+require "rsc.io/sampler" v1.3.0
+-- .info --
+{"Version":"v1.5.2","Name":"c4d4236f92427c64bfbcf1cc3f8142ab18f30b22","Short":"c4d4236f9242","Time":"2018-02-14T15:44:20Z"}
+-- buggy/buggy_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package buggy
+
+import "testing"
+
+func Test(t *testing.T) {
+ t.Fatal("buggy!")
+}
+-- go.mod --
+module "rsc.io/quote"
+
+require "rsc.io/sampler" v1.3.0
+-- quote.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package quote collects pithy sayings.
+package quote // import "rsc.io/quote"
+
+import "rsc.io/sampler"
+
+// Hello returns a greeting.
+func Hello() string {
+ return sampler.Hello()
+}
+
+// Glass returns a useful phrase for world travelers.
+func Glass() string {
+ // See http://www.oocities.org/nodotus/hbglass.html.
+ return "I can eat glass and it doesn't hurt me."
+}
+
+// Go returns a Go proverb.
+func Go() string {
+ return "Don't communicate by sharing memory, share memory by communicating."
+}
+
+// Opt returns an optimization truth.
+func Opt() string {
+ // Wisdom from ken.
+ return "If a program is too slow, it must have a loop."
+}
+-- quote_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package quote
+
+import (
+ "os"
+ "testing"
+)
+
+func init() {
+ os.Setenv("LC_ALL", "en")
+}
+
+func TestHello(t *testing.T) {
+ hello := "Hello, world."
+ if out := Hello(); out != hello {
+ t.Errorf("Hello() = %q, want %q", out, hello)
+ }
+}
+
+func TestGlass(t *testing.T) {
+ glass := "I can eat glass and it doesn't hurt me."
+ if out := Glass(); out != glass {
+ t.Errorf("Glass() = %q, want %q", out, glass)
+ }
+}
+
+func TestGo(t *testing.T) {
+ go1 := "Don't communicate by sharing memory, share memory by communicating."
+ if out := Go(); out != go1 {
+ t.Errorf("Go() = %q, want %q", out, go1)
+ }
+}
+
+func TestOpt(t *testing.T) {
+ opt := "If a program is too slow, it must have a loop."
+ if out := Opt(); out != opt {
+ t.Errorf("Opt() = %q, want %q", out, opt)
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.5.3-pre1.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.5.3-pre1.txt
new file mode 100644
index 00000000000..212ef13aaf8
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v1.5.3-pre1.txt
@@ -0,0 +1,100 @@
+rsc.io/quote@v1.5.3-pre1
+
+-- .mod --
+module "rsc.io/quote"
+
+require "rsc.io/sampler" v1.3.0
+-- .info --
+{"Version":"v1.5.3-pre1","Name":"2473dfd877c95382420e47686aa9076bf58c79e0","Short":"2473dfd877c9","Time":"2018-06-28T00:32:53Z"}
+-- buggy/buggy_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package buggy
+
+import "testing"
+
+func Test(t *testing.T) {
+ t.Fatal("buggy!")
+}
+-- go.mod --
+module "rsc.io/quote"
+
+require "rsc.io/sampler" v1.3.0
+-- quote.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package quote collects pithy sayings.
+package quote // import "rsc.io/quote"
+
+import "rsc.io/sampler"
+
+// A CHANGE!
+
+// Hello returns a greeting.
+func Hello() string {
+ return sampler.Hello()
+}
+
+// Glass returns a useful phrase for world travelers.
+func Glass() string {
+ // See http://www.oocities.org/nodotus/hbglass.html.
+ return "I can eat glass and it doesn't hurt me."
+}
+
+// Go returns a Go proverb.
+func Go() string {
+ return "Don't communicate by sharing memory, share memory by communicating."
+}
+
+// Opt returns an optimization truth.
+func Opt() string {
+ // Wisdom from ken.
+ return "If a program is too slow, it must have a loop."
+}
+-- quote_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package quote
+
+import (
+ "os"
+ "testing"
+)
+
+func init() {
+ os.Setenv("LC_ALL", "en")
+}
+
+func TestHello(t *testing.T) {
+ hello := "Hello, world."
+ if out := Hello(); out != hello {
+ t.Errorf("Hello() = %q, want %q", out, hello)
+ }
+}
+
+func TestGlass(t *testing.T) {
+ glass := "I can eat glass and it doesn't hurt me."
+ if out := Glass(); out != glass {
+ t.Errorf("Glass() = %q, want %q", out, glass)
+ }
+}
+
+func TestGo(t *testing.T) {
+ go1 := "Don't communicate by sharing memory, share memory by communicating."
+ if out := Go(); out != go1 {
+ t.Errorf("Go() = %q, want %q", out, go1)
+ }
+}
+
+func TestOpt(t *testing.T) {
+ opt := "If a program is too slow, it must have a loop."
+ if out := Opt(); out != opt {
+ t.Errorf("Opt() = %q, want %q", out, opt)
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v2.0.0.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v2.0.0.txt
new file mode 100644
index 00000000000..e461ed4231e
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v2.0.0.txt
@@ -0,0 +1,86 @@
+rsc.io/quote@v2.0.0
+
+-- .mod --
+module "rsc.io/quote"
+
+require "rsc.io/sampler" v1.3.0
+-- .info --
+{"Version":"v0.0.0-20180709153244-fd906ed3b100","Name":"fd906ed3b100e47181ffa9ec36d82294525c9109","Short":"fd906ed3b100","Time":"2018-07-09T15:32:44Z"}
+-- go.mod --
+module "rsc.io/quote"
+
+require "rsc.io/sampler" v1.3.0
+-- quote.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package quote collects pithy sayings.
+package quote // import "rsc.io/quote"
+
+import "rsc.io/sampler"
+
+// Hello returns a greeting.
+func HelloV2() string {
+ return sampler.Hello()
+}
+
+// Glass returns a useful phrase for world travelers.
+func GlassV2() string {
+ // See http://www.oocities.org/nodotus/hbglass.html.
+ return "I can eat glass and it doesn't hurt me."
+}
+
+// Go returns a Go proverb.
+func GoV2() string {
+ return "Don't communicate by sharing memory, share memory by communicating."
+}
+
+// Opt returns an optimization truth.
+func OptV2() string {
+ // Wisdom from ken.
+ return "If a program is too slow, it must have a loop."
+}
+-- quote_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package quote
+
+import (
+ "os"
+ "testing"
+)
+
+func init() {
+ os.Setenv("LC_ALL", "en")
+}
+
+func TestHello(t *testing.T) {
+ hello := "Hello, world."
+ if out := Hello(); out != hello {
+ t.Errorf("Hello() = %q, want %q", out, hello)
+ }
+}
+
+func TestGlass(t *testing.T) {
+ glass := "I can eat glass and it doesn't hurt me."
+ if out := Glass(); out != glass {
+ t.Errorf("Glass() = %q, want %q", out, glass)
+ }
+}
+
+func TestGo(t *testing.T) {
+ go1 := "Don't communicate by sharing memory, share memory by communicating."
+ if out := Go(); out != go1 {
+ t.Errorf("Go() = %q, want %q", out, go1)
+ }
+}
+
+func TestOpt(t *testing.T) {
+ opt := "If a program is too slow, it must have a loop."
+ if out := Opt(); out != opt {
+ t.Errorf("Opt() = %q, want %q", out, opt)
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v2_v2.0.1.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v2_v2.0.1.txt
new file mode 100644
index 00000000000..d51128c46b9
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v2_v2.0.1.txt
@@ -0,0 +1,86 @@
+rsc.io/quote/v2@v2.0.1
+
+-- .mod --
+module rsc.io/quote/v2
+
+require rsc.io/sampler v1.3.0
+-- .info --
+{"Version":"v2.0.1","Name":"754f68430672776c84704e2d10209a6ec700cd64","Short":"754f68430672","Time":"2018-07-09T16:25:34Z"}
+-- go.mod --
+module rsc.io/quote/v2
+
+require rsc.io/sampler v1.3.0
+-- quote.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package quote collects pithy sayings.
+package quote // import "rsc.io/quote"
+
+import "rsc.io/sampler"
+
+// Hello returns a greeting.
+func HelloV2() string {
+ return sampler.Hello()
+}
+
+// Glass returns a useful phrase for world travelers.
+func GlassV2() string {
+ // See http://www.oocities.org/nodotus/hbglass.html.
+ return "I can eat glass and it doesn't hurt me."
+}
+
+// Go returns a Go proverb.
+func GoV2() string {
+ return "Don't communicate by sharing memory, share memory by communicating."
+}
+
+// Opt returns an optimization truth.
+func OptV2() string {
+ // Wisdom from ken.
+ return "If a program is too slow, it must have a loop."
+}
+-- quote_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package quote
+
+import (
+ "os"
+ "testing"
+)
+
+func init() {
+ os.Setenv("LC_ALL", "en")
+}
+
+func TestHello(t *testing.T) {
+ hello := "Hello, world."
+ if out := Hello(); out != hello {
+ t.Errorf("Hello() = %q, want %q", out, hello)
+ }
+}
+
+func TestGlass(t *testing.T) {
+ glass := "I can eat glass and it doesn't hurt me."
+ if out := Glass(); out != glass {
+ t.Errorf("Glass() = %q, want %q", out, glass)
+ }
+}
+
+func TestGo(t *testing.T) {
+ go1 := "Don't communicate by sharing memory, share memory by communicating."
+ if out := Go(); out != go1 {
+ t.Errorf("Go() = %q, want %q", out, go1)
+ }
+}
+
+func TestOpt(t *testing.T) {
+ opt := "If a program is too slow, it must have a loop."
+ if out := Opt(); out != opt {
+ t.Errorf("Opt() = %q, want %q", out, opt)
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v3_v3.0.0.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v3_v3.0.0.txt
new file mode 100644
index 00000000000..0afe1f05199
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_quote_v3_v3.0.0.txt
@@ -0,0 +1,45 @@
+rsc.io/quote/v3@v3.0.0
+
+-- .mod --
+module rsc.io/quote/v3
+
+require rsc.io/sampler v1.3.0
+
+-- .info --
+{"Version":"v3.0.0","Name":"d88915d7e77ed0fd35d0a022a2f244e2202fd8c8","Short":"d88915d7e77e","Time":"2018-07-09T15:34:46Z"}
+-- go.mod --
+module rsc.io/quote/v3
+
+require rsc.io/sampler v1.3.0
+
+-- quote.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package quote collects pithy sayings.
+package quote // import "rsc.io/quote"
+
+import "rsc.io/sampler"
+
+// Hello returns a greeting.
+func HelloV3() string {
+ return sampler.Hello()
+}
+
+// Glass returns a useful phrase for world travelers.
+func GlassV3() string {
+ // See http://www.oocities.org/nodotus/hbglass.html.
+ return "I can eat glass and it doesn't hurt me."
+}
+
+// Go returns a Go proverb.
+func GoV3() string {
+ return "Don't communicate by sharing memory, share memory by communicating."
+}
+
+// Opt returns an optimization truth.
+func OptV3() string {
+ // Wisdom from ken.
+ return "If a program is too slow, it must have a loop."
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_sampler_v1.0.0.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_sampler_v1.0.0.txt
new file mode 100644
index 00000000000..c4b6a71c88c
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_sampler_v1.0.0.txt
@@ -0,0 +1,20 @@
+rsc.io/sampler@v1.0.0
+
+-- .mod --
+module "rsc.io/sampler"
+-- .info --
+{"Version":"v1.0.0","Name":"60bef405c52117ad21d2adb10872b95cf17f8fca","Short":"60bef405c521","Time":"2018-02-13T18:05:54Z"}
+-- go.mod --
+module "rsc.io/sampler"
+-- sampler.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package sampler shows simple texts.
+package sampler // import "rsc.io/sampler"
+
+// Hello returns a greeting.
+func Hello() string {
+ return "Hello, world."
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_sampler_v1.2.0.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_sampler_v1.2.0.txt
new file mode 100644
index 00000000000..98c35fa2389
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_sampler_v1.2.0.txt
@@ -0,0 +1,138 @@
+rsc.io/sampler@v1.2.0
+
+-- .mod --
+module "rsc.io/sampler"
+
+require "golang.org/x/text" v0.0.0-20170915032832-14c0d48ead0c
+-- .info --
+{"Version":"v1.2.0","Name":"25f24110b153246056eccc14a3a4cd81afaff586","Short":"25f24110b153","Time":"2018-02-13T18:13:45Z"}
+-- go.mod --
+module "rsc.io/sampler"
+
+require "golang.org/x/text" v0.0.0-20170915032832-14c0d48ead0c
+-- hello.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Translations by Google Translate.
+
+package sampler
+
+var hello = newText(`
+
+English: en: Hello, world.
+French: fr: Bonjour le monde.
+Spanish: es: Hola Mundo.
+
+`)
+-- hello_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sampler
+
+import (
+ "testing"
+
+ "golang.org/x/text/language"
+)
+
+var helloTests = []struct {
+ prefs []language.Tag
+ text string
+}{
+ {
+ []language.Tag{language.Make("en-US"), language.Make("fr")},
+ "Hello, world.",
+ },
+ {
+ []language.Tag{language.Make("fr"), language.Make("en-US")},
+ "Bonjour la monde.",
+ },
+}
+
+func TestHello(t *testing.T) {
+ for _, tt := range helloTests {
+ text := Hello(tt.prefs...)
+ if text != tt.text {
+ t.Errorf("Hello(%v) = %q, want %q", tt.prefs, text, tt.text)
+ }
+ }
+}
+-- sampler.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package sampler shows simple texts.
+package sampler // import "rsc.io/sampler"
+
+import (
+ "os"
+ "strings"
+
+ "golang.org/x/text/language"
+)
+
+// DefaultUserPrefs returns the default user language preferences.
+// It consults the $LC_ALL, $LC_MESSAGES, and $LANG environment
+// variables, in that order.
+func DefaultUserPrefs() []language.Tag {
+ var prefs []language.Tag
+ for _, k := range []string{"LC_ALL", "LC_MESSAGES", "LANG"} {
+ if env := os.Getenv(k); env != "" {
+ prefs = append(prefs, language.Make(env))
+ }
+ }
+ return prefs
+}
+
+// Hello returns a localized greeting.
+// If no prefs are given, Hello uses DefaultUserPrefs.
+func Hello(prefs ...language.Tag) string {
+ if len(prefs) == 0 {
+ prefs = DefaultUserPrefs()
+ }
+ return hello.find(prefs)
+}
+
+// A text is a localized text.
+type text struct {
+ byTag map[string]string
+ matcher language.Matcher
+}
+
+// newText creates a new localized text, given a list of translations.
+func newText(s string) *text {
+ t := &text{
+ byTag: make(map[string]string),
+ }
+ var tags []language.Tag
+ for _, line := range strings.Split(s, "\n") {
+ line = strings.TrimSpace(line)
+ if line == "" {
+ continue
+ }
+ f := strings.Split(line, ": ")
+ if len(f) != 3 {
+ continue
+ }
+ tag := language.Make(f[1])
+ tags = append(tags, tag)
+ t.byTag[tag.String()] = f[2]
+ }
+ t.matcher = language.NewMatcher(tags)
+ return t
+}
+
+// find finds the text to use for the given language tag preferences.
+func (t *text) find(prefs []language.Tag) string {
+ tag, _, _ := t.matcher.Match(prefs...)
+ s := t.byTag[tag.String()]
+ if strings.HasPrefix(s, "RTL ") {
+ s = "\u200F" + strings.TrimPrefix(s, "RTL ") + "\u200E"
+ }
+ return s
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_sampler_v1.2.1.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_sampler_v1.2.1.txt
new file mode 100644
index 00000000000..00b71bf0d59
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_sampler_v1.2.1.txt
@@ -0,0 +1,134 @@
+generated by ./addmod.bash rsc.io/sampler@v1.2.1
+
+-- .mod --
+module "rsc.io/sampler"
+
+require "golang.org/x/text" v0.0.0-20170915032832-14c0d48ead0c
+-- .info --
+{"Version":"v1.2.1","Name":"cac3af4f8a0ab40054fa6f8d423108a63a1255bb","Short":"cac3af4f8a0a","Time":"2018-02-13T18:16:22Z"}EOF
+-- hello.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Translations by Google Translate.
+
+package sampler
+
+var hello = newText(`
+
+English: en: Hello, world.
+French: fr: Bonjour le monde.
+Spanish: es: Hola Mundo.
+
+`)
+-- hello_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sampler
+
+import (
+ "testing"
+
+ "golang.org/x/text/language"
+)
+
+var helloTests = []struct {
+ prefs []language.Tag
+ text string
+}{
+ {
+ []language.Tag{language.Make("en-US"), language.Make("fr")},
+ "Hello, world.",
+ },
+ {
+ []language.Tag{language.Make("fr"), language.Make("en-US")},
+ "Bonjour le monde.",
+ },
+}
+
+func TestHello(t *testing.T) {
+ for _, tt := range helloTests {
+ text := Hello(tt.prefs...)
+ if text != tt.text {
+ t.Errorf("Hello(%v) = %q, want %q", tt.prefs, text, tt.text)
+ }
+ }
+}
+-- sampler.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package sampler shows simple texts.
+package sampler // import "rsc.io/sampler"
+
+import (
+ "os"
+ "strings"
+
+ "golang.org/x/text/language"
+)
+
+// DefaultUserPrefs returns the default user language preferences.
+// It consults the $LC_ALL, $LC_MESSAGES, and $LANG environment
+// variables, in that order.
+func DefaultUserPrefs() []language.Tag {
+ var prefs []language.Tag
+ for _, k := range []string{"LC_ALL", "LC_MESSAGES", "LANG"} {
+ if env := os.Getenv(k); env != "" {
+ prefs = append(prefs, language.Make(env))
+ }
+ }
+ return prefs
+}
+
+// Hello returns a localized greeting.
+// If no prefs are given, Hello uses DefaultUserPrefs.
+func Hello(prefs ...language.Tag) string {
+ if len(prefs) == 0 {
+ prefs = DefaultUserPrefs()
+ }
+ return hello.find(prefs)
+}
+
+// A text is a localized text.
+type text struct {
+ byTag map[string]string
+ matcher language.Matcher
+}
+
+// newText creates a new localized text, given a list of translations.
+func newText(s string) *text {
+ t := &text{
+ byTag: make(map[string]string),
+ }
+ var tags []language.Tag
+ for _, line := range strings.Split(s, "\n") {
+ line = strings.TrimSpace(line)
+ if line == "" {
+ continue
+ }
+ f := strings.Split(line, ": ")
+ if len(f) != 3 {
+ continue
+ }
+ tag := language.Make(f[1])
+ tags = append(tags, tag)
+ t.byTag[tag.String()] = f[2]
+ }
+ t.matcher = language.NewMatcher(tags)
+ return t
+}
+
+// find finds the text to use for the given language tag preferences.
+func (t *text) find(prefs []language.Tag) string {
+ tag, _, _ := t.matcher.Match(prefs...)
+ s := t.byTag[tag.String()]
+ if strings.HasPrefix(s, "RTL ") {
+ s = "\u200F" + strings.TrimPrefix(s, "RTL ") + "\u200E"
+ }
+ return s
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_sampler_v1.3.0.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_sampler_v1.3.0.txt
new file mode 100644
index 00000000000..febe51fd9a9
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_sampler_v1.3.0.txt
@@ -0,0 +1,202 @@
+rsc.io/sampler@v1.3.0
+
+-- .mod --
+module "rsc.io/sampler"
+
+require "golang.org/x/text" v0.0.0-20170915032832-14c0d48ead0c
+-- .info --
+{"Version":"v1.3.0","Name":"0cc034b51e57ed7832d4c67d526f75a900996e5c","Short":"0cc034b51e57","Time":"2018-02-13T19:05:03Z"}
+-- glass.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Translations from Frank da Cruz, Ethan Mollick, and many others.
+// See http://kermitproject.org/utf8.html.
+// http://www.oocities.org/nodotus/hbglass.html
+// https://en.wikipedia.org/wiki/I_Can_Eat_Glass
+
+package sampler
+
+var glass = newText(`
+
+English: en: I can eat glass and it doesn't hurt me.
+French: fr: Je peux manger du verre, ça ne me fait pas mal.
+Spanish: es: Puedo comer vidrio, no me hace daño.
+
+`)
+-- glass_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sampler
+
+import (
+ "testing"
+
+ "golang.org/x/text/language"
+ _ "rsc.io/testonly"
+)
+
+var glassTests = []struct {
+ prefs []language.Tag
+ text string
+}{
+ {
+ []language.Tag{language.Make("en-US"), language.Make("fr")},
+ "I can eat glass and it doesn't hurt me.",
+ },
+ {
+ []language.Tag{language.Make("fr"), language.Make("en-US")},
+ "Je peux manger du verre, ça ne me fait pas mal.",
+ },
+}
+
+func TestGlass(t *testing.T) {
+ for _, tt := range glassTests {
+ text := Glass(tt.prefs...)
+ if text != tt.text {
+ t.Errorf("Glass(%v) = %q, want %q", tt.prefs, text, tt.text)
+ }
+ }
+}
+-- go.mod --
+module "rsc.io/sampler"
+
+require "golang.org/x/text" v0.0.0-20170915032832-14c0d48ead0c
+-- hello.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Translations by Google Translate.
+
+package sampler
+
+var hello = newText(`
+
+English: en: Hello, world.
+French: fr: Bonjour le monde.
+Spanish: es: Hola Mundo.
+
+`)
+-- hello_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sampler
+
+import (
+ "testing"
+
+ "golang.org/x/text/language"
+)
+
+var helloTests = []struct {
+ prefs []language.Tag
+ text string
+}{
+ {
+ []language.Tag{language.Make("en-US"), language.Make("fr")},
+ "Hello, world.",
+ },
+ {
+ []language.Tag{language.Make("fr"), language.Make("en-US")},
+ "Bonjour le monde.",
+ },
+}
+
+func TestHello(t *testing.T) {
+ for _, tt := range helloTests {
+ text := Hello(tt.prefs...)
+ if text != tt.text {
+ t.Errorf("Hello(%v) = %q, want %q", tt.prefs, text, tt.text)
+ }
+ }
+}
+-- sampler.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package sampler shows simple texts.
+package sampler // import "rsc.io/sampler"
+
+import (
+ "os"
+ "strings"
+
+ "golang.org/x/text/language"
+)
+
+// DefaultUserPrefs returns the default user language preferences.
+// It consults the $LC_ALL, $LC_MESSAGES, and $LANG environment
+// variables, in that order.
+func DefaultUserPrefs() []language.Tag {
+ var prefs []language.Tag
+ for _, k := range []string{"LC_ALL", "LC_MESSAGES", "LANG"} {
+ if env := os.Getenv(k); env != "" {
+ prefs = append(prefs, language.Make(env))
+ }
+ }
+ return prefs
+}
+
+// Hello returns a localized greeting.
+// If no prefs are given, Hello uses DefaultUserPrefs.
+func Hello(prefs ...language.Tag) string {
+ if len(prefs) == 0 {
+ prefs = DefaultUserPrefs()
+ }
+ return hello.find(prefs)
+}
+
+// Glass returns a localized silly phrase.
+// If no prefs are given, Glass uses DefaultUserPrefs.
+func Glass(prefs ...language.Tag) string {
+ if len(prefs) == 0 {
+ prefs = DefaultUserPrefs()
+ }
+ return glass.find(prefs)
+}
+
+// A text is a localized text.
+type text struct {
+ byTag map[string]string
+ matcher language.Matcher
+}
+
+// newText creates a new localized text, given a list of translations.
+func newText(s string) *text {
+ t := &text{
+ byTag: make(map[string]string),
+ }
+ var tags []language.Tag
+ for _, line := range strings.Split(s, "\n") {
+ line = strings.TrimSpace(line)
+ if line == "" {
+ continue
+ }
+ f := strings.Split(line, ": ")
+ if len(f) != 3 {
+ continue
+ }
+ tag := language.Make(f[1])
+ tags = append(tags, tag)
+ t.byTag[tag.String()] = f[2]
+ }
+ t.matcher = language.NewMatcher(tags)
+ return t
+}
+
+// find finds the text to use for the given language tag preferences.
+func (t *text) find(prefs []language.Tag) string {
+ tag, _, _ := t.matcher.Match(prefs...)
+ s := t.byTag[tag.String()]
+ if strings.HasPrefix(s, "RTL ") {
+ s = "\u200F" + strings.TrimPrefix(s, "RTL ") + "\u200E"
+ }
+ return s
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_sampler_v1.3.1.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_sampler_v1.3.1.txt
new file mode 100644
index 00000000000..a293f108696
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_sampler_v1.3.1.txt
@@ -0,0 +1,201 @@
+rsc.io/sampler@v1.3.1
+
+-- .mod --
+module "rsc.io/sampler"
+
+require "golang.org/x/text" v0.0.0-20170915032832-14c0d48ead0c
+-- .info --
+{"Version":"v1.3.1","Name":"f545d0289d06e2add4556ea6a15fc4938014bf87","Short":"f545d0289d06","Time":"2018-02-14T16:34:12Z"}
+-- glass.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Translations from Frank da Cruz, Ethan Mollick, and many others.
+// See http://kermitproject.org/utf8.html.
+// http://www.oocities.org/nodotus/hbglass.html
+// https://en.wikipedia.org/wiki/I_Can_Eat_Glass
+
+package sampler
+
+var glass = newText(`
+
+English: en: I can eat glass and it doesn't hurt me.
+French: fr: Je peux manger du verre, ça ne me fait pas mal.
+Spanish: es: Puedo comer vidrio, no me hace daño.
+
+`)
+-- glass_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sampler
+
+import (
+ "testing"
+
+ "golang.org/x/text/language"
+)
+
+var glassTests = []struct {
+ prefs []language.Tag
+ text string
+}{
+ {
+ []language.Tag{language.Make("en-US"), language.Make("fr")},
+ "I can eat glass and it doesn't hurt me.",
+ },
+ {
+ []language.Tag{language.Make("fr"), language.Make("en-US")},
+ "Je peux manger du verre, ça ne me fait pas mal.",
+ },
+}
+
+func TestGlass(t *testing.T) {
+ for _, tt := range glassTests {
+ text := Glass(tt.prefs...)
+ if text != tt.text {
+ t.Errorf("Glass(%v) = %q, want %q", tt.prefs, text, tt.text)
+ }
+ }
+}
+-- go.mod --
+module "rsc.io/sampler"
+
+require "golang.org/x/text" v0.0.0-20170915032832-14c0d48ead0c
+-- hello.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Translations by Google Translate.
+
+package sampler
+
+var hello = newText(`
+
+English: en: Hello, world.
+French: fr: Bonjour le monde.
+Spanish: es: Hola Mundo.
+
+`)
+-- hello_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sampler
+
+import (
+ "testing"
+
+ "golang.org/x/text/language"
+)
+
+var helloTests = []struct {
+ prefs []language.Tag
+ text string
+}{
+ {
+ []language.Tag{language.Make("en-US"), language.Make("fr")},
+ "Hello, world.",
+ },
+ {
+ []language.Tag{language.Make("fr"), language.Make("en-US")},
+ "Bonjour le monde.",
+ },
+}
+
+func TestHello(t *testing.T) {
+ for _, tt := range helloTests {
+ text := Hello(tt.prefs...)
+ if text != tt.text {
+ t.Errorf("Hello(%v) = %q, want %q", tt.prefs, text, tt.text)
+ }
+ }
+}
+-- sampler.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package sampler shows simple texts in a variety of languages.
+package sampler // import "rsc.io/sampler"
+
+import (
+ "os"
+ "strings"
+
+ "golang.org/x/text/language"
+)
+
+// DefaultUserPrefs returns the default user language preferences.
+// It consults the $LC_ALL, $LC_MESSAGES, and $LANG environment
+// variables, in that order.
+func DefaultUserPrefs() []language.Tag {
+ var prefs []language.Tag
+ for _, k := range []string{"LC_ALL", "LC_MESSAGES", "LANG"} {
+ if env := os.Getenv(k); env != "" {
+ prefs = append(prefs, language.Make(env))
+ }
+ }
+ return prefs
+}
+
+// Hello returns a localized greeting.
+// If no prefs are given, Hello uses DefaultUserPrefs.
+func Hello(prefs ...language.Tag) string {
+ if len(prefs) == 0 {
+ prefs = DefaultUserPrefs()
+ }
+ return hello.find(prefs)
+}
+
+// Glass returns a localized silly phrase.
+// If no prefs are given, Glass uses DefaultUserPrefs.
+func Glass(prefs ...language.Tag) string {
+ if len(prefs) == 0 {
+ prefs = DefaultUserPrefs()
+ }
+ return glass.find(prefs)
+}
+
+// A text is a localized text.
+type text struct {
+ byTag map[string]string
+ matcher language.Matcher
+}
+
+// newText creates a new localized text, given a list of translations.
+func newText(s string) *text {
+ t := &text{
+ byTag: make(map[string]string),
+ }
+ var tags []language.Tag
+ for _, line := range strings.Split(s, "\n") {
+ line = strings.TrimSpace(line)
+ if line == "" {
+ continue
+ }
+ f := strings.Split(line, ": ")
+ if len(f) != 3 {
+ continue
+ }
+ tag := language.Make(f[1])
+ tags = append(tags, tag)
+ t.byTag[tag.String()] = f[2]
+ }
+ t.matcher = language.NewMatcher(tags)
+ return t
+}
+
+// find finds the text to use for the given language tag preferences.
+func (t *text) find(prefs []language.Tag) string {
+ tag, _, _ := t.matcher.Match(prefs...)
+ s := t.byTag[tag.String()]
+ if strings.HasPrefix(s, "RTL ") {
+ s = "\u200F" + strings.TrimPrefix(s, "RTL ") + "\u200E"
+ }
+ return s
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_sampler_v1.99.99.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_sampler_v1.99.99.txt
new file mode 100644
index 00000000000..5036d20ab58
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_sampler_v1.99.99.txt
@@ -0,0 +1,140 @@
+rsc.io/sampler@v1.99.99
+
+-- .mod --
+module "rsc.io/sampler"
+
+require "golang.org/x/text" v0.0.0-20170915032832-14c0d48ead0c
+-- .info --
+{"Version":"v1.99.99","Name":"732a3c400797d8835f2af34a9561f155bef85435","Short":"732a3c400797","Time":"2018-02-13T22:20:19Z"}
+-- go.mod --
+module "rsc.io/sampler"
+
+require "golang.org/x/text" v0.0.0-20170915032832-14c0d48ead0c
+-- hello.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Translations by Google Translate.
+
+package sampler
+
+var hello = newText(`
+
+English: en: 99 bottles of beer on the wall, 99 bottles of beer, ...
+
+`)
+-- hello_test.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sampler
+
+import (
+ "testing"
+
+ "golang.org/x/text/language"
+)
+
+var helloTests = []struct {
+ prefs []language.Tag
+ text string
+}{
+ {
+ []language.Tag{language.Make("en-US"), language.Make("fr")},
+ "Hello, world.",
+ },
+ {
+ []language.Tag{language.Make("fr"), language.Make("en-US")},
+ "Bonjour le monde.",
+ },
+}
+
+func TestHello(t *testing.T) {
+ for _, tt := range helloTests {
+ text := Hello(tt.prefs...)
+ if text != tt.text {
+ t.Errorf("Hello(%v) = %q, want %q", tt.prefs, text, tt.text)
+ }
+ }
+}
+-- sampler.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package sampler shows simple texts.
+package sampler // import "rsc.io/sampler"
+
+import (
+ "os"
+ "strings"
+
+ "golang.org/x/text/language"
+)
+
+// DefaultUserPrefs returns the default user language preferences.
+// It consults the $LC_ALL, $LC_MESSAGES, and $LANG environment
+// variables, in that order.
+func DefaultUserPrefs() []language.Tag {
+ var prefs []language.Tag
+ for _, k := range []string{"LC_ALL", "LC_MESSAGES", "LANG"} {
+ if env := os.Getenv(k); env != "" {
+ prefs = append(prefs, language.Make(env))
+ }
+ }
+ return prefs
+}
+
+// Hello returns a localized greeting.
+// If no prefs are given, Hello uses DefaultUserPrefs.
+func Hello(prefs ...language.Tag) string {
+ if len(prefs) == 0 {
+ prefs = DefaultUserPrefs()
+ }
+ return hello.find(prefs)
+}
+
+func Glass() string {
+ return "I can eat glass and it doesn't hurt me."
+}
+
+// A text is a localized text.
+type text struct {
+ byTag map[string]string
+ matcher language.Matcher
+}
+
+// newText creates a new localized text, given a list of translations.
+func newText(s string) *text {
+ t := &text{
+ byTag: make(map[string]string),
+ }
+ var tags []language.Tag
+ for _, line := range strings.Split(s, "\n") {
+ line = strings.TrimSpace(line)
+ if line == "" {
+ continue
+ }
+ f := strings.Split(line, ": ")
+ if len(f) != 3 {
+ continue
+ }
+ tag := language.Make(f[1])
+ tags = append(tags, tag)
+ t.byTag[tag.String()] = f[2]
+ }
+ t.matcher = language.NewMatcher(tags)
+ return t
+}
+
+// find finds the text to use for the given language tag preferences.
+func (t *text) find(prefs []language.Tag) string {
+ tag, _, _ := t.matcher.Match(prefs...)
+ s := t.byTag[tag.String()]
+ if strings.HasPrefix(s, "RTL ") {
+ s = "\u200F" + strings.TrimPrefix(s, "RTL ") + "\u200E"
+ }
+ return s
+}
diff --git a/libgo/go/cmd/go/testdata/mod/rsc.io_testonly_v1.0.0.txt b/libgo/go/cmd/go/testdata/mod/rsc.io_testonly_v1.0.0.txt
new file mode 100644
index 00000000000..dfb8ca24ec9
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/mod/rsc.io_testonly_v1.0.0.txt
@@ -0,0 +1,9 @@
+rsc.io/testonly v1.0.0
+written by hand
+
+-- .mod --
+module rsc.io/testonly
+-- .info --
+{"Version":"v1.0.0"}
+-- testonly.go --
+package testonly
diff --git a/libgo/go/cmd/go/testdata/savedir.go b/libgo/go/cmd/go/testdata/savedir.go
new file mode 100644
index 00000000000..48a63188607
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/savedir.go
@@ -0,0 +1,79 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+// Savedir archives a directory tree as a txtar archive printed to standard output.
+//
+// Usage:
+//
+// go run savedir.go /path/to/dir >saved.txt
+//
+// Typically the tree is later extracted during a test with tg.extract("testdata/saved.txt").
+//
+package main
+
+import (
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os"
+ "path/filepath"
+ "strings"
+ "unicode/utf8"
+
+ "../internal/txtar"
+)
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "usage: go run savedir.go dir >saved.txt\n")
+ os.Exit(2)
+}
+
+const goCmd = "vgo"
+
+func main() {
+ flag.Usage = usage
+ flag.Parse()
+ if flag.NArg() != 1 {
+ usage()
+ }
+
+ log.SetPrefix("savedir: ")
+ log.SetFlags(0)
+
+ dir := flag.Arg(0)
+
+ a := new(txtar.Archive)
+ dir = filepath.Clean(dir)
+ filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
+ if path == dir {
+ return nil
+ }
+ name := info.Name()
+ if strings.HasPrefix(name, ".") {
+ if info.IsDir() {
+ return filepath.SkipDir
+ }
+ return nil
+ }
+ if !info.Mode().IsRegular() {
+ return nil
+ }
+ data, err := ioutil.ReadFile(path)
+ if err != nil {
+ log.Fatal(err)
+ }
+ if !utf8.Valid(data) {
+ log.Printf("%s: ignoring invalid UTF-8 data", path)
+ return nil
+ }
+ a.Files = append(a.Files, txtar.File{Name: strings.TrimPrefix(path, dir+string(filepath.Separator)), Data: data})
+ return nil
+ })
+
+ data := txtar.Format(a)
+ os.Stdout.Write(data)
+}
diff --git a/libgo/go/cmd/go/testdata/script/README b/libgo/go/cmd/go/testdata/script/README
new file mode 100644
index 00000000000..a80233b8c38
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/README
@@ -0,0 +1,261 @@
+This directory holds test scripts *.txt run during 'go test cmd/go'.
+To run a specific script foo.txt
+
+ go test cmd/go -run=Script/^foo$
+
+In general script files should have short names: a few words, not whole sentences.
+The first word should be the general category of behavior being tested,
+often the name of a go subcommand (list, build, test, ...) or concept (vendor, pattern).
+
+Each script is a text archive (go doc cmd/go/internal/txtar).
+The script begins with an actual command script to run
+followed by the content of zero or more supporting files to
+create in the script's temporary file system before it starts executing.
+
+As an example, run_hello.txt says:
+
+ # hello world
+ go run hello.go
+ stderr 'hello world'
+ ! stdout .
+
+ -- hello.go --
+ package main
+ func main() { println("hello world") }
+
+Each script runs in a fresh temporary work directory tree, available to scripts as $WORK.
+Scripts also have access to these other environment variables:
+
+ GOARCH=<target GOARCH>
+ GOCACHE=<actual GOCACHE being used outside the test>
+ GOOS=<target GOOS>
+ GOPATH=$WORK/gopath
+ GOPROXY=<local module proxy serving from cmd/go/testdata/mod>
+ GOROOT=<actual GOROOT>
+ HOME=/no-home
+ PATH=<actual PATH>
+ TMPDIR=$WORK/tmp
+ devnull=<value of os.DevNull>
+
+The environment variable $exe (lowercase) is an empty string on most systems, ".exe" on Windows.
+
+The scripts supporting files are unpacked relative to $GOPATH/src (aka $WORK/gopath/src)
+and then the script begins execution in that directory as well. Thus the example above runs
+in $WORK/gopath/src with GOPATH=$WORK/gopath and $WORK/gopath/src/hello.go
+containing the listed contents.
+
+The lines at the top of the script are a sequence of commands to be executed
+by a tiny script engine in ../../script_test.go (not the system shell).
+The script stops and the overall test fails if any particular command fails.
+
+Each line is parsed into a sequence of space-separated command words,
+with environment variable expansion and # marking an end-of-line comment.
+Adding single quotes around text keeps spaces in that text from being treated
+as word separators and also disables environment variable expansion.
+Inside a single-quoted block of text, a repeated single quote indicates
+a literal single quote, as in:
+
+ 'Don''t communicate by sharing memory.'
+
+A line beginning with # is a comment and conventionally explains what is
+being done or tested at the start of a new phase in the script.
+
+The command prefix ! indicates that the command on the rest of the line
+(typically go or a matching predicate) must fail, not succeed. Only certain
+commands support this prefix. They are indicated below by [!] in the synopsis.
+
+The command prefix [cond] indicates that the command on the rest of the line
+should only run when the condition is satisfied. The available conditions are:
+
+ - GOOS and GOARCH values, like [386], [windows], and so on.
+ - Compiler names, like [gccgo], [gc].
+ - Test environment details:
+ - [short] for testing.Short()
+ - [cgo], [msan], [race] for whether cgo, msan, and the race detector can be used
+ - [net] for whether the external network can be used
+ - [link] for testenv.HasLink()
+ - [symlink] for testenv.HasSymlink()
+ - [exec:prog] for whether prog is available for execution (found by exec.LookPath)
+
+A condition can be negated: [!short] means to run the rest of the line
+when testing.Short() is false.
+
+The commands are:
+
+- cd dir
+ Change to the given directory for future commands.
+
+- cmp file1 file2
+ Check that the named files have the same content.
+ By convention, file1 is the actual data and file2 the expected data.
+ File1 can be "stdout" or "stderr" to use the standard output or standard error
+ from the most recent exec or go command.
+ (If the files have differing content, the failure prints a diff.)
+
+- cp src... dst
+ Copy the listed files to the target file or existing directory.
+
+- env [key=value...]
+ With no arguments, print the environment (useful for debugging).
+ Otherwise add the listed key=value pairs to the environment.
+
+- [!] exec program [args...]
+ Run the given executable program with the arguments.
+ It must (or must not) succeed.
+ Note that 'exec' does not terminate the script (unlike in Unix shells).
+
+- [!] exists [-readonly] file...
+ Each of the listed files or directories must (or must not) exist.
+ If -readonly is given, the files or directories must be unwritable.
+
+- [!] go args...
+ Run the (test copy of the) go command with the given arguments.
+ It must (or must not) succeed.
+
+- [!] grep [-count=N] pattern file
+ The file's content must (or must not) match the regular expression pattern.
+ For positive matches, -count=N specifies an exact number of matches to require.
+
+- mkdir path...
+ Create the listed directories, if they do not already exists.
+
+- rm file...
+ Remove the listed files or directories.
+
+- skip [message]
+ Mark the test skipped, including the message if given.
+
+- [!] stale path...
+ The packages named by the path arguments must (or must not)
+ be reported as "stale" by the go command.
+
+- [!] stderr [-count=N] pattern
+ Apply the grep command (see above) to the standard error
+ from the most recent exec or go command.
+
+- [!] stdout [-count=N] pattern
+ Apply the grep command (see above) to the standard output
+ from the most recent exec or go command.
+
+- stop [message]
+ Stop the test early (marking it as passing), including the message if given.
+
+- symlink file -> target
+ Create file as a symlink to target. The -> (like in ls -l output) is required.
+
+When TestScript runs a script and the script fails, by default TestScript shows
+the execution of the most recent phase of the script (since the last # comment)
+and only shows the # comments for earlier phases. For example, here is a
+multi-phase script with a bug in it:
+
+ # GOPATH with p1 in d2, p2 in d2
+ env GOPATH=$WORK/d1${:}$WORK/d2
+
+ # build & install p1
+ env
+ go install -i p1
+ ! stale p1
+ ! stale p2
+
+ # modify p2 - p1 should appear stale
+ cp $WORK/p2x.go $WORK/d2/src/p2/p2.go
+ stale p1 p2
+
+ # build & install p1 again
+ go install -i p11
+ ! stale p1
+ ! stale p2
+
+ -- $WORK/d1/src/p1/p1.go --
+ package p1
+ import "p2"
+ func F() { p2.F() }
+ -- $WORK/d2/src/p2/p2.go --
+ package p2
+ func F() {}
+ -- $WORK/p2x.go --
+ package p2
+ func F() {}
+ func G() {}
+
+The bug is that the final phase installs p11 instead of p1. The test failure looks like:
+
+ $ go test -run=Script
+ --- FAIL: TestScript (3.75s)
+ --- FAIL: TestScript/install_rebuild_gopath (0.16s)
+ script_test.go:223:
+ # GOPATH with p1 in d2, p2 in d2 (0.000s)
+ # build & install p1 (0.087s)
+ # modify p2 - p1 should appear stale (0.029s)
+ # build & install p1 again (0.022s)
+ > go install -i p11
+ [stderr]
+ can't load package: package p11: cannot find package "p11" in any of:
+ /Users/rsc/go/src/p11 (from $GOROOT)
+ $WORK/d1/src/p11 (from $GOPATH)
+ $WORK/d2/src/p11
+ [exit status 1]
+ FAIL: unexpected go command failure
+
+ script_test.go:73: failed at testdata/script/install_rebuild_gopath.txt:15 in $WORK/gopath/src
+
+ FAIL
+ exit status 1
+ FAIL cmd/go 4.875s
+ $
+
+Note that the commands in earlier phases have been hidden, so that the relevant
+commands are more easily found, and the elapsed time for a completed phase
+is shown next to the phase heading. To see the entire execution, use "go test -v",
+which also adds an initial environment dump to the beginning of the log.
+
+Note also that in reported output, the actual name of the per-script temporary directory
+has been consistently replaced with the literal string $WORK.
+
+The cmd/go test flag -testwork (which must appear on the "go test" command line after
+standard test flags) causes each test to log the name of its $WORK directory and other
+environment variable settings and also to leave that directory behind when it exits,
+for manual debugging of failing tests:
+
+ $ go test -run=Script -work
+ --- FAIL: TestScript (3.75s)
+ --- FAIL: TestScript/install_rebuild_gopath (0.16s)
+ script_test.go:223:
+ WORK=/tmp/cmd-go-test-745953508/script-install_rebuild_gopath
+ GOARCH=
+ GOCACHE=/Users/rsc/Library/Caches/go-build
+ GOOS=
+ GOPATH=$WORK/gopath
+ GOROOT=/Users/rsc/go
+ HOME=/no-home
+ TMPDIR=$WORK/tmp
+ exe=
+
+ # GOPATH with p1 in d2, p2 in d2 (0.000s)
+ # build & install p1 (0.085s)
+ # modify p2 - p1 should appear stale (0.030s)
+ # build & install p1 again (0.019s)
+ > go install -i p11
+ [stderr]
+ can't load package: package p11: cannot find package "p11" in any of:
+ /Users/rsc/go/src/p11 (from $GOROOT)
+ $WORK/d1/src/p11 (from $GOPATH)
+ $WORK/d2/src/p11
+ [exit status 1]
+ FAIL: unexpected go command failure
+
+ script_test.go:73: failed at testdata/script/install_rebuild_gopath.txt:15 in $WORK/gopath/src
+
+ FAIL
+ exit status 1
+ FAIL cmd/go 4.875s
+ $
+
+ $ WORK=/tmp/cmd-go-test-745953508/script-install_rebuild_gopath
+ $ cd $WORK/d1/src/p1
+ $ cat p1.go
+ package p1
+ import "p2"
+ func F() { p2.F() }
+ $
+
diff --git a/libgo/go/cmd/go/testdata/script/binary_only.txt b/libgo/go/cmd/go/testdata/script/binary_only.txt
new file mode 100644
index 00000000000..397904efaa8
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/binary_only.txt
@@ -0,0 +1,10 @@
+# check that error for missing binary-only says where it should be
+! go build b
+stderr pkg[\\/].*a\.a
+
+-- a/a.go --
+//go:binary-only-package
+
+package a
+-- b/b.go --
+package b; import "a"
diff --git a/libgo/go/cmd/go/testdata/script/build_GOTMPDIR.txt b/libgo/go/cmd/go/testdata/script/build_GOTMPDIR.txt
new file mode 100644
index 00000000000..4c387afbbab
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/build_GOTMPDIR.txt
@@ -0,0 +1,11 @@
+# Build should use GOTMPDIR if set.
+env GOTMPDIR=$WORK/my-favorite-tmpdir
+env GOCACHE=off
+mkdir $GOTMPDIR
+go build -work hello.go
+stderr ^WORK=.*my-favorite-tmpdir
+
+-- hello.go --
+package main
+func main() { println("hello") }
+
diff --git a/libgo/go/cmd/go/testdata/script/build_cache_compile.txt b/libgo/go/cmd/go/testdata/script/build_cache_compile.txt
new file mode 100644
index 00000000000..7db881a2682
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/build_cache_compile.txt
@@ -0,0 +1,18 @@
+# Set up fresh GOCACHE.
+env GOCACHE=$WORK/gocache
+mkdir $GOCACHE
+
+# Building trivial non-main package should run compiler the first time.
+go build -x lib.go
+stderr '(compile|gccgo)( |\.exe).*lib\.go'
+
+# ... but not again ...
+go build -x lib.go
+! stderr '(compile|gccgo)( |\.exe).*lib\.go'
+
+# ... unless we use -a.
+go build -a -x lib.go
+stderr '(compile|gccgo)( |\.exe)'
+
+-- lib.go --
+package lib
diff --git a/libgo/go/cmd/go/testdata/script/build_cache_link.txt b/libgo/go/cmd/go/testdata/script/build_cache_link.txt
new file mode 100644
index 00000000000..61e7ee46d3a
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/build_cache_link.txt
@@ -0,0 +1,23 @@
+# Set up fresh GOCACHE.
+env GOCACHE=$WORK/gocache
+mkdir $GOCACHE
+
+# Building a main package should run the compiler and linker ...
+go build -o $devnull -x main.go
+stderr '(compile|gccgo)( |\.exe).*main\.go'
+stderr '(link|gccgo)( |\.exe)'
+
+# ... and then the linker again ...
+go build -o $devnull -x main.go
+! stderr '(compile|gccgo)( |\.exe).*main\.go'
+stderr '(link|gccgo)( |\.exe)'
+
+# ... but the output binary can serve as a cache.
+go build -o main$exe -x main.go
+stderr '(link|gccgo)( |\.exe)'
+go build -o main$exe -x main.go
+! stderr '(link|gccgo)( |\.exe)'
+
+-- main.go --
+package main
+func main() {}
diff --git a/libgo/go/cmd/go/testdata/script/build_cache_output.txt b/libgo/go/cmd/go/testdata/script/build_cache_output.txt
new file mode 100644
index 00000000000..ee4099e5f35
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/build_cache_output.txt
@@ -0,0 +1,63 @@
+[!gc] skip
+
+# Set up fresh GOCACHE.
+env GOCACHE=$WORK/gocache
+mkdir $GOCACHE
+
+# Building a trivial non-main package should run compiler the first time.
+go build -x -gcflags=-m lib.go
+stderr 'compile( |\.exe"?)'
+stderr 'lib.go:2.* can inline f'
+
+# ... but not the second, even though it still prints the compiler output.
+go build -x -gcflags=-m lib.go
+! stderr 'compile( |\.exe"?)'
+stderr 'lib.go:2.* can inline f'
+
+# Building a trivial main package should run the compiler and linker the first time.
+go build -x -gcflags=-m -ldflags='-v -w' main.go
+stderr 'compile( |\.exe"?)'
+stderr 'main.go:2.* can inline main' # from compiler
+stderr 'link(\.exe"?)? -'
+stderr '\d+ symbols' # from linker
+
+# ... but not the second, even though it still prints the compiler and linker output.
+go build -x -gcflags=-m -ldflags='-v -w' main.go
+! stderr 'compile( |\.exe"?)'
+stderr 'main.go:2.* can inline main' # from compiler
+! stderr 'link(\.exe"?)? -'
+stderr '\d+ symbols' # from linker
+
+# Running a test should run the compiler, linker, and the test the first time.
+go test -v -x -gcflags=-m -ldflags=-v p_test.go
+stderr 'compile( |\.exe"?)'
+stderr 'p_test.go:.*can inline Test' # from compile of p_test
+stderr 'testmain\.go:.*inlin' # from compile of testmain
+stderr 'link(\.exe"?)? -'
+stderr '\d+ symbols' # from linker
+stderr 'p\.test( |\.exe"?)'
+stdout 'TEST' # from test
+
+# ... but not the second, even though it still prints the compiler, linker, and test output.
+go test -v -x -gcflags=-m -ldflags=-v p_test.go
+! stderr 'compile( |\.exe"?)'
+stderr 'p_test.go:.*can inline Test' # from compile of p_test
+stderr 'testmain\.go:.*inlin' # from compile of testmain
+! stderr 'link(\.exe"?)? -'
+stderr '\d+ symbols' # from linker
+! stderr 'p\.test( |\.exe"?)'
+stdout 'TEST' # from test
+
+
+-- lib.go --
+package p
+func f(x *int) *int { return x }
+
+-- main.go --
+package main
+func main() {}
+
+-- p_test.go --
+package p
+import "testing"
+func Test(t *testing.T) {println("TEST")}
diff --git a/libgo/go/cmd/go/testdata/script/cover_atomic_pkgall.txt b/libgo/go/cmd/go/testdata/script/cover_atomic_pkgall.txt
new file mode 100644
index 00000000000..c122c05cb68
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/cover_atomic_pkgall.txt
@@ -0,0 +1,23 @@
+[short] skip
+
+go test -coverpkg=all -covermode=atomic x
+stdout ok[\s\S]+?coverage
+
+[!race] stop
+
+go test -coverpkg=all -race x
+stdout ok[\s\S]+?coverage
+
+-- x/x.go --
+package x
+
+import _ "sync/atomic"
+
+func F() {}
+
+-- x/x_test.go --
+package x
+
+import "testing"
+
+func TestF(t *testing.T) { F() }
diff --git a/libgo/go/cmd/go/testdata/script/cover_pkgall_runtime.txt b/libgo/go/cmd/go/testdata/script/cover_pkgall_runtime.txt
new file mode 100644
index 00000000000..5d169d63126
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/cover_pkgall_runtime.txt
@@ -0,0 +1,21 @@
+# Issue 23882
+
+[short] skip
+
+go test -coverpkg=all x
+stdout ok[\s\S]+?coverage
+
+[!race] stop
+
+go test -coverpkg=all -race x
+stdout ok[\s\S]+?coverage
+
+-- x/x.go --
+package x
+import _ "runtime"
+func F() {}
+
+-- x/x_test.go --
+package x
+import "testing"
+func TestF(t *testing.T) { F() }
diff --git a/libgo/go/cmd/go/testdata/script/cpu_profile_twice.txt b/libgo/go/cmd/go/testdata/script/cpu_profile_twice.txt
new file mode 100644
index 00000000000..142d5ee718d
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/cpu_profile_twice.txt
@@ -0,0 +1,20 @@
+# Issue 23150
+
+[short] skip
+
+go test -o=$WORK/x.test -cpuprofile=$WORK/cpu_profile_twice.out x
+rm $WORK/cpu_profile_twice.out
+
+go test -o=$WORK/x.test -cpuprofile=$WORK/cpu_profile_twice.out x
+exists $WORK/cpu_profile_twice.out
+
+
+-- x/x_test.go --
+package x_test
+import (
+ "testing"
+ "time"
+)
+func TestSleep(t *testing.T) {
+ time.Sleep(10 * time.Millisecond)
+}
diff --git a/libgo/go/cmd/go/testdata/script/fileline.txt b/libgo/go/cmd/go/testdata/script/fileline.txt
new file mode 100644
index 00000000000..cdc3be2df8f
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/fileline.txt
@@ -0,0 +1,6 @@
+# look for short, relative file:line in error message
+! go run ../../gopath/x/y/z/err.go
+stderr ^..[\\/]x[\\/]y[\\/]z[\\/]err.go:
+
+-- ../x/y/z/err.go --
+package main; import "bar"
diff --git a/libgo/go/cmd/go/testdata/script/get_with_git_trace.txt b/libgo/go/cmd/go/testdata/script/get_with_git_trace.txt
new file mode 100644
index 00000000000..93341a302c8
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/get_with_git_trace.txt
@@ -0,0 +1,7 @@
+env GIT_TRACE=1
+
+[!net] skip
+[!exec:git] skip
+
+# go get should be success when GIT_TRACE set
+go get golang.org/x/text
diff --git a/libgo/go/cmd/go/testdata/script/goflags.txt b/libgo/go/cmd/go/testdata/script/goflags.txt
new file mode 100644
index 00000000000..20de325ac28
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/goflags.txt
@@ -0,0 +1,49 @@
+# GOFLAGS sets flags for commands
+
+env GOFLAGS='-e -f={{.Dir}} --test.benchtime=1s -count=10'
+go list asdfasdfasdf # succeeds because of -e
+go list runtime
+stdout '[\\/]runtime$'
+
+env GOFLAGS=-race OLDGOARCH=$GOARCH OLDGOOS=$GOOS GOARCH=386 GOOS=linux
+! go list runtime
+stderr 'race is only supported on'
+
+env GOARCH=$OLDGOARCH GOOS=$OLDGOOS
+
+# go env succeeds even though -f={{.Dir}} is inappropriate
+go env
+
+# bad flags are diagnosed
+env GOFLAGS=-typoflag
+! go list runtime
+stderr 'unknown flag -typoflag'
+
+env GOFLAGS=-
+! go list runtime
+stderr '^go: parsing \$GOFLAGS: non-flag "-"'
+
+env GOFLAGS=--
+! go list runtime
+stderr '^go: parsing \$GOFLAGS: non-flag "--"'
+
+env GOFLAGS=---oops
+! go list runtime
+stderr '^go: parsing \$GOFLAGS: non-flag "---oops"'
+
+env GOFLAGS=-=noname
+! go list runtime
+stderr '^go: parsing \$GOFLAGS: non-flag "-=noname"'
+
+env GOFLAGS=-f
+! go list runtime
+stderr '^go: flag needs an argument: -f \(from (\$GOFLAGS|%GOFLAGS%)\)$'
+
+env GOFLAGS=-e=asdf
+! go list runtime
+stderr '^go: invalid boolean value \"asdf\" for flag -e \(from (\$GOFLAGS|%GOFLAGS%)\)'
+
+# except in go bug (untested) and go env
+go env
+stdout GOFLAGS
+
diff --git a/libgo/go/cmd/go/testdata/script/help.txt b/libgo/go/cmd/go/testdata/script/help.txt
new file mode 100644
index 00000000000..cbbd15404b5
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/help.txt
@@ -0,0 +1,30 @@
+# go help shows overview.
+go help
+stdout 'Go is a tool'
+stdout 'bug.*start a bug report'
+
+# go help bug shows usage for bug
+go help bug
+stdout 'usage: go bug'
+stdout 'bug report'
+
+# go bug help is an error (bug takes no arguments)
+! go bug help
+stderr 'bug takes no arguments'
+
+# go help mod shows mod subcommands
+go help mod
+stdout 'go mod <command>'
+stdout tidy
+
+# go help mod tidy explains tidy
+go help mod tidy
+stdout 'usage: go mod tidy'
+
+# go mod help tidy does too
+go mod help tidy
+stdout 'usage: go mod tidy'
+
+# go mod --help doesn't print help but at least suggests it.
+! go mod --help
+stderr 'Run ''go help mod'' for usage.'
diff --git a/libgo/go/cmd/go/testdata/script/install_cleans_build.txt b/libgo/go/cmd/go/testdata/script/install_cleans_build.txt
new file mode 100644
index 00000000000..b8d322de629
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/install_cleans_build.txt
@@ -0,0 +1,22 @@
+# 'go install' with no arguments should clean up after go build
+cd mycmd
+go build
+exists mycmd$exe
+go install
+! exists mycmd$exe
+
+# 'go install mycmd' does not clean up, even in the mycmd directory
+go build
+exists mycmd$exe
+go install mycmd
+exists mycmd$exe
+
+# 'go install mycmd' should not clean up in an unrelated current directory either
+cd ..
+cp mycmd/mycmd$exe mycmd$exe
+go install mycmd
+exists mycmd$exe
+
+-- mycmd/main.go --
+package main
+func main() {}
diff --git a/libgo/go/cmd/go/testdata/script/install_cross_gobin.txt b/libgo/go/cmd/go/testdata/script/install_cross_gobin.txt
new file mode 100644
index 00000000000..f85e896f61e
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/install_cross_gobin.txt
@@ -0,0 +1,25 @@
+cd mycmd
+go build mycmd
+
+[gccgo] stop
+
+# cross-compile install with implicit GOBIN=$GOPATH/bin can make subdirectory
+env GOARCH=386
+[386] env GOARCH=amd64
+env GOOS=linux
+go install mycmd
+exists $GOPATH/bin/linux_$GOARCH/mycmd
+
+# cross-compile install with explicit GOBIN cannot make subdirectory
+env GOBIN=$WORK/bin
+! go install mycmd
+! exists $GOBIN/linux_$GOARCH
+
+# installing standard command should still work
+# (should also be mtime update only if cmd/pack is up-to-date).
+! stale cmd/pack
+[!short] go install cmd/pack
+
+-- mycmd/x.go --
+package main
+func main() {}
diff --git a/libgo/go/cmd/go/testdata/script/install_rebuild_gopath.txt b/libgo/go/cmd/go/testdata/script/install_rebuild_gopath.txt
new file mode 100644
index 00000000000..d42b07004bf
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/install_rebuild_gopath.txt
@@ -0,0 +1,28 @@
+# GOPATH with p1 in d1, p2 in d2
+env GOPATH=$WORK/d1${:}$WORK/d2
+
+# build & install p1
+go install -i p1
+! stale p1 p2
+
+# modify p2 - p1 should appear stale
+cp $WORK/p2x.go $WORK/d2/src/p2/p2.go
+stale p1 p2
+
+# build & install p1 again
+go install -i p1
+! stale p1 p2
+
+-- $WORK/d1/src/p1/p1.go --
+package p1
+import "p2"
+func F() { p2.F() }
+
+-- $WORK/d2/src/p2/p2.go --
+package p2
+func F() {}
+
+-- $WORK/p2x.go --
+package p2
+func F() {}
+func G() {}
diff --git a/libgo/go/cmd/go/testdata/script/install_rebuild_removed.txt b/libgo/go/cmd/go/testdata/script/install_rebuild_removed.txt
new file mode 100644
index 00000000000..e7620a08cae
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/install_rebuild_removed.txt
@@ -0,0 +1,42 @@
+# go command should detect package staleness as source file set changes
+go install mypkg
+! stale mypkg
+
+# z.go was not compiled; removing it should NOT make mypkg stale
+rm mypkg/z.go
+! stale mypkg
+
+# y.go was compiled; removing it should make mypkg stale
+rm mypkg/y.go
+stale mypkg
+
+# go command should detect executable staleness too
+go install mycmd
+! stale mycmd
+rm mycmd/z.go
+! stale mycmd
+rm mycmd/y.go
+stale mycmd
+
+-- mypkg/x.go --
+package mypkg
+
+-- mypkg/y.go --
+package mypkg
+
+-- mypkg/z.go --
+// +build missingtag
+
+package mypkg
+
+-- mycmd/x.go --
+package main
+func main() {}
+
+-- mycmd/y.go --
+package main
+
+-- mycmd/z.go --
+// +build missingtag
+
+package main
diff --git a/libgo/go/cmd/go/testdata/script/linkname.txt b/libgo/go/cmd/go/testdata/script/linkname.txt
new file mode 100644
index 00000000000..e2ec00c6edc
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/linkname.txt
@@ -0,0 +1,7 @@
+# check for linker name in error message about linker crash
+[!gc] skip
+! go build -ldflags=-crash_for_testing x.go
+stderr [\\/]tool[\\/].*[\\/]link
+
+-- x.go --
+package main; func main() {}
diff --git a/libgo/go/cmd/go/testdata/script/list_bad_import.txt b/libgo/go/cmd/go/testdata/script/list_bad_import.txt
new file mode 100644
index 00000000000..ba66b0937f8
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/list_bad_import.txt
@@ -0,0 +1,67 @@
+# This test matches mod_list_bad_import, but in GOPATH mode.
+# Please keep them in sync.
+
+env GO111MODULE=off
+cd example.com
+
+# Without -e, listing an otherwise-valid package with an unsatisfied direct import should fail.
+# BUG: Today it succeeds.
+go list -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}} {{range .DepsErrors}}bad dep: {{.Err}}{{end}}' example.com/direct
+! stdout ^error
+stdout 'incomplete'
+stdout 'bad dep: .*example.com[/\\]notfound'
+
+# Listing with -deps should also fail.
+# BUG: Today, it does not.
+# ! go list -deps example.com/direct
+# stderr example.com[/\\]notfound
+go list -deps example.com/direct
+stdout example.com/notfound
+
+
+# Listing an otherwise-valid package that imports some *other* package with an
+# unsatisfied import should also fail.
+# BUG: Today, it succeeds.
+go list -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}} {{range .DepsErrors}}bad dep: {{.Err}}{{end}}' example.com/indirect
+! stdout ^error
+stdout incomplete
+stdout 'bad dep: .*example.com[/\\]notfound'
+
+# Again, -deps should fail.
+# BUG: Again, it does not.
+# ! go list -deps example.com/indirect
+# stderr example.com[/\\]notfound
+go list -deps example.com/indirect
+stdout example.com/notfound
+
+
+# Listing the missing dependency directly should fail outright...
+! go list -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}}' example.com/notfound
+stderr 'no Go files in .*example.com[/\\]notfound'
+! stdout error
+! stdout incomplete
+
+# ...but listing with -e should succeed.
+go list -e -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}}' example.com/notfound
+stdout error
+stdout incomplete
+
+
+# The pattern "all" should match only packages that acutally exist,
+# ignoring those whose existence is merely implied by imports.
+go list -e -f '{{.ImportPath}}' all
+stdout example.com/direct
+stdout example.com/indirect
+! stdout example.com/notfound
+
+
+-- example.com/direct/direct.go --
+package direct
+import _ "example.com/notfound"
+
+-- example.com/indirect/indirect.go --
+package indirect
+import _ "example.com/direct"
+
+-- example.com/notfound/README --
+This directory intentionally left blank.
diff --git a/libgo/go/cmd/go/testdata/script/list_compiled_imports.txt b/libgo/go/cmd/go/testdata/script/list_compiled_imports.txt
new file mode 100644
index 00000000000..2c883b60610
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/list_compiled_imports.txt
@@ -0,0 +1,29 @@
+[!cgo] skip
+
+# go list should report import "C"
+cd x
+go list -f '{{.Imports}}'
+! stdout runtime/cgo
+! stdout unsafe
+! stdout syscall
+stdout C
+stdout unicode
+stdout unicode/utf16
+
+# go list -compiled should report imports in compiled files as well,
+# adding "runtime/cgo", "unsafe", and "syscall" but not dropping "C".
+go list -compiled -f '{{.Imports}}'
+[!gccgo] stdout runtime/cgo
+stdout unsafe
+stdout syscall
+stdout C
+stdout unicode
+stdout unicode/utf16
+
+-- x/x.go --
+package x
+import "C"
+import "unicode" // does not use unsafe, syscall, runtime/cgo, unicode/utf16
+-- x/x1.go --
+package x
+import "unicode/utf16" // does not use unsafe, syscall, runtime/cgo, unicode
diff --git a/libgo/go/cmd/go/testdata/script/list_find.txt b/libgo/go/cmd/go/testdata/script/list_find.txt
new file mode 100644
index 00000000000..dbe8fb0ac98
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/list_find.txt
@@ -0,0 +1,10 @@
+# go list -find should not report imports
+
+go list -f {{.Incomplete}} x/y/z... # should probably exit non-zero but never has
+stdout true
+go list -find -f '{{.Incomplete}} {{.Imports}}' x/y/z...
+stdout '^false \[\]'
+
+-- x/y/z/z.go --
+package z
+import "does/not/exist"
diff --git a/libgo/go/cmd/go/testdata/script/list_std.txt b/libgo/go/cmd/go/testdata/script/list_std.txt
new file mode 100644
index 00000000000..a63d74db120
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/list_std.txt
@@ -0,0 +1,12 @@
+[!gc] skip
+
+# listing GOROOT should only find standard packages
+cd $GOROOT/src
+go list -f '{{if not .Standard}}{{.ImportPath}}{{end}}' ./...
+! stdout .
+# TODO: ignore _/blah/go/src in output
+
+# our vendored packages should be reported as standard
+go list std cmd
+stdout golang_org/x/net/http2/hpack
+stdout cmd/vendor/golang\.org/x/arch/x86/x86asm
diff --git a/libgo/go/cmd/go/testdata/script/list_tags.txt b/libgo/go/cmd/go/testdata/script/list_tags.txt
new file mode 100644
index 00000000000..c5dc99e9fba
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/list_tags.txt
@@ -0,0 +1,8 @@
+# go list supports -tags
+go list -tags=thetag ./my...
+stdout mypkg
+
+-- mypkg/x.go --
+// +build thetag
+
+package mypkg
diff --git a/libgo/go/cmd/go/testdata/script/list_test_e.txt b/libgo/go/cmd/go/testdata/script/list_test_e.txt
new file mode 100644
index 00000000000..f1473322c65
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/list_test_e.txt
@@ -0,0 +1,9 @@
+# issue 25980: crash in go list -e -test
+go list -e -test -f '{{.Error}}' p
+stdout '^p[/\\]d_test.go:2:8: cannot find package "d" in any of:'
+
+-- p/d.go --
+package d
+-- p/d_test.go --
+package d_test
+import _ "d"
diff --git a/libgo/go/cmd/go/testdata/script/list_test_imports.txt b/libgo/go/cmd/go/testdata/script/list_test_imports.txt
new file mode 100644
index 00000000000..51d1ce9a696
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/list_test_imports.txt
@@ -0,0 +1,19 @@
+# issue 26880: list with tests has wrong variant in imports
+go list -test -f '{{.ImportPath}}:{{with .Imports}} {{join . ", "}}{{end}}' a b
+cmp stdout imports.txt
+
+-- a/a.go --
+package a; import _ "b"
+-- b/b.go --
+package b
+-- b/b_test.go --
+package b
+-- b/b_x_test.go --
+package b_test; import _ "a"
+
+-- imports.txt --
+a: b
+b:
+b.test: b [b.test], b_test [b.test], os, testing, testing/internal/testdeps
+b [b.test]:
+b_test [b.test]: a [b.test]
diff --git a/libgo/go/cmd/go/testdata/script/mod_bad_domain.txt b/libgo/go/cmd/go/testdata/script/mod_bad_domain.txt
new file mode 100644
index 00000000000..c9fd044cdc8
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_bad_domain.txt
@@ -0,0 +1,29 @@
+env GO111MODULE=on
+
+# explicit get should report errors about bad names
+! go get appengine
+stderr 'malformed module path "appengine": missing dot in first path element'
+! go get x/y.z
+stderr 'malformed module path "x/y.z": missing dot in first path element'
+
+# build should report all unsatisfied imports,
+# but should be more definitive about non-module import paths
+! go build ./useappengine
+stderr 'cannot find package'
+! go build ./usenonexistent
+stderr 'cannot find module providing package nonexistent.rsc.io'
+
+# go mod vendor and go mod tidy should ignore appengine imports.
+rm usenonexistent/x.go
+go mod tidy
+go mod vendor
+
+-- go.mod --
+module x
+
+-- useappengine/x.go --
+package useappengine
+import _ "appengine" // package does not exist
+-- usenonexistent/x.go --
+package usenonexistent
+import _ "nonexistent.rsc.io" // domain does not exist
diff --git a/libgo/go/cmd/go/testdata/script/mod_bad_filenames.txt b/libgo/go/cmd/go/testdata/script/mod_bad_filenames.txt
new file mode 100644
index 00000000000..6e0c8bd3023
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_bad_filenames.txt
@@ -0,0 +1,11 @@
+env GO111MODULE=on
+
+! go get rsc.io/badfile1 rsc.io/badfile2 rsc.io/badfile3 rsc.io/badfile4 rsc.io/badfile5
+! stderr 'unzip.*badfile1'
+stderr 'unzip.*badfile2[\\/]@v[\\/]v1.0.0.zip:.*malformed file path "☺.go": invalid char ''☺'''
+stderr 'unzip.*badfile3[\\/]@v[\\/]v1.0.0.zip: malformed file path "x\?y.go": invalid char ''\?'''
+stderr 'unzip.*badfile4[\\/]@v[\\/]v1.0.0.zip: case-insensitive file name collision: "x/Y.go" and "x/y.go"'
+stderr 'unzip.*badfile5[\\/]@v[\\/]v1.0.0.zip: case-insensitive file name collision: "x/y" and "x/Y"'
+
+-- go.mod --
+module x
diff --git a/libgo/go/cmd/go/testdata/script/mod_build_tags.txt b/libgo/go/cmd/go/testdata/script/mod_build_tags.txt
new file mode 100644
index 00000000000..1347eaacbf7
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_build_tags.txt
@@ -0,0 +1,30 @@
+# Test that build tags are used.
+# golang.org/issue/24053.
+
+env GO111MODULE=on
+
+cd x
+! go list -f {{.GoFiles}}
+stderr 'build constraints exclude all Go files'
+
+go list -f {{.GoFiles}} -tags tag1
+stdout '\[x.go\]'
+
+go list -f {{.GoFiles}} -tags tag2
+stdout '\[y\.go\]'
+
+go list -f {{.GoFiles}} -tags 'tag1 tag2'
+stdout '\[x\.go y\.go\]'
+
+-- x/go.mod --
+module x
+
+-- x/x.go --
+// +build tag1
+
+package y
+
+-- x/y.go --
+// +build tag2
+
+package y
diff --git a/libgo/go/cmd/go/testdata/script/mod_case.txt b/libgo/go/cmd/go/testdata/script/mod_case.txt
new file mode 100644
index 00000000000..ee818c2c07b
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_case.txt
@@ -0,0 +1,20 @@
+env GO111MODULE=on
+
+go get rsc.io/QUOTE
+go list -m all
+stdout '^rsc.io/quote v1.5.2'
+stdout '^rsc.io/QUOTE v1.5.2'
+
+go list -f 'DIR {{.Dir}} DEPS {{.Deps}}' rsc.io/QUOTE/QUOTE
+stdout 'DEPS.*rsc.io/quote'
+stdout 'DIR.*!q!u!o!t!e'
+
+go get rsc.io/QUOTE@v1.5.3-PRE
+go list -m all
+stdout '^rsc.io/QUOTE v1.5.3-PRE'
+
+go list -f '{{.Dir}}' rsc.io/QUOTE/QUOTE
+stdout '!q!u!o!t!e@v1.5.3-!p!r!e'
+
+-- go.mod --
+module x
diff --git a/libgo/go/cmd/go/testdata/script/mod_case_cgo.txt b/libgo/go/cmd/go/testdata/script/mod_case_cgo.txt
new file mode 100644
index 00000000000..917bce92d88
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_case_cgo.txt
@@ -0,0 +1,9 @@
+[!cgo] skip
+
+env GO111MODULE=on
+
+go get rsc.io/CGO
+go build rsc.io/CGO
+
+-- go.mod --
+module x
diff --git a/libgo/go/cmd/go/testdata/script/mod_convert_dep.txt b/libgo/go/cmd/go/testdata/script/mod_convert_dep.txt
new file mode 100644
index 00000000000..cc1083bcba2
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_convert_dep.txt
@@ -0,0 +1,9 @@
+env GO111MODULE=on
+
+cd $WORK/test/x
+go list -m all
+stdout '^m$'
+
+-- $WORK/test/Gopkg.lock --
+-- $WORK/test/x/x.go --
+package x // import "m/x"
diff --git a/libgo/go/cmd/go/testdata/script/mod_convert_git.txt b/libgo/go/cmd/go/testdata/script/mod_convert_git.txt
new file mode 100644
index 00000000000..5ef534a8f88
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_convert_git.txt
@@ -0,0 +1,10 @@
+env GO111MODULE=on
+
+# detect root of module tree as root of enclosing git repo
+cd $WORK/test/x
+go list -m all
+stdout '^m$'
+
+-- $WORK/test/.git/config --
+-- $WORK/test/x/x.go --
+package x // import "m/x"
diff --git a/libgo/go/cmd/go/testdata/script/mod_convert_glide.txt b/libgo/go/cmd/go/testdata/script/mod_convert_glide.txt
new file mode 100644
index 00000000000..50460bbf365
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_convert_glide.txt
@@ -0,0 +1,9 @@
+env GO111MODULE=on
+
+cd $WORK/test/x
+go list -m all
+stdout '^m$'
+
+-- $WORK/test/glide.lock --
+-- $WORK/test/x/x.go --
+package x // import "m/x"
diff --git a/libgo/go/cmd/go/testdata/script/mod_convert_glockfile.txt b/libgo/go/cmd/go/testdata/script/mod_convert_glockfile.txt
new file mode 100644
index 00000000000..4d9aaffab50
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_convert_glockfile.txt
@@ -0,0 +1,9 @@
+env GO111MODULE=on
+
+cd $WORK/test/x
+go list -m all
+stdout '^m$'
+
+-- $WORK/test/GLOCKFILE --
+-- $WORK/test/x/x.go --
+package x // import "m/x"
diff --git a/libgo/go/cmd/go/testdata/script/mod_convert_godeps.txt b/libgo/go/cmd/go/testdata/script/mod_convert_godeps.txt
new file mode 100644
index 00000000000..61fbab11240
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_convert_godeps.txt
@@ -0,0 +1,10 @@
+env GO111MODULE=on
+
+cd $WORK/test/x
+go list -m all
+stdout '^m$'
+
+-- $WORK/test/Godeps/Godeps.json --
+{}
+-- $WORK/test/x/x.go --
+package x // import "m/x"
diff --git a/libgo/go/cmd/go/testdata/script/mod_convert_tsv.txt b/libgo/go/cmd/go/testdata/script/mod_convert_tsv.txt
new file mode 100644
index 00000000000..5b82d85d653
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_convert_tsv.txt
@@ -0,0 +1,9 @@
+env GO111MODULE=on
+
+cd $WORK/test/x
+go list -m all
+stdout '^m$'
+
+-- $WORK/test/dependencies.tsv --
+-- $WORK/test/x/x.go --
+package x // import "m/x"
diff --git a/libgo/go/cmd/go/testdata/script/mod_convert_vendor_conf.txt b/libgo/go/cmd/go/testdata/script/mod_convert_vendor_conf.txt
new file mode 100644
index 00000000000..b45d3b69fe2
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_convert_vendor_conf.txt
@@ -0,0 +1,9 @@
+env GO111MODULE=on
+
+cd $WORK/test/x
+go list -m all
+stdout '^m$'
+
+-- $WORK/test/vendor.conf --
+-- $WORK/test/x/x.go --
+package x // import "m/x"
diff --git a/libgo/go/cmd/go/testdata/script/mod_convert_vendor_json.txt b/libgo/go/cmd/go/testdata/script/mod_convert_vendor_json.txt
new file mode 100644
index 00000000000..cb6e5fee15f
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_convert_vendor_json.txt
@@ -0,0 +1,10 @@
+env GO111MODULE=on
+
+cd $WORK/test/x
+go list -m all
+stdout '^m$'
+
+-- $WORK/test/vendor/vendor.json --
+{}
+-- $WORK/test/x/x.go --
+package x // import "m/x"
diff --git a/libgo/go/cmd/go/testdata/script/mod_convert_vendor_manifest.txt b/libgo/go/cmd/go/testdata/script/mod_convert_vendor_manifest.txt
new file mode 100644
index 00000000000..bcf185136ba
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_convert_vendor_manifest.txt
@@ -0,0 +1,10 @@
+env GO111MODULE=on
+
+cd $WORK/test/x
+go list -m all
+stdout '^m$'
+
+-- $WORK/test/vendor/manifest --
+{}
+-- $WORK/test/x/x.go --
+package x // import "m/x"
diff --git a/libgo/go/cmd/go/testdata/script/mod_convert_vendor_yml.txt b/libgo/go/cmd/go/testdata/script/mod_convert_vendor_yml.txt
new file mode 100644
index 00000000000..0cd245bace1
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_convert_vendor_yml.txt
@@ -0,0 +1,9 @@
+env GO111MODULE=on
+
+cd $WORK/test/x
+go list -m all
+stdout '^m$'
+
+-- $WORK/test/vendor.yml --
+-- $WORK/test/x/x.go --
+package x // import "m/x"
diff --git a/libgo/go/cmd/go/testdata/script/mod_doc.txt b/libgo/go/cmd/go/testdata/script/mod_doc.txt
new file mode 100644
index 00000000000..450d85754ea
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_doc.txt
@@ -0,0 +1,36 @@
+# go doc should find module documentation
+
+[gccgo] stop 'no go doc'
+
+env GO111MODULE=on
+
+go doc y
+stdout 'Package y is.*alphabet'
+stdout 'import "x/y"'
+go doc x/y
+stdout 'Package y is.*alphabet'
+! go doc quote.Hello
+stderr 'doc: symbol quote is not a type' # because quote is not in local cache
+go list rsc.io/quote # now it is
+go doc quote.Hello
+stdout 'Hello returns a greeting'
+go doc quote
+stdout 'Package quote collects pithy sayings.'
+
+# Double-check go doc y when y is not in GOPATH/src.
+env GOPATH=$WORK/altgopath
+go doc x/y
+stdout 'Package y is.*alphabet'
+go doc y
+stdout 'Package y is.*alphabet'
+
+-- go.mod --
+module x
+require rsc.io/quote v1.5.2
+
+-- y/y.go --
+// Package y is the next to last package of the alphabet.
+package y
+
+-- x.go --
+package x
diff --git a/libgo/go/cmd/go/testdata/script/mod_domain_root.txt b/libgo/go/cmd/go/testdata/script/mod_domain_root.txt
new file mode 100644
index 00000000000..e34cc29fa64
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_domain_root.txt
@@ -0,0 +1,12 @@
+# Module paths that are domain roots should resolve.
+# (example.com not example.com/something)
+
+env GO111MODULE=on
+go build
+
+-- go.mod --
+module x
+
+-- x.go --
+package x
+import _ "example.com"
diff --git a/libgo/go/cmd/go/testdata/script/mod_download.txt b/libgo/go/cmd/go/testdata/script/mod_download.txt
new file mode 100644
index 00000000000..6be6acb360c
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_download.txt
@@ -0,0 +1,64 @@
+env GO111MODULE=on
+
+# download with version should print nothing
+go mod download rsc.io/quote@v1.5.0
+! stdout .
+
+exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.info
+exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.mod
+exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.zip
+
+# download -json with version should print JSON
+go mod download -json 'rsc.io/quote@<=v1.5.0'
+stdout '^\t"Path": "rsc.io/quote"'
+stdout '^\t"Version": "v1.5.0"'
+stdout '^\t"Info": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)cache(\\\\|/)download(\\\\|/)rsc.io(\\\\|/)quote(\\\\|/)@v(\\\\|/)v1.5.0.info"'
+stdout '^\t"GoMod": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)cache(\\\\|/)download(\\\\|/)rsc.io(\\\\|/)quote(\\\\|/)@v(\\\\|/)v1.5.0.mod"'
+stdout '^\t"Zip": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)cache(\\\\|/)download(\\\\|/)rsc.io(\\\\|/)quote(\\\\|/)@v(\\\\|/)v1.5.0.zip"'
+stdout '^\t"Sum": "h1:6fJa6E\+wGadANKkUMlZ0DhXFpoKlslOQDCo259XtdIE="' # hash of testdata/mod version, not real version!
+stdout '^\t"GoModSum": "h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe\+TKr0="'
+! stdout '"Error"'
+
+# download queries above should not have added to go.mod.
+go list -m all
+! stdout rsc.io
+
+# add to go.mod so we can test non-query downloads
+go mod edit -require rsc.io/quote@v1.5.2
+! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.info
+! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod
+! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip
+
+# module loading will page in the info and mod files
+go list -m all
+exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.info
+exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod
+! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip
+
+# download will fetch and unpack the zip file
+go mod download
+exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.info
+exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod
+exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip
+exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
+
+go mod download -json
+stdout '^\t"Path": "rsc.io/quote"'
+stdout '^\t"Version": "v1.5.2"'
+stdout '^\t"Info": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)cache(\\\\|/)download(\\\\|/)rsc.io(\\\\|/)quote(\\\\|/)@v(\\\\|/)v1.5.2.info"'
+stdout '^\t"GoMod": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)cache(\\\\|/)download(\\\\|/)rsc.io(\\\\|/)quote(\\\\|/)@v(\\\\|/)v1.5.2.mod"'
+stdout '^\t"Zip": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)cache(\\\\|/)download(\\\\|/)rsc.io(\\\\|/)quote(\\\\|/)@v(\\\\|/)v1.5.2.zip"'
+stdout '^\t"Dir": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)rsc.io(\\\\|/)quote@v1.5.2"'
+
+# download will follow replacements
+go mod edit -require rsc.io/quote@v1.5.1 -replace rsc.io/quote@v1.5.1=rsc.io/quote@v1.5.3-pre1
+go mod download
+! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.1.zip
+exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.zip
+
+# download will not follow replacements for explicit module queries
+go mod download -json rsc.io/quote@v1.5.1
+exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.1.zip
+
+-- go.mod --
+module m
diff --git a/libgo/go/cmd/go/testdata/script/mod_edit.txt b/libgo/go/cmd/go/testdata/script/mod_edit.txt
new file mode 100644
index 00000000000..60a6f745361
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_edit.txt
@@ -0,0 +1,136 @@
+env GO111MODULE=on
+
+# Test that go mod edits and related mod flags work.
+# Also test that they can use a dummy name that isn't resolvable. golang.org/issue/24100
+
+# go mod init
+! go mod init
+stderr 'cannot determine module path'
+! exists go.mod
+
+go mod init x.x/y/z
+stderr 'creating new go.mod: module x.x/y/z'
+cmp go.mod $WORK/go.mod.init
+
+! go mod init
+cmp go.mod $WORK/go.mod.init
+
+# go mod edits
+go mod edit -droprequire=x.1 -require=x.1@v1.0.0 -require=x.2@v1.1.0 -droprequire=x.2 -exclude='x.1 @ v1.2.0' -exclude=x.1@v1.2.1 -replace=x.1@v1.3.0=y.1@v1.4.0 -replace='x.1@v1.4.0 = ../z'
+cmp go.mod $WORK/go.mod.edit1
+go mod edit -droprequire=x.1 -dropexclude=x.1@v1.2.1 -dropreplace=x.1@v1.3.0 -require=x.3@v1.99.0
+cmp go.mod $WORK/go.mod.edit2
+
+# go mod edit -json
+go mod edit -json
+cmp stdout $WORK/go.mod.json
+
+# go mod edit -replace
+go mod edit -replace=x.1@v1.3.0=y.1/v2@v2.3.5 -replace=x.1@v1.4.0=y.1/v2@v2.3.5
+cmp go.mod $WORK/go.mod.edit3
+go mod edit -replace=x.1=y.1/v2@v2.3.6
+cmp go.mod $WORK/go.mod.edit4
+go mod edit -dropreplace=x.1
+cmp go.mod $WORK/go.mod.edit5
+
+# go mod edit -fmt
+cp $WORK/go.mod.badfmt go.mod
+go mod edit -fmt -print # -print should avoid writing file
+cmp stdout $WORK/go.mod.edit4
+cmp go.mod $WORK/go.mod.badfmt
+go mod edit -fmt # without -print, should write file (and nothing to stdout)
+! stdout .
+cmp go.mod $WORK/go.mod.edit4
+
+-- x.go --
+package x
+
+-- w/w.go --
+package w
+
+-- $WORK/go.mod.init --
+module x.x/y/z
+-- $WORK/go.mod.edit1 --
+module x.x/y/z
+
+require x.1 v1.0.0
+
+exclude (
+ x.1 v1.2.0
+ x.1 v1.2.1
+)
+
+replace (
+ x.1 v1.3.0 => y.1 v1.4.0
+ x.1 v1.4.0 => ../z
+)
+-- $WORK/go.mod.edit2 --
+module x.x/y/z
+
+exclude x.1 v1.2.0
+
+replace x.1 v1.4.0 => ../z
+
+require x.3 v1.99.0
+-- $WORK/go.mod.json --
+{
+ "Module": {
+ "Path": "x.x/y/z"
+ },
+ "Require": [
+ {
+ "Path": "x.3",
+ "Version": "v1.99.0"
+ }
+ ],
+ "Exclude": [
+ {
+ "Path": "x.1",
+ "Version": "v1.2.0"
+ }
+ ],
+ "Replace": [
+ {
+ "Old": {
+ "Path": "x.1",
+ "Version": "v1.4.0"
+ },
+ "New": {
+ "Path": "../z"
+ }
+ }
+ ]
+}
+-- $WORK/go.mod.edit3 --
+module x.x/y/z
+
+exclude x.1 v1.2.0
+
+replace (
+ x.1 v1.3.0 => y.1/v2 v2.3.5
+ x.1 v1.4.0 => y.1/v2 v2.3.5
+)
+
+require x.3 v1.99.0
+-- $WORK/go.mod.edit4 --
+module x.x/y/z
+
+exclude x.1 v1.2.0
+
+replace x.1 => y.1/v2 v2.3.6
+
+require x.3 v1.99.0
+-- $WORK/go.mod.edit5 --
+module x.x/y/z
+
+exclude x.1 v1.2.0
+
+require x.3 v1.99.0
+-- $WORK/go.mod.badfmt --
+module x.x/y/z
+
+exclude x.1 v1.2.0
+
+replace x.1 => y.1/v2 v2.3.6
+
+require x.3 v1.99.0
diff --git a/libgo/go/cmd/go/testdata/script/mod_enabled.txt b/libgo/go/cmd/go/testdata/script/mod_enabled.txt
new file mode 100644
index 00000000000..8eef870b02b
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_enabled.txt
@@ -0,0 +1,82 @@
+# GO111MODULE=auto should only trigger outside GOPATH/src
+env GO111MODULE=auto
+
+cd $GOPATH/src/x/y/z
+go env GOMOD
+! stdout . # no non-empty lines
+! go list -m -f {{.GoMod}}
+stderr 'not using modules'
+
+cd $GOPATH/src/x/y/z/w
+go env GOMOD
+! stdout .
+
+cd $GOPATH/src/x/y
+go env GOMOD
+! stdout .
+
+cd $GOPATH/foo
+go env GOMOD
+stdout foo[/\\]go.mod
+go list -m -f {{.GoMod}}
+stdout foo[/\\]go.mod
+
+cd $GOPATH/foo/bar/baz
+go env GOMOD
+stdout foo[/\\]go.mod
+
+# GO111MODULE=on should trigger everywhere
+env GO111MODULE=on
+
+cd $GOPATH/src/x/y/z
+go env GOMOD
+stdout z[/\\]go.mod
+
+cd $GOPATH/src/x/y/z/w
+go env GOMOD
+stdout z[/\\]go.mod
+
+cd $GOPATH/src/x/y
+go env GOMOD
+! stdout .
+! go list -m
+stderr 'cannot find main module'
+
+cd $GOPATH/foo
+go env GOMOD
+stdout foo[/\\]go.mod
+
+cd $GOPATH/foo/bar/baz
+go env GOMOD
+stdout foo[/\\]go.mod
+
+# GO111MODULE=off should trigger nowhere
+env GO111MODULE=off
+
+cd $GOPATH/src/x/y/z
+go env GOMOD
+! stdout .+
+
+cd $GOPATH/foo
+go env GOMOD
+! stdout .+
+
+cd $GOPATH/foo/bar/baz
+go env GOMOD
+! stdout .+
+
+# GO111MODULE=auto should ignore and warn about /tmp/go.mod
+env GO111MODULE=auto
+cp $GOPATH/src/x/y/z/go.mod $WORK/tmp/go.mod
+mkdir $WORK/tmp/mydir
+cd $WORK/tmp/mydir
+go env GOMOD
+! stdout .+
+stderr '^go: warning: ignoring go.mod in system temp root '
+
+-- $GOPATH/src/x/y/z/go.mod --
+module x/y/z
+-- $GOPATH/src/x/y/z/w/w.txt --
+-- $GOPATH/foo/go.mod --
+module example.com/mod
+-- $GOPATH/foo/bar/baz/quux.txt --
diff --git a/libgo/go/cmd/go/testdata/script/mod_file_proxy.txt b/libgo/go/cmd/go/testdata/script/mod_file_proxy.txt
new file mode 100644
index 00000000000..8de6d7dbb88
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_file_proxy.txt
@@ -0,0 +1,25 @@
+# Allow (cached) downloads for -mod=readonly.
+env GO111MODULE=on
+env GOPATH=$WORK/gopath1
+cd $WORK/x
+go mod edit -fmt
+go list -mod=readonly
+env GOPROXY=file:///nonexist
+go list
+grep v1.5.1 $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/list
+
+# Use download cache as file:/// proxy.
+[windows] stop # TODO: file://$WORK puts backslashes in the URL
+env GOPATH=$WORK/gopath2
+env GOPROXY=file:///nonexist
+! go list
+env GOPROXY=file://$WORK/gopath1/pkg/mod/cache/download
+go list
+grep v1.5.1 $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/list
+
+-- $WORK/x/go.mod --
+module x
+require rsc.io/quote v1.5.1
+-- $WORK/x/x.go --
+package x
+import _ "rsc.io/quote"
diff --git a/libgo/go/cmd/go/testdata/script/mod_find.txt b/libgo/go/cmd/go/testdata/script/mod_find.txt
new file mode 100644
index 00000000000..f4ac8d01f56
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_find.txt
@@ -0,0 +1,91 @@
+# Derive module path from import comment.
+cd $WORK/x
+exists x.go
+go mod init
+stderr 'module x'
+
+# Import comment works even with CRLF line endings.
+rm go.mod
+addcrlf x.go
+go mod init
+stderr 'module x'
+
+# go mod should die in GOPATH if modules are not enabled for GOPATH
+cd $GOPATH/src/example.com/x/y
+! go mod init
+stderr 'go: modules disabled inside GOPATH/src by GO111MODULE=auto; see ''go help modules'''
+
+env GO111MODULE=on
+
+# Derive module path from location inside GOPATH.
+cd $GOPATH/src/example.com/x/y
+go mod init
+stderr 'module example.com/x/y$'
+rm go.mod
+
+# Module path from Godeps/Godeps.json overrides GOPATH.
+cd $GOPATH/src/example.com/x/y/z
+go mod init
+stderr 'unexpected.com/z'
+rm go.mod
+
+# Empty directory outside GOPATH fails.
+mkdir $WORK/empty
+cd $WORK/empty
+! go mod init
+stderr 'cannot determine module path for source directory'
+rm go.mod
+
+# Empty directory inside GOPATH/src uses location inside GOPATH.
+mkdir $GOPATH/src/empty
+cd $GOPATH/src/empty
+go mod init
+stderr 'empty'
+rm go.mod
+
+[!symlink] stop
+
+# gplink1/src/empty where gopathlink -> GOPATH
+symlink $WORK/gopathlink -> gopath
+cd $WORK/gopathlink/src/empty
+go mod init
+rm go.mod
+
+# GOPATH/src/link where link -> out of GOPATH
+symlink $GOPATH/src/link -> $WORK/empty
+cd $WORK/empty
+! go mod init
+cd $GOPATH/src/link
+go mod init
+stderr link
+rm go.mod
+
+# GOPATH/src/empty where GOPATH itself is a symlink
+env GOPATH=$WORK/gopathlink
+cd $GOPATH/src/empty
+go mod init
+rm go.mod
+cd $WORK/gopath/src/empty
+go mod init
+rm go.mod
+
+# GOPATH/src/link where GOPATH and link are both symlinks
+cd $GOPATH/src/link
+go mod init
+stderr link
+rm go.mod
+
+# Too hard: doesn't match unevaluated nor completely evaluated. (Only partially evaluated.)
+# Whether this works depends on which OS we are running on.
+# cd $WORK/gopath/src/link
+# ! go mod init
+
+-- $WORK/x/x.go --
+package x // import "x"
+
+-- $GOPATH/src/example.com/x/y/y.go --
+package y
+-- $GOPATH/src/example.com/x/y/z/z.go --
+package z
+-- $GOPATH/src/example.com/x/y/z/Godeps/Godeps.json --
+{"ImportPath": "unexpected.com/z"}
diff --git a/libgo/go/cmd/go/testdata/script/mod_fs_patterns.txt b/libgo/go/cmd/go/testdata/script/mod_fs_patterns.txt
new file mode 100644
index 00000000000..d7d3e0321b5
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_fs_patterns.txt
@@ -0,0 +1,66 @@
+# File system pattern searches should skip sub-modules and vendor directories.
+
+env GO111MODULE=on
+
+cd x
+
+# all packages
+go list all
+stdout ^m$
+stdout ^m/vendor$
+! stdout vendor/
+stdout ^m/y$
+! stdout ^m/y/z
+
+# path pattern
+go list m/...
+stdout ^m$
+stdout ^m/vendor$
+! stdout vendor/
+stdout ^m/y$
+! stdout ^m/y/z
+
+# directory pattern
+go list ./...
+stdout ^m$
+stdout ^m/vendor$
+! stdout vendor/
+stdout ^m/y$
+! stdout ^m/y/z
+
+# non-existent directory should not prompt lookups
+! go build -mod=readonly example.com/nonexist
+stderr 'import lookup disabled'
+
+! go build -mod=readonly ./nonexist
+! stderr 'import lookup disabled'
+stderr '^go: no such directory ./nonexist'
+
+! go build -mod=readonly ./go.mod
+! stderr 'import lookup disabled'
+stderr '^go: ./go.mod is not a directory'
+
+-- x/go.mod --
+module m
+
+-- x/x.go --
+package x
+
+-- x/vendor/v/v.go --
+package v
+import _ "golang.org/x/crypto"
+
+-- x/vendor/v.go --
+package main
+
+-- x/y/y.go --
+package y
+
+-- x/y/z/go.mod --
+syntax error!
+
+-- x/y/z/z.go --
+package z
+
+-- x/y/z/w/w.go --
+package w
diff --git a/libgo/go/cmd/go/testdata/script/mod_get_commit.txt b/libgo/go/cmd/go/testdata/script/mod_get_commit.txt
new file mode 100644
index 00000000000..589a791fd4d
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_get_commit.txt
@@ -0,0 +1,53 @@
+env GO111MODULE=on
+
+# @commit should resolve
+
+# golang.org/x/text/language@commit should not resolve with -m,
+# because that's not a module path.
+! go get -m golang.org/x/text/language@14c0d48
+
+# ... but it should work without -m.
+# because of -d, the compiler should not run
+go get -d -x golang.org/x/text/language@14c0d48
+! stderr 'compile|cp|gccgo .*language\.a$'
+
+# go get should skip build with no Go files in root
+go get golang.org/x/text@14c0d48
+
+# ... and go get should skip build with -m
+go get -m golang.org/x/text@14c0d48
+
+# dropping -d, we should see a build.
+go get -x golang.org/x/text/language@14c0d48
+stderr 'compile|cp|gccgo .*language\.a$'
+
+# BUG: after the build, the package should not be stale, as 'go install' would
+# not do anything further.
+go list -f '{{.Stale}}' golang.org/x/text/language
+stdout ^true
+
+# install after get should not run the compiler again.
+go install -x golang.org/x/text/language
+! stderr 'compile|cp|gccgo .*language\.a$'
+
+# even with -d, we should see an error for unknown packages.
+! go get -d -x golang.org/x/text/foo@14c0d48
+
+# get pseudo-version should record that version
+go get rsc.io/quote@v0.0.0-20180214005840-23179ee8a569
+grep 'rsc.io/quote v0.0.0-20180214005840-23179ee8a569' go.mod
+
+# but as commit should record as v1.5.1
+go get rsc.io/quote@23179ee8
+grep 'rsc.io/quote v1.5.1' go.mod
+
+# go mod edit -require does not interpret commits
+go mod edit -require rsc.io/quote@23179ee
+grep 'rsc.io/quote 23179ee' go.mod
+
+# but other commands fix them
+go mod graph
+grep 'rsc.io/quote v1.5.1' go.mod
+
+-- go.mod --
+module x
diff --git a/libgo/go/cmd/go/testdata/script/mod_get_downgrade.txt b/libgo/go/cmd/go/testdata/script/mod_get_downgrade.txt
new file mode 100644
index 00000000000..ac814dae08f
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_get_downgrade.txt
@@ -0,0 +1,39 @@
+env GO111MODULE=on
+
+# downgrade sampler should downgrade quote
+go get rsc.io/sampler@v1.0.0
+go list -m all
+stdout 'rsc.io/quote v1.4.0'
+stdout 'rsc.io/sampler v1.0.0'
+
+# downgrade sampler away should downgrade quote further
+go get rsc.io/sampler@none
+go list -m all
+stdout 'rsc.io/quote v1.3.0'
+
+# downgrade should report inconsistencies and not change go.mod
+go get rsc.io/quote@v1.5.1
+go list -m all
+stdout 'rsc.io/quote v1.5.1'
+stdout 'rsc.io/sampler v1.3.0'
+! go get rsc.io/sampler@v1.0.0 rsc.io/quote@v1.5.2 golang.org/x/text@none
+stderr 'go get: inconsistent versions:\n\trsc.io/quote@v1.5.2 requires golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c \(not golang.org/x/text@none\), rsc.io/sampler@v1.3.0 \(not rsc.io/sampler@v1.0.0\)'
+go list -m all
+stdout 'rsc.io/quote v1.5.1'
+stdout 'rsc.io/sampler v1.3.0'
+
+# go get -u args should limit upgrades
+cp go.mod.empty go.mod
+go get -u rsc.io/quote@v1.4.0 rsc.io/sampler@v1.0.0
+go list -m all
+stdout 'rsc.io/quote v1.4.0'
+stdout 'rsc.io/sampler v1.0.0'
+! stdout golang.org/x/text
+
+-- go.mod --
+module x
+require rsc.io/quote v1.5.1
+-- go.mod.empty --
+module x
+-- x.go --
+package x
diff --git a/libgo/go/cmd/go/testdata/script/mod_get_incompatible.txt b/libgo/go/cmd/go/testdata/script/mod_get_incompatible.txt
new file mode 100644
index 00000000000..b210715a5de
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_get_incompatible.txt
@@ -0,0 +1,26 @@
+env GO111MODULE=on
+
+go list x
+go list -m all
+stdout 'rsc.io/breaker v2.0.0\+incompatible'
+
+cp go.mod2 go.mod
+go get rsc.io/breaker@7307b30
+go list -m all
+stdout 'rsc.io/breaker v2.0.0\+incompatible'
+
+go get rsc.io/breaker@v2.0.0
+go list -m all
+stdout 'rsc.io/breaker v2.0.0\+incompatible'
+
+-- go.mod --
+module x
+
+-- go.mod2 --
+module x
+require rsc.io/breaker v1.0.0
+
+-- x.go --
+package x
+import "rsc.io/breaker"
+var _ = breaker.XX
diff --git a/libgo/go/cmd/go/testdata/script/mod_get_indirect.txt b/libgo/go/cmd/go/testdata/script/mod_get_indirect.txt
new file mode 100644
index 00000000000..3ae5833834b
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_get_indirect.txt
@@ -0,0 +1,51 @@
+env GO111MODULE=on
+
+# get -u should find quote v1.5.2
+go get -u
+go list -m all
+stdout 'quote v1.5.2$'
+grep 'rsc.io/quote v1.5.2$' go.mod
+
+# it should also update x/text later than requested by v1.5.2
+go list -m -f '{{.Path}} {{.Version}}{{if .Indirect}} // indirect{{end}}' all
+stdout '^golang.org/x/text [v0-9a-f\.-]+ // indirect'
+grep 'golang.org/x/text [v0-9a-f\.-]+ // indirect' go.mod
+
+# importing an empty module root as a package makes it direct.
+# TODO(bcmills): This doesn't seem correct. Fix is in the next change.
+cp $WORK/tmp/usetext.go x.go
+go list -e
+grep 'golang.org/x/text [v0-9a-f\.-]+ // indirect' go.mod
+
+# indirect tag should be removed upon seeing direct import.
+cp $WORK/tmp/uselang.go x.go
+go list
+grep 'rsc.io/quote v1.5.2$' go.mod
+grep 'golang.org/x/text [v0-9a-f\.-]+$' go.mod
+
+# indirect tag should be added by go mod tidy
+cp $WORK/tmp/usequote.go x.go
+go mod tidy
+grep 'rsc.io/quote v1.5.2$' go.mod
+grep 'golang.org/x/text [v0-9a-f\.-]+ // indirect' go.mod
+
+# requirement should be dropped entirely if not needed
+cp $WORK/tmp/uselang.go x.go
+go mod tidy
+! grep rsc.io/quote go.mod
+grep 'golang.org/x/text [v0-9a-f\.-]+$' go.mod
+
+-- go.mod --
+module x
+require rsc.io/quote v1.5.1
+-- x.go --
+package x
+-- $WORK/tmp/usetext.go --
+package x
+import _ "golang.org/x/text"
+-- $WORK/tmp/uselang.go --
+package x
+import _ "golang.org/x/text/language"
+-- $WORK/tmp/usequote.go --
+package x
+import _ "rsc.io/quote"
diff --git a/libgo/go/cmd/go/testdata/script/mod_get_local.txt b/libgo/go/cmd/go/testdata/script/mod_get_local.txt
new file mode 100644
index 00000000000..4edda993f1e
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_get_local.txt
@@ -0,0 +1,61 @@
+# Test 'go get' with a local module with a name that is not valid for network lookup.
+
+env GO111MODULE=on
+go mod edit -fmt
+cp go.mod go.mod.orig
+
+# 'go get -u -m' within the main module should work, even if it has a local-only name.
+cp go.mod.orig go.mod
+go get -u -m
+grep 'rsc.io/quote.*v1.5.2' go.mod
+grep 'golang.org/x/text.*v0.3.0' go.mod
+cp go.mod go.mod.implicitmod
+
+# 'go get -u -m' with the name of the main module should be equivalent to
+# 'go get -u -m' without any further arguments.
+cp go.mod.orig go.mod
+go get -u -m local
+cmp go.mod go.mod.implicitmod
+
+# 'go get -u -d' in the empty root of the main module should update the
+# dependencies of all packages in the module.
+cp go.mod.orig go.mod
+go get -u -d
+cmp go.mod go.mod.implicitmod
+
+# 'go get -u -d .' within a package in the main module updates all dependencies
+# of the main module.
+# TODO: Determine whether that behavior is a bug.
+# (https://golang.org/issue/26902)
+cp go.mod.orig go.mod
+cd uselang
+go get -u -d .
+cd ..
+grep 'rsc.io/quote.*v1.5.2' go.mod
+grep 'golang.org/x/text.*v0.3.0' go.mod
+cp go.mod go.mod.dotpkg
+
+# 'go get -u -d' with an explicit package in the main module updates
+# all dependencies of the main module.
+# TODO: Determine whether that behavior is a bug.
+# (https://golang.org/issue/26902)
+cp go.mod.orig go.mod
+go get -u -d local/uselang
+cmp go.mod go.mod.dotpkg
+
+
+-- go.mod --
+module local
+
+require (
+ golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
+ rsc.io/quote v1.3.0
+)
+
+-- uselang/uselang.go --
+package uselang
+import _ "golang.org/x/text/language"
+
+-- usequote/usequote.go --
+package usequote
+import _ "rsc.io/quote"
diff --git a/libgo/go/cmd/go/testdata/script/mod_get_moved.txt b/libgo/go/cmd/go/testdata/script/mod_get_moved.txt
new file mode 100644
index 00000000000..be914491552
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_get_moved.txt
@@ -0,0 +1,37 @@
+env GO111MODULE=on
+
+# A 'go get' that worked at a previous version should continue to work at that version,
+# even if the package was subsequently moved into a submodule.
+go mod init example.com/foo
+go get -d example.com/split/subpkg@v1.0.0
+go list -m all
+stdout 'example.com/split v1.0.0'
+
+# A 'go get' that simultaneously upgrades away conflicting package defitions is not ambiguous.
+go get example.com/split/subpkg@v1.1.0
+
+# A 'go get' without an upgrade should find the package.
+rm go.mod
+go mod init example.com/foo
+go get -d example.com/split/subpkg
+go list -m all
+stdout 'example.com/split/subpkg v1.1.0'
+
+
+# A 'go get' that worked at a previous version should continue to work at that version,
+# even if the package was subsequently moved into a parent module.
+rm go.mod
+go mod init example.com/foo
+go get -d example.com/join/subpkg@v1.0.0
+go list -m all
+stdout 'example.com/join/subpkg v1.0.0'
+
+# A 'go get' that simultaneously upgrades away conflicting package definitions is not ambiguous.
+go get example.com/join/subpkg@v1.1.0
+
+# A 'go get' without an upgrade should find the package.
+rm go.mod
+go mod init example.com/foo
+go get -d example.com/join/subpkg@v1.1.0
+go list -m all
+stdout 'example.com/join v1.1.0'
diff --git a/libgo/go/cmd/go/testdata/script/mod_get_none.txt b/libgo/go/cmd/go/testdata/script/mod_get_none.txt
new file mode 100644
index 00000000000..5aec209f59f
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_get_none.txt
@@ -0,0 +1,12 @@
+env GO111MODULE=on
+
+go mod init example.com/foo
+
+# 'go get bar@none' should be a no-op if module bar is not active.
+go get example.com/bar@none
+go list -m all
+! stdout example.com/bar
+
+go get example.com/bar@none
+go list -m all
+! stdout example.com/bar
diff --git a/libgo/go/cmd/go/testdata/script/mod_get_pseudo.txt b/libgo/go/cmd/go/testdata/script/mod_get_pseudo.txt
new file mode 100644
index 00000000000..3945fdfa893
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_get_pseudo.txt
@@ -0,0 +1,80 @@
+env GO111MODULE=on
+
+# Testing git->module converter's generation of +incompatible tags; turn off proxy.
+[!net] skip
+[!exec:git] skip
+env GOPROXY=
+
+# We can resolve the @master branch without unshallowing the local repository
+# (even with older gits), so try that before we do anything else.
+# (This replicates https://golang.org/issue/26713 with git 2.7.4.)
+go get -m github.com/rsc/legacytest@master
+go list -m all
+stdout '^github.com/rsc/legacytest v2\.0\.1-0\.\d{14}-7303f7796364\+incompatible$'
+
+# get should include incompatible tags in "latest" calculation.
+go get -m github.com/rsc/legacytest@latest
+go list
+go list -m all
+stdout '^github.com/rsc/legacytest v2\.0\.0\+incompatible$'
+
+# v2.0.1-0.pseudo+incompatible
+go get -m ...test@7303f77
+go list -m all
+stdout '^github.com/rsc/legacytest v2\.0\.1-0\.\d{14}-7303f7796364\+incompatible$'
+
+# v2.0.0+incompatible by tag+incompatible
+go get -m ...test@v2.0.0+incompatible
+go list -m all
+stdout '^github.com/rsc/legacytest v2\.0\.0\+incompatible$'
+
+# v2.0.0+incompatible by tag
+go get -m ...test@v2.0.0
+go list -m all
+stdout '^github.com/rsc/legacytest v2\.0\.0\+incompatible$'
+
+# v2.0.0+incompatible by hash (back on master)
+go get -m ...test@d7ae1e4
+go list -m all
+stdout '^github.com/rsc/legacytest v2\.0\.0\+incompatible$'
+
+# v1.2.1-0.pseudo
+go get -m ...test@d2d4c3e
+go list -m all
+stdout '^github.com/rsc/legacytest v1\.2\.1-0\.\d{14}-d2d4c3ea6623$'
+
+# v1.2.0
+go get -m ...test@9f6f860
+go list -m all
+stdout '^github.com/rsc/legacytest v1\.2\.0$'
+
+# v1.1.0-pre.0.pseudo
+go get -m ...test@fb3c628
+go list -m all
+stdout '^github.com/rsc/legacytest v1\.1\.0-pre\.0\.\d{14}-fb3c628075e3$'
+
+# v1.1.0-pre (no longer on master)
+go get -m ...test@731e3b1
+go list -m all
+stdout '^github.com/rsc/legacytest v1\.1\.0-pre$'
+
+# v1.0.1-0.pseudo
+go get -m ...test@fa4f5d6
+go list -m all
+stdout '^github.com/rsc/legacytest v1\.0\.1-0\.\d{14}-fa4f5d6a71c6$'
+
+# v1.0.0
+go get -m ...test@7fff7f3
+go list -m all
+stdout '^github.com/rsc/legacytest v1\.0\.0$'
+
+# v0.0.0-pseudo
+go get -m ...test@52853eb
+go list -m all
+stdout '^github.com/rsc/legacytest v0\.0\.0-\d{14}-52853eb7b552$'
+
+-- go.mod --
+module x
+-- x.go --
+package x
+import "github.com/rsc/legacytest"
diff --git a/libgo/go/cmd/go/testdata/script/mod_get_upgrade.txt b/libgo/go/cmd/go/testdata/script/mod_get_upgrade.txt
new file mode 100644
index 00000000000..5eb5ff96577
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_get_upgrade.txt
@@ -0,0 +1,41 @@
+env GO111MODULE=on
+
+go get rsc.io/quote@v1.5.1
+go list -m all
+stdout 'rsc.io/quote v1.5.1'
+grep 'rsc.io/quote v1.5.1$' go.mod
+
+# get -u should update all dependencies
+go get -u
+grep 'rsc.io/quote v1.5.2$' go.mod
+grep 'golang.org/x/text [v0-9a-f\.-]+ // indirect' go.mod
+
+# get -u rsc.io/sampler should update only sampler's dependencies
+cp go.mod-v1.5.1 go.mod
+go get -u rsc.io/sampler
+grep 'rsc.io/quote v1.5.1$' go.mod
+grep 'golang.org/x/text [v0-9a-f\.-]+ // indirect' go.mod
+
+# move to a pseudo-version after any tags
+go get -m rsc.io/quote@dd9747d
+grep 'rsc.io/quote v0.0.0-20180628003336-dd9747d19b04' go.mod
+
+# get -u should not jump off newer pseudo-version to earlier tag
+go get -m -u
+grep 'rsc.io/quote v0.0.0-20180628003336-dd9747d19b04' go.mod
+
+# move to earlier pseudo-version
+go get -m rsc.io/quote@e7a685a342
+grep 'rsc.io/quote v0.0.0-20180214005133-e7a685a342c0' go.mod
+
+# get -u should jump off earlier pseudo-version to newer tag
+go get -m -u
+grep 'rsc.io/quote v1.5.2' go.mod
+
+-- go.mod --
+module x
+require rsc.io/quote v1.1.0
+
+-- go.mod-v1.5.1 --
+module x
+require rsc.io/quote v1.5.1
diff --git a/libgo/go/cmd/go/testdata/script/mod_get_warning.txt b/libgo/go/cmd/go/testdata/script/mod_get_warning.txt
new file mode 100644
index 00000000000..36b5434c3ba
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_get_warning.txt
@@ -0,0 +1,10 @@
+# go get in GO111MODULE=auto should warn when not using modules and go.mod exists
+
+env GO111MODULE=auto
+mkdir z
+cd z
+! go get # fails because no code in directory, not the warning
+stderr 'go get: warning: modules disabled by GO111MODULE=auto in GOPATH/src;\n\tignoring ..[/\\]go.mod;\n\tsee ''go help modules'''
+
+-- go.mod --
+module x
diff --git a/libgo/go/cmd/go/testdata/script/mod_getmode_vendor.txt b/libgo/go/cmd/go/testdata/script/mod_getmode_vendor.txt
new file mode 100644
index 00000000000..3dd8d1b888d
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_getmode_vendor.txt
@@ -0,0 +1,23 @@
+env GO111MODULE=on
+
+go get -m rsc.io/quote@v1.5.1
+go mod vendor
+env GOPATH=$WORK/empty
+env GOPROXY=file:///nonexist
+
+go list -mod=vendor
+go list -mod=vendor -m -f '{{.Path}} {{.Version}} {{.Dir}}' all
+stdout '^rsc.io/quote v1.5.1 .*vendor[\\/]rsc.io[\\/]quote$'
+stdout '^golang.org/x/text v0.0.0.* .*vendor[\\/]golang.org[\\/]x[\\/]text$'
+
+! go list -mod=vendor -m rsc.io/quote@latest
+stderr 'module lookup disabled by -mod=vendor'
+! go get -mod=vendor -u
+stderr 'go get: disabled by -mod=vendor'
+
+-- go.mod --
+module x
+
+-- x.go --
+package x
+import _ "rsc.io/quote"
diff --git a/libgo/go/cmd/go/testdata/script/mod_go_version.txt b/libgo/go/cmd/go/testdata/script/mod_go_version.txt
new file mode 100644
index 00000000000..f2de74cee87
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_go_version.txt
@@ -0,0 +1,61 @@
+# Test support for declaring needed Go version in module.
+
+env GO111MODULE=on
+
+go list
+! go build
+stderr 'module requires Go 1.999'
+go build sub.1
+! go build badsub.1
+stderr 'module requires Go 1.11111'
+
+go build versioned.1
+go mod edit -require versioned.1@v1.1.0
+! go build versioned.1
+stderr 'module requires Go 1.99999'
+
+-- go.mod --
+module m
+go 1.999
+require (
+ sub.1 v1.0.0
+ badsub.1 v1.0.0
+ versioned.1 v1.0.0
+)
+replace (
+ sub.1 => ./sub
+ badsub.1 => ./badsub
+ versioned.1 v1.0.0 => ./versioned1
+ versioned.1 v1.1.0 => ./versioned2
+)
+
+-- x.go --
+package x
+
+-- sub/go.mod --
+module m
+go 1.11
+
+-- sub/x.go --
+package x
+
+-- badsub/go.mod --
+module m
+go 1.11111
+
+-- badsub/x.go --
+package x
+
+-- versioned1/go.mod --
+module versioned
+go 1.0
+
+-- versioned1/x.go --
+package x
+
+-- versioned2/go.mod --
+module versioned
+go 1.99999
+
+-- versioned2/x.go --
+package x
diff --git a/libgo/go/cmd/go/testdata/script/mod_gobuild_import.txt b/libgo/go/cmd/go/testdata/script/mod_gobuild_import.txt
new file mode 100644
index 00000000000..932b8b66f92
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_gobuild_import.txt
@@ -0,0 +1,74 @@
+# go/build's Import should find modules by invoking the go command
+
+go build -o $WORK/testimport.exe ./testimport
+
+# GO111MODULE=off
+env GO111MODULE=off
+! exec $WORK/testimport.exe x/y/z/w .
+
+# GO111MODULE=auto in GOPATH/src
+env GO111MODULE=
+! exec $WORK/testimport.exe x/y/z/w .
+env GO111MODULE=auto
+! exec $WORK/testimport.exe x/y/z/w .
+
+# GO111MODULE=auto outside GOPATH/src
+cd $GOPATH/other
+env GO111MODULE=
+exec $WORK/testimport.exe other/x/y/z/w .
+stdout w2.go
+
+! exec $WORK/testimport.exe x/y/z/w .
+stderr 'cannot find module providing package x/y/z/w'
+
+cd z
+env GO111MODULE=auto
+exec $WORK/testimport.exe other/x/y/z/w .
+stdout w2.go
+
+# GO111MODULE=on outside GOPATH/src
+env GO111MODULE=on
+exec $WORK/testimport.exe other/x/y/z/w .
+stdout w2.go
+
+# GO111MODULE=on in GOPATH/src
+cd $GOPATH/src
+exec $WORK/testimport.exe x/y/z/w .
+stdout w1.go
+cd w
+exec $WORK/testimport.exe x/y/z/w ..
+stdout w1.go
+
+-- go.mod --
+module x/y/z
+
+-- z.go --
+package z
+
+-- w/w1.go --
+package w
+
+-- testimport/x.go --
+package main
+
+import (
+ "fmt"
+ "go/build"
+ "log"
+ "os"
+ "strings"
+)
+
+func main() {
+ p, err := build.Import(os.Args[1], os.Args[2], 0)
+ if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Printf("%s\n%s\n", p.Dir, strings.Join(p.GoFiles, " "))
+}
+
+-- $GOPATH/other/go.mod --
+module other/x/y
+
+-- $GOPATH/other/z/w/w2.go --
+package w
diff --git a/libgo/go/cmd/go/testdata/script/mod_gofmt_invalid.txt b/libgo/go/cmd/go/testdata/script/mod_gofmt_invalid.txt
new file mode 100644
index 00000000000..21edc7dc2f4
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_gofmt_invalid.txt
@@ -0,0 +1,13 @@
+# Test for a crash in go fmt on invalid input when using modules.
+# Issue 26792.
+
+env GO111MODULE=on
+! go fmt x.go
+! stderr panic
+
+-- go.mod --
+module x
+
+-- x.go --
+// Missing package declaration.
+var V int
diff --git a/libgo/go/cmd/go/testdata/script/mod_gopkg_unstable.txt b/libgo/go/cmd/go/testdata/script/mod_gopkg_unstable.txt
new file mode 100644
index 00000000000..d945cf35b43
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_gopkg_unstable.txt
@@ -0,0 +1,22 @@
+env GO111MODULE=on
+
+cp go.mod.empty go.mod
+go get -d gopkg.in/dummy.v2-unstable
+
+cp x.go.txt x.go
+cp go.mod.empty go.mod
+go list
+
+[!net] skip
+
+env GOPROXY=
+go get gopkg.in/macaroon-bakery.v2-unstable/bakery
+go list -m all
+stdout 'gopkg.in/macaroon-bakery.v2-unstable v2.0.0-[0-9]+-[0-9a-f]+$'
+
+-- go.mod.empty --
+module m
+
+-- x.go.txt --
+package x
+import _ "gopkg.in/dummy.v2-unstable"
diff --git a/libgo/go/cmd/go/testdata/script/mod_graph.txt b/libgo/go/cmd/go/testdata/script/mod_graph.txt
new file mode 100644
index 00000000000..07968f531d2
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_graph.txt
@@ -0,0 +1,10 @@
+env GO111MODULE=on
+
+go mod graph
+stdout '^m rsc.io/quote@v1.5.2$'
+stdout '^rsc.io/quote@v1.5.2 rsc.io/sampler@v1.3.0$'
+! stdout '^m rsc.io/sampler@v1.3.0$'
+
+-- go.mod --
+module m
+require rsc.io/quote v1.5.2
diff --git a/libgo/go/cmd/go/testdata/script/mod_import.txt b/libgo/go/cmd/go/testdata/script/mod_import.txt
new file mode 100644
index 00000000000..3985b43144c
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_import.txt
@@ -0,0 +1,18 @@
+env GO111MODULE=on
+
+# latest rsc.io/quote should be v1.5.2 not v1.5.3-pre1
+go list
+go list -m all
+stdout 'rsc.io/quote v1.5.2'
+
+# but v1.5.3-pre1 should be a known version
+go list -m -versions rsc.io/quote
+stdout '^rsc.io/quote v1.0.0 v1.1.0 v1.2.0 v1.2.1 v1.3.0 v1.4.0 v1.5.0 v1.5.1 v1.5.2 v1.5.3-pre1$'
+
+-- go.mod --
+module x
+
+-- x.go --
+package x
+import _ "rsc.io/quote"
+
diff --git a/libgo/go/cmd/go/testdata/script/mod_import_mod.txt b/libgo/go/cmd/go/testdata/script/mod_import_mod.txt
new file mode 100644
index 00000000000..b035e3dec22
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_import_mod.txt
@@ -0,0 +1,7 @@
+# Test that GOPATH/pkg/mod is excluded
+env GO111MODULE=off
+! go list mod/foo
+stderr 'disallowed import path'
+
+-- mod/foo/foo.go --
+package foo
diff --git a/libgo/go/cmd/go/testdata/script/mod_init_dep.txt b/libgo/go/cmd/go/testdata/script/mod_init_dep.txt
new file mode 100644
index 00000000000..29c840b3833
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_init_dep.txt
@@ -0,0 +1,34 @@
+env GO111MODULE=on
+
+# modconv uses git directly to examine what old 'go get' would
+[!net] skip
+[!exec:git] skip
+
+# go build should populate go.mod from Gopkg.lock
+cp go.mod1 go.mod
+go build
+stderr 'copying requirements from Gopkg.lock'
+go list -m all
+! stderr 'copying requirements from Gopkg.lock'
+stdout 'rsc.io/sampler v1.0.0'
+
+# go list should populate go.mod from Gopkg.lock
+cp go.mod1 go.mod
+go list
+stderr 'copying requirements from Gopkg.lock'
+go list
+! stderr 'copying requirements from Gopkg.lock'
+go list -m all
+stdout 'rsc.io/sampler v1.0.0'
+
+-- go.mod1 --
+module x
+
+-- x.go --
+package x
+
+-- Gopkg.lock --
+[[projects]]
+ name = "rsc.io/sampler"
+ version = "v1.0.0"
+
diff --git a/libgo/go/cmd/go/testdata/script/mod_install_versioned.txt b/libgo/go/cmd/go/testdata/script/mod_install_versioned.txt
new file mode 100644
index 00000000000..03986d06a0a
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_install_versioned.txt
@@ -0,0 +1,12 @@
+env GO111MODULE=on
+
+go list -f '{{.Target}}' rsc.io/fortune
+! stdout fortune@v1
+stdout 'fortune(\.exe)?$'
+
+go list -f '{{.Target}}' rsc.io/fortune/v2
+! stdout v2
+stdout 'fortune(\.exe)?$'
+
+-- go.mod --
+module m
diff --git a/libgo/go/cmd/go/testdata/script/mod_internal.txt b/libgo/go/cmd/go/testdata/script/mod_internal.txt
new file mode 100644
index 00000000000..84e77c6d83c
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_internal.txt
@@ -0,0 +1,102 @@
+env GO111MODULE=on
+
+# golang.org/x/internal should be importable from other golang.org/x modules.
+rm go.mod
+go mod init golang.org/x/anything
+go build .
+
+# ...and their tests...
+go test
+stdout PASS
+
+# ...but that should not leak into other modules.
+! go build ./baddep
+stderr golang.org[/\\]notx[/\\]useinternal
+stderr 'use of internal package golang.org/x/.* not allowed'
+
+# Internal packages in the standard library should not leak into modules.
+! go build ./fromstd
+[!gccgo] stderr 'use of internal package internal/testenv not allowed'
+
+# Packages found via standard-library vendoring should not leak.
+! go build ./fromstdvendor
+[!gccgo] stderr 'use of vendored package golang_org/x/net/http/httpguts not allowed'
+
+env GO111MODULE=off
+! go build ./fromstdvendor
+[!gccgo] stderr 'cannot find package "golang_org/x/net/http/httpguts" in any of:'
+env GO111MODULE=on
+
+# Dependencies should be able to use their own internal modules...
+rm go.mod
+go mod init golang.org/notx
+go build ./throughdep
+
+# ... but other modules should not, even if they have transitive dependencies.
+! go build .
+stderr 'use of internal package golang.org/x/.* not allowed'
+
+# And transitive dependencies still should not leak.
+! go build ./baddep
+stderr golang.org[/\\]notx[/\\]useinternal
+stderr 'use of internal package golang.org/x/.* not allowed'
+
+# Replacing an internal module should keep it internal to the same paths.
+rm go.mod
+go mod init golang.org/notx
+go mod edit -replace golang.org/x/internal=./replace/golang.org/notx/internal
+go build ./throughdep
+
+! go build ./baddep
+stderr golang.org[/\\]notx[/\\]useinternal
+stderr 'use of internal package golang.org/x/.* not allowed'
+
+go mod edit -replace golang.org/x/internal=./vendor/golang.org/x/internal
+go build ./throughdep
+
+! go build ./baddep
+stderr golang.org[/\\]notx[/\\]useinternal
+stderr 'use of internal package golang.org/x/.* not allowed'
+
+-- useinternal.go --
+package useinternal
+import _ "golang.org/x/internal/subtle"
+
+-- useinternal_test.go --
+package useinternal_test
+import (
+ "testing"
+ _ "golang.org/x/internal/subtle"
+)
+
+func Test(*testing.T) {}
+
+-- throughdep/useinternal.go --
+package throughdep
+import _ "golang.org/x/useinternal"
+
+-- baddep/useinternal.go --
+package baddep
+import _ "golang.org/notx/useinternal"
+
+-- fromstd/useinternal.go --
+package fromstd
+import _ "internal/testenv"
+
+-- fromstdvendor/useinternal.go --
+package fromstdvendor
+import _ "golang_org/x/net/http/httpguts"
+
+-- replace/golang.org/notx/internal/go.mod --
+module golang.org/x/internal
+
+-- replace/golang.org/notx/internal/subtle/subtle.go --
+package subtle
+// Ha ha! Nothing here!
+
+-- vendor/golang.org/x/internal/go.mod --
+module golang.org/x/internal
+
+-- vendor/golang.org/x/internal/subtle/subtle.go --
+package subtle
+// Ha ha! Nothing here!
diff --git a/libgo/go/cmd/go/testdata/script/mod_list.txt b/libgo/go/cmd/go/testdata/script/mod_list.txt
new file mode 100644
index 00000000000..2fa079f49ae
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_list.txt
@@ -0,0 +1,60 @@
+env GO111MODULE=on
+
+# list {{.Dir}} shows main module and go.mod but not not-yet-downloaded dependency dir.
+go list -m -f '{{.Path}} {{.Main}} {{.GoMod}} {{.Dir}}' all
+stdout '^x true .*[\\/]src[\\/]go.mod .*[\\/]src$'
+stdout '^rsc.io/quote false .*[\\/]v1.5.2.mod $'
+
+# list {{.Dir}} shows dependency after download (and go list without -m downloads it)
+go list -f '{{.Dir}}' rsc.io/quote
+stdout '.*mod[\\/]rsc.io[\\/]quote@v1.5.2$'
+
+# downloaded dependencies are read-only
+exists -readonly $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
+exists -readonly $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/buggy
+
+# go clean -modcache can delete read-only dependencies
+go clean -modcache
+! exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
+
+# list {{.Dir}} shows replaced directories
+cp go.mod2 go.mod
+go list -f {{.Dir}} rsc.io/quote
+go list -m -f '{{.Path}} {{.Version}} {{.Dir}}{{with .Replace}} {{.GoMod}} => {{.Version}} {{.Dir}} {{.GoMod}}{{end}}' all
+stdout 'mod[\\/]rsc.io[\\/]quote@v1.5.1'
+stdout 'v1.3.0.*mod[\\/]rsc.io[\\/]sampler@v1.3.1 .*[\\/]v1.3.1.mod => v1.3.1.*sampler@v1.3.1 .*[\\/]v1.3.1.mod'
+
+# list std should work
+go list std
+[!gccgo] stdout ^math/big
+
+# rsc.io/quote/buggy should be listable as a package
+go list rsc.io/quote/buggy
+
+# rsc.io/quote/buggy should not be listable as a module
+go list -m -e -f '{{.Error.Err}}' nonexist rsc.io/quote/buggy
+stdout '^module "nonexist" is not a known dependency'
+stdout '^module "rsc.io/quote/buggy" is not a known dependency'
+
+! go list -m nonexist rsc.io/quote/buggy
+stderr '^go list -m nonexist: module "nonexist" is not a known dependency'
+stderr '^go list -m rsc.io/quote/buggy: module "rsc.io/quote/buggy" is not a known dependency'
+
+# Module loader does not interfere with list -e (golang.org/issue/24149).
+[!gccgo] go list -e -f '{{.Error.Err}}' database
+[!gccgo] stdout 'no Go files in '
+[!gccgo] ! go list database
+[!gccgo] stderr 'no Go files in '
+
+-- go.mod --
+module x
+require rsc.io/quote v1.5.2
+
+-- go.mod2 --
+module x
+require rsc.io/quote v1.5.1
+replace rsc.io/sampler v1.3.0 => rsc.io/sampler v1.3.1
+
+-- x.go --
+package x
+import _ "rsc.io/quote"
diff --git a/libgo/go/cmd/go/testdata/script/mod_list_bad_import.txt b/libgo/go/cmd/go/testdata/script/mod_list_bad_import.txt
new file mode 100644
index 00000000000..258eb6a5671
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_list_bad_import.txt
@@ -0,0 +1,73 @@
+# This test matches list_bad_import, but in module mode.
+# Please keep them in sync.
+
+env GO111MODULE=on
+cd example.com
+
+# Without -e, listing an otherwise-valid package with an unsatisfied direct import should fail.
+# BUG: Today it succeeds.
+go list -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}} {{range .DepsErrors}}bad dep: {{.Err}}{{end}}' example.com/direct
+! stdout ^error
+stdout 'incomplete'
+stdout 'bad dep: .*example.com/notfound'
+
+# Listing with -deps should also fail.
+# BUG: Today, it does not.
+# ! go list -deps example.com/direct
+# stderr example.com/notfound
+go list -deps example.com/direct
+stdout example.com/notfound
+
+
+# Listing an otherwise-valid package that imports some *other* package with an
+# unsatisfied import should also fail.
+# BUG: Today, it succeeds.
+go list -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}} {{range .DepsErrors}}bad dep: {{.Err}}{{end}}' example.com/indirect
+! stdout ^error
+stdout incomplete
+stdout 'bad dep: .*example.com/notfound'
+
+# Again, -deps should fail.
+# BUG: Again, it does not.
+# ! go list -deps example.com/indirect
+# stderr example.com/notfound
+go list -deps example.com/indirect
+stdout example.com/notfound
+
+
+# Listing the missing dependency directly should fail outright...
+! go list -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}}' example.com/notfound
+stderr 'cannot find module providing package example.com/notfound'
+! stdout error
+! stdout incomplete
+
+# ...but listing with -e should succeed.
+go list -e -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}}' example.com/notfound
+stdout error
+stdout incomplete
+
+
+# The pattern "all" should match only packages that acutally exist,
+# ignoring those whose existence is merely implied by imports.
+go list -e -f '{{.ImportPath}} {{.Error}}' all
+stdout example.com/direct
+stdout example.com/indirect
+# TODO: go list creates a dummy package with the import-not-found
+# but really the Error belongs on example.com/direct, and this package
+# should not be printed.
+# ! stdout example.com/notfound
+
+
+-- example.com/go.mod --
+module example.com
+
+-- example.com/direct/direct.go --
+package direct
+import _ "example.com/notfound"
+
+-- example.com/indirect/indirect.go --
+package indirect
+import _ "example.com/direct"
+
+-- example.com/notfound/README --
+This directory intentionally left blank.
diff --git a/libgo/go/cmd/go/testdata/script/mod_list_dir.txt b/libgo/go/cmd/go/testdata/script/mod_list_dir.txt
new file mode 100644
index 00000000000..6d9414794e5
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_list_dir.txt
@@ -0,0 +1,32 @@
+# go list with path to directory should work
+
+[gccgo] stop
+
+env GO111MODULE=off
+go list -f '{{.ImportPath}}' $GOROOT/src/math
+stdout ^math$
+
+env GO111MODULE=on
+go list -f '{{.ImportPath}}' $GOROOT/src/math
+stdout ^math$
+go list -f '{{.ImportPath}}' .
+stdout ^x$
+! go list -f '{{.ImportPath}}' $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
+stderr '^go: no such directory.*quote@v1.5.2'
+go mod download rsc.io/quote@v1.5.2
+go list -f '{{.ImportPath}}' $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
+stdout '^rsc.io/quote$'
+go list -f '{{.ImportPath}}' $GOPATH/pkg/mod/rsc.io/sampler@v1.3.0
+stdout '^rsc.io/sampler$'
+go get -d rsc.io/sampler@v1.3.1
+go list -f '{{.ImportPath}}' $GOPATH/pkg/mod/rsc.io/sampler@v1.3.1
+stdout '^rsc.io/sampler$'
+! go list -f '{{.ImportPath}}' $GOPATH/pkg/mod/rsc.io/sampler@v1.3.0
+stderr 'outside available modules'
+
+-- go.mod --
+module x
+require rsc.io/quote v1.5.2
+
+-- x.go --
+package x
diff --git a/libgo/go/cmd/go/testdata/script/mod_list_upgrade.txt b/libgo/go/cmd/go/testdata/script/mod_list_upgrade.txt
new file mode 100644
index 00000000000..474df0dc269
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_list_upgrade.txt
@@ -0,0 +1,8 @@
+env GO111MODULE=on
+
+go list -m -u all
+stdout 'rsc.io/quote v1.2.0 \[v1\.5\.2\]'
+
+-- go.mod --
+module x
+require rsc.io/quote v1.2.0
diff --git a/libgo/go/cmd/go/testdata/script/mod_load_badmod.txt b/libgo/go/cmd/go/testdata/script/mod_load_badmod.txt
new file mode 100644
index 00000000000..68c8b3792bd
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_load_badmod.txt
@@ -0,0 +1,26 @@
+# Unknown lines should be ignored in dependency go.mod files.
+env GO111MODULE=on
+go list -m all
+
+# ... and in replaced dependency go.mod files.
+cp go.mod go.mod.usesub
+go list -m all
+
+# ... but not in the main module.
+cp go.mod.bad go.mod
+! go list -m all
+stderr 'unknown directive: hello'
+
+-- go.mod --
+module m
+require rsc.io/badmod v1.0.0
+-- go.mod.bad --
+module m
+hello world
+-- go.mod.usesub --
+module m
+require rsc.io/badmod v1.0.0
+replace rsc.io/badmod v1.0.0 => ./sub
+-- sub/go.mod --
+module sub
+hello world
diff --git a/libgo/go/cmd/go/testdata/script/mod_local_replace.txt b/libgo/go/cmd/go/testdata/script/mod_local_replace.txt
new file mode 100644
index 00000000000..19bc8f39045
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_local_replace.txt
@@ -0,0 +1,23 @@
+# Test that local replacements work even with dummy module names.
+# golang.org/issue/24100.
+
+env GO111MODULE=on
+
+cd x/y
+go list -f '{{.Dir}}' zz
+stdout x[/\\]z$
+
+-- x/y/go.mod --
+module x/y
+require zz v1.0.0
+replace zz v1.0.0 => ../z
+
+-- x/y/y.go --
+package y
+import _ "zz"
+
+-- x/z/go.mod --
+module x/z
+
+-- x/z/z.go --
+package z
diff --git a/libgo/go/cmd/go/testdata/script/mod_multirepo.txt b/libgo/go/cmd/go/testdata/script/mod_multirepo.txt
new file mode 100644
index 00000000000..7f977e80f6e
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_multirepo.txt
@@ -0,0 +1,40 @@
+env GO111MODULE=on
+
+# initial standalone module should use no downloaded modules
+go list -deps -f {{.Dir}}
+! stdout 'pkg[\\/]mod'
+
+# v2 import should use a downloaded module
+# both without an explicit go.mod entry ...
+cp tmp/use_v2.go x.go
+go list -deps -f {{.Dir}}
+stdout 'pkg[\\/]mod[\\/]rsc.io[\\/]quote[\\/]v2@v2.0.1$'
+
+# ... and with one ...
+cp tmp/use_v2.mod go.mod
+go list -deps -f {{.Dir}}
+stdout 'pkg[\\/]mod[\\/]rsc.io[\\/]quote[\\/]v2@v2.0.1$'
+
+# ... and even if there is a v2 module in a subdirectory.
+mkdir v2
+cp x.go v2/x.go
+cp tmp/v2.mod v2/go.mod
+go list -deps -f {{.Dir}}
+stdout 'pkg[\\/]mod[\\/]rsc.io[\\/]quote[\\/]v2@v2.0.1$'
+
+-- go.mod --
+module rsc.io/quote
+
+-- x.go --
+package quote
+
+-- tmp/use_v2.go --
+package quote
+import _ "rsc.io/quote/v2"
+
+-- tmp/use_v2.mod --
+module rsc.io/quote
+require rsc.io/quote/v2 v2.0.1
+
+-- tmp/v2.mod --
+package rsc.io/quote/v2
diff --git a/libgo/go/cmd/go/testdata/script/mod_nomod.txt b/libgo/go/cmd/go/testdata/script/mod_nomod.txt
new file mode 100644
index 00000000000..c6fb791c514
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_nomod.txt
@@ -0,0 +1,43 @@
+# Test go commands with no module.
+env GO111MODULE=on
+
+# go mod edit fails unless given explicit mod file argument
+! go mod edit -json
+go mod edit -json x.mod
+
+# bug succeeds
+[exec:echo] env BROWSER=echo
+[exec:echo] go bug
+
+# commands that load the package in the current directory fail
+! go build
+! go fmt
+! go generate
+! go get
+! go install
+! go list
+! go run x.go
+! go test
+! go vet
+
+# clean succeeds, even with -modcache
+go clean -modcache
+
+# doc succeeds for standard library
+[!gccgo] go doc unsafe
+
+# env succeeds
+go env
+
+# tool succeeds
+go tool -n test2json
+
+# version succeeds
+go version
+
+-- x.mod --
+module m
+
+-- x.go --
+package main
+func main() {}
diff --git a/libgo/go/cmd/go/testdata/script/mod_patterns.txt b/libgo/go/cmd/go/testdata/script/mod_patterns.txt
new file mode 100644
index 00000000000..9b2ebdf02b9
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_patterns.txt
@@ -0,0 +1,66 @@
+env GO111MODULE=on
+
+cd m
+
+# 'go list all' should list all of the packages used (directly or indirectly) by
+# the packages in the main module, but no other packages from the standard
+# library or active modules.
+#
+# 'go list ...' should list packages in all active modules and the standard library.
+# But not cmd/* - see golang.org/issue/26924.
+#
+# 'go list example.com/m/...' should list packages in all modules that begin with 'example.com/m/'.
+#
+# 'go list ./...' should list only packages in the current module, not other active modules.
+#
+# Warnings about unmatched patterns should only be printed once.
+#
+# And the go command should be able to keep track of all this!
+go list -f '{{.ImportPath}}: {{.Match}}' all ... example.com/m/... ./... ./xyz...
+stdout 'example.com/m/useunicode: \[all \.\.\. example.com/m/... ./...\]'
+stdout 'example.com/m/useunsafe: \[all \.\.\. example.com/m/... ./...\]'
+[cgo] stdout 'example.com/m/useC: \[all \.\.\. example.com/m/... ./...\]'
+[!cgo] ! stdout example.com/m/useC
+stdout 'example.com/unused/useerrors: \[\.\.\.\]' # but not "all"
+stdout 'example.com/m/nested/useencoding: \[\.\.\. example.com/m/...\]' # but NOT "all" or "./..."
+[!gccgo] stdout '^unicode: \[all \.\.\.\]'
+[!gccgo] stdout '^unsafe: \[all \.\.\.\]'
+[!gccgo] stdout 'index/suffixarray: \[\.\.\.\]'
+! stdout cmd/pprof # golang.org/issue/26924
+
+stderr -count=1 '^go: warning: "./xyz..." matched no packages$'
+
+env CGO_ENABLED=0
+go list -f '{{.ImportPath}}: {{.Match}}' all ... example.com/m/... ./... ./xyz...
+! stdout example.com/m/useC
+
+-- m/go.mod --
+module example.com/m
+
+require example.com/unused v0.0.0 // indirect
+replace example.com/unused => ../unused
+
+require example.com/m/nested v0.0.0 // indirect
+replace example.com/m/nested => ../nested
+
+-- m/useC/useC.go --
+package useC
+import _ "C" // "C" is a pseudo-package, not an actual one
+-- m/useunicode/useunicode.go --
+package useunicode
+import _ "unicode"
+-- m/useunsafe/useunsafe.go --
+package useunsafe
+import _ "unsafe"
+
+-- unused/go.mod --
+module example.com/unused
+-- unused/useerrors/useerrors.go --
+package useerrors
+import _ "errors"
+
+-- nested/go.mod --
+module example.com/m/nested
+-- nested/useencoding/useencoding.go --
+package useencoding
+import _ "encoding"
diff --git a/libgo/go/cmd/go/testdata/script/mod_query.txt b/libgo/go/cmd/go/testdata/script/mod_query.txt
new file mode 100644
index 00000000000..4baaaa89ed9
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_query.txt
@@ -0,0 +1,24 @@
+env GO111MODULE=on
+
+go list -m -versions rsc.io/quote
+stdout '^rsc.io/quote v1.0.0 v1.1.0 v1.2.0 v1.2.1 v1.3.0 v1.4.0 v1.5.0 v1.5.1 v1.5.2 v1.5.3-pre1$'
+
+# latest rsc.io/quote should be v1.5.2 not v1.5.3-pre1
+go list -m rsc.io/quote@latest
+stdout 'rsc.io/quote v1.5.2$'
+
+go list -m rsc.io/quote@>v1.5.2
+stdout 'rsc.io/quote v1.5.3-pre1$'
+
+go list -m rsc.io/quote@<v1.5.4
+stdout 'rsc.io/quote v1.5.2$'
+
+! go list -m rsc.io/quote@>v1.5.3
+stderr 'go list -m rsc.io/quote: no matching versions for query ">v1.5.3"'
+
+go list -m -e -f '{{.Error.Err}}' rsc.io/quote@>v1.5.3
+stdout 'no matching versions for query ">v1.5.3"'
+
+-- go.mod --
+module x
+require rsc.io/quote v1.0.0
diff --git a/libgo/go/cmd/go/testdata/script/mod_query_exclude.txt b/libgo/go/cmd/go/testdata/script/mod_query_exclude.txt
new file mode 100644
index 00000000000..a64a8e10866
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_query_exclude.txt
@@ -0,0 +1,26 @@
+env GO111MODULE=on
+
+# get excluded version
+cp go.mod1 go.mod
+! go get rsc.io/quote@v1.5.0
+stderr 'rsc.io/quote@v1.5.0 excluded'
+
+# get non-excluded version
+cp go.mod1 go.mod
+go get rsc.io/quote@v1.5.1
+stderr 'rsc.io/quote v1.5.1'
+
+# get range with excluded version
+cp go.mod1 go.mod
+go get rsc.io/quote@>=v1.5
+go list -m ...quote
+stdout 'rsc.io/quote v1.5.[1-9]'
+
+-- go.mod1 --
+module x
+exclude rsc.io/quote v1.5.0
+
+-- x.go --
+package x
+import _ "rsc.io/quote"
+
diff --git a/libgo/go/cmd/go/testdata/script/mod_readonly.txt b/libgo/go/cmd/go/testdata/script/mod_readonly.txt
new file mode 100644
index 00000000000..1b5932e441e
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_readonly.txt
@@ -0,0 +1,42 @@
+env GO111MODULE=on
+
+# -mod=readonly must not resolve missing modules nor update go.mod
+#
+# TODO(bcmills): 'go list' should suffice, but today it does not fail due to
+# unresolved imports. When that is fixed, use 'go list' instead of 'go list all'.
+env GOFLAGS=-mod=readonly
+go mod edit -fmt
+cp go.mod go.mod.empty
+! go list all
+stderr 'import lookup disabled by -mod=readonly'
+cmp go.mod go.mod.empty
+
+# update go.mod - go get allowed
+go get rsc.io/quote
+grep rsc.io/quote go.mod
+
+# update go.mod - go mod tidy allowed
+cp go.mod.empty go.mod
+go mod tidy
+
+# -mod=readonly must succeed once go.mod is up-to-date...
+go list
+
+# ... even if it needs downloads
+go clean -modcache
+go list
+
+# -mod=readonly should reject inconsistent go.mod files
+# (ones that would be rewritten).
+go mod edit -require rsc.io/sampler@v1.2.0
+cp go.mod go.mod.inconsistent
+! go list
+stderr 'go: updates to go.mod needed, disabled by -mod=readonly'
+cmp go.mod go.mod.inconsistent
+
+-- go.mod --
+module m
+
+-- x.go --
+package x
+import _ "rsc.io/quote"
diff --git a/libgo/go/cmd/go/testdata/script/mod_replace.txt b/libgo/go/cmd/go/testdata/script/mod_replace.txt
new file mode 100644
index 00000000000..5894ed69f34
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_replace.txt
@@ -0,0 +1,87 @@
+env GO111MODULE=on
+
+go build -o a1.exe .
+exec ./a1.exe
+stdout 'Don''t communicate by sharing memory'
+
+# Modules can be replaced by local packages.
+go mod edit -replace=rsc.io/quote/v3=./local/rsc.io/quote/v3
+go build -o a2.exe .
+exec ./a2.exe
+stdout 'Concurrency is not parallelism.'
+
+# The module path of the replacement doesn't need to match.
+# (For example, it could be a long-running fork with its own import path.)
+go mod edit -replace=rsc.io/quote/v3=./local/not-rsc.io/quote/v3
+go build -o a3.exe .
+exec ./a3.exe
+stdout 'Clear is better than clever.'
+
+# However, the same module can't be used as two different paths.
+go mod edit -dropreplace=rsc.io/quote/v3 -replace=not-rsc.io/quote/v3@v3.0.0=rsc.io/quote/v3@v3.0.0 -require=not-rsc.io/quote/v3@v3.0.0
+! go build -o a4.exe .
+stderr 'rsc.io/quote/v3@v3.0.0 used for two different module paths \(not-rsc.io/quote/v3 and rsc.io/quote/v3\)'
+
+-- go.mod --
+module quoter
+
+require rsc.io/quote/v3 v3.0.0
+
+-- main.go --
+package main
+
+import (
+ "fmt"
+ "rsc.io/quote/v3"
+)
+
+func main() {
+ fmt.Println(quote.GoV3())
+}
+
+-- local/rsc.io/quote/v3/go.mod --
+module rsc.io/quote/v3
+
+require rsc.io/sampler v1.3.0
+
+-- local/rsc.io/quote/v3/quote.go --
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package quote collects pithy sayings.
+package quote
+
+import "rsc.io/sampler"
+
+// Hello returns a greeting.
+func HelloV3() string {
+ return sampler.Hello()
+}
+
+// Glass returns a useful phrase for world travelers.
+func GlassV3() string {
+ // See http://www.oocities.org/nodotus/hbglass.html.
+ return "I can eat glass and it doesn't hurt me."
+}
+
+// Go returns a REPLACED Go proverb.
+func GoV3() string {
+ return "Concurrency is not parallelism."
+}
+
+// Opt returns a optimization truth.
+func OptV3() string {
+ // Wisdom from ken.
+ return "If a program is too slow, it must have a loop."
+}
+
+-- local/not-rsc.io/quote/v3/go.mod --
+module not-rsc.io/quote/v3
+
+-- local/not-rsc.io/quote/v3/quote.go --
+package quote
+
+func GoV3() string {
+ return "Clear is better than clever."
+}
diff --git a/libgo/go/cmd/go/testdata/script/mod_require_exclude.txt b/libgo/go/cmd/go/testdata/script/mod_require_exclude.txt
new file mode 100644
index 00000000000..60f7e3fa913
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_require_exclude.txt
@@ -0,0 +1,33 @@
+# build with no newer version to satisfy exclude
+env GO111MODULE=on
+! go list -m all
+stderr 'no newer version available'
+
+# build with newer version available
+cp go.mod2 go.mod
+go list -m all
+stdout 'rsc.io/quote v1.5.2'
+
+# build with excluded newer version
+cp go.mod3 go.mod
+go list -m all
+stdout 'rsc.io/quote v1.5.1'
+
+-- x.go --
+package x
+import _ "rsc.io/quote"
+
+-- go.mod --
+module x
+exclude rsc.io/sampler latest
+require rsc.io/sampler latest
+
+-- go.mod2 --
+module x
+exclude rsc.io/quote v1.5.1
+require rsc.io/quote v1.5.1
+
+-- go.mod3 --
+module x
+exclude rsc.io/quote v1.5.2
+require rsc.io/quote v1.5.1
diff --git a/libgo/go/cmd/go/testdata/script/mod_test.txt b/libgo/go/cmd/go/testdata/script/mod_test.txt
new file mode 100644
index 00000000000..caeb25ada84
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_test.txt
@@ -0,0 +1,119 @@
+env GO111MODULE=on
+
+# A test in the module's root package should work.
+cd a/
+cp go.mod.empty go.mod
+go test
+stdout PASS
+
+cp go.mod.empty go.mod
+go list -deps
+! stdout ^testing$
+
+# list all should include test dependencies, like testing
+cp go.mod.empty go.mod
+go list all
+stdout ^testing$
+stdout ^rsc.io/quote$
+stdout ^rsc.io/testonly$
+
+# list -deps -tests should also include testing
+# but not deps of tests of deps (rsc.io/testonly).
+go list -deps -test
+stdout ^testing$
+stdout ^rsc.io/quote$
+! stdout ^rsc.io/testonly$
+
+# list -test all should succeed
+cp go.mod.empty go.mod
+go list -test all
+stdout '^testing'
+
+cp go.mod.empty go.mod
+go test
+stdout PASS
+
+# A test with the "_test" suffix in the module root should also work.
+cd ../b/
+go test
+stdout PASS
+
+# A test with the "_test" suffix of a *package* with a "_test" suffix should
+# even work (not that you should ever do that).
+cd ../c_test
+go test
+stdout PASS
+
+cd ../d_test
+go test
+stdout PASS
+
+-- a/go.mod.empty --
+module example.com/user/a
+
+-- a/a.go --
+package a
+
+-- a/a_test.go --
+package a
+
+import "testing"
+import _ "rsc.io/quote"
+
+func Test(t *testing.T) {}
+
+-- b/go.mod --
+module example.com/user/b
+
+-- b/b.go --
+package b
+
+-- b/b_test.go --
+package b_test
+
+import "testing"
+
+func Test(t *testing.T) {}
+
+-- c_test/go.mod --
+module example.com/c_test
+
+-- c_test/umm.go --
+// Package c_test is the non-test package for its import path!
+package c_test
+
+-- c_test/c_test_test.go --
+package c_test_test
+
+import "testing"
+
+func Test(t *testing.T) {}
+
+-- d_test/go.mod --
+// Package d is an ordinary package in a deceptively-named directory.
+module example.com/d
+
+-- d_test/d.go --
+package d
+
+-- d_test/d_test.go --
+package d_test
+
+import "testing"
+
+func Test(t *testing.T) {}
+
+-- e/go.mod --
+module example.com/e_test
+
+-- e/wat.go --
+// Package e_test is the non-test package for its import path,
+// in a deceptively-named directory!
+package e_test
+
+-- e/e_test.go --
+package e_test_test
+
+import "testing"
+
+func Test(t *testing.T) {}
diff --git a/libgo/go/cmd/go/testdata/script/mod_tidy.txt b/libgo/go/cmd/go/testdata/script/mod_tidy.txt
new file mode 100644
index 00000000000..449aa073a78
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_tidy.txt
@@ -0,0 +1,64 @@
+env GO111MODULE=on
+
+# tidy removes unused y, but everything else is used
+go mod tidy -v
+stderr '^unused y.1'
+! stderr '^unused [^y]'
+
+go list -m all
+! stdout '^y'
+stdout '^w.1 v1.2.0'
+stdout '^z.1 v1.2.0'
+
+# empty tidy should not crash
+cd triv
+go mod tidy
+
+-- go.mod --
+module m
+
+require (
+ x.1 v1.0.0
+ y.1 v1.0.0
+ w.1 v1.2.0
+)
+
+replace x.1 v1.0.0 => ./x
+replace y.1 v1.0.0 => ./y
+replace z.1 v1.1.0 => ./z
+replace z.1 v1.2.0 => ./z
+replace w.1 => ./w
+
+-- m.go --
+package m
+
+import _ "x.1"
+import _ "z.1/sub"
+
+-- w/go.mod --
+module w
+
+-- w/w.go --
+package w
+
+-- x/go.mod --
+module x
+require w.1 v1.1.0
+require z.1 v1.1.0
+
+-- x/x.go --
+package x
+import _ "w.1"
+
+-- y/go.mod --
+module y
+require z.1 v1.2.0
+
+-- z/go.mod --
+module z
+
+-- z/sub/sub.go --
+package sub
+
+-- triv/go.mod --
+module triv
diff --git a/libgo/go/cmd/go/testdata/script/mod_tidy_quote.txt b/libgo/go/cmd/go/testdata/script/mod_tidy_quote.txt
new file mode 100644
index 00000000000..423c7c246f9
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_tidy_quote.txt
@@ -0,0 +1,26 @@
+# Check that mod tidy does not introduce repeated
+# require statements when input go.mod has quoted requirements.
+env GO111MODULE=on
+
+go mod tidy
+grep -count=1 rsc.io/quote go.mod
+
+cp go.mod2 go.mod
+go mod tidy
+grep -count=1 rsc.io/quote go.mod
+
+
+-- go.mod --
+module x
+
+-- x.go --
+package x
+import "rsc.io/quote"
+func main() { _ = quote.Hello }
+
+-- go.mod2 --
+module x
+require (
+ "rsc.io/sampler" v1.3.0
+ "rsc.io/quote" v1.5.2
+)
diff --git a/libgo/go/cmd/go/testdata/script/mod_tidy_sum.txt b/libgo/go/cmd/go/testdata/script/mod_tidy_sum.txt
new file mode 100644
index 00000000000..5a15818543e
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_tidy_sum.txt
@@ -0,0 +1,33 @@
+env GO111MODULE=on
+
+# go.sum should list directly used modules and dependencies
+go get rsc.io/quote@v1.5.2
+go mod tidy
+grep rsc.io/sampler go.sum
+
+# go.sum should not normally lose old entries
+go get rsc.io/quote@v1.0.0
+grep 'rsc.io/quote v1.0.0' go.sum
+grep 'rsc.io/quote v1.5.2' go.sum
+grep rsc.io/sampler go.sum
+
+# go mod tidy should clear dead entries from go.sum
+go mod tidy
+grep 'rsc.io/quote v1.0.0' go.sum
+! grep 'rsc.io/quote v1.5.2' go.sum
+! grep rsc.io/sampler go.sum
+
+# go.sum with no entries is OK to keep
+# (better for version control not to delete and recreate.)
+cp x.go.noimports x.go
+go mod tidy
+exists go.sum
+! grep . go.sum
+
+-- go.mod --
+module x
+-- x.go --
+package x
+import _ "rsc.io/quote"
+-- x.go.noimports --
+package x
diff --git a/libgo/go/cmd/go/testdata/script/mod_upgrade_patch.txt b/libgo/go/cmd/go/testdata/script/mod_upgrade_patch.txt
new file mode 100644
index 00000000000..3c27cdbf7bb
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_upgrade_patch.txt
@@ -0,0 +1,29 @@
+env GO111MODULE=on
+
+go list -m all
+stdout '^rsc.io/quote v1.4.0'
+stdout '^rsc.io/sampler v1.0.0'
+
+# get -u=patch rsc.io/quote should take latest quote & patch update its deps
+go get -m -u=patch rsc.io/quote
+go list -m all
+stdout '^rsc.io/quote v1.5.2'
+stdout '^rsc.io/sampler v1.3.1'
+stdout '^golang.org/x/text v0.0.0-'
+
+# get -u=patch quote@v1.2.0 should take that version of quote & patch update its deps
+go get -m -u=patch rsc.io/quote@v1.2.0
+go list -m all
+stdout '^rsc.io/quote v1.2.0'
+stdout '^rsc.io/sampler v1.3.1'
+stdout '^golang.org/x/text v0.0.0-'
+
+# get -u=patch with no args applies to all deps
+go get -m -u=patch
+go list -m all
+stdout '^rsc.io/quote v1.2.1'
+
+-- go.mod --
+module x
+require rsc.io/quote v1.4.0
+
diff --git a/libgo/go/cmd/go/testdata/script/mod_vendor.txt b/libgo/go/cmd/go/testdata/script/mod_vendor.txt
new file mode 100644
index 00000000000..b3769a85041
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_vendor.txt
@@ -0,0 +1,230 @@
+env GO111MODULE=on
+
+go list -m all
+stdout '^x v1.0.0 => ./x'
+stdout '^w'
+
+[!short] go build
+[!short] ! go build -mod=vendor
+
+go list -f {{.Dir}} x
+stdout 'src[\\/]x'
+
+go mod vendor -v
+stderr '^# x v1.0.0 => ./x'
+stderr '^x'
+stderr '^# y v1.0.0 => ./y'
+stderr '^y'
+stderr '^# z v1.0.0 => ./z'
+stderr '^z'
+! stderr '^w'
+
+go list -f {{.Dir}} x
+stdout 'src[\\/]x'
+
+go list -f {{.Dir}} -m x
+stdout 'src[\\/]x'
+
+go list -mod=vendor -f {{.Dir}} x
+stdout 'src[\\/]vendor[\\/]x'
+
+go list -mod=vendor -f {{.Dir}} -m x
+stdout 'src[\\/]vendor[\\/]x'
+
+go list -f {{.Dir}} -m w
+stdout 'src[\\/]w'
+
+! go list -mod=vendor -f {{.Dir}} w
+stderr 'src[\\/]vendor[\\/]w'
+
+! exists vendor/x/testdata
+! exists vendor/a/foo/bar/b/main_test.go
+
+exists vendor/a/foo/AUTHORS.txt
+exists vendor/a/foo/CONTRIBUTORS
+exists vendor/a/foo/LICENSE
+exists vendor/a/foo/PATENTS
+exists vendor/a/foo/COPYING
+exists vendor/a/foo/COPYLEFT
+exists vendor/x/NOTICE!
+exists vendor/mysite/myname/mypkg/LICENSE.txt
+
+! exists vendor/a/foo/licensed-to-kill
+! exists vendor/w
+! exists vendor/w/LICENSE
+! exists vendor/x/x2
+! exists vendor/x/x2/LICENSE
+
+[short] stop
+
+go build
+go build -mod=vendor
+go test -mod=vendor . ./subdir
+go test -mod=vendor ./...
+
+-- go.mod --
+module m
+
+require (
+ a v1.0.0
+ mysite/myname/mypkg v1.0.0
+ w v1.0.0 // indirect
+ x v1.0.0
+ y v1.0.0
+ z v1.0.0
+)
+
+replace (
+ a v1.0.0 => ./a
+ mysite/myname/mypkg v1.0.0 => ./mypkg
+ w v1.0.0 => ./w
+ x v1.0.0 => ./x
+ y v1.0.0 => ./y
+ z v1.0.0 => ./z
+)
+
+-- a/foo/AUTHORS.txt --
+-- a/foo/CONTRIBUTORS --
+-- a/foo/LICENSE --
+-- a/foo/PATENTS --
+-- a/foo/COPYING --
+-- a/foo/COPYLEFT --
+-- a/foo/licensed-to-kill --
+-- w/LICENSE --
+-- x/NOTICE! --
+-- x/x2/LICENSE --
+-- mypkg/LICENSE.txt --
+
+-- a/foo/bar/b/main.go --
+package b
+-- a/foo/bar/b/main_test.go --
+package b
+
+import (
+ "os"
+ "testing"
+)
+
+func TestDir(t *testing.T) {
+ if _, err := os.Stat("../testdata/1"); err != nil {
+ t.Fatalf("testdata: %v", err)
+ }
+}
+-- a/foo/bar/c/main.go --
+package c
+-- a/foo/bar/c/main_test.go --
+package c
+
+import (
+ "os"
+ "testing"
+)
+
+func TestDir(t *testing.T) {
+ if _, err := os.Stat("../../../testdata/1"); err != nil {
+ t.Fatalf("testdata: %v", err)
+ }
+ if _, err := os.Stat("./testdata/1"); err != nil {
+ t.Fatalf("testdata: %v", err)
+ }
+}
+-- a/foo/bar/c/testdata/1 --
+-- a/foo/bar/testdata/1 --
+-- a/go.mod --
+module a
+-- a/main.go --
+package a
+-- a/main_test.go --
+package a
+
+import (
+ "os"
+ "testing"
+)
+
+func TestDir(t *testing.T) {
+ if _, err := os.Stat("./testdata/1"); err != nil {
+ t.Fatalf("testdata: %v", err)
+ }
+}
+-- a/testdata/1 --
+-- appengine.go --
+// +build appengine
+
+package m
+
+import _ "appengine"
+import _ "appengine/datastore"
+-- nonexistent.go --
+// +build alternatereality
+
+package m
+
+import _ "nonexistent.rsc.io"
+-- mypkg/go.mod --
+module me
+-- mypkg/mydir/d.go --
+package mydir
+-- subdir/v1_test.go --
+package m
+
+import _ "mysite/myname/mypkg/mydir"
+-- testdata1.go --
+package m
+
+import _ "a"
+-- testdata2.go --
+package m
+
+import _ "a/foo/bar/b"
+import _ "a/foo/bar/c"
+-- v1.go --
+package m
+
+import _ "x"
+-- v2.go --
+// +build abc
+
+package mMmMmMm
+
+import _ "y"
+-- v3.go --
+// +build !abc
+
+package m
+
+import _ "z"
+-- v4.go --
+// +build notmytag
+
+package m
+
+import _ "x/x1"
+-- w/go.mod --
+module w
+-- w/w.go --
+package w
+-- x/go.mod --
+module x
+-- x/testdata/x.txt --
+placeholder - want directory with no go files
+-- x/x.go --
+package x
+-- x/x1/x1.go --
+// +build notmytag
+
+package x1
+-- x/x2/dummy.txt --
+dummy
+-- x/x_test.go --
+package x
+
+import _ "w"
+-- y/go.mod --
+module y
+-- y/y.go --
+package y
+-- z/go.mod --
+module z
+-- z/z.go --
+package z
diff --git a/libgo/go/cmd/go/testdata/script/mod_vendor_build.txt b/libgo/go/cmd/go/testdata/script/mod_vendor_build.txt
new file mode 100644
index 00000000000..7b304dbb707
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_vendor_build.txt
@@ -0,0 +1,27 @@
+env GO111MODULE=on
+
+# initial conditions: using sampler v1.3.0, not listed in go.mod.
+go list -deps
+stdout rsc.io/sampler
+! grep 'rsc.io/sampler v1.3.0' go.mod
+
+# update to v1.3.1, now indirect in go.mod.
+go get rsc.io/sampler@v1.3.1
+grep 'rsc.io/sampler v1.3.1 // indirect' go.mod
+cp go.mod go.mod.good
+
+# vendoring can but should not need to make changes.
+go mod vendor
+cmp go.mod go.mod.good
+
+# go list -mod=vendor (or go build -mod=vendor) must not modify go.mod.
+# golang.org/issue/26704
+go list -mod=vendor
+cmp go.mod go.mod.good
+
+-- go.mod --
+module m
+
+-- x.go --
+package x
+import _ "rsc.io/quote"
diff --git a/libgo/go/cmd/go/testdata/script/mod_vendor_nodeps.txt b/libgo/go/cmd/go/testdata/script/mod_vendor_nodeps.txt
new file mode 100644
index 00000000000..e9a84ca9860
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_vendor_nodeps.txt
@@ -0,0 +1,9 @@
+env GO111MODULE=on
+
+go mod vendor
+stderr '^go: no dependencies to vendor'
+
+-- go.mod --
+module x
+-- x.go --
+package x
diff --git a/libgo/go/cmd/go/testdata/script/mod_verify.txt b/libgo/go/cmd/go/testdata/script/mod_verify.txt
new file mode 100644
index 00000000000..50c9b4a4375
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_verify.txt
@@ -0,0 +1,85 @@
+env GO111MODULE=on
+
+# With good go.sum, verify succeeds by avoiding download.
+cp go.sum.good go.sum
+go mod verify
+! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.1.0.zip
+
+# With bad go.sum, verify succeeds by avoiding download.
+cp go.sum.bad go.sum
+go mod verify
+! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.1.0.zip
+
+# With bad go.sum, sync (which must download) fails.
+# Even if the bad sum is in the old legacy go.modverify file.
+rm go.sum
+cp go.sum.bad go.modverify
+! go mod tidy
+stderr 'checksum mismatch'
+! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.1.0.zip
+
+# With good go.sum, sync works (and moves go.modverify to go.sum).
+rm go.sum
+cp go.sum.good go.modverify
+go mod tidy
+exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.1.0.zip
+exists $GOPATH/pkg/mod/rsc.io/quote@v1.1.0/quote.go
+! exists go.modverify
+
+# go.sum should have the new checksum for go.mod
+grep '^rsc.io/quote v1.1.0/go.mod ' go.sum
+
+# verify should work
+go mod verify
+
+# basic loading of module graph should detect incorrect go.mod files.
+go mod graph
+cp go.sum.bad2 go.sum
+! go mod graph
+stderr 'go.mod: checksum mismatch'
+
+# go.sum should be created and updated automatically.
+rm go.sum
+go mod graph
+exists go.sum
+grep '^rsc.io/quote v1.1.0/go.mod ' go.sum
+! grep '^rsc.io/quote v1.1.0 ' go.sum
+
+go mod tidy
+grep '^rsc.io/quote v1.1.0/go.mod ' go.sum
+grep '^rsc.io/quote v1.1.0 ' go.sum
+
+# sync should ignore missing ziphash; verify should not
+rm $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.1.0.ziphash
+go mod tidy
+! go mod verify
+
+# Packages below module root should not be mentioned in go.sum.
+rm go.sum
+go mod edit -droprequire rsc.io/quote
+go list rsc.io/quote/buggy # re-resolves import path and updates go.mod
+grep '^rsc.io/quote v1.5.2/go.mod ' go.sum
+! grep buggy go.sum
+
+# non-existent packages below module root should not be mentioned in go.sum
+go mod edit -droprequire rsc.io/quote
+! go list rsc.io/quote/morebuggy
+grep '^rsc.io/quote v1.5.2/go.mod ' go.sum
+! grep buggy go.sum
+
+-- go.mod --
+module x
+require rsc.io/quote v1.1.0
+
+-- x.go --
+package x
+import _ "rsc.io/quote"
+
+-- go.sum.good --
+rsc.io/quote v1.1.0 h1:a3YaZoizPtXyv6ZsJ74oo2L4/bwOSTKMY7MAyo4O/0c=
+
+-- go.sum.bad --
+rsc.io/quote v1.1.0 h1:a3YaZoizPtXyv6ZsJ74oo2L4/bwOSTKMY7MAyo4O/1c=
+
+-- go.sum.bad2 --
+rsc.io/quote v1.1.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl1=
diff --git a/libgo/go/cmd/go/testdata/script/mod_versions.txt b/libgo/go/cmd/go/testdata/script/mod_versions.txt
new file mode 100644
index 00000000000..fd5e5c589d2
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_versions.txt
@@ -0,0 +1,14 @@
+# Test rejection of pkg@version in GOPATH mode.
+env GO111MODULE=off
+! go get rsc.io/quote@v1.5.1
+stderr 'cannot use path@version syntax in GOPATH mode'
+! go build rsc.io/quote@v1.5.1
+stderr 'cannot use path@version syntax in GOPATH mode'
+
+env GO111MODULE=on
+cd x
+! go build rsc.io/quote@v1.5.1
+stderr 'can only use path@version syntax with ''go get'''
+
+-- x/go.mod --
+module x
diff --git a/libgo/go/cmd/go/testdata/script/mod_why.txt b/libgo/go/cmd/go/testdata/script/mod_why.txt
new file mode 100644
index 00000000000..4d556fc73ff
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/mod_why.txt
@@ -0,0 +1,114 @@
+env GO111MODULE=on
+
+go list -test all
+stdout rsc.io/quote
+stdout golang.org/x/text/language
+
+# why a package?
+go mod why golang.org/x/text/language
+cmp stdout why-language.txt
+
+# why a module?
+go mod why -m golang.org...
+cmp stdout why-text-module.txt
+
+# why a package used only in tests?
+go mod why rsc.io/testonly
+cmp stdout why-testonly.txt
+
+# why a module used only in tests?
+go mod why -m rsc.io/testonly
+cmp stdout why-testonly.txt
+
+# test package not needed
+go mod why golang.org/x/text/unused
+cmp stdout why-unused.txt
+
+# vendor doesn't use packages used only in tests.
+go mod why -vendor rsc.io/testonly
+cmp stdout why-vendor.txt
+
+# vendor doesn't use modules used only in tests.
+go mod why -vendor -m rsc.io/testonly
+cmp stdout why-vendor-module.txt
+
+# test multiple packages
+go mod why golang.org/x/text/language golang.org/x/text/unused
+cmp stdout why-both.txt
+
+# test multiple modules
+go mod why -m rsc.io/quote rsc.io/sampler
+cmp stdout why-both-module.txt
+
+-- go.mod --
+module mymodule
+require rsc.io/quote v1.5.2
+
+-- x/x.go --
+package x
+import _ "mymodule/z"
+
+-- y/y.go --
+package y
+
+-- y/y_test.go --
+package y
+import _ "rsc.io/quote"
+
+-- z/z.go --
+package z
+import _ "mymodule/y"
+
+
+-- why-language.txt --
+# golang.org/x/text/language
+mymodule/y
+mymodule/y.test
+rsc.io/quote
+rsc.io/sampler
+golang.org/x/text/language
+-- why-unused.txt --
+# golang.org/x/text/unused
+(main module does not need package golang.org/x/text/unused)
+-- why-text-module.txt --
+# golang.org/x/text
+mymodule/y
+mymodule/y.test
+rsc.io/quote
+rsc.io/sampler
+golang.org/x/text/language
+-- why-testonly.txt --
+# rsc.io/testonly
+mymodule/y
+mymodule/y.test
+rsc.io/quote
+rsc.io/sampler
+rsc.io/sampler.test
+rsc.io/testonly
+-- why-vendor.txt --
+# rsc.io/testonly
+(main module does not need to vendor package rsc.io/testonly)
+-- why-vendor-module.txt --
+# rsc.io/testonly
+(main module does not need to vendor module rsc.io/testonly)
+-- why-both.txt --
+# golang.org/x/text/language
+mymodule/y
+mymodule/y.test
+rsc.io/quote
+rsc.io/sampler
+golang.org/x/text/language
+
+# golang.org/x/text/unused
+(main module does not need package golang.org/x/text/unused)
+-- why-both-module.txt --
+# rsc.io/quote
+mymodule/y
+mymodule/y.test
+rsc.io/quote
+
+# rsc.io/sampler
+mymodule/y
+mymodule/y.test
+rsc.io/quote
+rsc.io/sampler
diff --git a/libgo/go/cmd/go/testdata/script/pattern_syntax_error.txt b/libgo/go/cmd/go/testdata/script/pattern_syntax_error.txt
new file mode 100644
index 00000000000..8e6549b5c54
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/pattern_syntax_error.txt
@@ -0,0 +1,10 @@
+# patterns match directories with syntax errors
+! go list ./...
+! go build ./...
+! go install ./...
+
+-- mypkg/x.go --
+package mypkg
+
+-- mypkg/y.go --
+pkg mypackage
diff --git a/libgo/go/cmd/go/testdata/script/run_hello.txt b/libgo/go/cmd/go/testdata/script/run_hello.txt
new file mode 100644
index 00000000000..8c4c1c16833
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/run_hello.txt
@@ -0,0 +1,7 @@
+# hello world
+go run hello.go
+stderr 'hello world'
+
+-- hello.go --
+package main
+func main() { println("hello world") }
diff --git a/libgo/go/cmd/go/testdata/script/test_badtest.txt b/libgo/go/cmd/go/testdata/script/test_badtest.txt
new file mode 100644
index 00000000000..42fcfed2fcc
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/test_badtest.txt
@@ -0,0 +1,30 @@
+! go test badtest/...
+! stdout ^ok
+stdout ^FAIL\tbadtest/badexec
+stdout ^FAIL\tbadtest/badsyntax
+stdout ^FAIL\tbadtest/badvar
+
+-- badtest/badexec/x_test.go --
+package badexec
+
+func init() {
+ panic("badexec")
+}
+
+-- badtest/badsyntax/x.go --
+package badsyntax
+
+-- badtest/badsyntax/x_test.go --
+package badsyntax
+
+func func func func func!
+
+-- badtest/badvar/x.go --
+package badvar
+
+-- badtest/badvar/x_test.go --
+package badvar_test
+
+func f() {
+ _ = notdefined
+}
diff --git a/libgo/go/cmd/go/testdata/script/test_compile_binary.txt b/libgo/go/cmd/go/testdata/script/test_compile_binary.txt
new file mode 100644
index 00000000000..6c01bc5729e
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/test_compile_binary.txt
@@ -0,0 +1,6 @@
+! go test -c compile_binary/...
+stderr 'build comment'
+
+-- compile_binary/foo_test.go --
+//+build foo
+package foo
diff --git a/libgo/go/cmd/go/testdata/script/vendor_complex.txt b/libgo/go/cmd/go/testdata/script/vendor_complex.txt
new file mode 100644
index 00000000000..6513451df85
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/script/vendor_complex.txt
@@ -0,0 +1,73 @@
+# smoke test for complex build configuration
+go build -o complex.exe complex
+[exec:gccgo] go build -compiler=gccgo -o complex.exe complex
+
+-- complex/main.go --
+package main
+
+import (
+ _ "complex/nest/sub/test12"
+ _ "complex/nest/sub/test23"
+ "complex/w"
+ "v"
+)
+
+func main() {
+ println(v.Hello + " " + w.World)
+}
+
+-- complex/nest/sub/test12/p.go --
+package test12
+
+// Check that vendor/v1 is used but vendor/v2 is NOT used (sub/vendor/v2 wins).
+
+import (
+ "v1"
+ "v2"
+)
+
+const x = v1.ComplexNestVendorV1
+const y = v2.ComplexNestSubVendorV2
+
+-- complex/nest/sub/test23/p.go --
+package test23
+
+// Check that vendor/v3 is used but vendor/v2 is NOT used (sub/vendor/v2 wins).
+
+import (
+ "v2"
+ "v3"
+)
+
+const x = v3.ComplexNestVendorV3
+const y = v2.ComplexNestSubVendorV2
+
+-- complex/nest/sub/vendor/v2/v2.go --
+package v2
+
+const ComplexNestSubVendorV2 = true
+
+-- complex/nest/vendor/v1/v1.go --
+package v1
+
+const ComplexNestVendorV1 = true
+
+-- complex/nest/vendor/v2/v2.go --
+package v2
+
+const ComplexNestVendorV2 = true
+
+-- complex/nest/vendor/v3/v3.go --
+package v3
+
+const ComplexNestVendorV3 = true
+
+-- complex/vendor/v/v.go --
+package v
+
+const Hello = "hello"
+
+-- complex/w/w.go --
+package w
+
+const World = "world"
diff --git a/libgo/go/cmd/go/testdata/src/badtest/badexec/x_test.go b/libgo/go/cmd/go/testdata/src/badtest/badexec/x_test.go
deleted file mode 100644
index 12f50517125..00000000000
--- a/libgo/go/cmd/go/testdata/src/badtest/badexec/x_test.go
+++ /dev/null
@@ -1,5 +0,0 @@
-package badexec
-
-func init() {
- panic("badexec")
-}
diff --git a/libgo/go/cmd/go/testdata/src/badtest/badsyntax/x.go b/libgo/go/cmd/go/testdata/src/badtest/badsyntax/x.go
deleted file mode 100644
index c8a5407a5ac..00000000000
--- a/libgo/go/cmd/go/testdata/src/badtest/badsyntax/x.go
+++ /dev/null
@@ -1 +0,0 @@
-package badsyntax
diff --git a/libgo/go/cmd/go/testdata/src/badtest/badsyntax/x_test.go b/libgo/go/cmd/go/testdata/src/badtest/badsyntax/x_test.go
deleted file mode 100644
index 5be10745d9b..00000000000
--- a/libgo/go/cmd/go/testdata/src/badtest/badsyntax/x_test.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package badsyntax
-
-func func func func func!
diff --git a/libgo/go/cmd/go/testdata/src/badtest/badvar/x.go b/libgo/go/cmd/go/testdata/src/badtest/badvar/x.go
deleted file mode 100644
index fdd46c4c721..00000000000
--- a/libgo/go/cmd/go/testdata/src/badtest/badvar/x.go
+++ /dev/null
@@ -1 +0,0 @@
-package badvar
diff --git a/libgo/go/cmd/go/testdata/src/badtest/badvar/x_test.go b/libgo/go/cmd/go/testdata/src/badtest/badvar/x_test.go
deleted file mode 100644
index c67df01c5ca..00000000000
--- a/libgo/go/cmd/go/testdata/src/badtest/badvar/x_test.go
+++ /dev/null
@@ -1,5 +0,0 @@
-package badvar_test
-
-func f() {
- _ = notdefined
-}
diff --git a/libgo/go/cmd/go/testdata/src/complex/main.go b/libgo/go/cmd/go/testdata/src/complex/main.go
deleted file mode 100644
index c38df019480..00000000000
--- a/libgo/go/cmd/go/testdata/src/complex/main.go
+++ /dev/null
@@ -1,12 +0,0 @@
-package main
-
-import (
- _ "complex/nest/sub/test12"
- _ "complex/nest/sub/test23"
- "complex/w"
- "v"
-)
-
-func main() {
- println(v.Hello + " " + w.World)
-}
diff --git a/libgo/go/cmd/go/testdata/src/complex/nest/sub/test12/p.go b/libgo/go/cmd/go/testdata/src/complex/nest/sub/test12/p.go
deleted file mode 100644
index 94943ec1bbe..00000000000
--- a/libgo/go/cmd/go/testdata/src/complex/nest/sub/test12/p.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package test12
-
-// Check that vendor/v1 is used but vendor/v2 is NOT used (sub/vendor/v2 wins).
-
-import (
- "v1"
- "v2"
-)
-
-const x = v1.ComplexNestVendorV1
-const y = v2.ComplexNestSubVendorV2
diff --git a/libgo/go/cmd/go/testdata/src/complex/nest/sub/test23/p.go b/libgo/go/cmd/go/testdata/src/complex/nest/sub/test23/p.go
deleted file mode 100644
index 8801a4812af..00000000000
--- a/libgo/go/cmd/go/testdata/src/complex/nest/sub/test23/p.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package test23
-
-// Check that vendor/v3 is used but vendor/v2 is NOT used (sub/vendor/v2 wins).
-
-import (
- "v2"
- "v3"
-)
-
-const x = v3.ComplexNestVendorV3
-const y = v2.ComplexNestSubVendorV2
diff --git a/libgo/go/cmd/go/testdata/src/complex/nest/sub/vendor/v2/v2.go b/libgo/go/cmd/go/testdata/src/complex/nest/sub/vendor/v2/v2.go
deleted file mode 100644
index 2991871710e..00000000000
--- a/libgo/go/cmd/go/testdata/src/complex/nest/sub/vendor/v2/v2.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package v2
-
-const ComplexNestSubVendorV2 = true
diff --git a/libgo/go/cmd/go/testdata/src/complex/nest/vendor/v1/v1.go b/libgo/go/cmd/go/testdata/src/complex/nest/vendor/v1/v1.go
deleted file mode 100644
index a55f5290a9a..00000000000
--- a/libgo/go/cmd/go/testdata/src/complex/nest/vendor/v1/v1.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package v1
-
-const ComplexNestVendorV1 = true
diff --git a/libgo/go/cmd/go/testdata/src/complex/nest/vendor/v2/v2.go b/libgo/go/cmd/go/testdata/src/complex/nest/vendor/v2/v2.go
deleted file mode 100644
index ac94def4e3e..00000000000
--- a/libgo/go/cmd/go/testdata/src/complex/nest/vendor/v2/v2.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package v2
-
-const ComplexNestVendorV2 = true
diff --git a/libgo/go/cmd/go/testdata/src/complex/nest/vendor/v3/v3.go b/libgo/go/cmd/go/testdata/src/complex/nest/vendor/v3/v3.go
deleted file mode 100644
index abf99b95745..00000000000
--- a/libgo/go/cmd/go/testdata/src/complex/nest/vendor/v3/v3.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package v3
-
-const ComplexNestVendorV3 = true
diff --git a/libgo/go/cmd/go/testdata/src/complex/vendor/v/v.go b/libgo/go/cmd/go/testdata/src/complex/vendor/v/v.go
deleted file mode 100644
index bb20d86f25a..00000000000
--- a/libgo/go/cmd/go/testdata/src/complex/vendor/v/v.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package v
-
-const Hello = "hello"
diff --git a/libgo/go/cmd/go/testdata/src/complex/w/w.go b/libgo/go/cmd/go/testdata/src/complex/w/w.go
deleted file mode 100644
index a9c7fbb3094..00000000000
--- a/libgo/go/cmd/go/testdata/src/complex/w/w.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package w
-
-const World = "world"
diff --git a/libgo/go/cmd/go/testdata/src/failfast_test.go b/libgo/go/cmd/go/testdata/src/failfast_test.go
index fef4d2a35e1..6e64d73fdf9 100644
--- a/libgo/go/cmd/go/testdata/src/failfast_test.go
+++ b/libgo/go/cmd/go/testdata/src/failfast_test.go
@@ -52,3 +52,11 @@ func TestFailingSubtestsA(t *testing.T) {
func TestFailingB(t *testing.T) {
t.Errorf("FAIL - %s", t.Name())
}
+
+func TestFatalC(t *testing.T) {
+ t.Fatalf("FAIL - %s", t.Name())
+}
+
+func TestFatalD(t *testing.T) {
+ t.Fatalf("FAIL - %s", t.Name())
+}
diff --git a/libgo/go/cmd/go/testdata/src/hello/hello.go b/libgo/go/cmd/go/testdata/src/hello/hello.go
new file mode 100644
index 00000000000..73d83e646f9
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/hello/hello.go
@@ -0,0 +1,5 @@
+package main
+
+func main() {
+ println("hello, world")
+}
diff --git a/libgo/go/cmd/go/testdata/src/testnorun/p.go b/libgo/go/cmd/go/testdata/src/testnorun/p.go
new file mode 100644
index 00000000000..71a9a561ef9
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/testnorun/p.go
@@ -0,0 +1,5 @@
+package p
+
+func init() {
+ panic("go test must not link and run test binaries without tests")
+}
diff --git a/libgo/go/cmd/go/testdata/src/vetfail/p1/p1.go b/libgo/go/cmd/go/testdata/src/vetfail/p1/p1.go
index 248317b779a..eaa9b183331 100644
--- a/libgo/go/cmd/go/testdata/src/vetfail/p1/p1.go
+++ b/libgo/go/cmd/go/testdata/src/vetfail/p1/p1.go
@@ -1,3 +1,5 @@
+// +build !foo-bar
+
package p1
import "fmt"
diff --git a/libgo/go/cmd/go/testdata/testcover/pkg1/a.go b/libgo/go/cmd/go/testdata/testcover/pkg1/a.go
new file mode 100644
index 00000000000..e2916119d4f
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/testcover/pkg1/a.go
@@ -0,0 +1,7 @@
+package pkg1
+
+import "fmt"
+
+func F() {
+ fmt.Println("pkg1")
+}
diff --git a/libgo/go/cmd/go/testdata/testcover/pkg2/a.go b/libgo/go/cmd/go/testdata/testcover/pkg2/a.go
new file mode 100644
index 00000000000..7bd9bd44ee9
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/testcover/pkg2/a.go
@@ -0,0 +1,7 @@
+package pkg2
+
+import "fmt"
+
+func F() {
+ fmt.Println("pkg2")
+}
diff --git a/libgo/go/cmd/go/testdata/testcover/pkg2/a_test.go b/libgo/go/cmd/go/testdata/testcover/pkg2/a_test.go
new file mode 100644
index 00000000000..4f791ad6ab0
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/testcover/pkg2/a_test.go
@@ -0,0 +1 @@
+package pkg2
diff --git a/libgo/go/cmd/go/testdata/testcover/pkg3/a.go b/libgo/go/cmd/go/testdata/testcover/pkg3/a.go
new file mode 100644
index 00000000000..bf86ed8dc0e
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/testcover/pkg3/a.go
@@ -0,0 +1,7 @@
+package pkg3
+
+import "fmt"
+
+func F() {
+ fmt.Println("pkg3")
+}
diff --git a/libgo/go/cmd/go/testdata/testcover/pkg3/a_test.go b/libgo/go/cmd/go/testdata/testcover/pkg3/a_test.go
new file mode 100644
index 00000000000..39c2c5a6fc5
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/testcover/pkg3/a_test.go
@@ -0,0 +1,7 @@
+package pkg3
+
+import "testing"
+
+func TestF(t *testing.T) {
+ F()
+}
diff --git a/libgo/go/cmd/go/testdata/testonly2/t.go b/libgo/go/cmd/go/testdata/testonly2/t.go
new file mode 100644
index 00000000000..82267d32e41
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/testonly2/t.go
@@ -0,0 +1,6 @@
+// This package is not a test-only package,
+// but it still matches the pattern ./testdata/testonly... when in cmd/go.
+
+package main
+
+func main() {}
diff --git a/libgo/go/cmd/go/testdata/vendormod.txt b/libgo/go/cmd/go/testdata/vendormod.txt
new file mode 100644
index 00000000000..cd009db5cf0
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/vendormod.txt
@@ -0,0 +1,160 @@
+generated by: go run savedir.go vendormod
+
+-- a/foo/AUTHORS.txt --
+-- a/foo/CONTRIBUTORS --
+-- a/foo/LICENSE --
+-- a/foo/PATENTS --
+-- a/foo/COPYING --
+-- a/foo/COPYLEFT --
+-- a/foo/licensed-to-kill --
+-- w/LICENSE --
+-- x/NOTICE! --
+-- x/x2/LICENSE --
+-- mypkg/LICENSE.txt --
+-- a/foo/bar/b/main.go --
+package b
+-- a/foo/bar/b/main_test.go --
+package b
+
+import (
+ "os"
+ "testing"
+)
+
+func TestDir(t *testing.T) {
+ if _, err := os.Stat("../testdata/1"); err != nil {
+ t.Fatalf("testdata: %v", err)
+ }
+}
+-- a/foo/bar/c/main.go --
+package c
+-- a/foo/bar/c/main_test.go --
+package c
+
+import (
+ "os"
+ "testing"
+)
+
+func TestDir(t *testing.T) {
+ if _, err := os.Stat("../../../testdata/1"); err != nil {
+ t.Fatalf("testdata: %v", err)
+ }
+ if _, err := os.Stat("./testdata/1"); err != nil {
+ t.Fatalf("testdata: %v", err)
+ }
+}
+-- a/foo/bar/c/testdata/1 --
+-- a/foo/bar/testdata/1 --
+-- a/gcc/go/gofrontend.mod --
+module a
+-- a/main.go --
+package a
+-- a/main_test.go --
+package a
+
+import (
+ "os"
+ "testing"
+)
+
+func TestDir(t *testing.T) {
+ if _, err := os.Stat("./testdata/1"); err != nil {
+ t.Fatalf("testdata: %v", err)
+ }
+}
+-- a/testdata/1 --
+-- appengine.go --
+// +build appengine
+
+package m
+
+import _ "appengine"
+import _ "appengine/datastore"
+-- go.mod --
+module m
+
+require (
+ a v1.0.0
+ mysite/myname/mypkg v1.0.0
+ w v1.0.0 // indirect
+ x v1.0.0
+ y v1.0.0
+ z v1.0.0
+)
+
+replace (
+ a v1.0.0 => ./a
+ mysite/myname/mypkg v1.0.0 => ./mypkg
+ w v1.0.0 => ./w
+ x v1.0.0 => ./x
+ y v1.0.0 => ./y
+ z v1.0.0 => ./z
+)
+-- mypkg/go.mod --
+module me
+-- mypkg/mydir/d.go --
+package mydir
+-- subdir/v1_test.go --
+package m
+
+import _ "mysite/myname/mypkg/mydir"
+-- testdata1.go --
+package m
+
+import _ "a"
+-- testdata2.go --
+package m
+
+import _ "a/foo/bar/b"
+import _ "a/foo/bar/c"
+-- v1.go --
+package m
+
+import _ "x"
+-- v2.go --
+// +build abc
+
+package mMmMmMm
+
+import _ "y"
+-- v3.go --
+// +build !abc
+
+package m
+
+import _ "z"
+-- v4.go --
+// +build notmytag
+
+package m
+
+import _ "x/x1"
+-- w/go.mod --
+module w
+-- w/w.go --
+package w
+-- x/go.mod --
+module x
+-- x/testdata/x.txt --
+placeholder - want directory with no go files
+-- x/x.go --
+package x
+-- x/x1/x1.go --
+// +build notmytag
+
+package x1
+-- x/x2/dummy.txt --
+dummy
+-- x/x_test.go --
+package x
+
+import _ "w"
+-- y/go.mod --
+module y
+-- y/y.go --
+package y
+-- z/go.mod --
+module z
+-- z/z.go --
+package z
diff --git a/libgo/go/cmd/go/vendor_test.go b/libgo/go/cmd/go/vendor_test.go
index 0e7a633240b..22aa643b003 100644
--- a/libgo/go/cmd/go/vendor_test.go
+++ b/libgo/go/cmd/go/vendor_test.go
@@ -332,7 +332,7 @@ func TestVendor12156(t *testing.T) {
// Module legacy support does path rewriting very similar to vendoring.
-func TestModLegacy(t *testing.T) {
+func TestLegacyMod(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/modlegacy"))
@@ -347,7 +347,7 @@ func TestModLegacy(t *testing.T) {
tg.run("build", "old/p1", "new/p1")
}
-func TestModLegacyGet(t *testing.T) {
+func TestLegacyModGet(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
tg := testgo(t)
diff --git a/libgo/go/cmd/internal/buildid/note.go b/libgo/go/cmd/internal/buildid/note.go
index f0439fb0bfb..2d26ea9961c 100644
--- a/libgo/go/cmd/internal/buildid/note.go
+++ b/libgo/go/cmd/internal/buildid/note.go
@@ -30,6 +30,7 @@ func ReadELFNote(filename, name string, typ int32) ([]byte, error) {
if err != nil {
return nil, err
}
+ defer f.Close()
for _, sect := range f.Sections {
if sect.Type != elf.SHT_NOTE {
continue
@@ -147,7 +148,7 @@ func readELF(name string, f *os.File, data []byte) (buildid string, err error) {
break
}
off += notesz
- align := uint64(p.Align)
+ align := p.Align
alignedOff := (off + align - 1) &^ (align - 1)
notesz += alignedOff - off
off = alignedOff
diff --git a/libgo/go/cmd/internal/objabi/flag.go b/libgo/go/cmd/internal/objabi/flag.go
index 1bd4bc9063a..30cd7dccac2 100644
--- a/libgo/go/cmd/internal/objabi/flag.go
+++ b/libgo/go/cmd/internal/objabi/flag.go
@@ -7,6 +7,9 @@ package objabi
import (
"flag"
"fmt"
+ "io"
+ "io/ioutil"
+ "log"
"os"
"strconv"
"strings"
@@ -20,18 +23,53 @@ func Flagfn1(name, usage string, f func(string)) {
flag.Var(fn1(f), name, usage)
}
-func Flagprint(fd int) {
- if fd == 1 {
- flag.CommandLine.SetOutput(os.Stdout)
- }
+func Flagprint(w io.Writer) {
+ flag.CommandLine.SetOutput(w)
flag.PrintDefaults()
}
func Flagparse(usage func()) {
flag.Usage = usage
+ os.Args = expandArgs(os.Args)
flag.Parse()
}
+// expandArgs expands "response files" arguments in the provided slice.
+//
+// A "response file" argument starts with '@' and the rest of that
+// argument is a filename with CR-or-CRLF-separated arguments. Each
+// argument in the named files can also contain response file
+// arguments. See Issue 18468.
+//
+// The returned slice 'out' aliases 'in' iff the input did not contain
+// any response file arguments.
+//
+// TODO: handle relative paths of recursive expansions in different directories?
+// Is there a spec for this? Are relative paths allowed?
+func expandArgs(in []string) (out []string) {
+ // out is nil until we see a "@" argument.
+ for i, s := range in {
+ if strings.HasPrefix(s, "@") {
+ if out == nil {
+ out = make([]string, 0, len(in)*2)
+ out = append(out, in[:i]...)
+ }
+ slurp, err := ioutil.ReadFile(s[1:])
+ if err != nil {
+ log.Fatal(err)
+ }
+ args := strings.Split(strings.TrimSpace(strings.Replace(string(slurp), "\r", "", -1)), "\n")
+ out = append(out, expandArgs(args)...)
+ } else if out != nil {
+ out = append(out, s)
+ }
+ }
+ if out == nil {
+ return in
+ }
+ return
+}
+
func AddVersionFlag() {
flag.Var(versionFlag{}, "V", "print version and exit")
}
@@ -107,21 +145,6 @@ func (c *count) IsCountFlag() bool {
return true
}
-type fn0 func()
-
-func (f fn0) Set(s string) error {
- f()
- return nil
-}
-
-func (f fn0) Get() interface{} { return nil }
-
-func (f fn0) String() string { return "" }
-
-func (f fn0) IsBoolFlag() bool {
- return true
-}
-
type fn1 func(string)
func (f fn1) Set(s string) error {
diff --git a/libgo/go/cmd/internal/objabi/funcdata.go b/libgo/go/cmd/internal/objabi/funcdata.go
index 80874edeb0f..a7827125bf6 100644
--- a/libgo/go/cmd/internal/objabi/funcdata.go
+++ b/libgo/go/cmd/internal/objabi/funcdata.go
@@ -13,9 +13,11 @@ package objabi
const (
PCDATA_StackMapIndex = 0
PCDATA_InlTreeIndex = 1
+ PCDATA_RegMapIndex = 2
FUNCDATA_ArgsPointerMaps = 0
FUNCDATA_LocalsPointerMaps = 1
FUNCDATA_InlTree = 2
+ FUNCDATA_RegPointerMaps = 3
// ArgsSizeUnknown is set in Func.argsize to mark all functions
// whose argument size is unknown (C vararg functions, and
diff --git a/libgo/go/cmd/internal/objabi/funcid.go b/libgo/go/cmd/internal/objabi/funcid.go
index 55f1328ba84..15a63ab8b34 100644
--- a/libgo/go/cmd/internal/objabi/funcid.go
+++ b/libgo/go/cmd/internal/objabi/funcid.go
@@ -13,6 +13,7 @@ type FuncID uint32
const (
FuncID_normal FuncID = iota // not a special function
+ FuncID_runtime_main
FuncID_goexit
FuncID_jmpdefer
FuncID_mcall
@@ -22,13 +23,11 @@ const (
FuncID_asmcgocall
FuncID_sigpanic
FuncID_runfinq
- FuncID_bgsweep
- FuncID_forcegchelper
- FuncID_timerproc
FuncID_gcBgMarkWorker
FuncID_systemstack_switch
FuncID_systemstack
FuncID_cgocallback_gofunc
FuncID_gogo
FuncID_externalthreadhandler
+ FuncID_debugCallV1
)
diff --git a/libgo/go/cmd/internal/objabi/head.go b/libgo/go/cmd/internal/objabi/head.go
index ff19606cd2b..23c7b62daf6 100644
--- a/libgo/go/cmd/internal/objabi/head.go
+++ b/libgo/go/cmd/internal/objabi/head.go
@@ -40,6 +40,7 @@ const (
Hdarwin
Hdragonfly
Hfreebsd
+ Hjs
Hlinux
Hnacl
Hnetbsd
@@ -57,6 +58,8 @@ func (h *HeadType) Set(s string) error {
*h = Hdragonfly
case "freebsd":
*h = Hfreebsd
+ case "js":
+ *h = Hjs
case "linux", "android":
*h = Hlinux
case "nacl":
@@ -85,6 +88,8 @@ func (h *HeadType) String() string {
return "dragonfly"
case Hfreebsd:
return "freebsd"
+ case Hjs:
+ return "js"
case Hlinux:
return "linux"
case Hnacl:
diff --git a/libgo/go/cmd/internal/objabi/reloctype.go b/libgo/go/cmd/internal/objabi/reloctype.go
index 2e0b916f7c1..a3e2868a1bc 100644
--- a/libgo/go/cmd/internal/objabi/reloctype.go
+++ b/libgo/go/cmd/internal/objabi/reloctype.go
@@ -167,7 +167,7 @@ const (
// R_ADDRPOWER_PCREL relocates two D-form instructions like R_ADDRPOWER, but
// inserts the displacement from the place being relocated to the address of the
- // the relocated symbol instead of just its address.
+ // relocated symbol instead of just its address.
R_ADDRPOWER_PCREL
// R_ADDRPOWER_TOCREL relocates two D-form instructions like R_ADDRPOWER, but
@@ -176,7 +176,7 @@ const (
R_ADDRPOWER_TOCREL
// R_ADDRPOWER_TOCREL relocates a D-form, DS-form instruction sequence like
- // R_ADDRPOWER_DS but inserts the offset from the TOC to the address of the the
+ // R_ADDRPOWER_DS but inserts the offset from the TOC to the address of the
// relocated symbol rather than the symbol's address.
R_ADDRPOWER_TOCREL_DS
@@ -193,6 +193,9 @@ const (
// R_ADDRCUOFF resolves to a pointer-sized offset from the start of the
// symbol's DWARF compile unit.
R_ADDRCUOFF
+
+ // R_WASMIMPORT resolves to the index of the WebAssembly function import.
+ R_WASMIMPORT
)
// IsDirectJump returns whether r is a relocation for a direct jump.
diff --git a/libgo/go/cmd/internal/objabi/reloctype_string.go b/libgo/go/cmd/internal/objabi/reloctype_string.go
index a6efe9cad04..2cd3a940454 100644
--- a/libgo/go/cmd/internal/objabi/reloctype_string.go
+++ b/libgo/go/cmd/internal/objabi/reloctype_string.go
@@ -2,16 +2,16 @@
package objabi
-import "fmt"
+import "strconv"
-const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFF"
+const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORT"
-var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 129, 136, 144, 152, 160, 166, 172, 178, 188, 197, 208, 219, 229, 238, 251, 265, 279, 293, 309, 323, 337, 348, 362, 377, 394, 412, 433, 443, 454, 467, 478}
+var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 129, 136, 144, 152, 160, 166, 172, 178, 188, 197, 208, 219, 229, 238, 251, 265, 279, 293, 309, 323, 337, 348, 362, 377, 394, 412, 433, 443, 454, 467, 478, 490}
func (i RelocType) String() string {
i -= 1
if i < 0 || i >= RelocType(len(_RelocType_index)-1) {
- return fmt.Sprintf("RelocType(%d)", i+1)
+ return "RelocType(" + strconv.FormatInt(int64(i+1), 10) + ")"
}
return _RelocType_name[_RelocType_index[i]:_RelocType_index[i+1]]
}
diff --git a/libgo/go/cmd/internal/objabi/symkind.go b/libgo/go/cmd/internal/objabi/symkind.go
index ea180d0bf86..b95a0d3c701 100644
--- a/libgo/go/cmd/internal/objabi/symkind.go
+++ b/libgo/go/cmd/internal/objabi/symkind.go
@@ -34,6 +34,7 @@ package objabi
type SymKind uint8
// Defined SymKind values.
+// These are used to index into cmd/link/internal/sym/AbiSymKindToSymKind
//
// TODO(rsc): Give idiomatic Go names.
//go:generate stringer -type=SymKind
@@ -58,4 +59,7 @@ const (
SDWARFINFO
SDWARFRANGE
SDWARFLOC
+ SDWARFMISC
+ // Update cmd/link/internal/sym/AbiSymKindToSymKind for new SymKind values.
+
)
diff --git a/libgo/go/cmd/internal/objabi/symkind_string.go b/libgo/go/cmd/internal/objabi/symkind_string.go
index 3064c8ee051..7152d6c0069 100644
--- a/libgo/go/cmd/internal/objabi/symkind_string.go
+++ b/libgo/go/cmd/internal/objabi/symkind_string.go
@@ -2,15 +2,15 @@
package objabi
-import "fmt"
+import "strconv"
-const _SymKind_name = "SxxxSTEXTSRODATASNOPTRDATASDATASBSSSNOPTRBSSSTLSBSSSDWARFINFOSDWARFRANGESDWARFLOC"
+const _SymKind_name = "SxxxSTEXTSRODATASNOPTRDATASDATASBSSSNOPTRBSSSTLSBSSSDWARFINFOSDWARFRANGESDWARFLOCSDWARFMISC"
-var _SymKind_index = [...]uint8{0, 4, 9, 16, 26, 31, 35, 44, 51, 61, 72, 81}
+var _SymKind_index = [...]uint8{0, 4, 9, 16, 26, 31, 35, 44, 51, 61, 72, 81, 91}
func (i SymKind) String() string {
if i >= SymKind(len(_SymKind_index)-1) {
- return fmt.Sprintf("SymKind(%d)", i)
+ return "SymKind(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _SymKind_name[_SymKind_index[i]:_SymKind_index[i+1]]
}
diff --git a/libgo/go/cmd/internal/objabi/util.go b/libgo/go/cmd/internal/objabi/util.go
index eafef6bfa71..a47e2f93a10 100644
--- a/libgo/go/cmd/internal/objabi/util.go
+++ b/libgo/go/cmd/internal/objabi/util.go
@@ -21,13 +21,14 @@ func envOr(key, value string) string {
var (
defaultGOROOT string // set by linker
- GOROOT = envOr("GOROOT", defaultGOROOT)
- GOARCH = envOr("GOARCH", defaultGOARCH)
- GOOS = envOr("GOOS", defaultGOOS)
- GO386 = envOr("GO386", defaultGO386)
- GOARM = goarm()
- GOMIPS = gomips()
- Version = version
+ GOROOT = envOr("GOROOT", defaultGOROOT)
+ GOARCH = envOr("GOARCH", defaultGOARCH)
+ GOOS = envOr("GOOS", defaultGOOS)
+ GO386 = envOr("GO386", defaultGO386)
+ GOARM = goarm()
+ GOMIPS = gomips()
+ GOMIPS64 = gomips64()
+ Version = version
)
func goarm() int {
@@ -53,6 +54,15 @@ func gomips() string {
panic("unreachable")
}
+func gomips64() string {
+ switch v := envOr("GOMIPS64", defaultGOMIPS64); v {
+ case "hardfloat", "softfloat":
+ return v
+ }
+ log.Fatalf("Invalid GOMIPS64 value. Must be hardfloat or softfloat.")
+ panic("unreachable")
+}
+
func Getgoextlinkenabled() string {
return envOr("GO_EXTLINK_ENABLED", defaultGO_EXTLINK_ENABLED)
}
@@ -95,6 +105,7 @@ var (
Fieldtrack_enabled int
Preemptibleloops_enabled int
Clobberdead_enabled int
+ DebugCPU_enabled int
)
// Toolchain experiments.
@@ -109,6 +120,7 @@ var exper = []struct {
{"framepointer", &framepointer_enabled},
{"preemptibleloops", &Preemptibleloops_enabled},
{"clobberdead", &Clobberdead_enabled},
+ {"debugcpu", &DebugCPU_enabled},
}
var defaultExpstring = Expstring()
diff --git a/libgo/go/cmd/internal/test2json/test2json.go b/libgo/go/cmd/internal/test2json/test2json.go
index 3e09c8d9151..f8052136be6 100644
--- a/libgo/go/cmd/internal/test2json/test2json.go
+++ b/libgo/go/cmd/internal/test2json/test2json.go
@@ -16,6 +16,7 @@ import (
"strconv"
"strings"
"time"
+ "unicode"
"unicode/utf8"
)
@@ -140,6 +141,7 @@ var (
[]byte("--- PASS: "),
[]byte("--- FAIL: "),
[]byte("--- SKIP: "),
+ []byte("--- BENCH: "),
}
fourSpace = []byte(" ")
@@ -173,6 +175,7 @@ func (c *converter) handleInputLine(line []byte) {
// "=== RUN "
// "=== PAUSE "
// "=== CONT "
+ actionColon := false
origLine := line
ok := false
indent := 0
@@ -186,6 +189,7 @@ func (c *converter) handleInputLine(line []byte) {
// "--- PASS: "
// "--- FAIL: "
// "--- SKIP: "
+ // "--- BENCH: "
// but possibly indented.
for bytes.HasPrefix(line, fourSpace) {
line = line[4:]
@@ -193,6 +197,7 @@ func (c *converter) handleInputLine(line []byte) {
}
for _, magic := range reports {
if bytes.HasPrefix(line, magic) {
+ actionColon = true
ok = true
break
}
@@ -206,8 +211,15 @@ func (c *converter) handleInputLine(line []byte) {
}
// Parse out action and test name.
- action := strings.ToLower(strings.TrimSuffix(strings.TrimSpace(string(line[4:4+6])), ":"))
- name := strings.TrimSpace(string(line[4+6:]))
+ i := 0
+ if actionColon {
+ i = bytes.IndexByte(line, ':') + 1
+ }
+ if i == 0 {
+ i = len(updates[0])
+ }
+ action := strings.ToLower(strings.TrimSuffix(strings.TrimSpace(string(line[4:i])), ":"))
+ name := strings.TrimSpace(string(line[i:]))
e := &event{Action: action}
if line[0] == '-' { // PASS or FAIL report
@@ -226,6 +238,7 @@ func (c *converter) handleInputLine(line []byte) {
if len(c.report) < indent {
// Nested deeper than expected.
// Treat this line as plain output.
+ c.output.write(origLine)
return
}
// Flush reports at this indentation level or deeper.
@@ -342,6 +355,15 @@ func (l *lineBuffer) write(b []byte) {
for i < len(l.b) {
j := bytes.IndexByte(l.b[i:], '\n')
if j < 0 {
+ if !l.mid {
+ if j := bytes.IndexByte(l.b[i:], '\t'); j >= 0 {
+ if isBenchmarkName(bytes.TrimRight(l.b[i:i+j], " ")) {
+ l.part(l.b[i : i+j+1])
+ l.mid = true
+ i += j + 1
+ }
+ }
+ }
break
}
e := i + j + 1
@@ -383,6 +405,21 @@ func (l *lineBuffer) flush() {
}
}
+var benchmark = []byte("Benchmark")
+
+// isBenchmarkName reports whether b is a valid benchmark name
+// that might appear as the first field in a benchmark result line.
+func isBenchmarkName(b []byte) bool {
+ if !bytes.HasPrefix(b, benchmark) {
+ return false
+ }
+ if len(b) == len(benchmark) { // just "Benchmark"
+ return true
+ }
+ r, _ := utf8.DecodeRune(b[len(benchmark):])
+ return !unicode.IsLower(r)
+}
+
// trimUTF8 returns a length t as close to len(b) as possible such that b[:t]
// does not end in the middle of a possibly-valid UTF-8 sequence.
//
diff --git a/libgo/go/cmd/internal/test2json/testdata/bench.json b/libgo/go/cmd/internal/test2json/testdata/bench.json
new file mode 100644
index 00000000000..69e417eb144
--- /dev/null
+++ b/libgo/go/cmd/internal/test2json/testdata/bench.json
@@ -0,0 +1,14 @@
+{"Action":"output","Output":"goos: darwin\n"}
+{"Action":"output","Output":"goarch: 386\n"}
+{"Action":"output","Output":"BenchmarkFoo-8 \t2000000000\t 0.00 ns/op\n"}
+{"Action":"output","Test":"BenchmarkFoo-8","Output":"--- BENCH: BenchmarkFoo-8\n"}
+{"Action":"output","Test":"BenchmarkFoo-8","Output":"\tx_test.go:8: My benchmark\n"}
+{"Action":"output","Test":"BenchmarkFoo-8","Output":"\tx_test.go:8: My benchmark\n"}
+{"Action":"output","Test":"BenchmarkFoo-8","Output":"\tx_test.go:8: My benchmark\n"}
+{"Action":"output","Test":"BenchmarkFoo-8","Output":"\tx_test.go:8: My benchmark\n"}
+{"Action":"output","Test":"BenchmarkFoo-8","Output":"\tx_test.go:8: My benchmark\n"}
+{"Action":"output","Test":"BenchmarkFoo-8","Output":"\tx_test.go:8: My benchmark\n"}
+{"Action":"bench","Test":"BenchmarkFoo-8"}
+{"Action":"output","Output":"PASS\n"}
+{"Action":"output","Output":"ok \tcommand-line-arguments\t0.009s\n"}
+{"Action":"pass"}
diff --git a/libgo/go/cmd/internal/test2json/testdata/bench.test b/libgo/go/cmd/internal/test2json/testdata/bench.test
new file mode 100644
index 00000000000..453bd5928a5
--- /dev/null
+++ b/libgo/go/cmd/internal/test2json/testdata/bench.test
@@ -0,0 +1,12 @@
+goos: darwin
+goarch: 386
+BenchmarkFoo-8 2000000000 0.00 ns/op
+--- BENCH: BenchmarkFoo-8
+ x_test.go:8: My benchmark
+ x_test.go:8: My benchmark
+ x_test.go:8: My benchmark
+ x_test.go:8: My benchmark
+ x_test.go:8: My benchmark
+ x_test.go:8: My benchmark
+PASS
+ok command-line-arguments 0.009s
diff --git a/libgo/go/cmd/internal/test2json/testdata/benchfail.json b/libgo/go/cmd/internal/test2json/testdata/benchfail.json
new file mode 100644
index 00000000000..ad3ac9e179a
--- /dev/null
+++ b/libgo/go/cmd/internal/test2json/testdata/benchfail.json
@@ -0,0 +1,6 @@
+{"Action":"output","Test":"BenchmarkFoo","Output":"--- FAIL: BenchmarkFoo\n"}
+{"Action":"output","Test":"BenchmarkFoo","Output":"\tx_test.go:8: My benchmark\n"}
+{"Action":"fail","Test":"BenchmarkFoo"}
+{"Action":"output","Output":"FAIL\n"}
+{"Action":"output","Output":"FAIL\tcommand-line-arguments\t0.008s\n"}
+{"Action":"fail"}
diff --git a/libgo/go/cmd/internal/test2json/testdata/benchfail.test b/libgo/go/cmd/internal/test2json/testdata/benchfail.test
new file mode 100644
index 00000000000..538d9577202
--- /dev/null
+++ b/libgo/go/cmd/internal/test2json/testdata/benchfail.test
@@ -0,0 +1,4 @@
+--- FAIL: BenchmarkFoo
+ x_test.go:8: My benchmark
+FAIL
+FAIL command-line-arguments 0.008s
diff --git a/libgo/go/cmd/internal/test2json/testdata/benchshort.json b/libgo/go/cmd/internal/test2json/testdata/benchshort.json
new file mode 100644
index 00000000000..8c61d95d8da
--- /dev/null
+++ b/libgo/go/cmd/internal/test2json/testdata/benchshort.json
@@ -0,0 +1,7 @@
+{"Action":"output","Output":"# This file ends in an early EOF to trigger the Benchmark prefix test,\n"}
+{"Action":"output","Output":"# which only happens when a benchmark prefix is seen ahead of the \\n.\n"}
+{"Action":"output","Output":"# Normally that's due to the benchmark running and the \\n coming later,\n"}
+{"Action":"output","Output":"# but to avoid questions of timing, we just use a file with no \\n at all.\n"}
+{"Action":"output","Output":"BenchmarkFoo \t"}
+{"Action":"output","Output":"10000 early EOF"}
+{"Action":"fail"}
diff --git a/libgo/go/cmd/internal/test2json/testdata/benchshort.test b/libgo/go/cmd/internal/test2json/testdata/benchshort.test
new file mode 100644
index 00000000000..0b173ab20d3
--- /dev/null
+++ b/libgo/go/cmd/internal/test2json/testdata/benchshort.test
@@ -0,0 +1,5 @@
+# This file ends in an early EOF to trigger the Benchmark prefix test,
+# which only happens when a benchmark prefix is seen ahead of the \n.
+# Normally that's due to the benchmark running and the \n coming later,
+# but to avoid questions of timing, we just use a file with no \n at all.
+BenchmarkFoo 10000 early EOF \ No newline at end of file
diff --git a/libgo/go/cmd/internal/test2json/testdata/issue23036.json b/libgo/go/cmd/internal/test2json/testdata/issue23036.json
new file mode 100644
index 00000000000..935c0c5fc0e
--- /dev/null
+++ b/libgo/go/cmd/internal/test2json/testdata/issue23036.json
@@ -0,0 +1,12 @@
+{"Action":"run","Test":"TestActualCase"}
+{"Action":"output","Test":"TestActualCase","Output":"=== RUN TestActualCase\n"}
+{"Action":"output","Test":"TestActualCase","Output":"--- FAIL: TestActualCase (0.00s)\n"}
+{"Action":"output","Test":"TestActualCase","Output":" foo_test.go:14: Differed.\n"}
+{"Action":"output","Test":"TestActualCase","Output":" Expected: MyTest:\n"}
+{"Action":"output","Test":"TestActualCase","Output":" --- FAIL: Test output from other tool\n"}
+{"Action":"output","Test":"TestActualCase","Output":" Actual: not expected\n"}
+{"Action":"fail","Test":"TestActualCase"}
+{"Action":"output","Output":"FAIL\n"}
+{"Action":"output","Output":"exit status 1\n"}
+{"Action":"output","Output":"FAIL github.com/org/project/badtest 0.049s\n"}
+{"Action":"fail"}
diff --git a/libgo/go/cmd/internal/test2json/testdata/issue23036.test b/libgo/go/cmd/internal/test2json/testdata/issue23036.test
new file mode 100644
index 00000000000..fd4774f4b63
--- /dev/null
+++ b/libgo/go/cmd/internal/test2json/testdata/issue23036.test
@@ -0,0 +1,9 @@
+=== RUN TestActualCase
+--- FAIL: TestActualCase (0.00s)
+ foo_test.go:14: Differed.
+ Expected: MyTest:
+ --- FAIL: Test output from other tool
+ Actual: not expected
+FAIL
+exit status 1
+FAIL github.com/org/project/badtest 0.049s
diff --git a/libgo/go/cmd/internal/test2json/testdata/issue23920.json b/libgo/go/cmd/internal/test2json/testdata/issue23920.json
new file mode 100644
index 00000000000..28f7bd56ac3
--- /dev/null
+++ b/libgo/go/cmd/internal/test2json/testdata/issue23920.json
@@ -0,0 +1,14 @@
+{"Action":"run","Test":"TestWithColons"}
+{"Action":"output","Test":"TestWithColons","Output":"=== RUN TestWithColons\n"}
+{"Action":"run","Test":"TestWithColons/[::1]"}
+{"Action":"output","Test":"TestWithColons/[::1]","Output":"=== RUN TestWithColons/[::1]\n"}
+{"Action":"run","Test":"TestWithColons/127.0.0.1:0"}
+{"Action":"output","Test":"TestWithColons/127.0.0.1:0","Output":"=== RUN TestWithColons/127.0.0.1:0\n"}
+{"Action":"output","Test":"TestWithColons","Output":"--- PASS: TestWithColons (0.00s)\n"}
+{"Action":"output","Test":"TestWithColons/[::1]","Output":" --- PASS: TestWithColons/[::1] (0.00s)\n"}
+{"Action":"pass","Test":"TestWithColons/[::1]"}
+{"Action":"output","Test":"TestWithColons/127.0.0.1:0","Output":" --- PASS: TestWithColons/127.0.0.1:0 (0.00s)\n"}
+{"Action":"pass","Test":"TestWithColons/127.0.0.1:0"}
+{"Action":"pass","Test":"TestWithColons"}
+{"Action":"output","Output":"PASS\n"}
+{"Action":"pass"}
diff --git a/libgo/go/cmd/internal/test2json/testdata/issue23920.test b/libgo/go/cmd/internal/test2json/testdata/issue23920.test
new file mode 100644
index 00000000000..43bf0580343
--- /dev/null
+++ b/libgo/go/cmd/internal/test2json/testdata/issue23920.test
@@ -0,0 +1,7 @@
+=== RUN TestWithColons
+=== RUN TestWithColons/[::1]
+=== RUN TestWithColons/127.0.0.1:0
+--- PASS: TestWithColons (0.00s)
+ --- PASS: TestWithColons/[::1] (0.00s)
+ --- PASS: TestWithColons/127.0.0.1:0 (0.00s)
+PASS
diff --git a/libgo/go/cmd/test2json/main.go b/libgo/go/cmd/test2json/main.go
index 7bdc867bbe5..0385d8f246c 100644
--- a/libgo/go/cmd/test2json/main.go
+++ b/libgo/go/cmd/test2json/main.go
@@ -45,15 +45,17 @@
// pause - the test has been paused
// cont - the test has continued running
// pass - the test passed
-// fail - the test failed
+// bench - the benchmark printed log output but did not fail
+// fail - the test or benchmark failed
// output - the test printed output
+// skip - the test was skipped or the package contained no tests
//
// The Package field, if present, specifies the package being tested.
// When the go command runs parallel tests in -json mode, events from
// different tests are interlaced; the Package field allows readers to
// separate them.
//
-// The Test field, if present, specifies the test or example, or benchmark
+// The Test field, if present, specifies the test, example, or benchmark
// function that caused the event. Events for the overall package test
// do not set Test.
//
@@ -67,6 +69,14 @@
// the concatenation of the Output fields of all output events is the exact
// output of the test execution.
//
+// When a benchmark runs, it typically produces a single line of output
+// giving timing results. That line is reported in an event with Action == "output"
+// and no Test field. If a benchmark logs output or reports a failure
+// (for example, by using b.Log or b.Error), that extra output is reported
+// as a sequence of events with Test set to the benchmark name, terminated
+// by a final event with Action == "bench" or "fail".
+// Benchmarks have no events with Action == "run", "pause", or "cont".
+//
package main
import (
diff --git a/libgo/go/cmd/vet/all/main.go b/libgo/go/cmd/vet/all/main.go
index 09167af6d53..09181f96895 100644
--- a/libgo/go/cmd/vet/all/main.go
+++ b/libgo/go/cmd/vet/all/main.go
@@ -192,6 +192,12 @@ func vetPlatforms(pp []platform) {
}
func (p platform) vet() {
+ if p.os == "linux" && p.arch == "riscv64" {
+ // TODO(tklauser): enable as soon as the riscv64 port has fully landed
+ fmt.Println("skipping linux/riscv64")
+ return
+ }
+
var buf bytes.Buffer
fmt.Fprintf(&buf, "go run main.go -p %s\n", p)
diff --git a/libgo/go/cmd/vet/all/whitelist/386.txt b/libgo/go/cmd/vet/all/whitelist/386.txt
index 505856f3686..f59094eb14f 100644
--- a/libgo/go/cmd/vet/all/whitelist/386.txt
+++ b/libgo/go/cmd/vet/all/whitelist/386.txt
@@ -1,6 +1,7 @@
// 386-specific vet whitelist. See readme.txt for details.
-runtime/asm_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: Compare is in package bytes
+internal/bytealg/compare_386.s: [386] cannot check cross-package assembly function: Compare is in package bytes
+internal/bytealg/compare_386.s: [386] cannot check cross-package assembly function: cmpstring is in package runtime
// startup code uses non-standard calling convention and intentionally
// omits args.
@@ -15,13 +16,9 @@ runtime/asm_386.s: [386] morestack: use of 4(SP) points beyond argument frame
runtime/asm_386.s: [386] ldt0setup: function ldt0setup missing Go declaration
runtime/asm_386.s: [386] emptyfunc: function emptyfunc missing Go declaration
runtime/asm_386.s: [386] aeshashbody: function aeshashbody missing Go declaration
-runtime/asm_386.s: [386] memeqbody: function memeqbody missing Go declaration
-runtime/asm_386.s: [386] cmpbody: function cmpbody missing Go declaration
runtime/asm_386.s: [386] addmoduledata: function addmoduledata missing Go declaration
runtime/duff_386.s: [386] duffzero: function duffzero missing Go declaration
runtime/duff_386.s: [386] duffcopy: function duffcopy missing Go declaration
runtime/asm_386.s: [386] uint32tofloat64: function uint32tofloat64 missing Go declaration
runtime/asm_386.s: [386] float64touint32: function float64touint32 missing Go declaration
-
-runtime/asm_386.s: [386] stackcheck: function stackcheck missing Go declaration
diff --git a/libgo/go/cmd/vet/all/whitelist/all.txt b/libgo/go/cmd/vet/all/whitelist/all.txt
index 6792d263a5e..397ee4e9875 100644
--- a/libgo/go/cmd/vet/all/whitelist/all.txt
+++ b/libgo/go/cmd/vet/all/whitelist/all.txt
@@ -11,9 +11,14 @@ go/types/scope.go: method WriteTo(w io.Writer, n int, recurse bool) should have
// Nothing much to do about cross-package assembly. Unfortunate.
runtime/asm_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: call is in package reflect
-runtime/asm_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: Equal is in package bytes
-runtime/asm_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: IndexByte is in package bytes
-runtime/asm_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: IndexByte is in package strings
+internal/bytealg/equal_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: Equal is in package bytes
+internal/bytealg/equal_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: memequal is in package runtime
+internal/bytealg/equal_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: memequal_varlen is in package runtime
+internal/bytealg/indexbyte_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: IndexByte is in package bytes
+internal/bytealg/indexbyte_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: IndexByte is in package strings
+
+// The write barrier is called directly by the compiler, so no Go def
+runtime/asm_ARCHSUFF.s: [GOARCH] gcWriteBarrier: function gcWriteBarrier missing Go declaration
// Legitimate vet complaints in which we are testing for correct runtime behavior
// in bad situations that vet can also detect statically.
@@ -22,7 +27,6 @@ encoding/json/decode_test.go: struct field m2 has json tag but is not exported
encoding/json/tagkey_test.go: struct field tag `:"BadFormat"` not compatible with reflect.StructTag.Get: bad syntax for struct tag key
runtime/testdata/testprog/deadlock.go: unreachable code
runtime/testdata/testprog/deadlock.go: unreachable code
-sync/cond_test.go: assignment copies lock value to c2: sync.Cond contains sync.noCopy
// Non-standard method signatures.
// These cases are basically ok.
diff --git a/libgo/go/cmd/vet/all/whitelist/amd64.txt b/libgo/go/cmd/vet/all/whitelist/amd64.txt
index ebde7be58b0..20e0d48d532 100644
--- a/libgo/go/cmd/vet/all/whitelist/amd64.txt
+++ b/libgo/go/cmd/vet/all/whitelist/amd64.txt
@@ -1,34 +1,22 @@
// amd64-specific vet whitelist. See readme.txt for details.
-
// False positives.
+// Nothing much to do about cross-package assembly. Unfortunate.
+internal/bytealg/compare_amd64.s: [amd64] cannot check cross-package assembly function: Compare is in package bytes
+internal/bytealg/compare_amd64.s: [amd64] cannot check cross-package assembly function: cmpstring is in package runtime
// reflect trampolines intentionally omit arg size. Same for morestack.
runtime/asm_amd64.s: [amd64] morestack: use of 8(SP) points beyond argument frame
runtime/asm_amd64.s: [amd64] morestack: use of 16(SP) points beyond argument frame
runtime/asm_amd64.s: [amd64] morestack: use of 8(SP) points beyond argument frame
-// Nothing much to do about cross-package assembly. Unfortunate.
-runtime/asm_amd64.s: [amd64] cannot check cross-package assembly function: indexShortStr is in package strings
-runtime/asm_amd64.s: [GOARCH] cannot check cross-package assembly function: Compare is in package bytes
-runtime/asm_amd64.s: [amd64] cannot check cross-package assembly function: indexShortStr is in package bytes
-runtime/asm_amd64.s: [amd64] cannot check cross-package assembly function: countByte is in package strings
-runtime/asm_amd64.s: [amd64] cannot check cross-package assembly function: countByte is in package bytes
-
// Intentionally missing declarations. These are special assembly routines.
// Some are jumped into from other routines, with values in specific registers.
// duff* have direct calls from the compiler.
// Others use the platform ABI.
// There is no sensible corresponding Go prototype.
runtime/asm_amd64.s: [amd64] aeshashbody: function aeshashbody missing Go declaration
-runtime/asm_amd64.s: [amd64] memeqbody: function memeqbody missing Go declaration
-runtime/asm_amd64.s: [amd64] cmpbody: function cmpbody missing Go declaration
-runtime/asm_amd64.s: [amd64] indexbytebody: function indexbytebody missing Go declaration
runtime/asm_amd64.s: [amd64] addmoduledata: function addmoduledata missing Go declaration
runtime/duff_amd64.s: [amd64] duffzero: function duffzero missing Go declaration
runtime/duff_amd64.s: [amd64] duffcopy: function duffcopy missing Go declaration
-runtime/asm_amd64.s: [amd64] stackcheck: function stackcheck missing Go declaration
-runtime/asm_amd64.s: [amd64] indexShortStr: function indexShortStr missing Go declaration
-runtime/asm_amd64.s: [amd64] countByte: function countByte missing Go declaration
-runtime/asm_amd64.s: [amd64] gcWriteBarrier: function gcWriteBarrier missing Go declaration
diff --git a/libgo/go/cmd/vet/all/whitelist/arm.txt b/libgo/go/cmd/vet/all/whitelist/arm.txt
index 839346c2d49..8f98782f940 100644
--- a/libgo/go/cmd/vet/all/whitelist/arm.txt
+++ b/libgo/go/cmd/vet/all/whitelist/arm.txt
@@ -1,15 +1,11 @@
// arm-specific vet whitelist. See readme.txt for details.
-runtime/asm_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: Compare is in package bytes
-
-// reflect trampolines intentionally omit arg size. Same for morestack.
-runtime/asm_arm.s: [arm] morestack: use of 4(R13) points beyond argument frame
+internal/bytealg/compare_arm.s: [arm] cannot check cross-package assembly function: Compare is in package bytes
+internal/bytealg/compare_arm.s: [arm] cannot check cross-package assembly function: cmpstring is in package runtime
// Intentionally missing declarations.
runtime/asm_arm.s: [arm] emptyfunc: function emptyfunc missing Go declaration
-runtime/asm_arm.s: [arm] abort: function abort missing Go declaration
runtime/asm_arm.s: [arm] armPublicationBarrier: function armPublicationBarrier missing Go declaration
-runtime/asm_arm.s: [arm] cmpbody: function cmpbody missing Go declaration
runtime/asm_arm.s: [arm] usplitR0: function usplitR0 missing Go declaration
runtime/asm_arm.s: [arm] addmoduledata: function addmoduledata missing Go declaration
runtime/duff_arm.s: [arm] duffzero: function duffzero missing Go declaration
diff --git a/libgo/go/cmd/vet/all/whitelist/arm64.txt b/libgo/go/cmd/vet/all/whitelist/arm64.txt
index 24fc6f42235..ee0292b4152 100644
--- a/libgo/go/cmd/vet/all/whitelist/arm64.txt
+++ b/libgo/go/cmd/vet/all/whitelist/arm64.txt
@@ -1,9 +1,9 @@
// arm64-specific vet whitelist. See readme.txt for details.
-runtime/asm_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: Compare is in package bytes
+internal/bytealg/compare_arm64.s: [arm64] cannot check cross-package assembly function: Compare is in package bytes
+internal/bytealg/compare_arm64.s: [arm64] cannot check cross-package assembly function: cmpstring is in package runtime
// Intentionally missing declarations.
-runtime/asm_arm64.s: [arm64] abort: function abort missing Go declaration
runtime/asm_arm64.s: [arm64] addmoduledata: function addmoduledata missing Go declaration
runtime/duff_arm64.s: [arm64] duffzero: function duffzero missing Go declaration
runtime/duff_arm64.s: [arm64] duffcopy: function duffcopy missing Go declaration
diff --git a/libgo/go/cmd/vet/all/whitelist/darwin_386.txt b/libgo/go/cmd/vet/all/whitelist/darwin_386.txt
index d19d7d7bd04..5c25e092f20 100644
--- a/libgo/go/cmd/vet/all/whitelist/darwin_386.txt
+++ b/libgo/go/cmd/vet/all/whitelist/darwin_386.txt
@@ -2,8 +2,4 @@
// Ok
-runtime/sys_darwin_386.s: [386] now: function now missing Go declaration
-runtime/sys_darwin_386.s: [386] bsdthread_start: function bsdthread_start missing Go declaration
-runtime/sys_darwin_386.s: [386] sysenter: function sysenter missing Go declaration
runtime/sys_darwin_386.s: [386] setldt: function setldt missing Go declaration
-runtime/sys_darwin_386.s: [386] cannot check cross-package assembly function: now is in package time
diff --git a/libgo/go/cmd/vet/all/whitelist/darwin_amd64.txt b/libgo/go/cmd/vet/all/whitelist/darwin_amd64.txt
index 94a4e8fa75b..fcdacb2dc1b 100644
--- a/libgo/go/cmd/vet/all/whitelist/darwin_amd64.txt
+++ b/libgo/go/cmd/vet/all/whitelist/darwin_amd64.txt
@@ -1,5 +1,3 @@
// darwin/amd64-specific vet whitelist. See readme.txt for details.
-runtime/sys_darwin_amd64.s: [amd64] bsdthread_start: function bsdthread_start missing Go declaration
runtime/sys_darwin_amd64.s: [amd64] settls: function settls missing Go declaration
-runtime/sys_darwin_amd64.s: [amd64] cannot check cross-package assembly function: now is in package time
diff --git a/libgo/go/cmd/vet/all/whitelist/darwin_arm.txt b/libgo/go/cmd/vet/all/whitelist/darwin_arm.txt
index 0e619be4623..1c25c6a9397 100644
--- a/libgo/go/cmd/vet/all/whitelist/darwin_arm.txt
+++ b/libgo/go/cmd/vet/all/whitelist/darwin_arm.txt
@@ -1,12 +1,5 @@
// darwin/arm-specific vet whitelist. See readme.txt for details.
-// False positives due to comments in assembly.
-// To be removed. See CL 27154.
-
-runtime/sys_darwin_arm.s: [arm] sigfwd: use of unnamed argument 0(FP); offset 0 is fn+0(FP)
-
-
// Ok.
-runtime/sys_darwin_arm.s: [arm] bsdthread_start: function bsdthread_start missing Go declaration
runtime/asm_arm.s: [arm] sigreturn: function sigreturn missing Go declaration
diff --git a/libgo/go/cmd/vet/all/whitelist/darwin_arm64.txt b/libgo/go/cmd/vet/all/whitelist/darwin_arm64.txt
index 793cccf8dd8..a1edb713832 100644
--- a/libgo/go/cmd/vet/all/whitelist/darwin_arm64.txt
+++ b/libgo/go/cmd/vet/all/whitelist/darwin_arm64.txt
@@ -1,8 +1,3 @@
// darwin/arm64-specific vet whitelist. See readme.txt for details.
-runtime/sys_darwin_arm64.s: [arm64] sigtramp: 24(RSP) should be infostyle+8(FP)
-runtime/sys_darwin_arm64.s: [arm64] sigtramp: 24(RSP) should be infostyle+8(FP)
-runtime/sys_darwin_arm64.s: [arm64] bsdthread_create: RET without writing to 4-byte ret+24(FP)
-runtime/sys_darwin_arm64.s: [arm64] bsdthread_start: function bsdthread_start missing Go declaration
-runtime/sys_darwin_arm64.s: [arm64] bsdthread_register: RET without writing to 4-byte ret+0(FP)
runtime/asm_arm64.s: [arm64] sigreturn: function sigreturn missing Go declaration
diff --git a/libgo/go/cmd/vet/all/whitelist/linux_ppc64x.txt b/libgo/go/cmd/vet/all/whitelist/linux_ppc64x.txt
index 21e87e37d8c..0091d97110b 100644
--- a/libgo/go/cmd/vet/all/whitelist/linux_ppc64x.txt
+++ b/libgo/go/cmd/vet/all/whitelist/linux_ppc64x.txt
@@ -2,4 +2,3 @@
runtime/sys_linux_ppc64x.s: [GOARCH] _sigtramp: function _sigtramp missing Go declaration
runtime/sys_linux_ppc64x.s: [GOARCH] _cgoSigtramp: function _cgoSigtramp missing Go declaration
-runtime/asm_ppc64x.s: [GOARCH] procyield: use of 24(R1) points beyond argument frame
diff --git a/libgo/go/cmd/vet/all/whitelist/mips.txt b/libgo/go/cmd/vet/all/whitelist/mips.txt
index ad29336ad1b..fa17c6233b2 100644
--- a/libgo/go/cmd/vet/all/whitelist/mips.txt
+++ b/libgo/go/cmd/vet/all/whitelist/mips.txt
@@ -1,4 +1,4 @@
-// mips64-specific vet whitelist. See readme.txt for details.
+// mips-specific (big endian) vet whitelist. See readme.txt for details.
// Work around if-def'd code. Will be fixed by golang.org/issue/17544.
runtime/sys_linux_mipsx.s: [mips] walltime: invalid offset sec_lo+0(FP); expected sec_lo+4(FP)
diff --git a/libgo/go/cmd/vet/all/whitelist/mips64x.txt b/libgo/go/cmd/vet/all/whitelist/mips64x.txt
index 5354d21c642..16877654458 100644
--- a/libgo/go/cmd/vet/all/whitelist/mips64x.txt
+++ b/libgo/go/cmd/vet/all/whitelist/mips64x.txt
@@ -1,6 +1,5 @@
// mips64-specific vet whitelist. See readme.txt for details.
-runtime/asm_mips64x.s: [GOARCH] abort: function abort missing Go declaration
runtime/duff_mips64x.s: [GOARCH] duffzero: function duffzero missing Go declaration
runtime/tls_mips64x.s: [GOARCH] save_g: function save_g missing Go declaration
runtime/tls_mips64x.s: [GOARCH] load_g: function load_g missing Go declaration
diff --git a/libgo/go/cmd/vet/all/whitelist/mipsle.txt b/libgo/go/cmd/vet/all/whitelist/mipsle.txt
index 929216905e6..9361dc43537 100644
--- a/libgo/go/cmd/vet/all/whitelist/mipsle.txt
+++ b/libgo/go/cmd/vet/all/whitelist/mipsle.txt
@@ -1,4 +1,4 @@
-// mips64-specific vet whitelist. See readme.txt for details.
+// mipsle-specific vet whitelist. See readme.txt for details.
// Work around if-def'd code. Will be fixed by golang.org/issue/17544.
runtime/sys_linux_mipsx.s: [mipsle] walltime: invalid offset sec_lo+4(FP); expected sec_lo+0(FP)
diff --git a/libgo/go/cmd/vet/all/whitelist/mipsx.txt b/libgo/go/cmd/vet/all/whitelist/mipsx.txt
index 860f8399211..1a2cd3ff624 100644
--- a/libgo/go/cmd/vet/all/whitelist/mipsx.txt
+++ b/libgo/go/cmd/vet/all/whitelist/mipsx.txt
@@ -1,9 +1,10 @@
-// mips64-specific vet whitelist. See readme.txt for details.
+// mips/mipsle-specific vet whitelist. See readme.txt for details.
+
+internal/bytealg/compare_mipsx.s: [GOARCH] cannot check cross-package assembly function: Compare is in package bytes
+internal/bytealg/compare_mipsx.s: [GOARCH] cannot check cross-package assembly function: cmpstring is in package runtime
-runtime/asm_mipsx.s: [GOARCH] abort: function abort missing Go declaration
runtime/tls_mipsx.s: [GOARCH] save_g: function save_g missing Go declaration
runtime/tls_mipsx.s: [GOARCH] load_g: function load_g missing Go declaration
-runtime/asm_mipsx.s: [GOARCH] cannot check cross-package assembly function: Compare is in package bytes
runtime/sys_linux_mipsx.s: [GOARCH] clone: 12(R29) should be mp+8(FP)
runtime/sys_linux_mipsx.s: [GOARCH] clone: 4(R29) should be flags+0(FP)
runtime/sys_linux_mipsx.s: [GOARCH] clone: 8(R29) should be stk+4(FP)
diff --git a/libgo/go/cmd/vet/all/whitelist/nacl_amd64p32.txt b/libgo/go/cmd/vet/all/whitelist/nacl_amd64p32.txt
index 4b2aad2aacd..1ec11f7ca87 100644
--- a/libgo/go/cmd/vet/all/whitelist/nacl_amd64p32.txt
+++ b/libgo/go/cmd/vet/all/whitelist/nacl_amd64p32.txt
@@ -1,5 +1,8 @@
// nacl/amd64p32-specific vet whitelist. See readme.txt for details.
+internal/bytealg/compare_amd64p32.s: [amd64p32] cannot check cross-package assembly function: Compare is in package bytes
+internal/bytealg/compare_amd64p32.s: [amd64p32] cannot check cross-package assembly function: cmpstring is in package runtime
+
// reflect trampolines intentionally omit arg size. Same for morestack.
runtime/asm_amd64p32.s: [amd64p32] morestack: use of 8(SP) points beyond argument frame
runtime/asm_amd64p32.s: [amd64p32] morestack: use of 16(SP) points beyond argument frame
@@ -20,10 +23,4 @@ runtime/sys_nacl_amd64p32.s: [amd64p32] settls: function settls missing Go decla
runtime/asm_amd64p32.s: [amd64p32] rt0_go: unknown variable argc
runtime/asm_amd64p32.s: [amd64p32] rt0_go: unknown variable argv
-runtime/asm_amd64p32.s: [amd64p32] memeqbody: function memeqbody missing Go declaration
-runtime/asm_amd64p32.s: [amd64p32] cannot check cross-package assembly function: Compare is in package bytes
-runtime/asm_amd64p32.s: [amd64p32] cmpbody: function cmpbody missing Go declaration
-runtime/asm_amd64p32.s: [amd64p32] indexbytebody: function indexbytebody missing Go declaration
runtime/asm_amd64p32.s: [amd64p32] asmcgocall: RET without writing to 4-byte ret+8(FP)
-
-runtime/asm_amd64p32.s: [amd64p32] stackcheck: function stackcheck missing Go declaration
diff --git a/libgo/go/cmd/vet/all/whitelist/ppc64x.txt b/libgo/go/cmd/vet/all/whitelist/ppc64x.txt
index 4f6444e1026..65a904ed481 100644
--- a/libgo/go/cmd/vet/all/whitelist/ppc64x.txt
+++ b/libgo/go/cmd/vet/all/whitelist/ppc64x.txt
@@ -1,10 +1,9 @@
// ppc64-specific vet whitelist. See readme.txt for details.
-runtime/asm_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: Compare is in package bytes
+internal/bytealg/compare_ppc64x.s: [GOARCH] cannot check cross-package assembly function: Compare is in package bytes
+internal/bytealg/compare_ppc64x.s: [GOARCH] cannot check cross-package assembly function: cmpstring is in package runtime
runtime/asm_ppc64x.s: [GOARCH] reginit: function reginit missing Go declaration
-runtime/asm_ppc64x.s: [GOARCH] abort: function abort missing Go declaration
-runtime/asm_ppc64x.s: [GOARCH] memeqbody: function memeqbody missing Go declaration
runtime/asm_ppc64x.s: [GOARCH] goexit: use of 24(R1) points beyond argument frame
runtime/asm_ppc64x.s: [GOARCH] addmoduledata: function addmoduledata missing Go declaration
runtime/duff_ppc64x.s: [GOARCH] duffzero: function duffzero missing Go declaration
diff --git a/libgo/go/cmd/vet/all/whitelist/s390x.txt b/libgo/go/cmd/vet/all/whitelist/s390x.txt
index f18236c4f11..5bc48e5afcf 100644
--- a/libgo/go/cmd/vet/all/whitelist/s390x.txt
+++ b/libgo/go/cmd/vet/all/whitelist/s390x.txt
@@ -1,17 +1,14 @@
-runtime/asm_s390x.s: [s390x] abort: function abort missing Go declaration
-runtime/asm_s390x.s: [s390x] memeqbody: function memeqbody missing Go declaration
-runtime/asm_s390x.s: [s390x] memeqbodyclc: function memeqbodyclc missing Go declaration
-runtime/asm_s390x.s: [s390x] indexbytebody: function indexbytebody missing Go declaration
-runtime/asm_s390x.s: [s390x] cannot check cross-package assembly function: Compare is in package bytes
-runtime/asm_s390x.s: [s390x] cmpbody: function cmpbody missing Go declaration
-runtime/asm_s390x.s: [s390x] cmpbodyclc: function cmpbodyclc missing Go declaration
-runtime/asm_s390x.s: [s390x] cannot check cross-package assembly function: supportsVX is in package strings
-runtime/asm_s390x.s: [s390x] cannot check cross-package assembly function: supportsVX is in package bytes
-runtime/asm_s390x.s: [s390x] cannot check cross-package assembly function: indexShortStr is in package strings
-runtime/asm_s390x.s: [s390x] cannot check cross-package assembly function: indexShortStr is in package bytes
-runtime/asm_s390x.s: [s390x] indexShortStr: function indexShortStr missing Go declaration
+internal/bytealg/compare_s390x.s: [s390x] cannot check cross-package assembly function: Compare is in package bytes
+internal/bytealg/compare_s390x.s: [s390x] cannot check cross-package assembly function: cmpstring is in package runtime
runtime/asm_s390x.s: [s390x] addmoduledata: function addmoduledata missing Go declaration
runtime/memclr_s390x.s: [s390x] memclr_s390x_exrl_xc: function memclr_s390x_exrl_xc missing Go declaration
runtime/memmove_s390x.s: [s390x] memmove_s390x_exrl_mvc: function memmove_s390x_exrl_mvc missing Go declaration
runtime/tls_s390x.s: [s390x] save_g: function save_g missing Go declaration
runtime/tls_s390x.s: [s390x] load_g: function load_g missing Go declaration
+internal/cpu/cpu_s390x.s: [s390x] stfle: invalid MOVD of ret+0(FP); cpu.facilityList is 32-byte value
+internal/cpu/cpu_s390x.s: [s390x] kmQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value
+internal/cpu/cpu_s390x.s: [s390x] kmcQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value
+internal/cpu/cpu_s390x.s: [s390x] kmctrQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value
+internal/cpu/cpu_s390x.s: [s390x] kmaQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value
+internal/cpu/cpu_s390x.s: [s390x] kimdQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value
+internal/cpu/cpu_s390x.s: [s390x] klmdQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value
diff --git a/libgo/go/cmd/vet/all/whitelist/wasm.txt b/libgo/go/cmd/vet/all/whitelist/wasm.txt
new file mode 100644
index 00000000000..7a8037f085e
--- /dev/null
+++ b/libgo/go/cmd/vet/all/whitelist/wasm.txt
@@ -0,0 +1,28 @@
+// wasm-specific vet whitelist. See readme.txt for details.
+
+// False positives.
+
+// Nothing much to do about cross-package assembly. Unfortunate.
+internal/bytealg/compare_wasm.s: [wasm] cannot check cross-package assembly function: Compare is in package bytes
+internal/bytealg/compare_wasm.s: [wasm] cannot check cross-package assembly function: cmpstring is in package runtime
+
+// morestack intentionally omits arg size.
+runtime/asm_wasm.s: [wasm] morestack: use of 8(SP) points beyond argument frame
+runtime/asm_wasm.s: [wasm] morestack: use of 16(SP) points beyond argument frame
+runtime/asm_wasm.s: [wasm] morestack: use of 8(SP) points beyond argument frame
+
+// rt0_go does not allocate a stack frame.
+runtime/asm_wasm.s: [wasm] rt0_go: use of 8(SP) points beyond argument frame
+
+// Calling WebAssembly import. No write from Go assembly.
+runtime/sys_wasm.s: [wasm] nanotime: RET without writing to 8-byte ret+0(FP)
+runtime/sys_wasm.s: [wasm] scheduleCallback: RET without writing to 4-byte ret+8(FP)
+syscall/js/js_js.s: [wasm] stringVal: RET without writing to 8-byte ret+16(FP)
+syscall/js/js_js.s: [wasm] valueGet: RET without writing to 8-byte ret+24(FP)
+syscall/js/js_js.s: [wasm] valueIndex: RET without writing to 8-byte ret+16(FP)
+syscall/js/js_js.s: [wasm] valueCall: RET without writing to 8-byte ret+48(FP)
+syscall/js/js_js.s: [wasm] valueInvoke: RET without writing to 8-byte ret+32(FP)
+syscall/js/js_js.s: [wasm] valueNew: RET without writing to 8-byte ret+32(FP)
+syscall/js/js_js.s: [wasm] valueLength: RET without writing to 8-byte ret+8(FP)
+syscall/js/js_js.s: [wasm] valuePrepareString: RET without writing to 8-byte ret+8(FP)
+syscall/js/js_js.s: [wasm] valueInstanceOf: RET without writing to 1-byte ret+16(FP)
diff --git a/libgo/go/cmd/vet/asmdecl.go b/libgo/go/cmd/vet/asmdecl.go
index b01d23d342b..ccf6269f1db 100644
--- a/libgo/go/cmd/vet/asmdecl.go
+++ b/libgo/go/cmd/vet/asmdecl.go
@@ -77,6 +77,7 @@ var (
asmArchPpc64 = asmArch{name: "ppc64", bigEndian: true, stack: "R1", lr: true}
asmArchPpc64LE = asmArch{name: "ppc64le", bigEndian: false, stack: "R1", lr: true}
asmArchS390X = asmArch{name: "s390x", bigEndian: true, stack: "R15", lr: true}
+ asmArchWasm = asmArch{name: "wasm", bigEndian: false, stack: "SP", lr: false}
arches = []*asmArch{
&asmArch386,
@@ -91,6 +92,7 @@ var (
&asmArchPpc64,
&asmArchPpc64LE,
&asmArchS390X,
+ &asmArchWasm,
}
)
@@ -104,6 +106,8 @@ func init() {
arch.ptrSize = int(arch.sizes.Sizeof(types.Typ[types.UnsafePointer]))
arch.maxAlign = int(arch.sizes.Alignof(types.Typ[types.Int64]))
}
+
+ registerPkgCheck("asmdecl", asmCheck)
}
var (
@@ -119,7 +123,7 @@ var (
)
func asmCheck(pkg *Package) {
- if !vet("asmdecl") {
+ if vcfg.VetxOnly {
return
}
@@ -240,17 +244,17 @@ Files:
continue
}
}
+ flag := m[3]
fn = knownFunc[fnName][arch]
if fn != nil {
size, _ := strconv.Atoi(m[5])
- flag := m[3]
if size != fn.size && (flag != "7" && !strings.Contains(flag, "NOSPLIT") || size != 0) {
badf("wrong argument size %d; expected $...-%d", size, fn.size)
}
}
localSize, _ = strconv.Atoi(m[4])
localSize += archDef.intSize
- if archDef.lr {
+ if archDef.lr && !strings.Contains(flag, "NOFRAME") {
// Account for caller's saved LR
localSize += archDef.intSize
}
diff --git a/libgo/go/cmd/vet/assign.go b/libgo/go/cmd/vet/assign.go
index bfa5b303293..223e80d4007 100644
--- a/libgo/go/cmd/vet/assign.go
+++ b/libgo/go/cmd/vet/assign.go
@@ -37,7 +37,7 @@ func checkAssignStmt(f *File, node ast.Node) {
}
for i, lhs := range stmt.Lhs {
rhs := stmt.Rhs[i]
- if hasSideEffects(lhs) || hasSideEffects(rhs) {
+ if hasSideEffects(f, lhs) || hasSideEffects(f, rhs) {
continue // expressions may not be equal
}
if reflect.TypeOf(lhs) != reflect.TypeOf(rhs) {
diff --git a/libgo/go/cmd/vet/atomic.go b/libgo/go/cmd/vet/atomic.go
index b2ca2d80f30..b425669e1ae 100644
--- a/libgo/go/cmd/vet/atomic.go
+++ b/libgo/go/cmd/vet/atomic.go
@@ -7,6 +7,7 @@ package main
import (
"go/ast"
"go/token"
+ "go/types"
)
func init() {
@@ -36,8 +37,9 @@ func checkAtomicAssignment(f *File, node ast.Node) {
if !ok {
continue
}
- pkg, ok := sel.X.(*ast.Ident)
- if !ok || pkg.Name != "atomic" {
+ pkgIdent, _ := sel.X.(*ast.Ident)
+ pkgName, ok := f.pkg.uses[pkgIdent].(*types.PkgName)
+ if !ok || pkgName.Imported().Path() != "sync/atomic" {
continue
}
diff --git a/libgo/go/cmd/vet/bool.go b/libgo/go/cmd/vet/bool.go
index 07c2a93dffa..1cd477f988c 100644
--- a/libgo/go/cmd/vet/bool.go
+++ b/libgo/go/cmd/vet/bool.go
@@ -31,7 +31,7 @@ func checkBool(f *File, n ast.Node) {
return
}
- comm := op.commutativeSets(e)
+ comm := op.commutativeSets(f, e)
for _, exprs := range comm {
op.checkRedundant(f, exprs)
op.checkSuspect(f, exprs)
@@ -53,14 +53,14 @@ var (
// expressions in e that are connected by op.
// For example, given 'a || b || f() || c || d' with the or op,
// commutativeSets returns {{b, a}, {d, c}}.
-func (op boolOp) commutativeSets(e *ast.BinaryExpr) [][]ast.Expr {
+func (op boolOp) commutativeSets(f *File, e *ast.BinaryExpr) [][]ast.Expr {
exprs := op.split(e)
// Partition the slice of expressions into commutative sets.
i := 0
var sets [][]ast.Expr
for j := 0; j <= len(exprs); j++ {
- if j == len(exprs) || hasSideEffects(exprs[j]) {
+ if j == len(exprs) || hasSideEffects(f, exprs[j]) {
if i < j {
sets = append(sets, exprs[i:j])
}
@@ -136,16 +136,27 @@ func (op boolOp) checkSuspect(f *File, exprs []ast.Expr) {
}
// hasSideEffects reports whether evaluation of e has side effects.
-func hasSideEffects(e ast.Expr) bool {
+func hasSideEffects(f *File, e ast.Expr) bool {
safe := true
ast.Inspect(e, func(node ast.Node) bool {
switch n := node.(type) {
- // Using CallExpr here will catch conversions
- // as well as function and method invocations.
- // We'll live with the false negatives for now.
case *ast.CallExpr:
- safe = false
- return false
+ typVal := f.pkg.types[n.Fun]
+ switch {
+ case typVal.IsType():
+ // Type conversion, which is safe.
+ case typVal.IsBuiltin():
+ // Builtin func, conservatively assumed to not
+ // be safe for now.
+ safe = false
+ return false
+ default:
+ // A non-builtin func or method call.
+ // Conservatively assume that all of them have
+ // side effects for now.
+ safe = false
+ return false
+ }
case *ast.UnaryExpr:
if n.Op == token.ARROW {
safe = false
diff --git a/libgo/go/cmd/vet/buildtag.go b/libgo/go/cmd/vet/buildtag.go
index 80d8f819240..ba3a361b911 100644
--- a/libgo/go/cmd/vet/buildtag.go
+++ b/libgo/go/cmd/vet/buildtag.go
@@ -18,12 +18,39 @@ var (
plusBuild = []byte("+build")
)
+func badfLine(f *File, line int, format string, args ...interface{}) {
+ msg := fmt.Sprintf(format, args...)
+ fmt.Fprintf(os.Stderr, "%s:%d: %s\n", f.name, line, msg)
+ setExit(1)
+}
+
// checkBuildTag checks that build tags are in the correct location and well-formed.
-func checkBuildTag(name string, data []byte) {
+func checkBuildTag(f *File) {
if !vet("buildtags") {
return
}
- lines := bytes.SplitAfter(data, nl)
+
+ // we must look at the raw lines, as build tags may appear in non-Go
+ // files such as assembly files.
+ lines := bytes.SplitAfter(f.content, nl)
+
+ // lineWithComment reports whether a line corresponds to a comment in
+ // the source file. If the source file wasn't Go, the function always
+ // returns true.
+ lineWithComment := func(line int) bool {
+ if f.file == nil {
+ // Current source file is not Go, so be conservative.
+ return true
+ }
+ for _, group := range f.file.Comments {
+ startLine := f.fset.Position(group.Pos()).Line
+ endLine := f.fset.Position(group.End()).Line
+ if startLine <= line && line <= endLine {
+ return true
+ }
+ }
+ return false
+ }
// Determine cutpoint where +build comments are no longer valid.
// They are valid in leading // comments in the file followed by
@@ -46,18 +73,29 @@ func checkBuildTag(name string, data []byte) {
if !bytes.HasPrefix(line, slashSlash) {
continue
}
+ if !bytes.Contains(line, plusBuild) {
+ // Check that the comment contains "+build" early, to
+ // avoid unnecessary lineWithComment calls that may
+ // incur linear searches.
+ continue
+ }
+ if !lineWithComment(i + 1) {
+ // This is a line in a Go source file that looks like a
+ // comment, but actually isn't - such as part of a raw
+ // string.
+ continue
+ }
+
text := bytes.TrimSpace(line[2:])
if bytes.HasPrefix(text, plusBuild) {
fields := bytes.Fields(text)
if !bytes.Equal(fields[0], plusBuild) {
// Comment is something like +buildasdf not +build.
- fmt.Fprintf(os.Stderr, "%s:%d: possible malformed +build comment\n", name, i+1)
- setExit(1)
+ badfLine(f, i+1, "possible malformed +build comment")
continue
}
if i >= cutoff {
- fmt.Fprintf(os.Stderr, "%s:%d: +build comment must appear before package clause and be followed by a blank line\n", name, i+1)
- setExit(1)
+ badfLine(f, i+1, "+build comment must appear before package clause and be followed by a blank line")
continue
}
// Check arguments.
@@ -65,15 +103,13 @@ func checkBuildTag(name string, data []byte) {
for _, arg := range fields[1:] {
for _, elem := range strings.Split(string(arg), ",") {
if strings.HasPrefix(elem, "!!") {
- fmt.Fprintf(os.Stderr, "%s:%d: invalid double negative in build constraint: %s\n", name, i+1, arg)
- setExit(1)
+ badfLine(f, i+1, "invalid double negative in build constraint: %s", arg)
break Args
}
elem = strings.TrimPrefix(elem, "!")
for _, c := range elem {
if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' {
- fmt.Fprintf(os.Stderr, "%s:%d: invalid non-alphanumeric build constraint: %s\n", name, i+1, arg)
- setExit(1)
+ badfLine(f, i+1, "invalid non-alphanumeric build constraint: %s", arg)
break Args
}
}
@@ -82,9 +118,8 @@ func checkBuildTag(name string, data []byte) {
continue
}
// Comment with +build but not at beginning.
- if bytes.Contains(line, plusBuild) && i < cutoff {
- fmt.Fprintf(os.Stderr, "%s:%d: possible malformed +build comment\n", name, i+1)
- setExit(1)
+ if i < cutoff {
+ badfLine(f, i+1, "possible malformed +build comment")
continue
}
}
diff --git a/libgo/go/cmd/vet/composite.go b/libgo/go/cmd/vet/composite.go
index f704f181bf0..861e040aac4 100644
--- a/libgo/go/cmd/vet/composite.go
+++ b/libgo/go/cmd/vet/composite.go
@@ -18,7 +18,7 @@ var compositeWhiteList = flag.Bool("compositewhitelist", true, "use composite wh
func init() {
register("composites",
- "check that composite literals used field-keyed elements",
+ "check that composite literals of types from imported packages use field-keyed elements",
checkUnkeyedLiteral,
compositeLit)
}
@@ -38,11 +38,19 @@ func checkUnkeyedLiteral(f *File, node ast.Node) {
// skip whitelisted types
return
}
- if _, ok := typ.Underlying().(*types.Struct); !ok {
+ under := typ.Underlying()
+ for {
+ ptr, ok := under.(*types.Pointer)
+ if !ok {
+ break
+ }
+ under = ptr.Elem().Underlying()
+ }
+ if _, ok := under.(*types.Struct); !ok {
// skip non-struct composite literals
return
}
- if isLocalType(f, typeName) {
+ if isLocalType(f, typ) {
// allow unkeyed locally defined composite literal
return
}
@@ -63,20 +71,16 @@ func checkUnkeyedLiteral(f *File, node ast.Node) {
f.Badf(cl.Pos(), "%s composite literal uses unkeyed fields", typeName)
}
-func isLocalType(f *File, typeName string) bool {
- if strings.HasPrefix(typeName, "struct{") {
+func isLocalType(f *File, typ types.Type) bool {
+ switch x := typ.(type) {
+ case *types.Struct:
// struct literals are local types
return true
+ case *types.Pointer:
+ return isLocalType(f, x.Elem())
+ case *types.Named:
+ // names in package foo are local to foo_test too
+ return strings.TrimSuffix(x.Obj().Pkg().Path(), "_test") == strings.TrimSuffix(f.pkg.path, "_test")
}
-
- pkgname := f.pkg.path
- if strings.HasPrefix(typeName, pkgname+".") {
- return true
- }
-
- // treat types as local inside test packages with _test name suffix
- if strings.HasSuffix(pkgname, "_test") {
- pkgname = pkgname[:len(pkgname)-len("_test")]
- }
- return strings.HasPrefix(typeName, pkgname+".")
+ return false
}
diff --git a/libgo/go/cmd/vet/copylock.go b/libgo/go/cmd/vet/copylock.go
index ce14e1af343..ed88ca89603 100644
--- a/libgo/go/cmd/vet/copylock.go
+++ b/libgo/go/cmd/vet/copylock.go
@@ -234,13 +234,11 @@ func lockPath(tpkg *types.Package, typ types.Type) typePath {
return nil
}
- // We're looking for cases in which a reference to this type
- // can be locked, but a value cannot. This differentiates
+ // We're looking for cases in which a pointer to this type
+ // is a sync.Locker, but a value is not. This differentiates
// embedded interfaces from embedded values.
- if plock := types.NewMethodSet(types.NewPointer(typ)).Lookup(tpkg, "Lock"); plock != nil {
- if lock := types.NewMethodSet(typ).Lookup(tpkg, "Lock"); lock == nil {
- return []types.Type{typ}
- }
+ if types.Implements(types.NewPointer(typ), lockerType) && !types.Implements(typ, lockerType) {
+ return []types.Type{typ}
}
nfields := styp.NumFields()
@@ -254,3 +252,15 @@ func lockPath(tpkg *types.Package, typ types.Type) typePath {
return nil
}
+
+var lockerType *types.Interface
+
+// Construct a sync.Locker interface type.
+func init() {
+ nullary := types.NewSignature(nil, nil, nil, false) // func()
+ methods := []*types.Func{
+ types.NewFunc(token.NoPos, nil, "Lock", nullary),
+ types.NewFunc(token.NoPos, nil, "Unlock", nullary),
+ }
+ lockerType = types.NewInterface(methods, nil).Complete()
+}
diff --git a/libgo/go/cmd/vet/dead.go b/libgo/go/cmd/vet/dead.go
index 130f619626d..0facec55258 100644
--- a/libgo/go/cmd/vet/dead.go
+++ b/libgo/go/cmd/vet/dead.go
@@ -45,7 +45,7 @@ func (f *File) updateDead(node ast.Node) {
}
for _, expr := range cc.List {
v := f.pkg.types[expr].Value
- if v == nil || constant.BoolVal(v) {
+ if v == nil || v.Kind() != constant.Bool || constant.BoolVal(v) {
continue BodyLoopBool
}
}
diff --git a/libgo/go/cmd/vet/doc.go b/libgo/go/cmd/vet/doc.go
index 3df975cacc4..d9af0a88759 100644
--- a/libgo/go/cmd/vet/doc.go
+++ b/libgo/go/cmd/vet/doc.go
@@ -119,22 +119,17 @@ Printf family
Flag: -printf
-Suspicious calls to functions in the Printf family, including any functions
-with these names, disregarding case:
- Print Printf Println
- Fprint Fprintf Fprintln
- Sprint Sprintf Sprintln
- Error Errorf
- Fatal Fatalf
- Log Logf
- Panic Panicf Panicln
-The -printfuncs flag can be used to redefine this list.
-If the function name ends with an 'f', the function is assumed to take
-a format descriptor string in the manner of fmt.Printf. If not, vet
-complains about arguments that look like format descriptor strings.
-
-It also checks for errors such as using a Writer as the first argument of
-Printf.
+Suspicious calls to fmt.Print, fmt.Printf, and related functions.
+The check applies to known functions (for example, those in package fmt)
+as well as any detected wrappers of known functions.
+
+The -printfuncs flag specifies a comma-separated list of names of
+additional known formatting functions. Each name can be of the form
+pkg.Name or pkg.Type.Name, where pkg is a complete import path,
+or else can be a case-insensitive unqualified identifier like "errorf".
+If a listed name ends in f, the function is assumed to be Printf-like,
+taking a format string before the argument list. Otherwise it is
+assumed to be Print-like, taking a list of arguments with no format string.
Range loop variables
diff --git a/libgo/go/cmd/vet/main.go b/libgo/go/cmd/vet/main.go
index 49c1d32f13d..c50d4885a07 100644
--- a/libgo/go/cmd/vet/main.go
+++ b/libgo/go/cmd/vet/main.go
@@ -4,10 +4,12 @@
// Vet is a simple checker for static errors in Go source code.
// See doc.go for more information.
+
package main
import (
"bytes"
+ "encoding/gob"
"encoding/json"
"flag"
"fmt"
@@ -22,8 +24,11 @@ import (
"io/ioutil"
"os"
"path/filepath"
+ "sort"
"strconv"
"strings"
+
+ "cmd/internal/objabi"
)
// Important! If you add flags here, make sure to update cmd/go/internal/vet/vetflag.go.
@@ -154,9 +159,31 @@ var (
// checkers is a two-level map.
// The outer level is keyed by a nil pointer, one of the AST vars above.
// The inner level is keyed by checker name.
- checkers = make(map[ast.Node]map[string]func(*File, ast.Node))
+ checkers = make(map[ast.Node]map[string]func(*File, ast.Node))
+ pkgCheckers = make(map[string]func(*Package))
+ exporters = make(map[string]func() interface{})
)
+// The exporters data as written to the vetx output file.
+type vetxExport struct {
+ Name string
+ Data interface{}
+}
+
+// Vet can provide its own "export information"
+// about package A to future invocations of vet
+// on packages importing A. If B imports A,
+// then running "go vet B" actually invokes vet twice:
+// first, it runs vet on A, in "vetx-only" mode, which
+// skips most checks and only computes export data
+// describing A. Then it runs vet on B, making A's vetx
+// data available for consultation. The vet of B
+// computes vetx data for B in addition to its
+// usual vet checks.
+
+// register registers the named check function,
+// to be called with AST nodes of the given types.
+// The registered functions are not called in vetx-only mode.
func register(name, usage string, fn func(*File, ast.Node), types ...ast.Node) {
report[name] = triStateFlag(name, unset, usage)
for _, typ := range types {
@@ -169,6 +196,25 @@ func register(name, usage string, fn func(*File, ast.Node), types ...ast.Node) {
}
}
+// registerPkgCheck registers a package-level checking function,
+// to be invoked with the whole package being vetted
+// before any of the per-node handlers.
+// The registered function fn is called even in vetx-only mode
+// (see comment above), so fn must take care not to report
+// errors when vcfg.VetxOnly is true.
+func registerPkgCheck(name string, fn func(*Package)) {
+ pkgCheckers[name] = fn
+}
+
+// registerExport registers a function to return vetx export data
+// that should be saved and provided to future invocations of vet
+// when checking packages importing this one.
+// The value returned by fn should be nil or else valid to encode using gob.
+// Typically a registerExport call is paired with a call to gob.Register.
+func registerExport(name string, fn func() interface{}) {
+ exporters[name] = fn
+}
+
// Usage is a replacement usage function for the flags package.
func Usage() {
fmt.Fprintf(os.Stderr, "Usage of vet:\n")
@@ -195,9 +241,11 @@ type File struct {
// Parsed package "foo" when checking package "foo_test"
basePkg *Package
- // The objects that are receivers of a "String() string" method.
+ // The keys are the objects that are receivers of a "String()
+ // string" method. The value reports whether the method has a
+ // pointer receiver.
// This is used by the recursiveStringer method in print.go.
- stringers map[*ast.Object]bool
+ stringerPtrs map[*ast.Object]bool
// Registered checkers to run.
checkers map[ast.Node][]func(*File, ast.Node)
@@ -207,6 +255,7 @@ type File struct {
}
func main() {
+ objabi.AddVersionFlag()
flag.Usage = Usage
flag.Parse()
@@ -293,6 +342,9 @@ type vetConfig struct {
ImportMap map[string]string
PackageFile map[string]string
Standard map[string]bool
+ PackageVetx map[string]string // map from import path to vetx data file
+ VetxOnly bool // only compute vetx output; don't run ordinary checks
+ VetxOutput string // file where vetx output should be written
SucceedOnTypecheckFailure bool
@@ -353,6 +405,28 @@ func doPackageCfg(cfgFile string) {
inittypes()
mustTypecheck = true
doPackage(vcfg.GoFiles, nil)
+ if vcfg.VetxOutput != "" {
+ out := make([]vetxExport, 0, len(exporters))
+ for name, fn := range exporters {
+ out = append(out, vetxExport{
+ Name: name,
+ Data: fn(),
+ })
+ }
+ // Sort the data so that it is consistent across builds.
+ sort.Slice(out, func(i, j int) bool {
+ return out[i].Name < out[j].Name
+ })
+ var buf bytes.Buffer
+ if err := gob.NewEncoder(&buf).Encode(out); err != nil {
+ errorf("encoding vet output: %v", err)
+ return
+ }
+ if err := ioutil.WriteFile(vcfg.VetxOutput, buf.Bytes(), 0666); err != nil {
+ errorf("saving vet output: %v", err)
+ return
+ }
+ }
}
// doPackageDir analyzes the single package found in the directory, if there is one,
@@ -413,23 +487,23 @@ func doPackage(names []string, basePkg *Package) *Package {
warnf("%s: %s", name, err)
return nil
}
- checkBuildTag(name, data)
var parsedFile *ast.File
if strings.HasSuffix(name, ".go") {
- parsedFile, err = parser.ParseFile(fs, name, data, 0)
+ parsedFile, err = parser.ParseFile(fs, name, data, parser.ParseComments)
if err != nil {
warnf("%s: %s", name, err)
return nil
}
astFiles = append(astFiles, parsedFile)
}
- files = append(files, &File{
+ file := &File{
fset: fs,
content: data,
name: name,
file: parsedFile,
dead: make(map[ast.Node]bool),
- })
+ }
+ files = append(files, file)
}
if len(astFiles) == 0 {
return nil
@@ -458,6 +532,19 @@ func doPackage(names []string, basePkg *Package) *Package {
}
// Check.
+ for _, file := range files {
+ file.pkg = pkg
+ file.basePkg = basePkg
+ }
+ for name, fn := range pkgCheckers {
+ if vet(name) {
+ fn(pkg)
+ }
+ }
+ if vcfg.VetxOnly {
+ return pkg
+ }
+
chk := make(map[ast.Node][]func(*File, ast.Node))
for typ, set := range checkers {
for name, fn := range set {
@@ -467,14 +554,12 @@ func doPackage(names []string, basePkg *Package) *Package {
}
}
for _, file := range files {
- file.pkg = pkg
- file.basePkg = basePkg
+ checkBuildTag(file)
file.checkers = chk
if file.file != nil {
file.walkFile(file.name, file.file)
}
}
- asmCheck(pkg)
return pkg
}
@@ -627,3 +712,39 @@ func (f *File) gofmt(x ast.Expr) string {
printer.Fprint(&f.b, f.fset, x)
return f.b.String()
}
+
+// imported[path][key] is previously written export data.
+var imported = make(map[string]map[string]interface{})
+
+// readVetx reads export data written by a previous
+// invocation of vet on an imported package (path).
+// The key is the name passed to registerExport
+// when the data was originally generated.
+// readVetx returns nil if the data is unavailable.
+func readVetx(path, key string) interface{} {
+ if path == "unsafe" || vcfg.ImportPath == "" {
+ return nil
+ }
+ m := imported[path]
+ if m == nil {
+ file := vcfg.PackageVetx[path]
+ if file == "" {
+ return nil
+ }
+ data, err := ioutil.ReadFile(file)
+ if err != nil {
+ return nil
+ }
+ var out []vetxExport
+ err = gob.NewDecoder(bytes.NewReader(data)).Decode(&out)
+ if err != nil {
+ return nil
+ }
+ m = make(map[string]interface{})
+ for _, x := range out {
+ m[x.Name] = x.Data
+ }
+ imported[path] = m
+ }
+ return m[key]
+}
diff --git a/libgo/go/cmd/vet/method.go b/libgo/go/cmd/vet/method.go
index b13ce2fcb56..5783278d2c2 100644
--- a/libgo/go/cmd/vet/method.go
+++ b/libgo/go/cmd/vet/method.go
@@ -166,9 +166,7 @@ func (f *File) matchParams(expect []string, actual []ast.Expr, prefix string) bo
// Does this one type match?
func (f *File) matchParamType(expect string, actual ast.Expr) bool {
- if strings.HasPrefix(expect, "=") {
- expect = expect[1:]
- }
+ expect = strings.TrimPrefix(expect, "=")
// Strip package name if we're in that package.
if n := len(f.file.Name.Name); len(expect) > n && expect[:n] == f.file.Name.Name && expect[n] == '.' {
expect = expect[n+1:]
diff --git a/libgo/go/cmd/vet/print.go b/libgo/go/cmd/vet/print.go
index 456fbcc044d..a55da1d3c81 100644
--- a/libgo/go/cmd/vet/print.go
+++ b/libgo/go/cmd/vet/print.go
@@ -8,6 +8,7 @@ package main
import (
"bytes"
+ "encoding/gob"
"flag"
"fmt"
"go/ast"
@@ -15,6 +16,7 @@ import (
"go/token"
"go/types"
"regexp"
+ "sort"
"strconv"
"strings"
"unicode/utf8"
@@ -27,6 +29,9 @@ func init() {
"check printf-like invocations",
checkFmtPrintfCall,
funcDecl, callExpr)
+ registerPkgCheck("printf", findPrintfLike)
+ registerExport("printf", exportPrintfLike)
+ gob.Register([]printfExport(nil))
}
func initPrintFlags() {
@@ -44,73 +49,304 @@ func initPrintFlags() {
name = name[:colon]
}
- isPrint[strings.ToLower(name)] = true
+ if !strings.Contains(name, ".") {
+ name = strings.ToLower(name)
+ }
+ isPrint[name] = true
}
}
-// TODO(rsc): Incorporate user-defined printf wrappers again.
-// The general plan is to allow vet of one package P to output
-// additional information to supply to later vets of packages
-// importing P. Then vet of P can record a list of printf wrappers
-// and the later vet using P.Printf will find it in the list and check it.
-// That's not ready for Go 1.10.
-// When that does happen, uncomment the user-defined printf
-// wrapper tests in testdata/print.go.
+var localPrintfLike = make(map[string]int)
+
+type printfExport struct {
+ Name string
+ Kind int
+}
+
+// printfImported maps from package name to the printf vet data
+// exported by that package.
+var printfImported = make(map[string]map[string]int)
+
+type printfWrapper struct {
+ name string
+ fn *ast.FuncDecl
+ format *ast.Field
+ args *ast.Field
+ callers []printfCaller
+ failed bool // if true, not a printf wrapper
+}
+
+type printfCaller struct {
+ w *printfWrapper
+ call *ast.CallExpr
+}
+
+// maybePrintfWrapper decides whether decl (a declared function) may be a wrapper
+// around a fmt.Printf or fmt.Print function. If so it returns a printfWrapper
+// function describing the declaration. Later processing will analyze the
+// graph of potential printf wrappers to pick out the ones that are true wrappers.
+// A function may be a Printf or Print wrapper if its last argument is ...interface{}.
+// If the next-to-last argument is a string, then this may be a Printf wrapper.
+// Otherwise it may be a Print wrapper.
+func maybePrintfWrapper(decl ast.Decl) *printfWrapper {
+ // Look for functions with final argument type ...interface{}.
+ fn, ok := decl.(*ast.FuncDecl)
+ if !ok || fn.Body == nil {
+ return nil
+ }
+ name := fn.Name.Name
+ if fn.Recv != nil {
+ // For (*T).Name or T.name, use "T.name".
+ rcvr := fn.Recv.List[0].Type
+ if ptr, ok := rcvr.(*ast.StarExpr); ok {
+ rcvr = ptr.X
+ }
+ id, ok := rcvr.(*ast.Ident)
+ if !ok {
+ return nil
+ }
+ name = id.Name + "." + name
+ }
+ params := fn.Type.Params.List
+ if len(params) == 0 {
+ return nil
+ }
+ args := params[len(params)-1]
+ if len(args.Names) != 1 {
+ return nil
+ }
+ ddd, ok := args.Type.(*ast.Ellipsis)
+ if !ok {
+ return nil
+ }
+ iface, ok := ddd.Elt.(*ast.InterfaceType)
+ if !ok || len(iface.Methods.List) > 0 {
+ return nil
+ }
+ var format *ast.Field
+ if len(params) >= 2 {
+ p := params[len(params)-2]
+ if len(p.Names) == 1 {
+ if id, ok := p.Type.(*ast.Ident); ok && id.Name == "string" {
+ format = p
+ }
+ }
+ }
+
+ return &printfWrapper{
+ name: name,
+ fn: fn,
+ format: format,
+ args: args,
+ }
+}
+
+// findPrintfLike scans the entire package to find printf-like functions.
+func findPrintfLike(pkg *Package) {
+ if vcfg.ImportPath == "" { // no type or vetx information; don't bother
+ return
+ }
+
+ // Gather potential wrappesr and call graph between them.
+ byName := make(map[string]*printfWrapper)
+ var wrappers []*printfWrapper
+ for _, file := range pkg.files {
+ if file.file == nil {
+ continue
+ }
+ for _, decl := range file.file.Decls {
+ w := maybePrintfWrapper(decl)
+ if w == nil {
+ continue
+ }
+ byName[w.name] = w
+ wrappers = append(wrappers, w)
+ }
+ }
+
+ // Walk the graph to figure out which are really printf wrappers.
+ for _, w := range wrappers {
+ // Scan function for calls that could be to other printf-like functions.
+ ast.Inspect(w.fn.Body, func(n ast.Node) bool {
+ if w.failed {
+ return false
+ }
+
+ // TODO: Relax these checks; issue 26555.
+ if assign, ok := n.(*ast.AssignStmt); ok {
+ for _, lhs := range assign.Lhs {
+ if match(lhs, w.format) || match(lhs, w.args) {
+ // Modifies the format
+ // string or args in
+ // some way, so not a
+ // simple wrapper.
+ w.failed = true
+ return false
+ }
+ }
+ }
+ if un, ok := n.(*ast.UnaryExpr); ok && un.Op == token.AND {
+ if match(un.X, w.format) || match(un.X, w.args) {
+ // Taking the address of the
+ // format string or args,
+ // so not a simple wrapper.
+ w.failed = true
+ return false
+ }
+ }
+
+ call, ok := n.(*ast.CallExpr)
+ if !ok || len(call.Args) == 0 || !match(call.Args[len(call.Args)-1], w.args) {
+ return true
+ }
+
+ pkgpath, name, kind := printfNameAndKind(pkg, call.Fun)
+ if kind != 0 {
+ checkPrintfFwd(pkg, w, call, kind)
+ return true
+ }
+
+ // If the call is to another function in this package,
+ // maybe we will find out it is printf-like later.
+ // Remember this call for later checking.
+ if pkgpath == "" && byName[name] != nil {
+ callee := byName[name]
+ callee.callers = append(callee.callers, printfCaller{w, call})
+ }
+
+ return true
+ })
+ }
+}
+
+func match(arg ast.Expr, param *ast.Field) bool {
+ id, ok := arg.(*ast.Ident)
+ return ok && id.Obj != nil && id.Obj.Decl == param
+}
+
+const (
+ kindPrintf = 1
+ kindPrint = 2
+)
+
+// printfLike reports whether a call to fn should be considered a call to a printf-like function.
+// It returns 0 (indicating not a printf-like function), kindPrintf, or kindPrint.
+func printfLike(pkg *Package, fn ast.Expr, byName map[string]*printfWrapper) int {
+ if id, ok := fn.(*ast.Ident); ok && id.Obj != nil {
+ if w := byName[id.Name]; w != nil && id.Obj.Decl == w.fn {
+ // Found call to function in same package.
+ return localPrintfLike[id.Name]
+ }
+ }
+ if sel, ok := fn.(*ast.SelectorExpr); ok {
+ if id, ok := sel.X.(*ast.Ident); ok && id.Name == "fmt" && strings.Contains(sel.Sel.Name, "rint") {
+ if strings.HasSuffix(sel.Sel.Name, "f") {
+ return kindPrintf
+ }
+ return kindPrint
+ }
+ }
+ return 0
+}
+
+// checkPrintfFwd checks that a printf-forwarding wrapper is forwarding correctly.
+// It diagnoses writing fmt.Printf(format, args) instead of fmt.Printf(format, args...).
+func checkPrintfFwd(pkg *Package, w *printfWrapper, call *ast.CallExpr, kind int) {
+ matched := kind == kindPrint ||
+ kind == kindPrintf && len(call.Args) >= 2 && match(call.Args[len(call.Args)-2], w.format)
+ if !matched {
+ return
+ }
+
+ if !call.Ellipsis.IsValid() {
+ typ, ok := pkg.types[call.Fun].Type.(*types.Signature)
+ if !ok {
+ return
+ }
+ if len(call.Args) > typ.Params().Len() {
+ // If we're passing more arguments than what the
+ // print/printf function can take, adding an ellipsis
+ // would break the program. For example:
+ //
+ // func foo(arg1 string, arg2 ...interface{} {
+ // fmt.Printf("%s %v", arg1, arg2)
+ // }
+ return
+ }
+ if !vcfg.VetxOnly {
+ desc := "printf"
+ if kind == kindPrint {
+ desc = "print"
+ }
+ pkg.files[0].Badf(call.Pos(), "missing ... in args forwarded to %s-like function", desc)
+ }
+ return
+ }
+ name := w.name
+ if localPrintfLike[name] == 0 {
+ localPrintfLike[name] = kind
+ for _, caller := range w.callers {
+ checkPrintfFwd(pkg, caller.w, caller.call, kind)
+ }
+ }
+}
+
+func exportPrintfLike() interface{} {
+ out := make([]printfExport, 0, len(localPrintfLike))
+ for name, kind := range localPrintfLike {
+ out = append(out, printfExport{
+ Name: name,
+ Kind: kind,
+ })
+ }
+ sort.Slice(out, func(i, j int) bool {
+ return out[i].Name < out[j].Name
+ })
+ return out
+}
// isPrint records the print functions.
// If a key ends in 'f' then it is assumed to be a formatted print.
var isPrint = map[string]bool{
- "fmt.Errorf": true,
- "fmt.Fprint": true,
- "fmt.Fprintf": true,
- "fmt.Fprintln": true,
- "fmt.Print": true,
- "fmt.Printf": true,
- "fmt.Println": true,
- "fmt.Sprint": true,
- "fmt.Sprintf": true,
- "fmt.Sprintln": true,
- "log.Fatal": true,
- "log.Fatalf": true,
- "log.Fatalln": true,
- "log.Logger.Fatal": true,
- "log.Logger.Fatalf": true,
- "log.Logger.Fatalln": true,
- "log.Logger.Panic": true,
- "log.Logger.Panicf": true,
- "log.Logger.Panicln": true,
- "log.Logger.Printf": true,
- "log.Logger.Println": true,
- "log.Panic": true,
- "log.Panicf": true,
- "log.Panicln": true,
- "log.Print": true,
- "log.Printf": true,
- "log.Println": true,
- "testing.B.Error": true,
- "testing.B.Errorf": true,
- "testing.B.Fatal": true,
- "testing.B.Fatalf": true,
- "testing.B.Log": true,
- "testing.B.Logf": true,
- "testing.B.Skip": true,
- "testing.B.Skipf": true,
- "testing.T.Error": true,
- "testing.T.Errorf": true,
- "testing.T.Fatal": true,
- "testing.T.Fatalf": true,
- "testing.T.Log": true,
- "testing.T.Logf": true,
- "testing.T.Skip": true,
- "testing.T.Skipf": true,
- "testing.TB.Error": true,
- "testing.TB.Errorf": true,
- "testing.TB.Fatal": true,
- "testing.TB.Fatalf": true,
- "testing.TB.Log": true,
- "testing.TB.Logf": true,
- "testing.TB.Skip": true,
- "testing.TB.Skipf": true,
+ "fmt.Errorf": true,
+ "fmt.Fprint": true,
+ "fmt.Fprintf": true,
+ "fmt.Fprintln": true,
+ "fmt.Print": true,
+ "fmt.Printf": true,
+ "fmt.Println": true,
+ "fmt.Sprint": true,
+ "fmt.Sprintf": true,
+ "fmt.Sprintln": true,
+
+ // testing.B, testing.T not auto-detected
+ // because the methods are picked up by embedding.
+ "testing.B.Error": true,
+ "testing.B.Errorf": true,
+ "testing.B.Fatal": true,
+ "testing.B.Fatalf": true,
+ "testing.B.Log": true,
+ "testing.B.Logf": true,
+ "testing.B.Skip": true,
+ "testing.B.Skipf": true,
+ "testing.T.Error": true,
+ "testing.T.Errorf": true,
+ "testing.T.Fatal": true,
+ "testing.T.Fatalf": true,
+ "testing.T.Log": true,
+ "testing.T.Logf": true,
+ "testing.T.Skip": true,
+ "testing.T.Skipf": true,
+
+ // testing.TB is an interface, so can't detect wrapping.
+ "testing.TB.Error": true,
+ "testing.TB.Errorf": true,
+ "testing.TB.Fatal": true,
+ "testing.TB.Fatalf": true,
+ "testing.TB.Log": true,
+ "testing.TB.Logf": true,
+ "testing.TB.Skip": true,
+ "testing.TB.Skipf": true,
}
// formatString returns the format string argument and its index within
@@ -187,12 +423,14 @@ func checkFmtPrintfCall(f *File, node ast.Node) {
if d, ok := node.(*ast.FuncDecl); ok && isStringer(f, d) {
// Remember we saw this.
- if f.stringers == nil {
- f.stringers = make(map[*ast.Object]bool)
+ if f.stringerPtrs == nil {
+ f.stringerPtrs = make(map[*ast.Object]bool)
}
if l := d.Recv.List; len(l) == 1 {
if n := l[0].Names; len(n) == 1 {
- f.stringers[n[0].Obj] = true
+ typ := f.pkg.types[l[0].Type]
+ _, ptrRecv := typ.Type.(*types.Pointer)
+ f.stringerPtrs[n[0].Obj] = ptrRecv
}
}
return
@@ -204,66 +442,93 @@ func checkFmtPrintfCall(f *File, node ast.Node) {
}
// Construct name like pkg.Printf or pkg.Type.Printf for lookup.
- var name string
- switch x := call.Fun.(type) {
+ _, name, kind := printfNameAndKind(f.pkg, call.Fun)
+ if kind == kindPrintf {
+ f.checkPrintf(call, name)
+ }
+ if kind == kindPrint {
+ f.checkPrint(call, name)
+ }
+}
+
+func printfName(pkg *Package, called ast.Expr) (pkgpath, name string) {
+ switch x := called.(type) {
case *ast.Ident:
- if fn, ok := f.pkg.uses[x].(*types.Func); ok {
- var pkg string
- if fn.Pkg() == nil || fn.Pkg() == f.pkg.typesPkg {
- pkg = vcfg.ImportPath
+ if fn, ok := pkg.uses[x].(*types.Func); ok {
+ if fn.Pkg() == nil || fn.Pkg() == pkg.typesPkg {
+ pkgpath = ""
} else {
- pkg = fn.Pkg().Path()
+ pkgpath = fn.Pkg().Path()
}
- name = pkg + "." + x.Name
- break
+ return pkgpath, x.Name
}
case *ast.SelectorExpr:
// Check for "fmt.Printf".
if id, ok := x.X.(*ast.Ident); ok {
- if pkgName, ok := f.pkg.uses[id].(*types.PkgName); ok {
- name = pkgName.Imported().Path() + "." + x.Sel.Name
- break
+ if pkgName, ok := pkg.uses[id].(*types.PkgName); ok {
+ return pkgName.Imported().Path(), x.Sel.Name
}
}
// Check for t.Logf where t is a *testing.T.
- if sel := f.pkg.selectors[x]; sel != nil {
+ if sel := pkg.selectors[x]; sel != nil {
recv := sel.Recv()
if p, ok := recv.(*types.Pointer); ok {
recv = p.Elem()
}
if named, ok := recv.(*types.Named); ok {
obj := named.Obj()
- var pkg string
- if obj.Pkg() == nil || obj.Pkg() == f.pkg.typesPkg {
- pkg = vcfg.ImportPath
+ if obj.Pkg() == nil || obj.Pkg() == pkg.typesPkg {
+ pkgpath = ""
} else {
- pkg = obj.Pkg().Path()
+ pkgpath = obj.Pkg().Path()
}
- name = pkg + "." + obj.Name() + "." + x.Sel.Name
- break
+ return pkgpath, obj.Name() + "." + x.Sel.Name
}
}
}
+ return "", ""
+}
+
+func printfNameAndKind(pkg *Package, called ast.Expr) (pkgpath, name string, kind int) {
+ pkgpath, name = printfName(pkg, called)
if name == "" {
- return
+ return pkgpath, name, 0
}
- shortName := name[strings.LastIndex(name, ".")+1:]
-
- _, ok = isPrint[name]
- if !ok {
- // Next look up just "printf", for use with -printfuncs.
- _, ok = isPrint[strings.ToLower(shortName)]
+ if pkgpath == "" {
+ kind = localPrintfLike[name]
+ } else if m, ok := printfImported[pkgpath]; ok {
+ kind = m[name]
+ } else {
+ var m map[string]int
+ if out, ok := readVetx(pkgpath, "printf").([]printfExport); ok {
+ m = make(map[string]int)
+ for _, x := range out {
+ m[x.Name] = x.Kind
+ }
+ }
+ printfImported[pkgpath] = m
+ kind = m[name]
}
- if ok {
- if strings.HasSuffix(name, "f") {
- f.checkPrintf(call, shortName)
- } else {
- f.checkPrint(call, shortName)
+
+ if kind == 0 {
+ _, ok := isPrint[pkgpath+"."+name]
+ if !ok {
+ // Next look up just "printf", for use with -printfuncs.
+ short := name[strings.LastIndex(name, ".")+1:]
+ _, ok = isPrint[strings.ToLower(short)]
+ }
+ if ok {
+ if strings.HasSuffix(name, "f") {
+ kind = kindPrintf
+ } else {
+ kind = kindPrint
+ }
}
}
+ return pkgpath, name, kind
}
// isStringer returns true if the provided declaration is a "String() string"
@@ -293,6 +558,7 @@ type formatState struct {
file *File
call *ast.CallExpr
argNum int // Which argument we're expecting to format now.
+ hasIndex bool // Whether the argument is indexed.
indexPending bool // Whether we have an indexed argument that has not resolved.
nbytes int // number of bytes of the format string consumed.
}
@@ -317,6 +583,7 @@ func (f *File) checkPrintf(call *ast.CallExpr, name string) {
// Hard part: check formats against args.
argNum := firstArg
maxArgNum := firstArg
+ anyIndex := false
for i, w := 0, 0; i < len(format); i += w {
w = 1
if format[i] != '%' {
@@ -330,6 +597,9 @@ func (f *File) checkPrintf(call *ast.CallExpr, name string) {
if !f.okPrintfArg(call, state) { // One error per format is enough.
return
}
+ if state.hasIndex {
+ anyIndex = true
+ }
if len(state.argNums) > 0 {
// Continue with the next sequential argument.
argNum = state.argNums[len(state.argNums)-1] + 1
@@ -344,6 +614,10 @@ func (f *File) checkPrintf(call *ast.CallExpr, name string) {
if call.Ellipsis.IsValid() && maxArgNum >= len(call.Args)-1 {
return
}
+ // If any formats are indexed, extra arguments are ignored.
+ if anyIndex {
+ return
+ }
// There should be no leftover arguments.
if maxArgNum != len(call.Args) {
expect := maxArgNum - firstArg
@@ -402,6 +676,7 @@ func (s *formatState) parseIndex() bool {
arg := int(arg32)
arg += s.firstArg - 1 // We want to zero-index the actual arguments.
s.argNum = arg
+ s.hasIndex = true
s.indexPending = true
return true
}
@@ -522,7 +797,7 @@ var printVerbs = []printVerb{
{'%', noFlag, 0},
{'b', numFlag, argInt | argFloat | argComplex},
{'c', "-", argRune | argInt},
- {'d', numFlag, argInt},
+ {'d', numFlag, argInt | argPointer},
{'e', sharpNumFlag, argFloat | argComplex},
{'E', sharpNumFlag, argFloat | argComplex},
{'f', sharpNumFlag, argFloat | argComplex},
@@ -537,8 +812,8 @@ var printVerbs = []printVerb{
{'T', "-", anyType},
{'U', "-#", argRune | argInt},
{'v', allFlags, anyType},
- {'x', sharpNumFlag, argRune | argInt | argString},
- {'X', sharpNumFlag, argRune | argInt | argString},
+ {'x', sharpNumFlag, argRune | argInt | argString | argPointer},
+ {'X', sharpNumFlag, argRune | argInt | argString | argPointer},
}
// okPrintfArg compares the formatState to the arguments actually present,
@@ -569,6 +844,11 @@ func (f *File) okPrintfArg(call *ast.CallExpr, state *formatState) (ok bool) {
return false
}
for _, flag := range state.flags {
+ // TODO: Disable complaint about '0' for Go 1.10. To be fixed properly in 1.11.
+ // See issues 23598 and 23605.
+ if flag == '0' {
+ continue
+ }
if !strings.ContainsRune(v.flags, rune(flag)) {
f.Badf(call.Pos(), "%s format %s has unrecognized flag %c", state.name, state.format, flag)
return false
@@ -623,9 +903,10 @@ func (f *File) okPrintfArg(call *ast.CallExpr, state *formatState) (ok bool) {
// recursiveStringer reports whether the provided argument is r or &r for the
// fmt.Stringer receiver identifier r.
func (f *File) recursiveStringer(e ast.Expr) bool {
- if len(f.stringers) == 0 {
+ if len(f.stringerPtrs) == 0 {
return false
}
+ ptr := false
var obj *ast.Object
switch e := e.(type) {
case *ast.Ident:
@@ -633,13 +914,13 @@ func (f *File) recursiveStringer(e ast.Expr) bool {
case *ast.UnaryExpr:
if id, ok := e.X.(*ast.Ident); ok && e.Op == token.AND {
obj = id.Obj
+ ptr = true
}
}
// It's unlikely to be a recursive stringer if it has a Format method.
if typ := f.pkg.types[e].Type; typ != nil {
- // Not a perfect match; see issue 6259.
- if f.hasMethod(typ, "Format") {
+ if f.isFormatter(typ) {
return false
}
}
@@ -647,7 +928,16 @@ func (f *File) recursiveStringer(e ast.Expr) bool {
// We compare the underlying Object, which checks that the identifier
// is the one we declared as the receiver for the String method in
// which this printf appears.
- return f.stringers[obj]
+ ptrRecv, exist := f.stringerPtrs[obj]
+ if !exist {
+ return false
+ }
+ // We also need to check that using &t when we declared String
+ // on (t *T) is ok; in such a case, the address is printed.
+ if ptr && ptrRecv {
+ return false
+ }
+ return true
}
// isFunctionValue reports whether the expression is a function as opposed to a function call.
@@ -681,7 +971,7 @@ func (f *File) argCanBeChecked(call *ast.CallExpr, formatArg int, state *formatS
// There are bad indexes in the format or there are fewer arguments than the format needs.
// This is the argument number relative to the format: Printf("%s", "hi") will give 1 for the "hi".
arg := argNum - state.firstArg + 1 // People think of arguments as 1-indexed.
- f.Badf(call.Pos(), "%s format %s reads arg #%d, but call has only %v", state.name, state.format, arg, count(len(call.Args)-state.firstArg, "arg"))
+ f.Badf(call.Pos(), "%s format %s reads arg #%d, but call has %v", state.name, state.format, arg, count(len(call.Args)-state.firstArg, "arg"))
return false
}
@@ -694,7 +984,7 @@ const (
flagsRE = `[+\-#]*`
indexOptRE = `(\[[0-9]+\])?`
numOptRE = `([0-9]+|` + indexOptRE + `\*)?`
- verbRE = `[bcdefgopqstvxEFGUX]`
+ verbRE = `[bcdefgopqstvxEFGTUX]`
)
// checkPrint checks a call to an unformatted print routine such as Println.
diff --git a/libgo/go/cmd/vet/testdata/asm/asm.go b/libgo/go/cmd/vet/testdata/asm/asm.go
index e6d6d031061..2237ddc3b05 100644
--- a/libgo/go/cmd/vet/testdata/asm/asm.go
+++ b/libgo/go/cmd/vet/testdata/asm/asm.go
@@ -43,3 +43,6 @@ func wrapper(x int)
func f15271() (x uint32)
func f17584(x float32, y complex64)
+
+func noframe1(x int32)
+func noframe2(x int32)
diff --git a/libgo/go/cmd/vet/testdata/asm/asm3.s b/libgo/go/cmd/vet/testdata/asm/asm3.s
index 3d69356a0f9..83e53862d7d 100644
--- a/libgo/go/cmd/vet/testdata/asm/asm3.s
+++ b/libgo/go/cmd/vet/testdata/asm/asm3.s
@@ -176,3 +176,17 @@ TEXT ·leaf(SB),0,$-4-12
MOVW y+4(FP), AX
MOVW AX, ret+8(FP)
RET
+
+TEXT ·noframe1(SB),0,$0-4
+ MOVW 0(R13), AX // Okay; our saved LR
+ MOVW 4(R13), AX // Okay; caller's saved LR
+ MOVW x+8(R13), AX // Okay; x argument
+ MOVW 12(R13), AX // ERROR "use of 12\(R13\) points beyond argument frame"
+ RET
+
+TEXT ·noframe2(SB),NOFRAME,$0-4
+ MOVW 0(R13), AX // Okay; caller's saved LR
+ MOVW x+4(R13), AX // Okay; x argument
+ MOVW 8(R13), AX // ERROR "use of 8\(R13\) points beyond argument frame"
+ MOVW 12(R13), AX // ERROR "use of 12\(R13\) points beyond argument frame"
+ RET
diff --git a/libgo/go/cmd/vet/testdata/atomic.go b/libgo/go/cmd/vet/testdata/atomic.go
index d5a8e611844..69730b4e6f0 100644
--- a/libgo/go/cmd/vet/testdata/atomic.go
+++ b/libgo/go/cmd/vet/testdata/atomic.go
@@ -43,10 +43,20 @@ func AtomicTests() {
{
// A variable declaration creates a new variable in the current scope.
- x := atomic.AddUint64(&x, 1) // ERROR "declaration of .x. shadows declaration at testdata/atomic.go:16"
+ x := atomic.AddUint64(&x, 1) // ERROR "declaration of .x. shadows declaration at atomic.go:16"
// Re-declaration assigns a new value.
x, w := atomic.AddUint64(&x, 1), 10 // ERROR "direct assignment to atomic value"
_ = w
}
}
+
+type T struct{}
+
+func (T) AddUint64(addr *uint64, delta uint64) uint64 { return 0 }
+
+func NonAtomic() {
+ x := uint64(1)
+ var atomic T
+ x = atomic.AddUint64(&x, 1) // ok; not the imported pkg
+}
diff --git a/libgo/go/cmd/vet/testdata/bool.go b/libgo/go/cmd/vet/testdata/bool.go
index af6cc011dd6..80c44d25ca3 100644
--- a/libgo/go/cmd/vet/testdata/bool.go
+++ b/libgo/go/cmd/vet/testdata/bool.go
@@ -8,15 +8,33 @@ package testdata
import "io"
+type T int
+
+func (t T) Foo() int { return int(t) }
+
+type FT func() int
+
+var S []int
+
func RatherStupidConditions() {
var f, g func() int
if f() == 0 || f() == 0 { // OK f might have side effects
}
+ var t T
+ _ = t.Foo() == 2 || t.Foo() == 2 // OK Foo might have side effects
if v, w := f(), g(); v == w || v == w { // ERROR "redundant or: v == w || v == w"
}
_ = f == nil || f == nil // ERROR "redundant or: f == nil || f == nil"
- _ = i == byte(1) || i == byte(1) // TODO conversions are treated as if they may have side effects
+ _ = i == byte(1) || i == byte(1) // ERROR "redundant or: i == byte(1) || i == byte(1)"
+ _ = i == T(2) || i == T(2) // ERROR "redundant or: i == T(2) || i == T(2)"
+ _ = FT(f) == nil || FT(f) == nil // ERROR "redundant or: FT(f) == nil || FT(f) == nil"
+
+ _ = (func() int)(f) == nil || (func() int)(f) == nil // ERROR "redundant or: (func() int)(f) == nil || (func() int)(f) == nil"
+ _ = append(S, 3) == nil || append(S, 3) == nil // OK append has side effects
+
+ var namedFuncVar FT
+ _ = namedFuncVar() == namedFuncVar() // OK still func calls
var c chan int
_ = 0 == <-c || 0 == <-c // OK subsequent receives may yield different values
diff --git a/libgo/go/cmd/vet/testdata/buildtag/buildtag.go b/libgo/go/cmd/vet/testdata/buildtag/buildtag.go
index f12f895dfb1..c2fd6aaaf2f 100644
--- a/libgo/go/cmd/vet/testdata/buildtag/buildtag.go
+++ b/libgo/go/cmd/vet/testdata/buildtag/buildtag.go
@@ -9,6 +9,10 @@
package testdata
-// +build toolate // ERROR "build comment must appear before package clause and be followed by a blank line"
+// +build toolate // ERROR "build comment must appear before package clause and be followed by a blank line$"
var _ = 3
+
+var _ = `
+// +build notacomment
+`
diff --git a/libgo/go/cmd/vet/testdata/composite.go b/libgo/go/cmd/vet/testdata/composite.go
index 2e6ce262cc1..3fe3eac78cb 100644
--- a/libgo/go/cmd/vet/testdata/composite.go
+++ b/libgo/go/cmd/vet/testdata/composite.go
@@ -62,6 +62,11 @@ var Okay6 = []MyStruct{
{"aa", "bb", "cc"},
}
+var Okay7 = []*MyStruct{
+ {"foo", "bar", "baz"},
+ {"aa", "bb", "cc"},
+}
+
// Testing is awkward because we need to reference things from a separate package
// to trigger the warnings.
@@ -101,3 +106,15 @@ var whitelistedPoint = image.Point{1, 2}
// Do not check type from unknown package.
// See issue 15408.
var unknownPkgVar = unknownpkg.Foobar{"foo", "bar"}
+
+// A named pointer slice of CaseRange to test issue 23539. In
+// particular, we're interested in how some slice elements omit their
+// type.
+var goodNamedPointerSliceLiteral = []*unicode.CaseRange{
+ {Lo: 1, Hi: 2},
+ &unicode.CaseRange{Lo: 1, Hi: 2},
+}
+var badNamedPointerSliceLiteral = []*unicode.CaseRange{
+ {1, 2}, // ERROR "unkeyed fields"
+ &unicode.CaseRange{1, 2}, // ERROR "unkeyed fields"
+}
diff --git a/libgo/go/cmd/vet/testdata/deadcode.go b/libgo/go/cmd/vet/testdata/deadcode.go
index 5370bc32f65..d1a7adee38d 100644
--- a/libgo/go/cmd/vet/testdata/deadcode.go
+++ b/libgo/go/cmd/vet/testdata/deadcode.go
@@ -2123,3 +2123,12 @@ var _ = func() {
// goto without label used to panic
goto
}
+
+func _() int {
+ // Empty switch tag with non-bool case value used to panic.
+ switch {
+ case 1:
+ println()
+ }
+ println()
+}
diff --git a/libgo/go/cmd/vet/testdata/print.go b/libgo/go/cmd/vet/testdata/print.go
index 55ab84fae76..ecafed5fa2f 100644
--- a/libgo/go/cmd/vet/testdata/print.go
+++ b/libgo/go/cmd/vet/testdata/print.go
@@ -14,6 +14,7 @@ package testdata
import (
"fmt"
. "fmt"
+ logpkg "log" // renamed to make it harder to see
"math"
"os"
"testing"
@@ -79,7 +80,7 @@ func PrintfTests() {
fmt.Printf("%G %G %G %G", 3e9, x, fslice, c)
fmt.Printf("%b %b %b %b", 3e9, x, fslice, c)
fmt.Printf("%o %o", 3, i)
- fmt.Printf("%p %p", p, nil)
+ fmt.Printf("%p", p)
fmt.Printf("%q %q %q %q", 3, i, 'x', r)
fmt.Printf("%s %s %s", "hi", s, []byte{65})
fmt.Printf("%t %t", true, b)
@@ -122,6 +123,7 @@ func PrintfTests() {
fmt.Printf("%g", imap) // ERROR "Printf format %g has arg imap of wrong type map\[int\]int"
fmt.Printf("%G", i) // ERROR "Printf format %G has arg i of wrong type int"
fmt.Printf("%o", x) // ERROR "Printf format %o has arg x of wrong type float64"
+ fmt.Printf("%p", nil) // ERROR "Printf format %p has arg nil of wrong type untyped nil"
fmt.Printf("%p", 23) // ERROR "Printf format %p has arg 23 of wrong type int"
fmt.Printf("%q", x) // ERROR "Printf format %q has arg x of wrong type float64"
fmt.Printf("%s", b) // ERROR "Printf format %s has arg b of wrong type bool"
@@ -130,8 +132,8 @@ func PrintfTests() {
fmt.Printf("%U", x) // ERROR "Printf format %U has arg x of wrong type float64"
fmt.Printf("%x", nil) // ERROR "Printf format %x has arg nil of wrong type untyped nil"
fmt.Printf("%X", 2.3) // ERROR "Printf format %X has arg 2.3 of wrong type float64"
- fmt.Printf("%s", stringerv) // ERROR "Printf format %s has arg stringerv of wrong type testdata.stringer"
- fmt.Printf("%t", stringerv) // ERROR "Printf format %t has arg stringerv of wrong type testdata.stringer"
+ fmt.Printf("%s", stringerv) // ERROR "Printf format %s has arg stringerv of wrong type testdata.ptrStringer"
+ fmt.Printf("%t", stringerv) // ERROR "Printf format %t has arg stringerv of wrong type testdata.ptrStringer"
fmt.Printf("%s", embeddedStringerv) // ERROR "Printf format %s has arg embeddedStringerv of wrong type testdata.embeddedStringer"
fmt.Printf("%t", embeddedStringerv) // ERROR "Printf format %t has arg embeddedStringerv of wrong type testdata.embeddedStringer"
fmt.Printf("%q", notstringerv) // ERROR "Printf format %q has arg notstringerv of wrong type testdata.notstringer"
@@ -147,6 +149,7 @@ func PrintfTests() {
fmt.Println() // not an error
fmt.Println("%s", "hi") // ERROR "Println call has possible formatting directive %s"
fmt.Println("%v", "hi") // ERROR "Println call has possible formatting directive %v"
+ fmt.Println("%T", "hi") // ERROR "Println call has possible formatting directive %T"
fmt.Println("0.0%") // correct (trailing % couldn't be a formatting directive)
fmt.Printf("%s", "hi", 3) // ERROR "Printf call needs 1 arg but has 2 args"
_ = fmt.Sprintf("%"+("s"), "hi", 3) // ERROR "Sprintf call needs 1 arg but has 2 args"
@@ -166,13 +169,25 @@ func PrintfTests() {
Printf("hi") // ok
const format = "%s %s\n"
Printf(format, "hi", "there")
- Printf(format, "hi") // ERROR "Printf format %s reads arg #2, but call has only 1 arg$"
- Printf("%s %d %.3v %q", "str", 4) // ERROR "Printf format %.3v reads arg #3, but call has only 2 args"
- f := new(stringer)
+ Printf(format, "hi") // ERROR "Printf format %s reads arg #2, but call has 1 arg$"
+ Printf("%s %d %.3v %q", "str", 4) // ERROR "Printf format %.3v reads arg #3, but call has 2 args"
+ f := new(ptrStringer)
f.Warn(0, "%s", "hello", 3) // ERROR "Warn call has possible formatting directive %s"
f.Warnf(0, "%s", "hello", 3) // ERROR "Warnf call needs 1 arg but has 2 args"
f.Warnf(0, "%r", "hello") // ERROR "Warnf format %r has unknown verb r"
f.Warnf(0, "%#s", "hello") // ERROR "Warnf format %#s has unrecognized flag #"
+ f.Warn2(0, "%s", "hello", 3) // ERROR "Warn2 call has possible formatting directive %s"
+ f.Warnf2(0, "%s", "hello", 3) // ERROR "Warnf2 call needs 1 arg but has 2 args"
+ f.Warnf2(0, "%r", "hello") // ERROR "Warnf2 format %r has unknown verb r"
+ f.Warnf2(0, "%#s", "hello") // ERROR "Warnf2 format %#s has unrecognized flag #"
+ f.Wrap(0, "%s", "hello", 3) // ERROR "Wrap call has possible formatting directive %s"
+ f.Wrapf(0, "%s", "hello", 3) // ERROR "Wrapf call needs 1 arg but has 2 args"
+ f.Wrapf(0, "%r", "hello") // ERROR "Wrapf format %r has unknown verb r"
+ f.Wrapf(0, "%#s", "hello") // ERROR "Wrapf format %#s has unrecognized flag #"
+ f.Wrap2(0, "%s", "hello", 3) // ERROR "Wrap2 call has possible formatting directive %s"
+ f.Wrapf2(0, "%s", "hello", 3) // ERROR "Wrapf2 call needs 1 arg but has 2 args"
+ f.Wrapf2(0, "%r", "hello") // ERROR "Wrapf2 format %r has unknown verb r"
+ f.Wrapf2(0, "%#s", "hello") // ERROR "Wrapf2 format %#s has unrecognized flag #"
fmt.Printf("%#s", FormatterVal(true)) // correct (the type is responsible for formatting)
Printf("d%", 2) // ERROR "Printf format % is missing verb at end of string"
Printf("%d", percentDV)
@@ -180,6 +195,7 @@ func PrintfTests() {
Printf("%d", notPercentDV) // ERROR "Printf format %d has arg notPercentDV of wrong type testdata.notPercentDStruct"
Printf("%d", &notPercentDV) // ERROR "Printf format %d has arg &notPercentDV of wrong type \*testdata.notPercentDStruct"
Printf("%p", &notPercentDV) // Works regardless: we print it as a pointer.
+ Printf("%q", &percentDV) // ERROR "Printf format %q has arg &percentDV of wrong type \*testdata.percentDStruct"
Printf("%s", percentSV)
Printf("%s", &percentSV)
// Good argument reorderings.
@@ -240,7 +256,7 @@ func PrintfTests() {
// Multiple string arguments before variadic args
// errorf("WARNING", "foobar") // OK
// errorf("INFO", "s=%s, n=%d", "foo", 1) // OK
- // errorf("ERROR", "%d") // no error "errorf format %d reads arg #1, but call has only 0 args"
+ // errorf("ERROR", "%d") // no error "errorf format %d reads arg #1, but call has 0 args"
// Printf from external package
// externalprintf.Printf("%d", 42) // OK
@@ -248,7 +264,7 @@ func PrintfTests() {
// level := 123
// externalprintf.Logf(level, "%d", 42) // OK
// externalprintf.Errorf(level, level, "foo %q bar", "foobar") // OK
- // externalprintf.Logf(level, "%d") // no error "Logf format %d reads arg #1, but call has only 0 args"
+ // externalprintf.Logf(level, "%d") // no error "Logf format %d reads arg #1, but call has 0 args"
// var formatStr = "%s %s"
// externalprintf.Sprintf(formatStr, "a", "b") // OK
// externalprintf.Logf(level, formatStr, "a", "b") // OK
@@ -269,9 +285,10 @@ func PrintfTests() {
Printf("%d %[0]d %d %[2]d x", 1, 2, 3, 4) // ERROR "Printf format has invalid argument index \[0\]"
Printf("%d %[3]d %d %[-2]d x", 1, 2, 3, 4) // ERROR "Printf format has invalid argument index \[-2\]"
Printf("%d %[3]d %d %[2234234234234]d x", 1, 2, 3, 4) // ERROR "Printf format has invalid argument index \[2234234234234\]"
- Printf("%d %[3]d %-10d %[2]d x", 1, 2, 3) // ERROR "Printf format %-10d reads arg #4, but call has only 3 args"
- Printf("%d %[3]d %d %[2]d x", 1, 2, 3, 4, 5) // ERROR "Printf call needs 4 args but has 5 args"
+ Printf("%d %[3]d %-10d %[2]d x", 1, 2, 3) // ERROR "Printf format %-10d reads arg #4, but call has 3 args"
Printf("%[1][3]d x", 1, 2) // ERROR "Printf format %\[1\]\[ has unknown verb \["
+ Printf("%[1]d x", 1, 2) // OK
+ Printf("%d %[3]d %d %[2]d x", 1, 2, 3, 4, 5) // OK
// wrote Println but meant Fprintln
Printf("%p\n", os.Stdout) // OK
@@ -279,6 +296,31 @@ func PrintfTests() {
Printf(someString(), "hello") // OK
+ // Printf wrappers in package log should be detected automatically
+ logpkg.Fatal("%d", 1) // ERROR "Fatal call has possible formatting directive %d"
+ logpkg.Fatalf("%d", "x") // ERROR "Fatalf format %d has arg \x22x\x22 of wrong type string"
+ logpkg.Fatalln("%d", 1) // ERROR "Fatalln call has possible formatting directive %d"
+ logpkg.Panic("%d", 1) // ERROR "Panic call has possible formatting directive %d"
+ logpkg.Panicf("%d", "x") // ERROR "Panicf format %d has arg \x22x\x22 of wrong type string"
+ logpkg.Panicln("%d", 1) // ERROR "Panicln call has possible formatting directive %d"
+ logpkg.Print("%d", 1) // ERROR "Print call has possible formatting directive %d"
+ logpkg.Printf("%d", "x") // ERROR "Printf format %d has arg \x22x\x22 of wrong type string"
+ logpkg.Println("%d", 1) // ERROR "Println call has possible formatting directive %d"
+
+ // Methods too.
+ var l *logpkg.Logger
+ l.Fatal("%d", 1) // ERROR "Fatal call has possible formatting directive %d"
+ l.Fatalf("%d", "x") // ERROR "Fatalf format %d has arg \x22x\x22 of wrong type string"
+ l.Fatalln("%d", 1) // ERROR "Fatalln call has possible formatting directive %d"
+ l.Panic("%d", 1) // ERROR "Panic call has possible formatting directive %d"
+ l.Panicf("%d", "x") // ERROR "Panicf format %d has arg \x22x\x22 of wrong type string"
+ l.Panicln("%d", 1) // ERROR "Panicln call has possible formatting directive %d"
+ l.Print("%d", 1) // ERROR "Print call has possible formatting directive %d"
+ l.Printf("%d", "x") // ERROR "Printf format %d has arg \x22x\x22 of wrong type string"
+ l.Println("%d", 1) // ERROR "Println call has possible formatting directive %d"
+
+ // Issue 26486
+ dbg("", 1) // no error "call has arguments but no formatting directive"
}
func someString() string { return "X" }
@@ -352,25 +394,65 @@ func multi() []interface{} {
panic("don't call - testing only")
}
-type stringer float64
+type stringer int
-var stringerv stringer
+func (stringer) String() string { return "string" }
-func (*stringer) String() string {
+type ptrStringer float64
+
+var stringerv ptrStringer
+
+func (*ptrStringer) String() string {
return "string"
}
-func (*stringer) Warn(int, ...interface{}) string {
+func (p *ptrStringer) Warn2(x int, args ...interface{}) string {
+ return p.Warn(x, args...)
+}
+
+func (p *ptrStringer) Warnf2(x int, format string, args ...interface{}) string {
+ return p.Warnf(x, format, args...)
+}
+
+func (*ptrStringer) Warn(x int, args ...interface{}) string {
return "warn"
}
-func (*stringer) Warnf(int, string, ...interface{}) string {
+func (*ptrStringer) Warnf(x int, format string, args ...interface{}) string {
return "warnf"
}
+func (p *ptrStringer) Wrap2(x int, args ...interface{}) string {
+ return p.Wrap(x, args...)
+}
+
+func (p *ptrStringer) Wrapf2(x int, format string, args ...interface{}) string {
+ return p.Wrapf(x, format, args...)
+}
+
+func (*ptrStringer) Wrap(x int, args ...interface{}) string {
+ return fmt.Sprint(args...)
+}
+
+func (*ptrStringer) Wrapf(x int, format string, args ...interface{}) string {
+ return fmt.Sprintf(format, args...)
+}
+
+func (*ptrStringer) BadWrap(x int, args ...interface{}) string {
+ return fmt.Sprint(args) // ERROR "missing ... in args forwarded to print-like function"
+}
+
+func (*ptrStringer) BadWrapf(x int, format string, args ...interface{}) string {
+ return fmt.Sprintf(format, args) // ERROR "missing ... in args forwarded to printf-like function"
+}
+
+func (*ptrStringer) WrapfFalsePositive(x int, arg1 string, arg2 ...interface{}) string {
+ return fmt.Sprintf("%s %v", arg1, arg2)
+}
+
type embeddedStringer struct {
foo string
- stringer
+ ptrStringer
bar int
}
@@ -440,6 +522,7 @@ type recursivePtrStringer int
func (p *recursivePtrStringer) String() string {
_ = fmt.Sprintf("%v", *p)
+ _ = fmt.Sprint(&p) // ok; prints address
return fmt.Sprintln(p) // ERROR "Sprintln arg p causes recursive call to String method"
}
@@ -478,13 +561,17 @@ type RecursiveStruct2 struct {
var recursiveStruct1V = &RecursiveStruct1{}
-// Issue 17798: unexported stringer cannot be formatted.
+type unexportedInterface struct {
+ f interface{}
+}
+
+// Issue 17798: unexported ptrStringer cannot be formatted.
type unexportedStringer struct {
- t stringer
+ t ptrStringer
}
type unexportedStringerOtherFields struct {
s string
- t stringer
+ t ptrStringer
S string
}
@@ -502,7 +589,23 @@ type errorer struct{}
func (e errorer) Error() string { return "errorer" }
+type unexportedCustomError struct {
+ e errorer
+}
+
+type errorInterface interface {
+ error
+ ExtraMethod()
+}
+
+type unexportedErrorInterface struct {
+ e errorInterface
+}
+
func UnexportedStringerOrError() {
+ fmt.Printf("%s", unexportedInterface{"foo"}) // ok; prints {foo}
+ fmt.Printf("%s", unexportedInterface{3}) // ok; we can't see the problem
+
us := unexportedStringer{}
fmt.Printf("%s", us) // ERROR "Printf format %s has arg us of wrong type testdata.unexportedStringer"
fmt.Printf("%s", &us) // ERROR "Printf format %s has arg &us of wrong type [*]testdata.unexportedStringer"
@@ -528,8 +631,37 @@ func UnexportedStringerOrError() {
fmt.Printf("%s", uef) // ERROR "Printf format %s has arg uef of wrong type testdata.unexportedErrorOtherFields"
fmt.Printf("%s", &uef) // ERROR "Printf format %s has arg &uef of wrong type [*]testdata.unexportedErrorOtherFields"
+ uce := unexportedCustomError{
+ e: errorer{},
+ }
+ fmt.Printf("%s", uce) // ERROR "Printf format %s has arg uce of wrong type testdata.unexportedCustomError"
+
+ uei := unexportedErrorInterface{}
+ fmt.Printf("%s", uei) // ERROR "Printf format %s has arg uei of wrong type testdata.unexportedErrorInterface"
fmt.Println("foo\n", "bar") // not an error
- fmt.Println("foo\n") // ERROR "Println arg list ends with redundant newline"
- fmt.Println("foo\\n") // not an error
- fmt.Println(`foo\n`) // not an error
+
+ fmt.Println("foo\n") // ERROR "Println arg list ends with redundant newline"
+ fmt.Println("foo\\n") // not an error
+ fmt.Println(`foo\n`) // not an error
+
+ intSlice := []int{3, 4}
+ fmt.Printf("%s", intSlice) // ERROR "Printf format %s has arg intSlice of wrong type \[\]int"
+ nonStringerArray := [1]unexportedStringer{{}}
+ fmt.Printf("%s", nonStringerArray) // ERROR "Printf format %s has arg nonStringerArray of wrong type \[1\]testdata.unexportedStringer"
+ fmt.Printf("%s", []stringer{3, 4}) // not an error
+ fmt.Printf("%s", [2]stringer{3, 4}) // not an error
+}
+
+// TODO: Disable complaint about '0' for Go 1.10. To be fixed properly in 1.11.
+// See issues 23598 and 23605.
+func DisableErrorForFlag0() {
+ fmt.Printf("%0t", true)
+}
+
+// Issue 26486.
+func dbg(format string, args ...interface{}) {
+ if format == "" {
+ format = "%v"
+ }
+ fmt.Printf(format, args...)
}
diff --git a/libgo/go/cmd/vet/testdata/shadow.go b/libgo/go/cmd/vet/testdata/shadow.go
index 3b61137b87c..c55cb2772a9 100644
--- a/libgo/go/cmd/vet/testdata/shadow.go
+++ b/libgo/go/cmd/vet/testdata/shadow.go
@@ -17,7 +17,7 @@ func ShadowRead(f *os.File, buf []byte) (err error) {
_ = err
}
if f != nil {
- _, err := f.Read(buf) // ERROR "declaration of .err. shadows declaration at testdata/shadow.go:13"
+ _, err := f.Read(buf) // ERROR "declaration of .err. shadows declaration at shadow.go:13"
if err != nil {
return err
}
@@ -25,8 +25,8 @@ func ShadowRead(f *os.File, buf []byte) (err error) {
_ = i
}
if f != nil {
- x := one() // ERROR "declaration of .x. shadows declaration at testdata/shadow.go:14"
- var _, err = f.Read(buf) // ERROR "declaration of .err. shadows declaration at testdata/shadow.go:13"
+ x := one() // ERROR "declaration of .x. shadows declaration at shadow.go:14"
+ var _, err = f.Read(buf) // ERROR "declaration of .err. shadows declaration at shadow.go:13"
if x == 1 && err != nil {
return err
}
@@ -46,7 +46,7 @@ func ShadowRead(f *os.File, buf []byte) (err error) {
if shadowTemp := shadowTemp; true { // OK: obviously intentional idiomatic redeclaration
var f *os.File // OK because f is not mentioned later in the function.
// The declaration of x is a shadow because x is mentioned below.
- var x int // ERROR "declaration of .x. shadows declaration at testdata/shadow.go:14"
+ var x int // ERROR "declaration of .x. shadows declaration at shadow.go:14"
_, _, _ = x, f, shadowTemp
}
// Use a couple of variables to trigger shadowing errors.
diff --git a/libgo/go/cmd/vet/testdata/structtag.go b/libgo/go/cmd/vet/testdata/structtag.go
index c87e42f5d00..ce21e803c80 100644
--- a/libgo/go/cmd/vet/testdata/structtag.go
+++ b/libgo/go/cmd/vet/testdata/structtag.go
@@ -44,40 +44,40 @@ type AnonymousXML struct{}
type DuplicateJSONFields struct {
JSON int `json:"a"`
- DuplicateJSON int `json:"a"` // ERROR "struct field DuplicateJSON repeats json tag .a. also at testdata/structtag.go:46"
+ DuplicateJSON int `json:"a"` // ERROR "struct field DuplicateJSON repeats json tag .a. also at structtag.go:46"
IgnoredJSON int `json:"-"`
OtherIgnoredJSON int `json:"-"`
OmitJSON int `json:",omitempty"`
OtherOmitJSON int `json:",omitempty"`
- DuplicateOmitJSON int `json:"a,omitempty"` // ERROR "struct field DuplicateOmitJSON repeats json tag .a. also at testdata/structtag.go:46"
+ DuplicateOmitJSON int `json:"a,omitempty"` // ERROR "struct field DuplicateOmitJSON repeats json tag .a. also at structtag.go:46"
NonJSON int `foo:"a"`
DuplicateNonJSON int `foo:"a"`
Embedded struct {
DuplicateJSON int `json:"a"` // OK because its not in the same struct type
}
- AnonymousJSON `json:"a"` // ERROR "struct field AnonymousJSON repeats json tag .a. also at testdata/structtag.go:46"
+ AnonymousJSON `json:"a"` // ERROR "struct field AnonymousJSON repeats json tag .a. also at structtag.go:46"
XML int `xml:"a"`
- DuplicateXML int `xml:"a"` // ERROR "struct field DuplicateXML repeats xml tag .a. also at testdata/structtag.go:60"
+ DuplicateXML int `xml:"a"` // ERROR "struct field DuplicateXML repeats xml tag .a. also at structtag.go:60"
IgnoredXML int `xml:"-"`
OtherIgnoredXML int `xml:"-"`
OmitXML int `xml:",omitempty"`
OtherOmitXML int `xml:",omitempty"`
- DuplicateOmitXML int `xml:"a,omitempty"` // ERROR "struct field DuplicateOmitXML repeats xml tag .a. also at testdata/structtag.go:60"
+ DuplicateOmitXML int `xml:"a,omitempty"` // ERROR "struct field DuplicateOmitXML repeats xml tag .a. also at structtag.go:60"
NonXML int `foo:"a"`
DuplicateNonXML int `foo:"a"`
Embedded struct {
DuplicateXML int `xml:"a"` // OK because its not in the same struct type
}
- AnonymousXML `xml:"a"` // ERROR "struct field AnonymousXML repeats xml tag .a. also at testdata/structtag.go:60"
+ AnonymousXML `xml:"a"` // ERROR "struct field AnonymousXML repeats xml tag .a. also at structtag.go:60"
Attribute struct {
XMLName xml.Name `xml:"b"`
NoDup int `xml:"b"` // OK because XMLName above affects enclosing struct.
Attr int `xml:"b,attr"` // OK because <b b="0"><b>0</b></b> is valid.
- DupAttr int `xml:"b,attr"` // ERROR "struct field DupAttr repeats xml attribute tag .b. also at testdata/structtag.go:76"
- DupOmitAttr int `xml:"b,omitempty,attr"` // ERROR "struct field DupOmitAttr repeats xml attribute tag .b. also at testdata/structtag.go:76"
+ DupAttr int `xml:"b,attr"` // ERROR "struct field DupAttr repeats xml attribute tag .b. also at structtag.go:76"
+ DupOmitAttr int `xml:"b,omitempty,attr"` // ERROR "struct field DupOmitAttr repeats xml attribute tag .b. also at structtag.go:76"
- AnonymousXML `xml:"b,attr"` // ERROR "struct field AnonymousXML repeats xml attribute tag .b. also at testdata/structtag.go:76"
+ AnonymousXML `xml:"b,attr"` // ERROR "struct field AnonymousXML repeats xml attribute tag .b. also at structtag.go:76"
}
}
diff --git a/libgo/go/cmd/vet/types.go b/libgo/go/cmd/vet/types.go
index d83611b4da0..5f8e481e01b 100644
--- a/libgo/go/cmd/vet/types.go
+++ b/libgo/go/cmd/vet/types.go
@@ -12,7 +12,6 @@ import (
"go/importer"
"go/token"
"go/types"
- "runtime"
)
// stdImporter is the importer we use to import packages.
@@ -173,7 +172,7 @@ func (f *File) matchArgTypeInternal(t printfArgType, typ types.Type, arg ast.Exp
return true // %s matches []byte
}
// Recur: []int matches %d.
- return t&argPointer != 0 || f.matchArgTypeInternal(t, typ.Elem().Underlying(), arg, inProgress)
+ return t&argPointer != 0 || f.matchArgTypeInternal(t, typ.Elem(), arg, inProgress)
case *types.Slice:
// Same as array.
@@ -202,8 +201,8 @@ func (f *File) matchArgTypeInternal(t printfArgType, typ types.Type, arg ast.Exp
if str, ok := typ.Elem().Underlying().(*types.Struct); ok {
return f.matchStructArgType(t, str, arg, inProgress)
}
- // The rest can print with %p as pointers, or as integers with %x etc.
- return t&(argInt|argPointer) != 0
+ // Check whether the rest can print pointers.
+ return t&argPointer != 0
case *types.Struct:
return f.matchStructArgType(t, typ, arg, inProgress)
@@ -255,7 +254,7 @@ func (f *File) matchArgTypeInternal(t printfArgType, typ types.Type, arg ast.Exp
return t&(argInt|argRune) != 0
case types.UntypedNil:
- return t&argPointer != 0 // TODO?
+ return false
case types.Invalid:
if *verbose {
@@ -270,7 +269,19 @@ func (f *File) matchArgTypeInternal(t printfArgType, typ types.Type, arg ast.Exp
}
func isConvertibleToString(typ types.Type) bool {
- return types.AssertableTo(errorType, typ) || stringerType != nil && types.AssertableTo(stringerType, typ)
+ if bt, ok := typ.(*types.Basic); ok && bt.Kind() == types.UntypedNil {
+ // We explicitly don't want untyped nil, which is
+ // convertible to both of the interfaces below, as it
+ // would just panic anyway.
+ return false
+ }
+ if types.ConvertibleTo(typ, errorType) {
+ return true // via .Error()
+ }
+ if stringerType != nil && types.ConvertibleTo(typ, stringerType) {
+ return true // via .String()
+ }
+ return false
}
// hasBasicType reports whether x's type is a types.Basic with the given kind.
@@ -299,15 +310,4 @@ func (f *File) matchStructArgType(t printfArgType, typ *types.Struct, arg ast.Ex
return true
}
-// hasMethod reports whether the type contains a method with the given name.
-// It is part of the workaround for Formatters and should be deleted when
-// that workaround is no longer necessary.
-// TODO: This could be better once issue 6259 is fixed.
-func (f *File) hasMethod(typ types.Type, name string) bool {
- // assume we have an addressable variable of type typ
- obj, _, _ := types.LookupFieldOrMethod(typ, true, f.pkg.typesPkg, name)
- _, ok := obj.(*types.Func)
- return ok
-}
-
-var archSizes = types.SizesFor(runtime.Compiler, build.Default.GOARCH)
+var archSizes = types.SizesFor("gc", build.Default.GOARCH)
diff --git a/libgo/go/cmd/vet/vet_test.go b/libgo/go/cmd/vet/vet_test.go
index 116b77e971b..3e42525e89b 100644
--- a/libgo/go/cmd/vet/vet_test.go
+++ b/libgo/go/cmd/vet/vet_test.go
@@ -6,12 +6,17 @@ package main_test
import (
"bytes"
+ "errors"
"fmt"
"internal/testenv"
+ "io/ioutil"
+ "log"
"os"
"os/exec"
"path/filepath"
+ "regexp"
"runtime"
+ "strconv"
"strings"
"sync"
"testing"
@@ -19,7 +24,7 @@ import (
const (
dataDir = "testdata"
- binary = "testvet.exe"
+ binary = "./testvet.exe"
)
// We implement TestMain so remove the test binary when all is done.
@@ -29,16 +34,6 @@ func TestMain(m *testing.M) {
os.Exit(result)
}
-func MustHavePerl(t *testing.T) {
- switch runtime.GOOS {
- case "plan9", "windows":
- t.Skipf("skipping test: perl not available on %s", runtime.GOOS)
- }
- if _, err := exec.LookPath("perl"); err != nil {
- t.Skipf("skipping test: perl not found in path")
- }
-}
-
var (
buildMu sync.Mutex // guards following
built = false // We have built the binary.
@@ -55,7 +50,6 @@ func Build(t *testing.T) {
t.Skip("cannot run on this environment")
}
testenv.MustHaveGoBuild(t)
- MustHavePerl(t)
cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", binary)
output, err := cmd.CombinedOutput()
if err != nil {
@@ -67,26 +61,19 @@ func Build(t *testing.T) {
}
func Vet(t *testing.T, files []string) {
- errchk := filepath.Join(runtime.GOROOT(), "test", "errchk")
- if _, err := os.Stat(errchk); err != nil {
- t.Skipf("skipping because no errchk: %v", err)
- }
flags := []string{
- "./" + binary,
"-printfuncs=Warn:1,Warnf:1",
"-all",
"-shadow",
}
- cmd := exec.Command(errchk, append(flags, files...)...)
- if !run(cmd, t) {
- t.Fatal("vet command failed")
- }
+ cmd := exec.Command(binary, append(flags, files...)...)
+ errchk(cmd, files, t)
}
-// Run this shell script, but do it in Go so it can be run by "go test".
-// go build -o testvet
-// $(GOROOT)/test/errchk ./testvet -shadow -printfuncs='Warn:1,Warnf:1' testdata/*.go testdata/*.s
-// rm testvet
+// TestVet is equivalent to running this:
+// go build -o ./testvet
+// errorCheck the output of ./testvet -shadow -printfuncs='Warn:1,Warnf:1' testdata/*.go testdata/*.s
+// rm ./testvet
//
// TestVet tests self-contained files in testdata/*.go.
@@ -98,7 +85,6 @@ func TestVet(t *testing.T) {
Build(t)
t.Parallel()
- // errchk ./testvet
gos, err := filepath.Glob(filepath.Join(dataDir, "*.go"))
if err != nil {
t.Fatal(err)
@@ -130,21 +116,23 @@ func TestVet(t *testing.T) {
}
func TestVetPrint(t *testing.T) {
- Build(t)
- errchk := filepath.Join(runtime.GOROOT(), "test", "errchk")
- if _, err := os.Stat(errchk); err != nil {
- t.Skipf("skipping because no errchk: %v", err)
+ if runtime.Compiler == "gccgo" {
+ // This test currently fails with gccgo because, in
+ // the absence of standard library sources, gccgo can
+ // not deduce that the standard log package formatting
+ // functions are just printf wrappers.
+ t.Skip("skipping for gccgo because there are no standard library sources")
}
+
+ Build(t)
+ file := filepath.Join("testdata", "print.go")
cmd := exec.Command(
- errchk,
- "go", "vet", "-vettool=./"+binary,
+ "go", "vet", "-vettool="+binary,
"-printf",
"-printfuncs=Warn:1,Warnf:1",
- "testdata/print.go",
+ file,
)
- if !run(cmd, t) {
- t.Fatal("vet command failed")
- }
+ errchk(cmd, []string{file}, t)
}
func TestVetAsm(t *testing.T) {
@@ -161,7 +149,6 @@ func TestVetAsm(t *testing.T) {
}
t.Parallel()
- // errchk ./testvet
Vet(t, append(gos, asms...))
}
@@ -187,23 +174,20 @@ func TestVetDirs(t *testing.T) {
}
}
-func run(c *exec.Cmd, t *testing.T) bool {
+func errchk(c *exec.Cmd, files []string, t *testing.T) {
output, err := c.CombinedOutput()
- if err != nil {
+ if _, ok := err.(*exec.ExitError); !ok {
t.Logf("vet output:\n%s", output)
t.Fatal(err)
}
- // Errchk delights by not returning non-zero status if it finds errors, so we look at the output.
- // It prints "BUG" if there is a failure.
- if !c.ProcessState.Success() {
- t.Logf("vet output:\n%s", output)
- return false
+ fullshort := make([]string, 0, len(files)*2)
+ for _, f := range files {
+ fullshort = append(fullshort, f, filepath.Base(f))
}
- ok := !bytes.Contains(output, []byte("BUG"))
- if !ok {
- t.Logf("vet output:\n%s", output)
+ err = errorCheck(string(output), false, fullshort...)
+ if err != nil {
+ t.Errorf("error check failed: %s", err)
}
- return ok
}
// TestTags verifies that the -tags argument controls which files to check.
@@ -220,7 +204,7 @@ func TestTags(t *testing.T) {
"-v", // We're going to look at the files it examines.
"testdata/tagtest",
}
- cmd := exec.Command("./"+binary, args...)
+ cmd := exec.Command(binary, args...)
output, err := cmd.CombinedOutput()
if err != nil {
t.Fatal(err)
@@ -240,10 +224,225 @@ func TestTags(t *testing.T) {
func TestVetVerbose(t *testing.T) {
t.Parallel()
Build(t)
- cmd := exec.Command("./"+binary, "-v", "-all", "testdata/cgo/cgo3.go")
+ cmd := exec.Command(binary, "-v", "-all", "testdata/cgo/cgo3.go")
out, err := cmd.CombinedOutput()
if err != nil {
t.Logf("%s", out)
t.Error(err)
}
}
+
+// All declarations below were adapted from test/run.go.
+
+// errorCheck matches errors in outStr against comments in source files.
+// For each line of the source files which should generate an error,
+// there should be a comment of the form // ERROR "regexp".
+// If outStr has an error for a line which has no such comment,
+// this function will report an error.
+// Likewise if outStr does not have an error for a line which has a comment,
+// or if the error message does not match the <regexp>.
+// The <regexp> syntax is Perl but its best to stick to egrep.
+//
+// Sources files are supplied as fullshort slice.
+// It consists of pairs: full path to source file and it's base name.
+func errorCheck(outStr string, wantAuto bool, fullshort ...string) (err error) {
+ var errs []error
+ out := splitOutput(outStr, wantAuto)
+ // Cut directory name.
+ for i := range out {
+ for j := 0; j < len(fullshort); j += 2 {
+ full, short := fullshort[j], fullshort[j+1]
+ out[i] = strings.Replace(out[i], full, short, -1)
+ }
+ }
+
+ var want []wantedError
+ for j := 0; j < len(fullshort); j += 2 {
+ full, short := fullshort[j], fullshort[j+1]
+ want = append(want, wantedErrors(full, short)...)
+ }
+ for _, we := range want {
+ var errmsgs []string
+ if we.auto {
+ errmsgs, out = partitionStrings("<autogenerated>", out)
+ } else {
+ errmsgs, out = partitionStrings(we.prefix, out)
+ }
+ if len(errmsgs) == 0 {
+ errs = append(errs, fmt.Errorf("%s:%d: missing error %q", we.file, we.lineNum, we.reStr))
+ continue
+ }
+ matched := false
+ n := len(out)
+ for _, errmsg := range errmsgs {
+ // Assume errmsg says "file:line: foo".
+ // Cut leading "file:line: " to avoid accidental matching of file name instead of message.
+ text := errmsg
+ if i := strings.Index(text, " "); i >= 0 {
+ text = text[i+1:]
+ }
+ if we.re.MatchString(text) {
+ matched = true
+ } else {
+ out = append(out, errmsg)
+ }
+ }
+ if !matched {
+ errs = append(errs, fmt.Errorf("%s:%d: no match for %#q in:\n\t%s", we.file, we.lineNum, we.reStr, strings.Join(out[n:], "\n\t")))
+ continue
+ }
+ }
+
+ if len(out) > 0 {
+ errs = append(errs, fmt.Errorf("Unmatched Errors:"))
+ for _, errLine := range out {
+ errs = append(errs, fmt.Errorf("%s", errLine))
+ }
+ }
+
+ if len(errs) == 0 {
+ return nil
+ }
+ if len(errs) == 1 {
+ return errs[0]
+ }
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "\n")
+ for _, err := range errs {
+ fmt.Fprintf(&buf, "%s\n", err.Error())
+ }
+ return errors.New(buf.String())
+}
+
+func splitOutput(out string, wantAuto bool) []string {
+ // gc error messages continue onto additional lines with leading tabs.
+ // Split the output at the beginning of each line that doesn't begin with a tab.
+ // <autogenerated> lines are impossible to match so those are filtered out.
+ var res []string
+ for _, line := range strings.Split(out, "\n") {
+ line = strings.TrimSuffix(line, "\r") // normalize Windows output
+ if strings.HasPrefix(line, "\t") {
+ res[len(res)-1] += "\n" + line
+ } else if strings.HasPrefix(line, "go tool") || strings.HasPrefix(line, "#") || !wantAuto && strings.HasPrefix(line, "<autogenerated>") {
+ continue
+ } else if strings.TrimSpace(line) != "" {
+ res = append(res, line)
+ }
+ }
+ return res
+}
+
+// matchPrefix reports whether s starts with file name prefix followed by a :,
+// and possibly preceded by a directory name.
+func matchPrefix(s, prefix string) bool {
+ i := strings.Index(s, ":")
+ if i < 0 {
+ return false
+ }
+ j := strings.LastIndex(s[:i], "/")
+ s = s[j+1:]
+ if len(s) <= len(prefix) || s[:len(prefix)] != prefix {
+ return false
+ }
+ if s[len(prefix)] == ':' {
+ return true
+ }
+ return false
+}
+
+func partitionStrings(prefix string, strs []string) (matched, unmatched []string) {
+ for _, s := range strs {
+ if matchPrefix(s, prefix) {
+ matched = append(matched, s)
+ } else {
+ unmatched = append(unmatched, s)
+ }
+ }
+ return
+}
+
+type wantedError struct {
+ reStr string
+ re *regexp.Regexp
+ lineNum int
+ auto bool // match <autogenerated> line
+ file string
+ prefix string
+}
+
+var (
+ errRx = regexp.MustCompile(`// (?:GC_)?ERROR (.*)`)
+ errAutoRx = regexp.MustCompile(`// (?:GC_)?ERRORAUTO (.*)`)
+ errQuotesRx = regexp.MustCompile(`"([^"]*)"`)
+ lineRx = regexp.MustCompile(`LINE(([+-])([0-9]+))?`)
+)
+
+// wantedErrors parses expected errors from comments in a file.
+func wantedErrors(file, short string) (errs []wantedError) {
+ cache := make(map[string]*regexp.Regexp)
+
+ src, err := ioutil.ReadFile(file)
+ if err != nil {
+ log.Fatal(err)
+ }
+ for i, line := range strings.Split(string(src), "\n") {
+ lineNum := i + 1
+ if strings.Contains(line, "////") {
+ // double comment disables ERROR
+ continue
+ }
+ var auto bool
+ m := errAutoRx.FindStringSubmatch(line)
+ if m != nil {
+ auto = true
+ } else {
+ m = errRx.FindStringSubmatch(line)
+ }
+ if m == nil {
+ continue
+ }
+ all := m[1]
+ mm := errQuotesRx.FindAllStringSubmatch(all, -1)
+ if mm == nil {
+ log.Fatalf("%s:%d: invalid errchk line: %s", file, lineNum, line)
+ }
+ for _, m := range mm {
+ replacedOnce := false
+ rx := lineRx.ReplaceAllStringFunc(m[1], func(m string) string {
+ if replacedOnce {
+ return m
+ }
+ replacedOnce = true
+ n := lineNum
+ if strings.HasPrefix(m, "LINE+") {
+ delta, _ := strconv.Atoi(m[5:])
+ n += delta
+ } else if strings.HasPrefix(m, "LINE-") {
+ delta, _ := strconv.Atoi(m[5:])
+ n -= delta
+ }
+ return fmt.Sprintf("%s:%d", short, n)
+ })
+ re := cache[rx]
+ if re == nil {
+ var err error
+ re, err = regexp.Compile(rx)
+ if err != nil {
+ log.Fatalf("%s:%d: invalid regexp \"%#q\" in ERROR line: %v", file, lineNum, rx, err)
+ }
+ cache[rx] = re
+ }
+ prefix := fmt.Sprintf("%s:%d", short, lineNum)
+ errs = append(errs, wantedError{
+ reStr: rx,
+ re: re,
+ prefix: prefix,
+ auto: auto,
+ lineNum: lineNum,
+ file: short,
+ })
+ }
+ }
+
+ return
+}