From 73df946d56c74384511a194dd01dbe099584fd1a Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 28 Apr 2024 15:14:23 +0200 Subject: Adding upstream version 1.16.10. Signed-off-by: Daniel Baumann --- src/cmd/go/alldocs.go | 2935 +++++++++++++++++ src/cmd/go/go11.go | 10 + src/cmd/go/go_test.go | 2832 +++++++++++++++++ src/cmd/go/go_unix_test.go | 35 + src/cmd/go/go_windows_test.go | 50 + src/cmd/go/help_test.go | 33 + src/cmd/go/init_test.go | 42 + src/cmd/go/internal/auth/auth.go | 25 + src/cmd/go/internal/auth/netrc.go | 110 + src/cmd/go/internal/auth/netrc_test.go | 58 + src/cmd/go/internal/base/base.go | 186 ++ src/cmd/go/internal/base/env.go | 15 + src/cmd/go/internal/base/flag.go | 71 + src/cmd/go/internal/base/goflags.go | 153 + src/cmd/go/internal/base/path.go | 52 + src/cmd/go/internal/base/signal.go | 31 + src/cmd/go/internal/base/signal_notunix.go | 17 + src/cmd/go/internal/base/signal_unix.go | 18 + src/cmd/go/internal/base/tool.go | 44 + src/cmd/go/internal/bug/bug.go | 211 ++ src/cmd/go/internal/cache/cache.go | 524 ++++ src/cmd/go/internal/cache/cache_test.go | 269 ++ src/cmd/go/internal/cache/default.go | 97 + src/cmd/go/internal/cache/hash.go | 174 + src/cmd/go/internal/cache/hash_test.go | 51 + src/cmd/go/internal/cfg/cfg.go | 393 +++ src/cmd/go/internal/clean/clean.go | 390 +++ src/cmd/go/internal/cmdflag/flag.go | 129 + src/cmd/go/internal/doc/doc.go | 135 + src/cmd/go/internal/envcmd/env.go | 537 ++++ src/cmd/go/internal/fix/fix.go | 63 + src/cmd/go/internal/fmtcmd/fmt.go | 117 + src/cmd/go/internal/fsys/fsys.go | 689 ++++ src/cmd/go/internal/fsys/fsys_test.go | 1094 +++++++ src/cmd/go/internal/generate/generate.go | 456 +++ src/cmd/go/internal/generate/generate_test.go | 254 ++ src/cmd/go/internal/get/get.go | 621 ++++ src/cmd/go/internal/get/tag_test.go | 100 + src/cmd/go/internal/help/help.go | 196 ++ src/cmd/go/internal/help/helpdoc.go | 875 ++++++ src/cmd/go/internal/imports/build.go | 251 ++ src/cmd/go/internal/imports/read.go | 249 ++ src/cmd/go/internal/imports/read_test.go | 228 ++ src/cmd/go/internal/imports/scan.go | 107 + src/cmd/go/internal/imports/scan_test.go | 94 + src/cmd/go/internal/imports/tags.go | 58 + src/cmd/go/internal/imports/testdata/android/.h.go | 3 + .../internal/imports/testdata/android/a_android.go | 3 + .../imports/testdata/android/b_android_arm64.go | 3 + .../internal/imports/testdata/android/c_linux.go | 3 + .../imports/testdata/android/d_linux_arm64.go | 3 + src/cmd/go/internal/imports/testdata/android/e.go | 5 + src/cmd/go/internal/imports/testdata/android/f.go | 5 + src/cmd/go/internal/imports/testdata/android/g.go | 5 + .../go/internal/imports/testdata/android/tags.txt | 1 + .../go/internal/imports/testdata/android/want.txt | 6 + src/cmd/go/internal/imports/testdata/illumos/.h.go | 3 + .../internal/imports/testdata/illumos/a_illumos.go | 3 + .../imports/testdata/illumos/b_illumos_amd64.go | 3 + .../internal/imports/testdata/illumos/c_solaris.go | 3 + .../imports/testdata/illumos/d_solaris_amd64.go | 3 + src/cmd/go/internal/imports/testdata/illumos/e.go | 5 + src/cmd/go/internal/imports/testdata/illumos/f.go | 5 + src/cmd/go/internal/imports/testdata/illumos/g.go | 5 + .../go/internal/imports/testdata/illumos/tags.txt | 1 + .../go/internal/imports/testdata/illumos/want.txt | 6 + src/cmd/go/internal/imports/testdata/star/tags.txt | 1 + src/cmd/go/internal/imports/testdata/star/want.txt | 4 + src/cmd/go/internal/imports/testdata/star/x.go | 3 + src/cmd/go/internal/imports/testdata/star/x1.go | 9 + .../go/internal/imports/testdata/star/x_darwin.go | 3 + .../go/internal/imports/testdata/star/x_windows.go | 3 + src/cmd/go/internal/list/context.go | 37 + src/cmd/go/internal/list/list.go | 761 +++++ src/cmd/go/internal/load/flag.go | 93 + src/cmd/go/internal/load/flag_test.go | 135 + src/cmd/go/internal/load/path.go | 18 + src/cmd/go/internal/load/pkg.go | 2594 +++++++++++++++ src/cmd/go/internal/load/pkg_test.go | 78 + src/cmd/go/internal/load/search.go | 56 + src/cmd/go/internal/load/test.go | 752 +++++ .../lockedfile/internal/filelock/filelock.go | 99 + .../lockedfile/internal/filelock/filelock_fcntl.go | 216 ++ .../lockedfile/internal/filelock/filelock_other.go | 36 + .../lockedfile/internal/filelock/filelock_plan9.go | 36 + .../lockedfile/internal/filelock/filelock_test.go | 211 ++ .../lockedfile/internal/filelock/filelock_unix.go | 44 + .../internal/filelock/filelock_windows.go | 66 + src/cmd/go/internal/lockedfile/lockedfile.go | 187 ++ .../go/internal/lockedfile/lockedfile_filelock.go | 66 + src/cmd/go/internal/lockedfile/lockedfile_plan9.go | 96 + src/cmd/go/internal/lockedfile/lockedfile_test.go | 271 ++ src/cmd/go/internal/lockedfile/mutex.go | 67 + src/cmd/go/internal/lockedfile/transform_test.go | 104 + src/cmd/go/internal/modcmd/download.go | 214 ++ src/cmd/go/internal/modcmd/edit.go | 505 +++ src/cmd/go/internal/modcmd/graph.go | 84 + src/cmd/go/internal/modcmd/init.go | 51 + src/cmd/go/internal/modcmd/mod.go | 33 + src/cmd/go/internal/modcmd/tidy.go | 77 + src/cmd/go/internal/modcmd/vendor.go | 379 +++ src/cmd/go/internal/modcmd/verify.go | 128 + src/cmd/go/internal/modcmd/why.go | 139 + src/cmd/go/internal/modconv/convert.go | 108 + src/cmd/go/internal/modconv/convert_test.go | 189 ++ src/cmd/go/internal/modconv/dep.go | 132 + src/cmd/go/internal/modconv/glide.go | 41 + src/cmd/go/internal/modconv/glock.go | 23 + src/cmd/go/internal/modconv/godeps.go | 30 + src/cmd/go/internal/modconv/modconv.go | 19 + src/cmd/go/internal/modconv/modconv_test.go | 69 + .../go/internal/modconv/testdata/cockroach.glock | 41 + src/cmd/go/internal/modconv/testdata/cockroach.out | 31 + .../internal/modconv/testdata/dockermachine.godeps | 159 + .../go/internal/modconv/testdata/dockermachine.out | 33 + .../go/internal/modconv/testdata/dockerman.glide | 52 + src/cmd/go/internal/modconv/testdata/dockerman.out | 16 + src/cmd/go/internal/modconv/testdata/govmomi.out | 5 + .../go/internal/modconv/testdata/govmomi.vmanifest | 46 + src/cmd/go/internal/modconv/testdata/juju.out | 106 + src/cmd/go/internal/modconv/testdata/juju.tsv | 106 + src/cmd/go/internal/modconv/testdata/moby.out | 105 + src/cmd/go/internal/modconv/testdata/moby.vconf | 149 + .../go/internal/modconv/testdata/panicparse.out | 8 + .../go/internal/modconv/testdata/panicparse.vyml | 17 + .../go/internal/modconv/testdata/prometheus.out | 258 ++ .../go/internal/modconv/testdata/prometheus.vjson | 1605 ++++++++++ src/cmd/go/internal/modconv/testdata/traefik.dep | 79 + src/cmd/go/internal/modconv/testdata/traefik.out | 14 + src/cmd/go/internal/modconv/testdata/upspin.dep | 57 + src/cmd/go/internal/modconv/testdata/upspin.out | 8 + src/cmd/go/internal/modconv/tsv.go | 23 + src/cmd/go/internal/modconv/vconf.go | 26 + src/cmd/go/internal/modconv/vjson.go | 29 + src/cmd/go/internal/modconv/vmanifest.go | 29 + src/cmd/go/internal/modconv/vyml.go | 41 + src/cmd/go/internal/modfetch/bootstrap.go | 17 + src/cmd/go/internal/modfetch/cache.go | 652 ++++ src/cmd/go/internal/modfetch/cache_test.go | 24 + src/cmd/go/internal/modfetch/codehost/codehost.go | 315 ++ src/cmd/go/internal/modfetch/codehost/git.go | 875 ++++++ src/cmd/go/internal/modfetch/codehost/git_test.go | 640 ++++ src/cmd/go/internal/modfetch/codehost/shell.go | 141 + src/cmd/go/internal/modfetch/codehost/svn.go | 154 + src/cmd/go/internal/modfetch/codehost/vcs.go | 616 ++++ src/cmd/go/internal/modfetch/coderepo.go | 1082 +++++++ src/cmd/go/internal/modfetch/coderepo_test.go | 802 +++++ src/cmd/go/internal/modfetch/fetch.go | 844 +++++ src/cmd/go/internal/modfetch/insecure.go | 16 + src/cmd/go/internal/modfetch/key.go | 9 + src/cmd/go/internal/modfetch/proxy.go | 431 +++ src/cmd/go/internal/modfetch/pseudo.go | 252 ++ src/cmd/go/internal/modfetch/pseudo_test.go | 154 + src/cmd/go/internal/modfetch/repo.go | 455 +++ src/cmd/go/internal/modfetch/sumdb.go | 279 ++ .../modfetch/zip_sum_test/testdata/zip_sums.csv | 2119 +++++++++++++ .../internal/modfetch/zip_sum_test/zip_sum_test.go | 230 ++ src/cmd/go/internal/modget/get.go | 1687 ++++++++++ src/cmd/go/internal/modget/query.go | 357 +++ src/cmd/go/internal/modinfo/info.go | 58 + src/cmd/go/internal/modload/build.go | 361 +++ src/cmd/go/internal/modload/buildlist.go | 308 ++ src/cmd/go/internal/modload/help.go | 64 + src/cmd/go/internal/modload/import.go | 600 ++++ src/cmd/go/internal/modload/import_test.go | 96 + src/cmd/go/internal/modload/init.go | 1072 +++++++ src/cmd/go/internal/modload/list.go | 191 ++ src/cmd/go/internal/modload/load.go | 1364 ++++++++ src/cmd/go/internal/modload/modfile.go | 591 ++++ src/cmd/go/internal/modload/mvs.go | 113 + src/cmd/go/internal/modload/mvs_test.go | 31 + src/cmd/go/internal/modload/query.go | 1111 +++++++ src/cmd/go/internal/modload/query_test.go | 216 ++ src/cmd/go/internal/modload/search.go | 219 ++ src/cmd/go/internal/modload/stat_openfile.go | 28 + src/cmd/go/internal/modload/stat_unix.go | 32 + src/cmd/go/internal/modload/stat_windows.go | 21 + src/cmd/go/internal/modload/vendor.go | 219 ++ src/cmd/go/internal/mvs/errors.go | 101 + src/cmd/go/internal/mvs/mvs.go | 481 +++ src/cmd/go/internal/mvs/mvs_test.go | 525 ++++ src/cmd/go/internal/par/queue.go | 88 + src/cmd/go/internal/par/queue_test.go | 79 + src/cmd/go/internal/par/work.go | 190 ++ src/cmd/go/internal/par/work_test.go | 77 + src/cmd/go/internal/renameio/renameio.go | 94 + src/cmd/go/internal/renameio/renameio_test.go | 160 + src/cmd/go/internal/renameio/umask_test.go | 42 + src/cmd/go/internal/robustio/robustio.go | 53 + src/cmd/go/internal/robustio/robustio_darwin.go | 21 + src/cmd/go/internal/robustio/robustio_flaky.go | 91 + src/cmd/go/internal/robustio/robustio_other.go | 27 + src/cmd/go/internal/robustio/robustio_windows.go | 27 + src/cmd/go/internal/run/run.go | 144 + src/cmd/go/internal/search/search.go | 639 ++++ src/cmd/go/internal/search/search_test.go | 165 + src/cmd/go/internal/str/path.go | 51 + src/cmd/go/internal/str/str.go | 155 + src/cmd/go/internal/str/str_test.go | 27 + src/cmd/go/internal/test/cover.go | 84 + src/cmd/go/internal/test/flagdefs.go | 34 + src/cmd/go/internal/test/flagdefs_test.go | 39 + src/cmd/go/internal/test/genflags.go | 91 + src/cmd/go/internal/test/test.go | 1720 ++++++++++ src/cmd/go/internal/test/testflag.go | 412 +++ src/cmd/go/internal/tool/tool.go | 147 + src/cmd/go/internal/trace/trace.go | 206 ++ src/cmd/go/internal/txtar/archive.go | 140 + src/cmd/go/internal/txtar/archive_test.go | 67 + src/cmd/go/internal/vcs/discovery.go | 97 + src/cmd/go/internal/vcs/discovery_test.go | 110 + src/cmd/go/internal/vcs/vcs.go | 1363 ++++++++ src/cmd/go/internal/vcs/vcs_test.go | 578 ++++ src/cmd/go/internal/version/exe.go | 263 ++ src/cmd/go/internal/version/version.go | 224 ++ src/cmd/go/internal/vet/vet.go | 118 + src/cmd/go/internal/vet/vetflag.go | 192 ++ src/cmd/go/internal/web/api.go | 236 ++ src/cmd/go/internal/web/bootstrap.go | 23 + src/cmd/go/internal/web/file_test.go | 60 + src/cmd/go/internal/web/http.go | 249 ++ src/cmd/go/internal/web/url.go | 95 + src/cmd/go/internal/web/url_other.go | 21 + src/cmd/go/internal/web/url_other_test.go | 36 + src/cmd/go/internal/web/url_test.go | 77 + src/cmd/go/internal/web/url_windows.go | 43 + src/cmd/go/internal/web/url_windows_test.go | 94 + src/cmd/go/internal/work/action.go | 859 +++++ src/cmd/go/internal/work/build.go | 929 ++++++ src/cmd/go/internal/work/build_test.go | 277 ++ src/cmd/go/internal/work/buildid.go | 698 ++++ src/cmd/go/internal/work/exec.go | 3316 ++++++++++++++++++++ src/cmd/go/internal/work/exec_test.go | 86 + src/cmd/go/internal/work/gc.go | 693 ++++ src/cmd/go/internal/work/gccgo.go | 618 ++++ src/cmd/go/internal/work/init.go | 286 ++ src/cmd/go/internal/work/security.go | 310 ++ src/cmd/go/internal/work/security_test.go | 277 ++ src/cmd/go/internal/work/testgo.go | 48 + src/cmd/go/main.go | 235 ++ src/cmd/go/mkalldocs.sh | 13 + src/cmd/go/note_test.go | 72 + src/cmd/go/proxy_test.go | 492 +++ src/cmd/go/script_test.go | 1448 +++++++++ src/cmd/go/testdata/addmod.go | 154 + src/cmd/go/testdata/failssh/ssh | 2 + src/cmd/go/testdata/mod/README | 36 + .../mod/example.com_ambiguous_a_b_v0.0.0-empty.txt | 12 + .../mod/example.com_ambiguous_a_v1.0.0.txt | 18 + .../testdata/mod/example.com_badchain_a_v1.0.0.txt | 12 + .../testdata/mod/example.com_badchain_a_v1.1.0.txt | 12 + .../testdata/mod/example.com_badchain_b_v1.0.0.txt | 12 + .../testdata/mod/example.com_badchain_b_v1.1.0.txt | 12 + .../testdata/mod/example.com_badchain_c_v1.0.0.txt | 8 + .../testdata/mod/example.com_badchain_c_v1.1.0.txt | 8 + .../mod/example.com_cmd_v1.0.0-exclude.txt | 28 + .../mod/example.com_cmd_v1.0.0-newerself.txt | 28 + .../mod/example.com_cmd_v1.0.0-replace.txt | 28 + src/cmd/go/testdata/mod/example.com_cmd_v1.0.0.txt | 27 + src/cmd/go/testdata/mod/example.com_cmd_v1.9.0.txt | 30 + .../testdata/mod/example.com_dotgo.go_v1.0.0.txt | 16 + .../testdata/mod/example.com_downgrade_v2.0.0.txt | 9 + .../mod/example.com_downgrade_v2_v2.0.1.txt | 13 + .../mod/example.com_incompatiblewithsub_v1.0.0.txt | 8 + ...com_incompatiblewithsub_v2.0.0+incompatible.txt | 8 + .../mod/example.com_invalidpath_v1_v1.0.0.txt | 13 + .../mod/example.com_join_subpkg_v1.0.0.txt | 9 + .../mod/example.com_join_subpkg_v1.1.0.txt | 9 + .../go/testdata/mod/example.com_join_v1.0.0.txt | 7 + .../go/testdata/mod/example.com_join_v1.1.0.txt | 9 + .../mod/example.com_latemigrate_v2_v2.0.0.txt | 14 + .../mod/example.com_latemigrate_v2_v2.0.1.txt | 20 + .../testdata/mod/example.com_missingpkg_v1.0.0.txt | 11 + .../mod/example.com_missingpkg_v1.0.1-beta.txt | 8 + .../testdata/mod/example.com_nest_sub_v1.0.0.txt | 12 + .../go/testdata/mod/example.com_nest_v1.0.0.txt | 12 + .../go/testdata/mod/example.com_nest_v1.1.0.txt | 12 + .../testdata/mod/example.com_newcycle_a_v1.0.0.txt | 10 + .../testdata/mod/example.com_newcycle_a_v1.0.1.txt | 10 + .../testdata/mod/example.com_newcycle_b_v1.0.0.txt | 8 + .../go/testdata/mod/example.com_noroot_v1.0.0.txt | 8 + .../go/testdata/mod/example.com_noroot_v1.0.1.txt | 8 + ...m_notags_v0.0.0-20190507143103-cc8cbe209b64.txt | 9 + .../mod/example.com_printversion_v0.1.0.txt | 33 + .../mod/example.com_printversion_v1.0.0.txt | 41 + ...oupgrade_v0.0.0-20190430073000-30950c05d534.txt | 13 + .../mod/example.com_pseudoupgrade_v0.1.0.txt | 13 + ...pgrade_v0.1.1-0.20190429073117-b5426c86b553.txt | 13 + .../go/testdata/mod/example.com_quote_v1.5.2.txt | 9 + ...ple.com_retract_ambiguous_nested_v1.9.0-bad.txt | 10 + .../example.com_retract_ambiguous_other_v1.0.0.txt | 12 + .../mod/example.com_retract_ambiguous_v1.0.0.txt | 9 + .../example.com_retract_incompatible_v1.0.0.txt | 19 + ...om_retract_incompatible_v2.0.0+incompatible.txt | 9 + .../mod/example.com_retract_missingmod_v1.0.0.txt | 10 + .../mod/example.com_retract_missingmod_v1.9.0.txt | 4 + .../example.com_retract_rationale_v1.0.0-block.txt | 6 + ...m_retract_rationale_v1.0.0-blockwithcomment.txt | 6 + .../example.com_retract_rationale_v1.0.0-empty.txt | 8 + .../example.com_retract_rationale_v1.0.0-long.txt | 8 + ...ple.com_retract_rationale_v1.0.0-multiline1.txt | 8 + ...ple.com_retract_rationale_v1.0.0-multiline2.txt | 8 + .../example.com_retract_rationale_v1.0.0-order.txt | 6 + ...le.com_retract_rationale_v1.0.0-unprintable.txt | 8 + .../example.com_retract_rationale_v1.0.1-order.txt | 6 + .../mod/example.com_retract_rationale_v1.9.0.txt | 48 + .../mod/example.com_retract_rename_v1.0.0-bad.txt | 16 + .../mod/example.com_retract_rename_v1.9.0-new.txt | 22 + .../mod/example.com_retract_self_all_v1.9.0.txt | 14 + .../example.com_retract_self_prerelease_v1.0.0.txt | 16 + .../example.com_retract_self_prerelease_v1.9.0.txt | 19 + ...mple.com_retract_self_prerelease_v1.9.1-pre.txt | 16 + .../example.com_retract_self_prev_v1.0.0-bad.txt | 14 + .../mod/example.com_retract_self_prev_v1.1.0.txt | 14 + .../mod/example.com_retract_self_prev_v1.9.0.txt | 18 + ..._self_pseudo_v0.0.0-20200325131415-0123456789ab | 20 + .../example.com_retract_self_pseudo_v1.0.0-bad.txt | 14 + .../mod/example.com_retract_self_pseudo_v1.9.0.txt | 16 + .../mod/example.com_retract_v1.0.0-bad.txt | 10 + .../mod/example.com_retract_v1.0.0-good.txt | 10 + .../mod/example.com_retract_v1.0.0-unused.txt | 10 + .../go/testdata/mod/example.com_retract_v1.1.0.txt | 13 + ...xample.com_split-incompatible_subpkg_v0.1.0.txt | 14 + ....com_split-incompatible_v2.0.0+incompatible.txt | 10 + ..._split-incompatible_v2.1.0-pre+incompatible.txt | 10 + .../mod/example.com_split_subpkg_v1.1.0.txt | 11 + .../go/testdata/mod/example.com_split_v1.0.0.txt | 9 + .../go/testdata/mod/example.com_split_v1.1.0.txt | 9 + .../go/testdata/mod/example.com_stack_v1.0.0.txt | 18 + .../go/testdata/mod/example.com_stack_v1.0.1.txt | 18 + .../go/testdata/mod/example.com_tools_v1.0.0.txt | 12 + .../mod/example.com_usemissingpre_v1.0.0.txt | 13 + src/cmd/go/testdata/mod/example.com_v1.0.0.txt | 9 + .../go/testdata/mod/example.com_version_v1.0.0.txt | 11 + .../go/testdata/mod/example.com_version_v1.0.1.txt | 11 + .../go/testdata/mod/example.com_version_v1.1.0.txt | 11 + .../mod/example.net_ambiguous_nested_v0.1.0.txt | 19 + .../testdata/mod/example.net_ambiguous_v0.1.0.txt | 19 + .../testdata/mod/example.net_ambiguous_v0.2.0.txt | 18 + .../testdata/mod/example.net_pkgadded_v1.0.0.txt | 17 + .../testdata/mod/example.net_pkgadded_v1.1.0.txt | 19 + .../testdata/mod/example.net_pkgadded_v1.2.0.txt | 20 + ...modtest5_v0.0.0-20190619020302-197a620e0c9a.txt | 10 + ..._v0.5.0-alpha.0.20190619023908-3da23a9deb9e.txt | 10 + ...hub.com_dmitshur-test_modtest5_v0.5.0-alpha.txt | 10 + .../mod/golang.org_notx_useinternal_v0.1.0.txt | 13 + .../testdata/mod/golang.org_x_internal_v0.1.0.txt | 43 + ...g_x_text_v0.0.0-20170915032832-14c0d48ead0c.txt | 47 + .../go/testdata/mod/golang.org_x_text_v0.3.0.txt | 47 + .../mod/golang.org_x_useinternal_v0.1.0.txt | 13 + .../mod/gopkg.in_dummy.v2-unstable_v2.0.0.txt | 9 + .../testdata/mod/not-rsc.io_quote_v0.1.0-nomod.txt | 59 + .../patch.example.com_depofdirectpatch_v1.0.0.txt | 11 + .../patch.example.com_depofdirectpatch_v1.0.1.txt | 11 + .../mod/patch.example.com_direct_v1.0.0.txt | 21 + .../mod/patch.example.com_direct_v1.0.1.txt | 27 + .../mod/patch.example.com_direct_v1.1.0.txt | 21 + .../mod/patch.example.com_indirect_v1.0.0.txt | 11 + .../mod/patch.example.com_indirect_v1.0.1.txt | 11 + .../mod/patch.example.com_indirect_v1.1.0.txt | 11 + src/cmd/go/testdata/mod/rsc.io_!c!g!o_v1.0.0.txt | 19 + .../go/testdata/mod/rsc.io_!q!u!o!t!e_v1.5.2.txt | 88 + .../mod/rsc.io_!q!u!o!t!e_v1.5.3-!p!r!e.txt | 88 + src/cmd/go/testdata/mod/rsc.io_badfile1_v1.0.0.txt | 14 + src/cmd/go/testdata/mod/rsc.io_badfile2_v1.0.0.txt | 12 + src/cmd/go/testdata/mod/rsc.io_badfile3_v1.0.0.txt | 12 + src/cmd/go/testdata/mod/rsc.io_badfile4_v1.0.0.txt | 15 + src/cmd/go/testdata/mod/rsc.io_badfile5_v1.0.0.txt | 13 + src/cmd/go/testdata/mod/rsc.io_badmod_v1.0.0.txt | 11 + src/cmd/go/testdata/mod/rsc.io_badsum_v1.0.0.txt | 14 + src/cmd/go/testdata/mod/rsc.io_badsum_v1.0.1.txt | 14 + src/cmd/go/testdata/mod/rsc.io_badzip_v1.0.0.txt | 11 + src/cmd/go/testdata/mod/rsc.io_breaker_v1.0.0.txt | 11 + .../mod/rsc.io_breaker_v2.0.0+incompatible.txt | 11 + src/cmd/go/testdata/mod/rsc.io_breaker_v2.0.0.txt | 11 + src/cmd/go/testdata/mod/rsc.io_fortune_v1.0.0.txt | 15 + .../go/testdata/mod/rsc.io_fortune_v2_v2.0.0.txt | 21 + ...io_quote_v0.0.0-20180214005133-e7a685a342c0.txt | 60 + ...io_quote_v0.0.0-20180214005840-23179ee8a569.txt | 86 + ...io_quote_v0.0.0-20180628003336-dd9747d19b04.txt | 100 + ...io_quote_v0.0.0-20180709153244-fd906ed3b100.txt | 86 + ...io_quote_v0.0.0-20180709160352-0d003b9c4bfa.txt | 98 + ...io_quote_v0.0.0-20180709162749-b44a0b17b2d1.txt | 104 + ...io_quote_v0.0.0-20180709162816-fe488b867524.txt | 104 + ...io_quote_v0.0.0-20180709162918-a91498bed0a7.txt | 98 + ...io_quote_v0.0.0-20180710144737-5d9f230bcfba.txt | 104 + src/cmd/go/testdata/mod/rsc.io_quote_v1.0.0.txt | 35 + src/cmd/go/testdata/mod/rsc.io_quote_v1.1.0.txt | 48 + src/cmd/go/testdata/mod/rsc.io_quote_v1.2.0.txt | 61 + src/cmd/go/testdata/mod/rsc.io_quote_v1.2.1.txt | 60 + src/cmd/go/testdata/mod/rsc.io_quote_v1.3.0.txt | 73 + src/cmd/go/testdata/mod/rsc.io_quote_v1.4.0.txt | 79 + src/cmd/go/testdata/mod/rsc.io_quote_v1.5.0.txt | 79 + src/cmd/go/testdata/mod/rsc.io_quote_v1.5.1.txt | 86 + src/cmd/go/testdata/mod/rsc.io_quote_v1.5.2.txt | 98 + .../go/testdata/mod/rsc.io_quote_v1.5.3-pre1.txt | 100 + src/cmd/go/testdata/mod/rsc.io_quote_v2.0.0.txt | 86 + src/cmd/go/testdata/mod/rsc.io_quote_v2_v2.0.1.txt | 86 + src/cmd/go/testdata/mod/rsc.io_quote_v3_v3.0.0.txt | 45 + src/cmd/go/testdata/mod/rsc.io_sampler_v1.0.0.txt | 20 + src/cmd/go/testdata/mod/rsc.io_sampler_v1.2.0.txt | 138 + src/cmd/go/testdata/mod/rsc.io_sampler_v1.2.1.txt | 134 + src/cmd/go/testdata/mod/rsc.io_sampler_v1.3.0.txt | 202 ++ src/cmd/go/testdata/mod/rsc.io_sampler_v1.3.1.txt | 201 ++ .../go/testdata/mod/rsc.io_sampler_v1.99.99.txt | 140 + src/cmd/go/testdata/mod/rsc.io_testonly_v1.0.0.txt | 9 + src/cmd/go/testdata/modlegacy/src/new/go.mod | 1 + src/cmd/go/testdata/modlegacy/src/new/new.go | 3 + src/cmd/go/testdata/modlegacy/src/new/p1/p1.go | 7 + src/cmd/go/testdata/modlegacy/src/new/p2/p2.go | 1 + src/cmd/go/testdata/modlegacy/src/new/sub/go.mod | 1 + .../go/testdata/modlegacy/src/new/sub/inner/go.mod | 1 + .../go/testdata/modlegacy/src/new/sub/inner/x/x.go | 1 + .../go/testdata/modlegacy/src/new/sub/x/v1/y/y.go | 1 + src/cmd/go/testdata/modlegacy/src/old/p1/p1.go | 5 + src/cmd/go/testdata/modlegacy/src/old/p2/p2.go | 1 + src/cmd/go/testdata/savedir.go | 79 + src/cmd/go/testdata/script/README | 310 ++ src/cmd/go/testdata/script/bug.txt | 46 + src/cmd/go/testdata/script/build_GOTMPDIR.txt | 50 + src/cmd/go/testdata/script/build_acl_windows.txt | 44 + src/cmd/go/testdata/script/build_arm.txt | 13 + .../go/testdata/script/build_cache_arch_mode.txt | 21 + src/cmd/go/testdata/script/build_cache_compile.txt | 21 + .../go/testdata/script/build_cache_disabled.txt | 50 + src/cmd/go/testdata/script/build_cache_gomips.txt | 40 + src/cmd/go/testdata/script/build_cache_link.txt | 26 + src/cmd/go/testdata/script/build_cache_output.txt | 67 + .../go/testdata/script/build_cache_trimpath.txt | 47 + .../testdata/script/build_cd_gopath_different.txt | 73 + .../script/build_cgo_consistent_results.txt | 23 + .../go/testdata/script/build_darwin_cc_arch.txt | 24 + src/cmd/go/testdata/script/build_dash_n_cgo.txt | 18 + .../go/testdata/script/build_dash_o_dev_null.txt | 13 + src/cmd/go/testdata/script/build_dash_x.txt | 49 + src/cmd/go/testdata/script/build_exe.txt | 25 + src/cmd/go/testdata/script/build_gcflags.txt | 22 + src/cmd/go/testdata/script/build_gopath_order.txt | 36 + src/cmd/go/testdata/script/build_i.txt | 41 + src/cmd/go/testdata/script/build_i_deprecate.txt | 24 + .../go/testdata/script/build_import_comment.txt | 68 + src/cmd/go/testdata/script/build_import_cycle.txt | 13 + src/cmd/go/testdata/script/build_internal.txt | 63 + src/cmd/go/testdata/script/build_issue6480.txt | 128 + .../script/build_link_x_import_path_escape.txt | 22 + src/cmd/go/testdata/script/build_multi_main.txt | 43 + src/cmd/go/testdata/script/build_n_cgo.txt | 17 + src/cmd/go/testdata/script/build_no_go.txt | 41 + src/cmd/go/testdata/script/build_nocache.txt | 40 + src/cmd/go/testdata/script/build_output.txt | 117 + src/cmd/go/testdata/script/build_overlay.txt | 308 ++ .../build_package_not_stale_trailing_slash.txt | 13 + .../script/build_patterns_outside_gopath.txt | 36 + .../go/testdata/script/build_plugin_non_main.txt | 13 + .../go/testdata/script/build_relative_pkgdir.txt | 9 + .../go/testdata/script/build_relative_tmpdir.txt | 18 + .../go/testdata/script/build_runtime_gcflags.txt | 11 + .../go/testdata/script/build_tag_goexperiment.txt | 104 + src/cmd/go/testdata/script/build_tags_no_comma.txt | 4 + src/cmd/go/testdata/script/build_test_only.txt | 19 + src/cmd/go/testdata/script/build_trimpath.txt | 162 + src/cmd/go/testdata/script/build_trimpath_cgo.txt | 184 ++ .../go/testdata/script/build_unsupported_goos.txt | 6 + src/cmd/go/testdata/script/build_vendor.txt | 42 + src/cmd/go/testdata/script/cache_unix.txt | 36 + src/cmd/go/testdata/script/cache_vet.txt | 22 + src/cmd/go/testdata/script/cgo_asm_error.txt | 25 + src/cmd/go/testdata/script/cgo_bad_directives.txt | 129 + .../go/testdata/script/cgo_depends_on_syscall.txt | 15 + .../go/testdata/script/cgo_flag_contains_space.txt | 16 + src/cmd/go/testdata/script/cgo_path.txt | 43 + src/cmd/go/testdata/script/cgo_path_space.txt | 56 + src/cmd/go/testdata/script/cgo_syso_issue29253.txt | 31 + src/cmd/go/testdata/script/clean_binary.txt | 78 + src/cmd/go/testdata/script/clean_cache_n.txt | 25 + src/cmd/go/testdata/script/clean_testcache.txt | 26 + src/cmd/go/testdata/script/cmd_import_error.txt | 16 + src/cmd/go/testdata/script/cover_asm.txt | 33 + src/cmd/go/testdata/script/cover_atomic_pkgall.txt | 25 + .../go/testdata/script/cover_blank_func_decl.txt | 35 + src/cmd/go/testdata/script/cover_cgo.txt | 42 + .../go/testdata/script/cover_cgo_extra_file.txt | 48 + .../go/testdata/script/cover_cgo_extra_test.txt | 49 + src/cmd/go/testdata/script/cover_cgo_xtest.txt | 45 + src/cmd/go/testdata/script/cover_dash_c.txt | 31 + src/cmd/go/testdata/script/cover_dep_loop.txt | 36 + src/cmd/go/testdata/script/cover_dot_import.txt | 29 + src/cmd/go/testdata/script/cover_error.txt | 74 + .../go/testdata/script/cover_import_main_loop.txt | 26 + src/cmd/go/testdata/script/cover_mod_empty.txt | 9 + src/cmd/go/testdata/script/cover_modes.txt | 25 + src/cmd/go/testdata/script/cover_pattern.txt | 41 + .../script/cover_pkgall_multiple_mains.txt | 46 + .../go/testdata/script/cover_pkgall_runtime.txt | 23 + src/cmd/go/testdata/script/cover_runs.txt | 13 + src/cmd/go/testdata/script/cover_statements.txt | 61 + .../testdata/script/cover_sync_atomic_import.txt | 28 + src/cmd/go/testdata/script/cpu_profile_twice.txt | 22 + src/cmd/go/testdata/script/devnull.txt | 26 + src/cmd/go/testdata/script/doc.txt | 75 + src/cmd/go/testdata/script/embed.txt | 109 + src/cmd/go/testdata/script/embed_fmt.txt | 22 + src/cmd/go/testdata/script/env_write.txt | 175 ++ src/cmd/go/testdata/script/fileline.txt | 8 + src/cmd/go/testdata/script/fmt_load_errors.txt | 19 + src/cmd/go/testdata/script/gccgo_link_c.txt | 16 + src/cmd/go/testdata/script/gccgo_m.txt | 19 + src/cmd/go/testdata/script/gccgo_mangle.txt | 15 + src/cmd/go/testdata/script/gcflags_patterns.txt | 92 + src/cmd/go/testdata/script/generate.txt | 91 + .../go/testdata/script/generate_bad_imports.txt | 15 + src/cmd/go/testdata/script/generate_env.txt | 32 + src/cmd/go/testdata/script/generate_invalid.txt | 203 ++ src/cmd/go/testdata/script/get_404_meta.txt | 11 + src/cmd/go/testdata/script/get_brace.txt | 51 + .../testdata/script/get_custom_domain_wildcard.txt | 6 + src/cmd/go/testdata/script/get_dash_t.txt | 9 + src/cmd/go/testdata/script/get_domain_root.txt | 20 + .../go/testdata/script/get_dot_slash_download.txt | 10 + src/cmd/go/testdata/script/get_dotfiles.txt | 64 + src/cmd/go/testdata/script/get_go_file.txt | 60 + src/cmd/go/testdata/script/get_goroot.txt | 53 + src/cmd/go/testdata/script/get_insecure.txt | 51 + .../testdata/script/get_insecure_custom_domain.txt | 6 + .../go/testdata/script/get_insecure_deprecated.txt | 21 + src/cmd/go/testdata/script/get_insecure_env.txt | 29 + .../go/testdata/script/get_insecure_redirect.txt | 12 + src/cmd/go/testdata/script/get_insecure_update.txt | 12 + .../go/testdata/script/get_internal_wildcard.txt | 6 + src/cmd/go/testdata/script/get_issue11307.txt | 9 + src/cmd/go/testdata/script/get_legacy.txt | 58 + src/cmd/go/testdata/script/get_non_pkg.txt | 14 + src/cmd/go/testdata/script/get_race.txt | 8 + src/cmd/go/testdata/script/get_test_only.txt | 6 + src/cmd/go/testdata/script/get_tilde.txt | 24 + src/cmd/go/testdata/script/get_update.txt | 25 + src/cmd/go/testdata/script/get_update_all.txt | 9 + .../script/get_update_unknown_protocol.txt | 14 + src/cmd/go/testdata/script/get_update_wildcard.txt | 16 + .../go/testdata/script/get_vcs_error_message.txt | 9 + src/cmd/go/testdata/script/get_vendor.txt | 95 + src/cmd/go/testdata/script/get_with_git_trace.txt | 9 + src/cmd/go/testdata/script/goflags.txt | 59 + src/cmd/go/testdata/script/gopath_install.txt | 53 + src/cmd/go/testdata/script/gopath_local.txt | 117 + src/cmd/go/testdata/script/gopath_moved_repo.txt | 67 + src/cmd/go/testdata/script/gopath_paths.txt | 43 + src/cmd/go/testdata/script/gopath_std_vendor.txt | 44 + .../go/testdata/script/gopath_vendor_dup_err.txt | 25 + src/cmd/go/testdata/script/goroot_executable.txt | 111 + src/cmd/go/testdata/script/govcs.txt | 174 + src/cmd/go/testdata/script/help.txt | 51 + src/cmd/go/testdata/script/import_cycle.txt | 12 + src/cmd/go/testdata/script/import_ignore.txt | 11 + src/cmd/go/testdata/script/import_main.txt | 114 + .../go/testdata/script/install_cgo_excluded.txt | 15 + .../go/testdata/script/install_cleans_build.txt | 25 + src/cmd/go/testdata/script/install_cmd_gobin.txt | 10 + src/cmd/go/testdata/script/install_cross_gobin.txt | 25 + .../script/install_msan_and_race_require_cgo.txt | 18 + .../go/testdata/script/install_rebuild_gopath.txt | 30 + .../go/testdata/script/install_rebuild_removed.txt | 44 + .../script/install_relative_gobin_fail.txt | 12 + .../go/testdata/script/install_shadow_gopath.txt | 20 + src/cmd/go/testdata/script/issue36000.txt | 6 + src/cmd/go/testdata/script/ldflag.txt | 44 + .../go/testdata/script/link_matching_actionid.txt | 38 + .../go/testdata/script/link_syso_issue33139.txt | 43 + src/cmd/go/testdata/script/linkname.txt | 9 + src/cmd/go/testdata/script/list_ambiguous_path.txt | 38 + src/cmd/go/testdata/script/list_bad_import.txt | 72 + src/cmd/go/testdata/script/list_case_collision.txt | 41 + .../go/testdata/script/list_compiled_imports.txt | 31 + src/cmd/go/testdata/script/list_constraints.txt | 86 + src/cmd/go/testdata/script/list_dedup_packages.txt | 31 + src/cmd/go/testdata/script/list_err_cycle.txt | 15 + src/cmd/go/testdata/script/list_err_stack.txt | 27 + src/cmd/go/testdata/script/list_find.txt | 22 + .../go/testdata/script/list_gofile_in_goroot.txt | 76 + src/cmd/go/testdata/script/list_importmap.txt | 27 + src/cmd/go/testdata/script/list_linkshared.txt | 16 + src/cmd/go/testdata/script/list_load_err.txt | 79 + src/cmd/go/testdata/script/list_overlay.txt | 63 + src/cmd/go/testdata/script/list_parse_err.txt | 45 + src/cmd/go/testdata/script/list_permissions.txt | 84 + src/cmd/go/testdata/script/list_shadow.txt | 25 + src/cmd/go/testdata/script/list_split_main.txt | 25 + src/cmd/go/testdata/script/list_std.txt | 25 + src/cmd/go/testdata/script/list_symlink.txt | 12 + .../go/testdata/script/list_symlink_internal.txt | 27 + .../script/list_symlink_vendor_issue14054.txt | 28 + .../script/list_symlink_vendor_issue15201.txt | 21 + src/cmd/go/testdata/script/list_test_e.txt | 11 + src/cmd/go/testdata/script/list_test_err.txt | 129 + src/cmd/go/testdata/script/list_test_imports.txt | 21 + .../go/testdata/script/list_test_non_go_files.txt | 13 + src/cmd/go/testdata/script/list_test_simple.txt | 67 + .../script/list_wildcard_skip_nonmatching.txt | 17 + src/cmd/go/testdata/script/load_test_pkg_err.txt | 30 + src/cmd/go/testdata/script/mod_all.txt | 444 +++ src/cmd/go/testdata/script/mod_alt_goroot.txt | 20 + .../go/testdata/script/mod_ambiguous_import.txt | 48 + src/cmd/go/testdata/script/mod_auth.txt | 35 + src/cmd/go/testdata/script/mod_bad_domain.txt | 47 + src/cmd/go/testdata/script/mod_bad_filenames.txt | 11 + src/cmd/go/testdata/script/mod_build_info_err.txt | 33 + src/cmd/go/testdata/script/mod_build_tags.txt | 33 + src/cmd/go/testdata/script/mod_build_versioned.txt | 17 + src/cmd/go/testdata/script/mod_cache_rw.txt | 49 + src/cmd/go/testdata/script/mod_case.txt | 25 + src/cmd/go/testdata/script/mod_case_cgo.txt | 11 + src/cmd/go/testdata/script/mod_clean_cache.txt | 58 + src/cmd/go/testdata/script/mod_concurrent.txt | 32 + src/cmd/go/testdata/script/mod_convert_dep.txt | 30 + src/cmd/go/testdata/script/mod_convert_git.txt | 40 + src/cmd/go/testdata/script/mod_convert_glide.txt | 18 + .../go/testdata/script/mod_convert_glockfile.txt | 18 + src/cmd/go/testdata/script/mod_convert_godeps.txt | 19 + src/cmd/go/testdata/script/mod_convert_tsv.txt | 18 + .../testdata/script/mod_convert_tsv_insecure.txt | 27 + .../go/testdata/script/mod_convert_vendor_conf.txt | 18 + .../go/testdata/script/mod_convert_vendor_json.txt | 19 + .../script/mod_convert_vendor_manifest.txt | 19 + .../go/testdata/script/mod_convert_vendor_yml.txt | 18 + src/cmd/go/testdata/script/mod_dir.txt | 20 + src/cmd/go/testdata/script/mod_doc.txt | 89 + src/cmd/go/testdata/script/mod_domain_root.txt | 12 + src/cmd/go/testdata/script/mod_dot.txt | 131 + src/cmd/go/testdata/script/mod_download.txt | 170 + .../script/mod_download_concurrent_read.txt | 110 + src/cmd/go/testdata/script/mod_download_hash.txt | 24 + src/cmd/go/testdata/script/mod_download_json.txt | 9 + .../go/testdata/script/mod_download_partial.txt | 68 + .../testdata/script/mod_download_replace_file.txt | 16 + src/cmd/go/testdata/script/mod_e.txt | 89 + src/cmd/go/testdata/script/mod_edit.txt | 303 ++ src/cmd/go/testdata/script/mod_edit_go.txt | 23 + src/cmd/go/testdata/script/mod_empty_err.txt | 36 + src/cmd/go/testdata/script/mod_enabled.txt | 93 + src/cmd/go/testdata/script/mod_file_proxy.txt | 36 + src/cmd/go/testdata/script/mod_find.txt | 104 + src/cmd/go/testdata/script/mod_fs_patterns.txt | 97 + .../go/testdata/script/mod_get_ambiguous_arg.txt | 107 + .../testdata/script/mod_get_ambiguous_import.txt | 60 + .../go/testdata/script/mod_get_ambiguous_pkg.txt | 87 + src/cmd/go/testdata/script/mod_get_changes.txt | 70 + src/cmd/go/testdata/script/mod_get_cmd.txt | 20 + src/cmd/go/testdata/script/mod_get_commit.txt | 51 + src/cmd/go/testdata/script/mod_get_direct.txt | 20 + src/cmd/go/testdata/script/mod_get_downgrade.txt | 56 + .../testdata/script/mod_get_downgrade_missing.txt | 43 + src/cmd/go/testdata/script/mod_get_errors.txt | 69 + src/cmd/go/testdata/script/mod_get_extra.txt | 69 + src/cmd/go/testdata/script/mod_get_fallback.txt | 10 + src/cmd/go/testdata/script/mod_get_fossil.txt | 29 + src/cmd/go/testdata/script/mod_get_go_file.txt | 68 + src/cmd/go/testdata/script/mod_get_hash.txt | 19 + .../go/testdata/script/mod_get_incompatible.txt | 26 + src/cmd/go/testdata/script/mod_get_indirect.txt | 59 + .../testdata/script/mod_get_insecure_redirect.txt | 34 + src/cmd/go/testdata/script/mod_get_issue37438.txt | 37 + .../go/testdata/script/mod_get_latest_pseudo.txt | 10 + src/cmd/go/testdata/script/mod_get_local.txt | 62 + src/cmd/go/testdata/script/mod_get_main.txt | 51 + src/cmd/go/testdata/script/mod_get_major.txt | 23 + .../go/testdata/script/mod_get_missing_ziphash.txt | 55 + src/cmd/go/testdata/script/mod_get_moved.txt | 40 + src/cmd/go/testdata/script/mod_get_newcycle.txt | 14 + src/cmd/go/testdata/script/mod_get_none.txt | 12 + src/cmd/go/testdata/script/mod_get_nopkgs.txt | 40 + src/cmd/go/testdata/script/mod_get_patch.txt | 130 + src/cmd/go/testdata/script/mod_get_patchbound.txt | 84 + src/cmd/go/testdata/script/mod_get_patchcycle.txt | 64 + src/cmd/go/testdata/script/mod_get_patchmod.txt | 82 + src/cmd/go/testdata/script/mod_get_patterns.txt | 42 + src/cmd/go/testdata/script/mod_get_pkgtags.txt | 116 + .../script/mod_get_prefer_incompatible.txt | 29 + src/cmd/go/testdata/script/mod_get_private_vcs.txt | 11 + .../testdata/script/mod_get_promote_implicit.txt | 92 + src/cmd/go/testdata/script/mod_get_pseudo.txt | 82 + .../script/mod_get_pseudo_other_branch.txt | 67 + .../go/testdata/script/mod_get_pseudo_prefix.txt | 64 + src/cmd/go/testdata/script/mod_get_replaced.txt | 111 + src/cmd/go/testdata/script/mod_get_retract.txt | 59 + .../testdata/script/mod_get_retract_ambiguous.txt | 10 + src/cmd/go/testdata/script/mod_get_split.txt | 157 + src/cmd/go/testdata/script/mod_get_sum_noroot.txt | 11 + src/cmd/go/testdata/script/mod_get_svn.txt | 36 + src/cmd/go/testdata/script/mod_get_tags.txt | 45 + src/cmd/go/testdata/script/mod_get_test.txt | 58 + .../testdata/script/mod_get_too_many_redirects.txt | 10 + .../go/testdata/script/mod_get_trailing_slash.txt | 37 + src/cmd/go/testdata/script/mod_get_upgrade.txt | 46 + .../go/testdata/script/mod_get_upgrade_pseudo.txt | 70 + src/cmd/go/testdata/script/mod_get_wild.txt | 95 + src/cmd/go/testdata/script/mod_getmode_vendor.txt | 30 + src/cmd/go/testdata/script/mod_getx.txt | 14 + .../go/testdata/script/mod_git_export_subst.txt | 21 + src/cmd/go/testdata/script/mod_go_version.txt | 110 + .../go/testdata/script/mod_go_version_mixed.txt | 43 + src/cmd/go/testdata/script/mod_gobuild_import.txt | 133 + src/cmd/go/testdata/script/mod_gofmt_invalid.txt | 13 + src/cmd/go/testdata/script/mod_gomodcache.txt | 60 + src/cmd/go/testdata/script/mod_gonoproxy.txt | 54 + src/cmd/go/testdata/script/mod_gopkg_unstable.txt | 24 + src/cmd/go/testdata/script/mod_goroot_errors.txt | 53 + src/cmd/go/testdata/script/mod_graph.txt | 10 + src/cmd/go/testdata/script/mod_help.txt | 6 + src/cmd/go/testdata/script/mod_import.txt | 18 + src/cmd/go/testdata/script/mod_import_cycle.txt | 40 + .../go/testdata/script/mod_import_issue41113.txt | 28 + .../go/testdata/script/mod_import_issue42891.txt | 14 + src/cmd/go/testdata/script/mod_import_meta.txt | 45 + src/cmd/go/testdata/script/mod_import_mod.txt | 7 + src/cmd/go/testdata/script/mod_import_v1suffix.txt | 11 + src/cmd/go/testdata/script/mod_in_testdata_dir.txt | 45 + src/cmd/go/testdata/script/mod_indirect.txt | 81 + src/cmd/go/testdata/script/mod_indirect_main.txt | 65 + src/cmd/go/testdata/script/mod_indirect_tidy.txt | 60 + src/cmd/go/testdata/script/mod_init_dep.txt | 44 + src/cmd/go/testdata/script/mod_init_empty.txt | 18 + src/cmd/go/testdata/script/mod_init_glide.txt | 34 + src/cmd/go/testdata/script/mod_init_path.txt | 20 + src/cmd/go/testdata/script/mod_init_tidy.txt | 30 + src/cmd/go/testdata/script/mod_install_hint.txt | 5 + .../go/testdata/script/mod_install_pkg_version.txt | 203 ++ .../go/testdata/script/mod_install_versioned.txt | 14 + src/cmd/go/testdata/script/mod_internal.txt | 96 + src/cmd/go/testdata/script/mod_invalid_path.txt | 64 + .../go/testdata/script/mod_invalid_path_plus.txt | 32 + src/cmd/go/testdata/script/mod_invalid_version.txt | 251 ++ src/cmd/go/testdata/script/mod_issue35317.txt | 8 + src/cmd/go/testdata/script/mod_lazy_downgrade.txt | 145 + .../go/testdata/script/mod_lazy_import_allmod.txt | 172 + src/cmd/go/testdata/script/mod_lazy_new_import.txt | 107 + .../go/testdata/script/mod_lazy_test_horizon.txt | 131 + .../testdata/script/mod_lazy_test_of_test_dep.txt | 145 + src/cmd/go/testdata/script/mod_list.txt | 61 + src/cmd/go/testdata/script/mod_list_bad_import.txt | 75 + .../script/mod_list_compiled_concurrent.txt | 41 + src/cmd/go/testdata/script/mod_list_dir.txt | 36 + src/cmd/go/testdata/script/mod_list_direct.txt | 24 + src/cmd/go/testdata/script/mod_list_e_readonly.txt | 15 + src/cmd/go/testdata/script/mod_list_pseudo.txt | 39 + .../go/testdata/script/mod_list_replace_dir.txt | 27 + src/cmd/go/testdata/script/mod_list_retract.txt | 108 + src/cmd/go/testdata/script/mod_list_std.txt | 90 + src/cmd/go/testdata/script/mod_list_test.txt | 30 + src/cmd/go/testdata/script/mod_list_upgrade.txt | 12 + .../go/testdata/script/mod_list_upgrade_pseudo.txt | 26 + src/cmd/go/testdata/script/mod_load_badchain.txt | 103 + src/cmd/go/testdata/script/mod_load_badmod.txt | 25 + src/cmd/go/testdata/script/mod_load_badzip.txt | 13 + .../testdata/script/mod_load_replace_mismatch.txt | 23 + src/cmd/go/testdata/script/mod_local_replace.txt | 23 + src/cmd/go/testdata/script/mod_missing_repo.txt | 15 + .../testdata/script/mod_missingpkg_prerelease.txt | 17 + src/cmd/go/testdata/script/mod_modinfo.txt | 89 + src/cmd/go/testdata/script/mod_multirepo.txt | 41 + src/cmd/go/testdata/script/mod_nomod.txt | 43 + src/cmd/go/testdata/script/mod_notall.txt | 99 + src/cmd/go/testdata/script/mod_off.txt | 35 + src/cmd/go/testdata/script/mod_off_init.txt | 5 + src/cmd/go/testdata/script/mod_outside.txt | 328 ++ src/cmd/go/testdata/script/mod_overlay.txt | 254 ++ src/cmd/go/testdata/script/mod_patterns.txt | 78 + src/cmd/go/testdata/script/mod_patterns_vendor.txt | 28 + src/cmd/go/testdata/script/mod_permissions.txt | 57 + .../go/testdata/script/mod_prefer_compatible.txt | 65 + src/cmd/go/testdata/script/mod_proxy_errors.txt | 19 + src/cmd/go/testdata/script/mod_proxy_https.txt | 19 + src/cmd/go/testdata/script/mod_proxy_invalid.txt | 8 + src/cmd/go/testdata/script/mod_proxy_list.txt | 37 + src/cmd/go/testdata/script/mod_pseudo_cache.txt | 29 + src/cmd/go/testdata/script/mod_query.txt | 43 + src/cmd/go/testdata/script/mod_query_empty.txt | 73 + src/cmd/go/testdata/script/mod_query_exclude.txt | 46 + src/cmd/go/testdata/script/mod_query_main.txt | 43 + src/cmd/go/testdata/script/mod_readonly.txt | 131 + src/cmd/go/testdata/script/mod_replace.txt | 129 + src/cmd/go/testdata/script/mod_replace_gopkgin.txt | 80 + src/cmd/go/testdata/script/mod_replace_import.txt | 144 + .../go/testdata/script/mod_replace_readonly.txt | 62 + src/cmd/go/testdata/script/mod_require_exclude.txt | 81 + src/cmd/go/testdata/script/mod_retention.txt | 145 + src/cmd/go/testdata/script/mod_retract.txt | 45 + .../go/testdata/script/mod_retract_fix_version.txt | 48 + .../testdata/script/mod_retract_incompatible.txt | 15 + .../go/testdata/script/mod_retract_pseudo_base.txt | 62 + .../go/testdata/script/mod_retract_rationale.txt | 79 + src/cmd/go/testdata/script/mod_retract_rename.txt | 28 + src/cmd/go/testdata/script/mod_retract_replace.txt | 61 + src/cmd/go/testdata/script/mod_run_path.txt | 15 + src/cmd/go/testdata/script/mod_std_vendor.txt | 78 + src/cmd/go/testdata/script/mod_string_alias.txt | 14 + src/cmd/go/testdata/script/mod_sum_ambiguous.txt | 62 + src/cmd/go/testdata/script/mod_sum_lookup.txt | 34 + src/cmd/go/testdata/script/mod_sum_readonly.txt | 87 + src/cmd/go/testdata/script/mod_sum_replaced.txt | 28 + src/cmd/go/testdata/script/mod_sumdb.txt | 39 + src/cmd/go/testdata/script/mod_sumdb_cache.txt | 54 + src/cmd/go/testdata/script/mod_sumdb_file_path.txt | 56 + src/cmd/go/testdata/script/mod_sumdb_golang.txt | 54 + src/cmd/go/testdata/script/mod_sumdb_proxy.txt | 65 + src/cmd/go/testdata/script/mod_symlink.txt | 45 + src/cmd/go/testdata/script/mod_symlink_dotgo.txt | 17 + .../go/testdata/script/mod_tagged_import_cycle.txt | 106 + src/cmd/go/testdata/script/mod_test.txt | 128 + src/cmd/go/testdata/script/mod_test_cached.txt | 76 + src/cmd/go/testdata/script/mod_test_files.txt | 50 + src/cmd/go/testdata/script/mod_tidy.txt | 72 + src/cmd/go/testdata/script/mod_tidy_cycle.txt | 75 + src/cmd/go/testdata/script/mod_tidy_error.txt | 39 + src/cmd/go/testdata/script/mod_tidy_old.txt | 46 + src/cmd/go/testdata/script/mod_tidy_quote.txt | 26 + src/cmd/go/testdata/script/mod_tidy_replace.txt | 138 + src/cmd/go/testdata/script/mod_tidy_sum.txt | 33 + src/cmd/go/testdata/script/mod_tidy_too_new.txt | 48 + src/cmd/go/testdata/script/mod_upgrade_patch.txt | 110 + src/cmd/go/testdata/script/mod_vcs_missing.txt | 28 + src/cmd/go/testdata/script/mod_vendor.txt | 312 ++ src/cmd/go/testdata/script/mod_vendor_auto.txt | 256 ++ src/cmd/go/testdata/script/mod_vendor_build.txt | 41 + src/cmd/go/testdata/script/mod_vendor_embed.txt | 179 ++ src/cmd/go/testdata/script/mod_vendor_nodeps.txt | 9 + src/cmd/go/testdata/script/mod_vendor_replace.txt | 66 + src/cmd/go/testdata/script/mod_vendor_trimpath.txt | 45 + src/cmd/go/testdata/script/mod_vendor_unused.txt | 67 + .../go/testdata/script/mod_vendor_unused_only.txt | 17 + src/cmd/go/testdata/script/mod_verify.txt | 87 + src/cmd/go/testdata/script/mod_versions.txt | 14 + src/cmd/go/testdata/script/mod_why.txt | 130 + src/cmd/go/testdata/script/modfile_flag.txt | 93 + src/cmd/go/testdata/script/noncanonical_import.txt | 19 + .../go/testdata/script/pattern_syntax_error.txt | 12 + .../go/testdata/script/prevent_sys_unix_import.txt | 6 + src/cmd/go/testdata/script/run_dirs.txt | 11 + src/cmd/go/testdata/script/run_hello.txt | 9 + src/cmd/go/testdata/script/run_hello_pkg.txt | 17 + src/cmd/go/testdata/script/run_internal.txt | 64 + src/cmd/go/testdata/script/run_issue11709.txt | 15 + .../go/testdata/script/run_set_executable_name.txt | 50 + src/cmd/go/testdata/script/run_vendor.txt | 34 + src/cmd/go/testdata/script/run_wildcard.txt | 7 + src/cmd/go/testdata/script/script_wait.txt | 25 + src/cmd/go/testdata/script/std_vendor.txt | 43 + src/cmd/go/testdata/script/test_bad_example.txt | 13 + src/cmd/go/testdata/script/test_badtest.txt | 49 + .../testdata/script/test_benchmark_chatty_fail.txt | 32 + .../script/test_benchmark_chatty_success.txt | 29 + .../go/testdata/script/test_benchmark_fatal.txt | 19 + .../go/testdata/script/test_benchmark_labels.txt | 23 + .../go/testdata/script/test_benchmark_timeout.txt | 18 + src/cmd/go/testdata/script/test_build_failure.txt | 31 + src/cmd/go/testdata/script/test_cache_inputs.txt | 251 ++ src/cmd/go/testdata/script/test_chatty_fail.txt | 32 + .../testdata/script/test_chatty_parallel_fail.txt | 58 + .../script/test_chatty_parallel_success.txt | 52 + .../script/test_chatty_parallel_success_sleepy.txt | 39 + src/cmd/go/testdata/script/test_chatty_success.txt | 27 + .../go/testdata/script/test_cleanup_failnow.txt | 47 + src/cmd/go/testdata/script/test_compile_binary.txt | 8 + .../go/testdata/script/test_compile_tempfile.txt | 11 + src/cmd/go/testdata/script/test_deadline.txt | 54 + src/cmd/go/testdata/script/test_empty.txt | 53 + src/cmd/go/testdata/script/test_env_term.txt | 15 + src/cmd/go/testdata/script/test_example_goexit.txt | 29 + src/cmd/go/testdata/script/test_exit.txt | 131 + src/cmd/go/testdata/script/test_fail_fast.txt | 113 + src/cmd/go/testdata/script/test_flag.txt | 40 + src/cmd/go/testdata/script/test_flags.txt | 132 + src/cmd/go/testdata/script/test_generated_main.txt | 34 + .../go/testdata/script/test_go111module_cache.txt | 15 + .../go/testdata/script/test_import_error_stack.txt | 31 + src/cmd/go/testdata/script/test_json.txt | 74 + src/cmd/go/testdata/script/test_json_exit.txt | 102 + .../go/testdata/script/test_json_interleaved.txt | 27 + .../go/testdata/script/test_json_panic_exit.txt | 69 + src/cmd/go/testdata/script/test_main.txt | 92 + src/cmd/go/testdata/script/test_main_archive.txt | 32 + src/cmd/go/testdata/script/test_main_panic.txt | 30 + src/cmd/go/testdata/script/test_main_twice.txt | 27 + .../script/test_match_benchmark_labels.txt | 18 + .../testdata/script/test_match_no_benchmarks.txt | 13 + .../go/testdata/script/test_match_no_subtests.txt | 12 + .../script/test_match_no_subtests_failure.txt | 15 + .../script/test_match_no_subtests_parallel.txt | 19 + src/cmd/go/testdata/script/test_match_no_tests.txt | 11 + .../script/test_match_no_tests_build_failure.txt | 19 + .../script/test_match_no_tests_with_subtests.txt | 12 + .../testdata/script/test_match_only_benchmarks.txt | 13 + .../go/testdata/script/test_match_only_example.txt | 31 + .../testdata/script/test_match_only_subtests.txt | 14 + .../script/test_match_only_subtests_parallel.txt | 21 + .../go/testdata/script/test_match_only_tests.txt | 13 + src/cmd/go/testdata/script/test_minus_n.txt | 14 + src/cmd/go/testdata/script/test_no_run_example.txt | 30 + src/cmd/go/testdata/script/test_no_tests.txt | 15 + .../go/testdata/script/test_parallel_number.txt | 25 + src/cmd/go/testdata/script/test_profile.txt | 19 + src/cmd/go/testdata/script/test_race.txt | 51 + .../script/test_race_cover_mode_issue20435.txt | 48 + src/cmd/go/testdata/script/test_race_install.txt | 18 + .../go/testdata/script/test_race_install_cgo.txt | 93 + src/cmd/go/testdata/script/test_rebuildall.txt | 14 + src/cmd/go/testdata/script/test_regexps.txt | 79 + .../go/testdata/script/test_relative_cmdline.txt | 50 + .../go/testdata/script/test_relative_import.txt | 31 + .../script/test_relative_import_dash_i.txt | 32 + src/cmd/go/testdata/script/test_source_order.txt | 54 + src/cmd/go/testdata/script/test_status.txt | 18 + .../script/test_syntax_error_says_fail.txt | 25 + src/cmd/go/testdata/script/test_timeout.txt | 23 + src/cmd/go/testdata/script/test_vendor.txt | 57 + src/cmd/go/testdata/script/test_vet.txt | 92 + .../script/test_write_profiles_on_timeout.txt | 17 + .../go/testdata/script/test_xtestonly_works.txt | 27 + src/cmd/go/testdata/script/testing_issue40908.txt | 25 + src/cmd/go/testdata/script/toolexec.txt | 85 + src/cmd/go/testdata/script/vendor_complex.txt | 75 + .../testdata/script/vendor_gopath_issue11409.txt | 52 + src/cmd/go/testdata/script/vendor_import.txt | 104 + .../go/testdata/script/vendor_import_missing.txt | 7 + src/cmd/go/testdata/script/vendor_import_wrong.txt | 20 + src/cmd/go/testdata/script/vendor_issue12156.txt | 16 + .../go/testdata/script/vendor_list_issue11977.txt | 17 + src/cmd/go/testdata/script/vendor_resolve.txt | 21 + .../go/testdata/script/vendor_test_issue11864.txt | 20 + .../go/testdata/script/vendor_test_issue14613.txt | 22 + src/cmd/go/testdata/script/version.txt | 52 + src/cmd/go/testdata/script/version_replace.txt | 33 + src/cmd/go/testdata/script/vet.txt | 62 + src/cmd/go/testdata/script/vet_asm.txt | 32 + src/cmd/go/testdata/script/vet_deps.txt | 34 + src/cmd/go/testdata/script/vet_flags.txt | 93 + src/cmd/go/testdata/script/vet_internal.txt | 71 + .../go/testdata/testterminal18153/terminal_test.go | 39 + src/cmd/go/testdata/vendormod.txt | 160 + 938 files changed, 97301 insertions(+) create mode 100644 src/cmd/go/alldocs.go create mode 100644 src/cmd/go/go11.go create mode 100644 src/cmd/go/go_test.go create mode 100644 src/cmd/go/go_unix_test.go create mode 100644 src/cmd/go/go_windows_test.go create mode 100644 src/cmd/go/help_test.go create mode 100644 src/cmd/go/init_test.go create mode 100644 src/cmd/go/internal/auth/auth.go create mode 100644 src/cmd/go/internal/auth/netrc.go create mode 100644 src/cmd/go/internal/auth/netrc_test.go create mode 100644 src/cmd/go/internal/base/base.go create mode 100644 src/cmd/go/internal/base/env.go create mode 100644 src/cmd/go/internal/base/flag.go create mode 100644 src/cmd/go/internal/base/goflags.go create mode 100644 src/cmd/go/internal/base/path.go create mode 100644 src/cmd/go/internal/base/signal.go create mode 100644 src/cmd/go/internal/base/signal_notunix.go create mode 100644 src/cmd/go/internal/base/signal_unix.go create mode 100644 src/cmd/go/internal/base/tool.go create mode 100644 src/cmd/go/internal/bug/bug.go create mode 100644 src/cmd/go/internal/cache/cache.go create mode 100644 src/cmd/go/internal/cache/cache_test.go create mode 100644 src/cmd/go/internal/cache/default.go create mode 100644 src/cmd/go/internal/cache/hash.go create mode 100644 src/cmd/go/internal/cache/hash_test.go create mode 100644 src/cmd/go/internal/cfg/cfg.go create mode 100644 src/cmd/go/internal/clean/clean.go create mode 100644 src/cmd/go/internal/cmdflag/flag.go create mode 100644 src/cmd/go/internal/doc/doc.go create mode 100644 src/cmd/go/internal/envcmd/env.go create mode 100644 src/cmd/go/internal/fix/fix.go create mode 100644 src/cmd/go/internal/fmtcmd/fmt.go create mode 100644 src/cmd/go/internal/fsys/fsys.go create mode 100644 src/cmd/go/internal/fsys/fsys_test.go create mode 100644 src/cmd/go/internal/generate/generate.go create mode 100644 src/cmd/go/internal/generate/generate_test.go create mode 100644 src/cmd/go/internal/get/get.go create mode 100644 src/cmd/go/internal/get/tag_test.go create mode 100644 src/cmd/go/internal/help/help.go create mode 100644 src/cmd/go/internal/help/helpdoc.go create mode 100644 src/cmd/go/internal/imports/build.go create mode 100644 src/cmd/go/internal/imports/read.go create mode 100644 src/cmd/go/internal/imports/read_test.go create mode 100644 src/cmd/go/internal/imports/scan.go create mode 100644 src/cmd/go/internal/imports/scan_test.go create mode 100644 src/cmd/go/internal/imports/tags.go create mode 100644 src/cmd/go/internal/imports/testdata/android/.h.go create mode 100644 src/cmd/go/internal/imports/testdata/android/a_android.go create mode 100644 src/cmd/go/internal/imports/testdata/android/b_android_arm64.go create mode 100644 src/cmd/go/internal/imports/testdata/android/c_linux.go create mode 100644 src/cmd/go/internal/imports/testdata/android/d_linux_arm64.go create mode 100644 src/cmd/go/internal/imports/testdata/android/e.go create mode 100644 src/cmd/go/internal/imports/testdata/android/f.go create mode 100644 src/cmd/go/internal/imports/testdata/android/g.go create mode 100644 src/cmd/go/internal/imports/testdata/android/tags.txt create mode 100644 src/cmd/go/internal/imports/testdata/android/want.txt create mode 100644 src/cmd/go/internal/imports/testdata/illumos/.h.go create mode 100644 src/cmd/go/internal/imports/testdata/illumos/a_illumos.go create mode 100644 src/cmd/go/internal/imports/testdata/illumos/b_illumos_amd64.go create mode 100644 src/cmd/go/internal/imports/testdata/illumos/c_solaris.go create mode 100644 src/cmd/go/internal/imports/testdata/illumos/d_solaris_amd64.go create mode 100644 src/cmd/go/internal/imports/testdata/illumos/e.go create mode 100644 src/cmd/go/internal/imports/testdata/illumos/f.go create mode 100644 src/cmd/go/internal/imports/testdata/illumos/g.go create mode 100644 src/cmd/go/internal/imports/testdata/illumos/tags.txt create mode 100644 src/cmd/go/internal/imports/testdata/illumos/want.txt create mode 100644 src/cmd/go/internal/imports/testdata/star/tags.txt create mode 100644 src/cmd/go/internal/imports/testdata/star/want.txt create mode 100644 src/cmd/go/internal/imports/testdata/star/x.go create mode 100644 src/cmd/go/internal/imports/testdata/star/x1.go create mode 100644 src/cmd/go/internal/imports/testdata/star/x_darwin.go create mode 100644 src/cmd/go/internal/imports/testdata/star/x_windows.go create mode 100644 src/cmd/go/internal/list/context.go create mode 100644 src/cmd/go/internal/list/list.go create mode 100644 src/cmd/go/internal/load/flag.go create mode 100644 src/cmd/go/internal/load/flag_test.go create mode 100644 src/cmd/go/internal/load/path.go create mode 100644 src/cmd/go/internal/load/pkg.go create mode 100644 src/cmd/go/internal/load/pkg_test.go create mode 100644 src/cmd/go/internal/load/search.go create mode 100644 src/cmd/go/internal/load/test.go create mode 100644 src/cmd/go/internal/lockedfile/internal/filelock/filelock.go create mode 100644 src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go create mode 100644 src/cmd/go/internal/lockedfile/internal/filelock/filelock_other.go create mode 100644 src/cmd/go/internal/lockedfile/internal/filelock/filelock_plan9.go create mode 100644 src/cmd/go/internal/lockedfile/internal/filelock/filelock_test.go create mode 100644 src/cmd/go/internal/lockedfile/internal/filelock/filelock_unix.go create mode 100644 src/cmd/go/internal/lockedfile/internal/filelock/filelock_windows.go create mode 100644 src/cmd/go/internal/lockedfile/lockedfile.go create mode 100644 src/cmd/go/internal/lockedfile/lockedfile_filelock.go create mode 100644 src/cmd/go/internal/lockedfile/lockedfile_plan9.go create mode 100644 src/cmd/go/internal/lockedfile/lockedfile_test.go create mode 100644 src/cmd/go/internal/lockedfile/mutex.go create mode 100644 src/cmd/go/internal/lockedfile/transform_test.go create mode 100644 src/cmd/go/internal/modcmd/download.go create mode 100644 src/cmd/go/internal/modcmd/edit.go create mode 100644 src/cmd/go/internal/modcmd/graph.go create mode 100644 src/cmd/go/internal/modcmd/init.go create mode 100644 src/cmd/go/internal/modcmd/mod.go create mode 100644 src/cmd/go/internal/modcmd/tidy.go create mode 100644 src/cmd/go/internal/modcmd/vendor.go create mode 100644 src/cmd/go/internal/modcmd/verify.go create mode 100644 src/cmd/go/internal/modcmd/why.go create mode 100644 src/cmd/go/internal/modconv/convert.go create mode 100644 src/cmd/go/internal/modconv/convert_test.go create mode 100644 src/cmd/go/internal/modconv/dep.go create mode 100644 src/cmd/go/internal/modconv/glide.go create mode 100644 src/cmd/go/internal/modconv/glock.go create mode 100644 src/cmd/go/internal/modconv/godeps.go create mode 100644 src/cmd/go/internal/modconv/modconv.go create mode 100644 src/cmd/go/internal/modconv/modconv_test.go create mode 100644 src/cmd/go/internal/modconv/testdata/cockroach.glock create mode 100644 src/cmd/go/internal/modconv/testdata/cockroach.out create mode 100644 src/cmd/go/internal/modconv/testdata/dockermachine.godeps create mode 100644 src/cmd/go/internal/modconv/testdata/dockermachine.out create mode 100644 src/cmd/go/internal/modconv/testdata/dockerman.glide create mode 100644 src/cmd/go/internal/modconv/testdata/dockerman.out create mode 100644 src/cmd/go/internal/modconv/testdata/govmomi.out create mode 100644 src/cmd/go/internal/modconv/testdata/govmomi.vmanifest create mode 100644 src/cmd/go/internal/modconv/testdata/juju.out create mode 100644 src/cmd/go/internal/modconv/testdata/juju.tsv create mode 100644 src/cmd/go/internal/modconv/testdata/moby.out create mode 100644 src/cmd/go/internal/modconv/testdata/moby.vconf create mode 100644 src/cmd/go/internal/modconv/testdata/panicparse.out create mode 100644 src/cmd/go/internal/modconv/testdata/panicparse.vyml create mode 100644 src/cmd/go/internal/modconv/testdata/prometheus.out create mode 100644 src/cmd/go/internal/modconv/testdata/prometheus.vjson create mode 100644 src/cmd/go/internal/modconv/testdata/traefik.dep create mode 100644 src/cmd/go/internal/modconv/testdata/traefik.out create mode 100644 src/cmd/go/internal/modconv/testdata/upspin.dep create mode 100644 src/cmd/go/internal/modconv/testdata/upspin.out create mode 100644 src/cmd/go/internal/modconv/tsv.go create mode 100644 src/cmd/go/internal/modconv/vconf.go create mode 100644 src/cmd/go/internal/modconv/vjson.go create mode 100644 src/cmd/go/internal/modconv/vmanifest.go create mode 100644 src/cmd/go/internal/modconv/vyml.go create mode 100644 src/cmd/go/internal/modfetch/bootstrap.go create mode 100644 src/cmd/go/internal/modfetch/cache.go create mode 100644 src/cmd/go/internal/modfetch/cache_test.go create mode 100644 src/cmd/go/internal/modfetch/codehost/codehost.go create mode 100644 src/cmd/go/internal/modfetch/codehost/git.go create mode 100644 src/cmd/go/internal/modfetch/codehost/git_test.go create mode 100644 src/cmd/go/internal/modfetch/codehost/shell.go create mode 100644 src/cmd/go/internal/modfetch/codehost/svn.go create mode 100644 src/cmd/go/internal/modfetch/codehost/vcs.go create mode 100644 src/cmd/go/internal/modfetch/coderepo.go create mode 100644 src/cmd/go/internal/modfetch/coderepo_test.go create mode 100644 src/cmd/go/internal/modfetch/fetch.go create mode 100644 src/cmd/go/internal/modfetch/insecure.go create mode 100644 src/cmd/go/internal/modfetch/key.go create mode 100644 src/cmd/go/internal/modfetch/proxy.go create mode 100644 src/cmd/go/internal/modfetch/pseudo.go create mode 100644 src/cmd/go/internal/modfetch/pseudo_test.go create mode 100644 src/cmd/go/internal/modfetch/repo.go create mode 100644 src/cmd/go/internal/modfetch/sumdb.go create mode 100644 src/cmd/go/internal/modfetch/zip_sum_test/testdata/zip_sums.csv create mode 100644 src/cmd/go/internal/modfetch/zip_sum_test/zip_sum_test.go create mode 100644 src/cmd/go/internal/modget/get.go create mode 100644 src/cmd/go/internal/modget/query.go create mode 100644 src/cmd/go/internal/modinfo/info.go create mode 100644 src/cmd/go/internal/modload/build.go create mode 100644 src/cmd/go/internal/modload/buildlist.go create mode 100644 src/cmd/go/internal/modload/help.go create mode 100644 src/cmd/go/internal/modload/import.go create mode 100644 src/cmd/go/internal/modload/import_test.go create mode 100644 src/cmd/go/internal/modload/init.go create mode 100644 src/cmd/go/internal/modload/list.go create mode 100644 src/cmd/go/internal/modload/load.go create mode 100644 src/cmd/go/internal/modload/modfile.go create mode 100644 src/cmd/go/internal/modload/mvs.go create mode 100644 src/cmd/go/internal/modload/mvs_test.go create mode 100644 src/cmd/go/internal/modload/query.go create mode 100644 src/cmd/go/internal/modload/query_test.go create mode 100644 src/cmd/go/internal/modload/search.go create mode 100644 src/cmd/go/internal/modload/stat_openfile.go create mode 100644 src/cmd/go/internal/modload/stat_unix.go create mode 100644 src/cmd/go/internal/modload/stat_windows.go create mode 100644 src/cmd/go/internal/modload/vendor.go create mode 100644 src/cmd/go/internal/mvs/errors.go create mode 100644 src/cmd/go/internal/mvs/mvs.go create mode 100644 src/cmd/go/internal/mvs/mvs_test.go create mode 100644 src/cmd/go/internal/par/queue.go create mode 100644 src/cmd/go/internal/par/queue_test.go create mode 100644 src/cmd/go/internal/par/work.go create mode 100644 src/cmd/go/internal/par/work_test.go create mode 100644 src/cmd/go/internal/renameio/renameio.go create mode 100644 src/cmd/go/internal/renameio/renameio_test.go create mode 100644 src/cmd/go/internal/renameio/umask_test.go create mode 100644 src/cmd/go/internal/robustio/robustio.go create mode 100644 src/cmd/go/internal/robustio/robustio_darwin.go create mode 100644 src/cmd/go/internal/robustio/robustio_flaky.go create mode 100644 src/cmd/go/internal/robustio/robustio_other.go create mode 100644 src/cmd/go/internal/robustio/robustio_windows.go create mode 100644 src/cmd/go/internal/run/run.go create mode 100644 src/cmd/go/internal/search/search.go create mode 100644 src/cmd/go/internal/search/search_test.go create mode 100644 src/cmd/go/internal/str/path.go create mode 100644 src/cmd/go/internal/str/str.go create mode 100644 src/cmd/go/internal/str/str_test.go create mode 100644 src/cmd/go/internal/test/cover.go create mode 100644 src/cmd/go/internal/test/flagdefs.go create mode 100644 src/cmd/go/internal/test/flagdefs_test.go create mode 100644 src/cmd/go/internal/test/genflags.go create mode 100644 src/cmd/go/internal/test/test.go create mode 100644 src/cmd/go/internal/test/testflag.go create mode 100644 src/cmd/go/internal/tool/tool.go create mode 100644 src/cmd/go/internal/trace/trace.go create mode 100644 src/cmd/go/internal/txtar/archive.go create mode 100644 src/cmd/go/internal/txtar/archive_test.go create mode 100644 src/cmd/go/internal/vcs/discovery.go create mode 100644 src/cmd/go/internal/vcs/discovery_test.go create mode 100644 src/cmd/go/internal/vcs/vcs.go create mode 100644 src/cmd/go/internal/vcs/vcs_test.go create mode 100644 src/cmd/go/internal/version/exe.go create mode 100644 src/cmd/go/internal/version/version.go create mode 100644 src/cmd/go/internal/vet/vet.go create mode 100644 src/cmd/go/internal/vet/vetflag.go create mode 100644 src/cmd/go/internal/web/api.go create mode 100644 src/cmd/go/internal/web/bootstrap.go create mode 100644 src/cmd/go/internal/web/file_test.go create mode 100644 src/cmd/go/internal/web/http.go create mode 100644 src/cmd/go/internal/web/url.go create mode 100644 src/cmd/go/internal/web/url_other.go create mode 100644 src/cmd/go/internal/web/url_other_test.go create mode 100644 src/cmd/go/internal/web/url_test.go create mode 100644 src/cmd/go/internal/web/url_windows.go create mode 100644 src/cmd/go/internal/web/url_windows_test.go create mode 100644 src/cmd/go/internal/work/action.go create mode 100644 src/cmd/go/internal/work/build.go create mode 100644 src/cmd/go/internal/work/build_test.go create mode 100644 src/cmd/go/internal/work/buildid.go create mode 100644 src/cmd/go/internal/work/exec.go create mode 100644 src/cmd/go/internal/work/exec_test.go create mode 100644 src/cmd/go/internal/work/gc.go create mode 100644 src/cmd/go/internal/work/gccgo.go create mode 100644 src/cmd/go/internal/work/init.go create mode 100644 src/cmd/go/internal/work/security.go create mode 100644 src/cmd/go/internal/work/security_test.go create mode 100644 src/cmd/go/internal/work/testgo.go create mode 100644 src/cmd/go/main.go create mode 100755 src/cmd/go/mkalldocs.sh create mode 100644 src/cmd/go/note_test.go create mode 100644 src/cmd/go/proxy_test.go create mode 100644 src/cmd/go/script_test.go create mode 100644 src/cmd/go/testdata/addmod.go create mode 100755 src/cmd/go/testdata/failssh/ssh create mode 100644 src/cmd/go/testdata/mod/README create mode 100644 src/cmd/go/testdata/mod/example.com_ambiguous_a_b_v0.0.0-empty.txt create mode 100644 src/cmd/go/testdata/mod/example.com_ambiguous_a_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_badchain_a_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_badchain_a_v1.1.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_badchain_b_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_badchain_b_v1.1.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_badchain_c_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_badchain_c_v1.1.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_cmd_v1.0.0-exclude.txt create mode 100644 src/cmd/go/testdata/mod/example.com_cmd_v1.0.0-newerself.txt create mode 100644 src/cmd/go/testdata/mod/example.com_cmd_v1.0.0-replace.txt create mode 100644 src/cmd/go/testdata/mod/example.com_cmd_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_cmd_v1.9.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_dotgo.go_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_downgrade_v2.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_downgrade_v2_v2.0.1.txt create mode 100644 src/cmd/go/testdata/mod/example.com_incompatiblewithsub_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_incompatiblewithsub_v2.0.0+incompatible.txt create mode 100644 src/cmd/go/testdata/mod/example.com_invalidpath_v1_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_join_subpkg_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_join_subpkg_v1.1.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_join_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_join_v1.1.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_latemigrate_v2_v2.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_latemigrate_v2_v2.0.1.txt create mode 100644 src/cmd/go/testdata/mod/example.com_missingpkg_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_missingpkg_v1.0.1-beta.txt create mode 100644 src/cmd/go/testdata/mod/example.com_nest_sub_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_nest_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_nest_v1.1.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_newcycle_a_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_newcycle_a_v1.0.1.txt create mode 100644 src/cmd/go/testdata/mod/example.com_newcycle_b_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_noroot_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_noroot_v1.0.1.txt create mode 100644 src/cmd/go/testdata/mod/example.com_notags_v0.0.0-20190507143103-cc8cbe209b64.txt create mode 100644 src/cmd/go/testdata/mod/example.com_printversion_v0.1.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_printversion_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_pseudoupgrade_v0.0.0-20190430073000-30950c05d534.txt create mode 100644 src/cmd/go/testdata/mod/example.com_pseudoupgrade_v0.1.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_pseudoupgrade_v0.1.1-0.20190429073117-b5426c86b553.txt create mode 100644 src/cmd/go/testdata/mod/example.com_quote_v1.5.2.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_ambiguous_nested_v1.9.0-bad.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_ambiguous_other_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_ambiguous_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_incompatible_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_incompatible_v2.0.0+incompatible.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_missingmod_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_missingmod_v1.9.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-block.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-blockwithcomment.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-empty.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-long.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-multiline1.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-multiline2.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-order.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-unprintable.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.1-order.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_rationale_v1.9.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_rename_v1.0.0-bad.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_rename_v1.9.0-new.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_self_all_v1.9.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_self_prerelease_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_self_prerelease_v1.9.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_self_prerelease_v1.9.1-pre.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_self_prev_v1.0.0-bad.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_self_prev_v1.1.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_self_prev_v1.9.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_self_pseudo_v0.0.0-20200325131415-0123456789ab create mode 100644 src/cmd/go/testdata/mod/example.com_retract_self_pseudo_v1.0.0-bad.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_self_pseudo_v1.9.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_v1.0.0-bad.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_v1.0.0-good.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_v1.0.0-unused.txt create mode 100644 src/cmd/go/testdata/mod/example.com_retract_v1.1.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_split-incompatible_subpkg_v0.1.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_split-incompatible_v2.0.0+incompatible.txt create mode 100644 src/cmd/go/testdata/mod/example.com_split-incompatible_v2.1.0-pre+incompatible.txt create mode 100644 src/cmd/go/testdata/mod/example.com_split_subpkg_v1.1.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_split_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_split_v1.1.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_stack_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_stack_v1.0.1.txt create mode 100644 src/cmd/go/testdata/mod/example.com_tools_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_usemissingpre_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_version_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.com_version_v1.0.1.txt create mode 100644 src/cmd/go/testdata/mod/example.com_version_v1.1.0.txt create mode 100644 src/cmd/go/testdata/mod/example.net_ambiguous_nested_v0.1.0.txt create mode 100644 src/cmd/go/testdata/mod/example.net_ambiguous_v0.1.0.txt create mode 100644 src/cmd/go/testdata/mod/example.net_ambiguous_v0.2.0.txt create mode 100644 src/cmd/go/testdata/mod/example.net_pkgadded_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/example.net_pkgadded_v1.1.0.txt create mode 100644 src/cmd/go/testdata/mod/example.net_pkgadded_v1.2.0.txt create mode 100644 src/cmd/go/testdata/mod/github.com_dmitshur-test_modtest5_v0.0.0-20190619020302-197a620e0c9a.txt create mode 100644 src/cmd/go/testdata/mod/github.com_dmitshur-test_modtest5_v0.5.0-alpha.0.20190619023908-3da23a9deb9e.txt create mode 100644 src/cmd/go/testdata/mod/github.com_dmitshur-test_modtest5_v0.5.0-alpha.txt create mode 100644 src/cmd/go/testdata/mod/golang.org_notx_useinternal_v0.1.0.txt create mode 100644 src/cmd/go/testdata/mod/golang.org_x_internal_v0.1.0.txt create mode 100644 src/cmd/go/testdata/mod/golang.org_x_text_v0.0.0-20170915032832-14c0d48ead0c.txt create mode 100644 src/cmd/go/testdata/mod/golang.org_x_text_v0.3.0.txt create mode 100644 src/cmd/go/testdata/mod/golang.org_x_useinternal_v0.1.0.txt create mode 100644 src/cmd/go/testdata/mod/gopkg.in_dummy.v2-unstable_v2.0.0.txt create mode 100644 src/cmd/go/testdata/mod/not-rsc.io_quote_v0.1.0-nomod.txt create mode 100644 src/cmd/go/testdata/mod/patch.example.com_depofdirectpatch_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/patch.example.com_depofdirectpatch_v1.0.1.txt create mode 100644 src/cmd/go/testdata/mod/patch.example.com_direct_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/patch.example.com_direct_v1.0.1.txt create mode 100644 src/cmd/go/testdata/mod/patch.example.com_direct_v1.1.0.txt create mode 100644 src/cmd/go/testdata/mod/patch.example.com_indirect_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/patch.example.com_indirect_v1.0.1.txt create mode 100644 src/cmd/go/testdata/mod/patch.example.com_indirect_v1.1.0.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_!c!g!o_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_!q!u!o!t!e_v1.5.2.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_!q!u!o!t!e_v1.5.3-!p!r!e.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_badfile1_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_badfile2_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_badfile3_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_badfile4_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_badfile5_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_badmod_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_badsum_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_badsum_v1.0.1.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_badzip_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_breaker_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_breaker_v2.0.0+incompatible.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_breaker_v2.0.0.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_fortune_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_fortune_v2_v2.0.0.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180214005133-e7a685a342c0.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180214005840-23179ee8a569.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180628003336-dd9747d19b04.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709153244-fd906ed3b100.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709160352-0d003b9c4bfa.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162749-b44a0b17b2d1.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162816-fe488b867524.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162918-a91498bed0a7.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180710144737-5d9f230bcfba.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_quote_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_quote_v1.1.0.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_quote_v1.2.0.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_quote_v1.2.1.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_quote_v1.3.0.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_quote_v1.4.0.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_quote_v1.5.0.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_quote_v1.5.1.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_quote_v1.5.2.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_quote_v1.5.3-pre1.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_quote_v2.0.0.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_quote_v2_v2.0.1.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_quote_v3_v3.0.0.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_sampler_v1.0.0.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_sampler_v1.2.0.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_sampler_v1.2.1.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_sampler_v1.3.0.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_sampler_v1.3.1.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_sampler_v1.99.99.txt create mode 100644 src/cmd/go/testdata/mod/rsc.io_testonly_v1.0.0.txt create mode 100644 src/cmd/go/testdata/modlegacy/src/new/go.mod create mode 100644 src/cmd/go/testdata/modlegacy/src/new/new.go create mode 100644 src/cmd/go/testdata/modlegacy/src/new/p1/p1.go create mode 100644 src/cmd/go/testdata/modlegacy/src/new/p2/p2.go create mode 100644 src/cmd/go/testdata/modlegacy/src/new/sub/go.mod create mode 100644 src/cmd/go/testdata/modlegacy/src/new/sub/inner/go.mod create mode 100644 src/cmd/go/testdata/modlegacy/src/new/sub/inner/x/x.go create mode 100644 src/cmd/go/testdata/modlegacy/src/new/sub/x/v1/y/y.go create mode 100644 src/cmd/go/testdata/modlegacy/src/old/p1/p1.go create mode 100644 src/cmd/go/testdata/modlegacy/src/old/p2/p2.go create mode 100644 src/cmd/go/testdata/savedir.go create mode 100644 src/cmd/go/testdata/script/README create mode 100644 src/cmd/go/testdata/script/bug.txt create mode 100644 src/cmd/go/testdata/script/build_GOTMPDIR.txt create mode 100644 src/cmd/go/testdata/script/build_acl_windows.txt create mode 100644 src/cmd/go/testdata/script/build_arm.txt create mode 100644 src/cmd/go/testdata/script/build_cache_arch_mode.txt create mode 100644 src/cmd/go/testdata/script/build_cache_compile.txt create mode 100644 src/cmd/go/testdata/script/build_cache_disabled.txt create mode 100644 src/cmd/go/testdata/script/build_cache_gomips.txt create mode 100644 src/cmd/go/testdata/script/build_cache_link.txt create mode 100644 src/cmd/go/testdata/script/build_cache_output.txt create mode 100644 src/cmd/go/testdata/script/build_cache_trimpath.txt create mode 100644 src/cmd/go/testdata/script/build_cd_gopath_different.txt create mode 100644 src/cmd/go/testdata/script/build_cgo_consistent_results.txt create mode 100644 src/cmd/go/testdata/script/build_darwin_cc_arch.txt create mode 100644 src/cmd/go/testdata/script/build_dash_n_cgo.txt create mode 100644 src/cmd/go/testdata/script/build_dash_o_dev_null.txt create mode 100644 src/cmd/go/testdata/script/build_dash_x.txt create mode 100644 src/cmd/go/testdata/script/build_exe.txt create mode 100644 src/cmd/go/testdata/script/build_gcflags.txt create mode 100644 src/cmd/go/testdata/script/build_gopath_order.txt create mode 100644 src/cmd/go/testdata/script/build_i.txt create mode 100644 src/cmd/go/testdata/script/build_i_deprecate.txt create mode 100644 src/cmd/go/testdata/script/build_import_comment.txt create mode 100644 src/cmd/go/testdata/script/build_import_cycle.txt create mode 100644 src/cmd/go/testdata/script/build_internal.txt create mode 100644 src/cmd/go/testdata/script/build_issue6480.txt create mode 100644 src/cmd/go/testdata/script/build_link_x_import_path_escape.txt create mode 100644 src/cmd/go/testdata/script/build_multi_main.txt create mode 100644 src/cmd/go/testdata/script/build_n_cgo.txt create mode 100644 src/cmd/go/testdata/script/build_no_go.txt create mode 100644 src/cmd/go/testdata/script/build_nocache.txt create mode 100644 src/cmd/go/testdata/script/build_output.txt create mode 100644 src/cmd/go/testdata/script/build_overlay.txt create mode 100644 src/cmd/go/testdata/script/build_package_not_stale_trailing_slash.txt create mode 100644 src/cmd/go/testdata/script/build_patterns_outside_gopath.txt create mode 100644 src/cmd/go/testdata/script/build_plugin_non_main.txt create mode 100644 src/cmd/go/testdata/script/build_relative_pkgdir.txt create mode 100644 src/cmd/go/testdata/script/build_relative_tmpdir.txt create mode 100644 src/cmd/go/testdata/script/build_runtime_gcflags.txt create mode 100644 src/cmd/go/testdata/script/build_tag_goexperiment.txt create mode 100644 src/cmd/go/testdata/script/build_tags_no_comma.txt create mode 100644 src/cmd/go/testdata/script/build_test_only.txt create mode 100644 src/cmd/go/testdata/script/build_trimpath.txt create mode 100644 src/cmd/go/testdata/script/build_trimpath_cgo.txt create mode 100644 src/cmd/go/testdata/script/build_unsupported_goos.txt create mode 100644 src/cmd/go/testdata/script/build_vendor.txt create mode 100644 src/cmd/go/testdata/script/cache_unix.txt create mode 100644 src/cmd/go/testdata/script/cache_vet.txt create mode 100644 src/cmd/go/testdata/script/cgo_asm_error.txt create mode 100644 src/cmd/go/testdata/script/cgo_bad_directives.txt create mode 100644 src/cmd/go/testdata/script/cgo_depends_on_syscall.txt create mode 100644 src/cmd/go/testdata/script/cgo_flag_contains_space.txt create mode 100644 src/cmd/go/testdata/script/cgo_path.txt create mode 100644 src/cmd/go/testdata/script/cgo_path_space.txt create mode 100644 src/cmd/go/testdata/script/cgo_syso_issue29253.txt create mode 100644 src/cmd/go/testdata/script/clean_binary.txt create mode 100644 src/cmd/go/testdata/script/clean_cache_n.txt create mode 100644 src/cmd/go/testdata/script/clean_testcache.txt create mode 100644 src/cmd/go/testdata/script/cmd_import_error.txt create mode 100644 src/cmd/go/testdata/script/cover_asm.txt create mode 100644 src/cmd/go/testdata/script/cover_atomic_pkgall.txt create mode 100644 src/cmd/go/testdata/script/cover_blank_func_decl.txt create mode 100644 src/cmd/go/testdata/script/cover_cgo.txt create mode 100644 src/cmd/go/testdata/script/cover_cgo_extra_file.txt create mode 100644 src/cmd/go/testdata/script/cover_cgo_extra_test.txt create mode 100644 src/cmd/go/testdata/script/cover_cgo_xtest.txt create mode 100644 src/cmd/go/testdata/script/cover_dash_c.txt create mode 100644 src/cmd/go/testdata/script/cover_dep_loop.txt create mode 100644 src/cmd/go/testdata/script/cover_dot_import.txt create mode 100644 src/cmd/go/testdata/script/cover_error.txt create mode 100644 src/cmd/go/testdata/script/cover_import_main_loop.txt create mode 100644 src/cmd/go/testdata/script/cover_mod_empty.txt create mode 100644 src/cmd/go/testdata/script/cover_modes.txt create mode 100644 src/cmd/go/testdata/script/cover_pattern.txt create mode 100644 src/cmd/go/testdata/script/cover_pkgall_multiple_mains.txt create mode 100644 src/cmd/go/testdata/script/cover_pkgall_runtime.txt create mode 100644 src/cmd/go/testdata/script/cover_runs.txt create mode 100644 src/cmd/go/testdata/script/cover_statements.txt create mode 100644 src/cmd/go/testdata/script/cover_sync_atomic_import.txt create mode 100644 src/cmd/go/testdata/script/cpu_profile_twice.txt create mode 100644 src/cmd/go/testdata/script/devnull.txt create mode 100644 src/cmd/go/testdata/script/doc.txt create mode 100644 src/cmd/go/testdata/script/embed.txt create mode 100644 src/cmd/go/testdata/script/embed_fmt.txt create mode 100644 src/cmd/go/testdata/script/env_write.txt create mode 100644 src/cmd/go/testdata/script/fileline.txt create mode 100644 src/cmd/go/testdata/script/fmt_load_errors.txt create mode 100644 src/cmd/go/testdata/script/gccgo_link_c.txt create mode 100644 src/cmd/go/testdata/script/gccgo_m.txt create mode 100644 src/cmd/go/testdata/script/gccgo_mangle.txt create mode 100644 src/cmd/go/testdata/script/gcflags_patterns.txt create mode 100644 src/cmd/go/testdata/script/generate.txt create mode 100644 src/cmd/go/testdata/script/generate_bad_imports.txt create mode 100644 src/cmd/go/testdata/script/generate_env.txt create mode 100644 src/cmd/go/testdata/script/generate_invalid.txt create mode 100644 src/cmd/go/testdata/script/get_404_meta.txt create mode 100644 src/cmd/go/testdata/script/get_brace.txt create mode 100644 src/cmd/go/testdata/script/get_custom_domain_wildcard.txt create mode 100644 src/cmd/go/testdata/script/get_dash_t.txt create mode 100644 src/cmd/go/testdata/script/get_domain_root.txt create mode 100644 src/cmd/go/testdata/script/get_dot_slash_download.txt create mode 100644 src/cmd/go/testdata/script/get_dotfiles.txt create mode 100644 src/cmd/go/testdata/script/get_go_file.txt create mode 100644 src/cmd/go/testdata/script/get_goroot.txt create mode 100644 src/cmd/go/testdata/script/get_insecure.txt create mode 100644 src/cmd/go/testdata/script/get_insecure_custom_domain.txt create mode 100644 src/cmd/go/testdata/script/get_insecure_deprecated.txt create mode 100644 src/cmd/go/testdata/script/get_insecure_env.txt create mode 100644 src/cmd/go/testdata/script/get_insecure_redirect.txt create mode 100644 src/cmd/go/testdata/script/get_insecure_update.txt create mode 100644 src/cmd/go/testdata/script/get_internal_wildcard.txt create mode 100644 src/cmd/go/testdata/script/get_issue11307.txt create mode 100644 src/cmd/go/testdata/script/get_legacy.txt create mode 100644 src/cmd/go/testdata/script/get_non_pkg.txt create mode 100644 src/cmd/go/testdata/script/get_race.txt create mode 100644 src/cmd/go/testdata/script/get_test_only.txt create mode 100644 src/cmd/go/testdata/script/get_tilde.txt create mode 100644 src/cmd/go/testdata/script/get_update.txt create mode 100644 src/cmd/go/testdata/script/get_update_all.txt create mode 100644 src/cmd/go/testdata/script/get_update_unknown_protocol.txt create mode 100644 src/cmd/go/testdata/script/get_update_wildcard.txt create mode 100644 src/cmd/go/testdata/script/get_vcs_error_message.txt create mode 100644 src/cmd/go/testdata/script/get_vendor.txt create mode 100644 src/cmd/go/testdata/script/get_with_git_trace.txt create mode 100644 src/cmd/go/testdata/script/goflags.txt create mode 100644 src/cmd/go/testdata/script/gopath_install.txt create mode 100644 src/cmd/go/testdata/script/gopath_local.txt create mode 100644 src/cmd/go/testdata/script/gopath_moved_repo.txt create mode 100644 src/cmd/go/testdata/script/gopath_paths.txt create mode 100644 src/cmd/go/testdata/script/gopath_std_vendor.txt create mode 100644 src/cmd/go/testdata/script/gopath_vendor_dup_err.txt create mode 100644 src/cmd/go/testdata/script/goroot_executable.txt create mode 100644 src/cmd/go/testdata/script/govcs.txt create mode 100644 src/cmd/go/testdata/script/help.txt create mode 100644 src/cmd/go/testdata/script/import_cycle.txt create mode 100644 src/cmd/go/testdata/script/import_ignore.txt create mode 100644 src/cmd/go/testdata/script/import_main.txt create mode 100644 src/cmd/go/testdata/script/install_cgo_excluded.txt create mode 100644 src/cmd/go/testdata/script/install_cleans_build.txt create mode 100644 src/cmd/go/testdata/script/install_cmd_gobin.txt create mode 100644 src/cmd/go/testdata/script/install_cross_gobin.txt create mode 100644 src/cmd/go/testdata/script/install_msan_and_race_require_cgo.txt create mode 100644 src/cmd/go/testdata/script/install_rebuild_gopath.txt create mode 100644 src/cmd/go/testdata/script/install_rebuild_removed.txt create mode 100644 src/cmd/go/testdata/script/install_relative_gobin_fail.txt create mode 100644 src/cmd/go/testdata/script/install_shadow_gopath.txt create mode 100644 src/cmd/go/testdata/script/issue36000.txt create mode 100644 src/cmd/go/testdata/script/ldflag.txt create mode 100644 src/cmd/go/testdata/script/link_matching_actionid.txt create mode 100644 src/cmd/go/testdata/script/link_syso_issue33139.txt create mode 100644 src/cmd/go/testdata/script/linkname.txt create mode 100644 src/cmd/go/testdata/script/list_ambiguous_path.txt create mode 100644 src/cmd/go/testdata/script/list_bad_import.txt create mode 100644 src/cmd/go/testdata/script/list_case_collision.txt create mode 100644 src/cmd/go/testdata/script/list_compiled_imports.txt create mode 100644 src/cmd/go/testdata/script/list_constraints.txt create mode 100644 src/cmd/go/testdata/script/list_dedup_packages.txt create mode 100644 src/cmd/go/testdata/script/list_err_cycle.txt create mode 100644 src/cmd/go/testdata/script/list_err_stack.txt create mode 100644 src/cmd/go/testdata/script/list_find.txt create mode 100644 src/cmd/go/testdata/script/list_gofile_in_goroot.txt create mode 100644 src/cmd/go/testdata/script/list_importmap.txt create mode 100644 src/cmd/go/testdata/script/list_linkshared.txt create mode 100644 src/cmd/go/testdata/script/list_load_err.txt create mode 100644 src/cmd/go/testdata/script/list_overlay.txt create mode 100644 src/cmd/go/testdata/script/list_parse_err.txt create mode 100644 src/cmd/go/testdata/script/list_permissions.txt create mode 100644 src/cmd/go/testdata/script/list_shadow.txt create mode 100644 src/cmd/go/testdata/script/list_split_main.txt create mode 100644 src/cmd/go/testdata/script/list_std.txt create mode 100644 src/cmd/go/testdata/script/list_symlink.txt create mode 100644 src/cmd/go/testdata/script/list_symlink_internal.txt create mode 100644 src/cmd/go/testdata/script/list_symlink_vendor_issue14054.txt create mode 100644 src/cmd/go/testdata/script/list_symlink_vendor_issue15201.txt create mode 100644 src/cmd/go/testdata/script/list_test_e.txt create mode 100644 src/cmd/go/testdata/script/list_test_err.txt create mode 100644 src/cmd/go/testdata/script/list_test_imports.txt create mode 100644 src/cmd/go/testdata/script/list_test_non_go_files.txt create mode 100644 src/cmd/go/testdata/script/list_test_simple.txt create mode 100644 src/cmd/go/testdata/script/list_wildcard_skip_nonmatching.txt create mode 100644 src/cmd/go/testdata/script/load_test_pkg_err.txt create mode 100644 src/cmd/go/testdata/script/mod_all.txt create mode 100644 src/cmd/go/testdata/script/mod_alt_goroot.txt create mode 100644 src/cmd/go/testdata/script/mod_ambiguous_import.txt create mode 100644 src/cmd/go/testdata/script/mod_auth.txt create mode 100644 src/cmd/go/testdata/script/mod_bad_domain.txt create mode 100644 src/cmd/go/testdata/script/mod_bad_filenames.txt create mode 100644 src/cmd/go/testdata/script/mod_build_info_err.txt create mode 100644 src/cmd/go/testdata/script/mod_build_tags.txt create mode 100644 src/cmd/go/testdata/script/mod_build_versioned.txt create mode 100644 src/cmd/go/testdata/script/mod_cache_rw.txt create mode 100644 src/cmd/go/testdata/script/mod_case.txt create mode 100644 src/cmd/go/testdata/script/mod_case_cgo.txt create mode 100644 src/cmd/go/testdata/script/mod_clean_cache.txt create mode 100644 src/cmd/go/testdata/script/mod_concurrent.txt create mode 100644 src/cmd/go/testdata/script/mod_convert_dep.txt create mode 100644 src/cmd/go/testdata/script/mod_convert_git.txt create mode 100644 src/cmd/go/testdata/script/mod_convert_glide.txt create mode 100644 src/cmd/go/testdata/script/mod_convert_glockfile.txt create mode 100644 src/cmd/go/testdata/script/mod_convert_godeps.txt create mode 100644 src/cmd/go/testdata/script/mod_convert_tsv.txt create mode 100644 src/cmd/go/testdata/script/mod_convert_tsv_insecure.txt create mode 100644 src/cmd/go/testdata/script/mod_convert_vendor_conf.txt create mode 100644 src/cmd/go/testdata/script/mod_convert_vendor_json.txt create mode 100644 src/cmd/go/testdata/script/mod_convert_vendor_manifest.txt create mode 100644 src/cmd/go/testdata/script/mod_convert_vendor_yml.txt create mode 100644 src/cmd/go/testdata/script/mod_dir.txt create mode 100644 src/cmd/go/testdata/script/mod_doc.txt create mode 100644 src/cmd/go/testdata/script/mod_domain_root.txt create mode 100644 src/cmd/go/testdata/script/mod_dot.txt create mode 100644 src/cmd/go/testdata/script/mod_download.txt create mode 100644 src/cmd/go/testdata/script/mod_download_concurrent_read.txt create mode 100644 src/cmd/go/testdata/script/mod_download_hash.txt create mode 100644 src/cmd/go/testdata/script/mod_download_json.txt create mode 100644 src/cmd/go/testdata/script/mod_download_partial.txt create mode 100644 src/cmd/go/testdata/script/mod_download_replace_file.txt create mode 100644 src/cmd/go/testdata/script/mod_e.txt create mode 100644 src/cmd/go/testdata/script/mod_edit.txt create mode 100644 src/cmd/go/testdata/script/mod_edit_go.txt create mode 100644 src/cmd/go/testdata/script/mod_empty_err.txt create mode 100644 src/cmd/go/testdata/script/mod_enabled.txt create mode 100644 src/cmd/go/testdata/script/mod_file_proxy.txt create mode 100644 src/cmd/go/testdata/script/mod_find.txt create mode 100644 src/cmd/go/testdata/script/mod_fs_patterns.txt create mode 100644 src/cmd/go/testdata/script/mod_get_ambiguous_arg.txt create mode 100644 src/cmd/go/testdata/script/mod_get_ambiguous_import.txt create mode 100644 src/cmd/go/testdata/script/mod_get_ambiguous_pkg.txt create mode 100644 src/cmd/go/testdata/script/mod_get_changes.txt create mode 100644 src/cmd/go/testdata/script/mod_get_cmd.txt create mode 100644 src/cmd/go/testdata/script/mod_get_commit.txt create mode 100644 src/cmd/go/testdata/script/mod_get_direct.txt create mode 100644 src/cmd/go/testdata/script/mod_get_downgrade.txt create mode 100644 src/cmd/go/testdata/script/mod_get_downgrade_missing.txt create mode 100644 src/cmd/go/testdata/script/mod_get_errors.txt create mode 100644 src/cmd/go/testdata/script/mod_get_extra.txt create mode 100644 src/cmd/go/testdata/script/mod_get_fallback.txt create mode 100644 src/cmd/go/testdata/script/mod_get_fossil.txt create mode 100644 src/cmd/go/testdata/script/mod_get_go_file.txt create mode 100644 src/cmd/go/testdata/script/mod_get_hash.txt create mode 100644 src/cmd/go/testdata/script/mod_get_incompatible.txt create mode 100644 src/cmd/go/testdata/script/mod_get_indirect.txt create mode 100644 src/cmd/go/testdata/script/mod_get_insecure_redirect.txt create mode 100644 src/cmd/go/testdata/script/mod_get_issue37438.txt create mode 100644 src/cmd/go/testdata/script/mod_get_latest_pseudo.txt create mode 100644 src/cmd/go/testdata/script/mod_get_local.txt create mode 100644 src/cmd/go/testdata/script/mod_get_main.txt create mode 100644 src/cmd/go/testdata/script/mod_get_major.txt create mode 100644 src/cmd/go/testdata/script/mod_get_missing_ziphash.txt create mode 100644 src/cmd/go/testdata/script/mod_get_moved.txt create mode 100644 src/cmd/go/testdata/script/mod_get_newcycle.txt create mode 100644 src/cmd/go/testdata/script/mod_get_none.txt create mode 100644 src/cmd/go/testdata/script/mod_get_nopkgs.txt create mode 100644 src/cmd/go/testdata/script/mod_get_patch.txt create mode 100644 src/cmd/go/testdata/script/mod_get_patchbound.txt create mode 100644 src/cmd/go/testdata/script/mod_get_patchcycle.txt create mode 100644 src/cmd/go/testdata/script/mod_get_patchmod.txt create mode 100644 src/cmd/go/testdata/script/mod_get_patterns.txt create mode 100644 src/cmd/go/testdata/script/mod_get_pkgtags.txt create mode 100644 src/cmd/go/testdata/script/mod_get_prefer_incompatible.txt create mode 100644 src/cmd/go/testdata/script/mod_get_private_vcs.txt create mode 100644 src/cmd/go/testdata/script/mod_get_promote_implicit.txt create mode 100644 src/cmd/go/testdata/script/mod_get_pseudo.txt create mode 100644 src/cmd/go/testdata/script/mod_get_pseudo_other_branch.txt create mode 100644 src/cmd/go/testdata/script/mod_get_pseudo_prefix.txt create mode 100644 src/cmd/go/testdata/script/mod_get_replaced.txt create mode 100644 src/cmd/go/testdata/script/mod_get_retract.txt create mode 100644 src/cmd/go/testdata/script/mod_get_retract_ambiguous.txt create mode 100644 src/cmd/go/testdata/script/mod_get_split.txt create mode 100644 src/cmd/go/testdata/script/mod_get_sum_noroot.txt create mode 100644 src/cmd/go/testdata/script/mod_get_svn.txt create mode 100644 src/cmd/go/testdata/script/mod_get_tags.txt create mode 100644 src/cmd/go/testdata/script/mod_get_test.txt create mode 100644 src/cmd/go/testdata/script/mod_get_too_many_redirects.txt create mode 100644 src/cmd/go/testdata/script/mod_get_trailing_slash.txt create mode 100644 src/cmd/go/testdata/script/mod_get_upgrade.txt create mode 100644 src/cmd/go/testdata/script/mod_get_upgrade_pseudo.txt create mode 100644 src/cmd/go/testdata/script/mod_get_wild.txt create mode 100644 src/cmd/go/testdata/script/mod_getmode_vendor.txt create mode 100644 src/cmd/go/testdata/script/mod_getx.txt create mode 100644 src/cmd/go/testdata/script/mod_git_export_subst.txt create mode 100644 src/cmd/go/testdata/script/mod_go_version.txt create mode 100644 src/cmd/go/testdata/script/mod_go_version_mixed.txt create mode 100644 src/cmd/go/testdata/script/mod_gobuild_import.txt create mode 100644 src/cmd/go/testdata/script/mod_gofmt_invalid.txt create mode 100644 src/cmd/go/testdata/script/mod_gomodcache.txt create mode 100644 src/cmd/go/testdata/script/mod_gonoproxy.txt create mode 100644 src/cmd/go/testdata/script/mod_gopkg_unstable.txt create mode 100644 src/cmd/go/testdata/script/mod_goroot_errors.txt create mode 100644 src/cmd/go/testdata/script/mod_graph.txt create mode 100644 src/cmd/go/testdata/script/mod_help.txt create mode 100644 src/cmd/go/testdata/script/mod_import.txt create mode 100644 src/cmd/go/testdata/script/mod_import_cycle.txt create mode 100644 src/cmd/go/testdata/script/mod_import_issue41113.txt create mode 100644 src/cmd/go/testdata/script/mod_import_issue42891.txt create mode 100644 src/cmd/go/testdata/script/mod_import_meta.txt create mode 100644 src/cmd/go/testdata/script/mod_import_mod.txt create mode 100644 src/cmd/go/testdata/script/mod_import_v1suffix.txt create mode 100644 src/cmd/go/testdata/script/mod_in_testdata_dir.txt create mode 100644 src/cmd/go/testdata/script/mod_indirect.txt create mode 100644 src/cmd/go/testdata/script/mod_indirect_main.txt create mode 100644 src/cmd/go/testdata/script/mod_indirect_tidy.txt create mode 100644 src/cmd/go/testdata/script/mod_init_dep.txt create mode 100644 src/cmd/go/testdata/script/mod_init_empty.txt create mode 100644 src/cmd/go/testdata/script/mod_init_glide.txt create mode 100644 src/cmd/go/testdata/script/mod_init_path.txt create mode 100644 src/cmd/go/testdata/script/mod_init_tidy.txt create mode 100644 src/cmd/go/testdata/script/mod_install_hint.txt create mode 100644 src/cmd/go/testdata/script/mod_install_pkg_version.txt create mode 100644 src/cmd/go/testdata/script/mod_install_versioned.txt create mode 100644 src/cmd/go/testdata/script/mod_internal.txt create mode 100644 src/cmd/go/testdata/script/mod_invalid_path.txt create mode 100644 src/cmd/go/testdata/script/mod_invalid_path_plus.txt create mode 100644 src/cmd/go/testdata/script/mod_invalid_version.txt create mode 100644 src/cmd/go/testdata/script/mod_issue35317.txt create mode 100644 src/cmd/go/testdata/script/mod_lazy_downgrade.txt create mode 100644 src/cmd/go/testdata/script/mod_lazy_import_allmod.txt create mode 100644 src/cmd/go/testdata/script/mod_lazy_new_import.txt create mode 100644 src/cmd/go/testdata/script/mod_lazy_test_horizon.txt create mode 100644 src/cmd/go/testdata/script/mod_lazy_test_of_test_dep.txt create mode 100644 src/cmd/go/testdata/script/mod_list.txt create mode 100644 src/cmd/go/testdata/script/mod_list_bad_import.txt create mode 100644 src/cmd/go/testdata/script/mod_list_compiled_concurrent.txt create mode 100644 src/cmd/go/testdata/script/mod_list_dir.txt create mode 100644 src/cmd/go/testdata/script/mod_list_direct.txt create mode 100644 src/cmd/go/testdata/script/mod_list_e_readonly.txt create mode 100644 src/cmd/go/testdata/script/mod_list_pseudo.txt create mode 100644 src/cmd/go/testdata/script/mod_list_replace_dir.txt create mode 100644 src/cmd/go/testdata/script/mod_list_retract.txt create mode 100644 src/cmd/go/testdata/script/mod_list_std.txt create mode 100644 src/cmd/go/testdata/script/mod_list_test.txt create mode 100644 src/cmd/go/testdata/script/mod_list_upgrade.txt create mode 100644 src/cmd/go/testdata/script/mod_list_upgrade_pseudo.txt create mode 100644 src/cmd/go/testdata/script/mod_load_badchain.txt create mode 100644 src/cmd/go/testdata/script/mod_load_badmod.txt create mode 100644 src/cmd/go/testdata/script/mod_load_badzip.txt create mode 100644 src/cmd/go/testdata/script/mod_load_replace_mismatch.txt create mode 100644 src/cmd/go/testdata/script/mod_local_replace.txt create mode 100644 src/cmd/go/testdata/script/mod_missing_repo.txt create mode 100644 src/cmd/go/testdata/script/mod_missingpkg_prerelease.txt create mode 100644 src/cmd/go/testdata/script/mod_modinfo.txt create mode 100644 src/cmd/go/testdata/script/mod_multirepo.txt create mode 100644 src/cmd/go/testdata/script/mod_nomod.txt create mode 100644 src/cmd/go/testdata/script/mod_notall.txt create mode 100644 src/cmd/go/testdata/script/mod_off.txt create mode 100644 src/cmd/go/testdata/script/mod_off_init.txt create mode 100644 src/cmd/go/testdata/script/mod_outside.txt create mode 100644 src/cmd/go/testdata/script/mod_overlay.txt create mode 100644 src/cmd/go/testdata/script/mod_patterns.txt create mode 100644 src/cmd/go/testdata/script/mod_patterns_vendor.txt create mode 100644 src/cmd/go/testdata/script/mod_permissions.txt create mode 100644 src/cmd/go/testdata/script/mod_prefer_compatible.txt create mode 100644 src/cmd/go/testdata/script/mod_proxy_errors.txt create mode 100644 src/cmd/go/testdata/script/mod_proxy_https.txt create mode 100644 src/cmd/go/testdata/script/mod_proxy_invalid.txt create mode 100644 src/cmd/go/testdata/script/mod_proxy_list.txt create mode 100644 src/cmd/go/testdata/script/mod_pseudo_cache.txt create mode 100644 src/cmd/go/testdata/script/mod_query.txt create mode 100644 src/cmd/go/testdata/script/mod_query_empty.txt create mode 100644 src/cmd/go/testdata/script/mod_query_exclude.txt create mode 100644 src/cmd/go/testdata/script/mod_query_main.txt create mode 100644 src/cmd/go/testdata/script/mod_readonly.txt create mode 100644 src/cmd/go/testdata/script/mod_replace.txt create mode 100644 src/cmd/go/testdata/script/mod_replace_gopkgin.txt create mode 100644 src/cmd/go/testdata/script/mod_replace_import.txt create mode 100644 src/cmd/go/testdata/script/mod_replace_readonly.txt create mode 100644 src/cmd/go/testdata/script/mod_require_exclude.txt create mode 100644 src/cmd/go/testdata/script/mod_retention.txt create mode 100644 src/cmd/go/testdata/script/mod_retract.txt create mode 100644 src/cmd/go/testdata/script/mod_retract_fix_version.txt create mode 100644 src/cmd/go/testdata/script/mod_retract_incompatible.txt create mode 100644 src/cmd/go/testdata/script/mod_retract_pseudo_base.txt create mode 100644 src/cmd/go/testdata/script/mod_retract_rationale.txt create mode 100644 src/cmd/go/testdata/script/mod_retract_rename.txt create mode 100644 src/cmd/go/testdata/script/mod_retract_replace.txt create mode 100644 src/cmd/go/testdata/script/mod_run_path.txt create mode 100644 src/cmd/go/testdata/script/mod_std_vendor.txt create mode 100644 src/cmd/go/testdata/script/mod_string_alias.txt create mode 100644 src/cmd/go/testdata/script/mod_sum_ambiguous.txt create mode 100644 src/cmd/go/testdata/script/mod_sum_lookup.txt create mode 100644 src/cmd/go/testdata/script/mod_sum_readonly.txt create mode 100644 src/cmd/go/testdata/script/mod_sum_replaced.txt create mode 100644 src/cmd/go/testdata/script/mod_sumdb.txt create mode 100644 src/cmd/go/testdata/script/mod_sumdb_cache.txt create mode 100644 src/cmd/go/testdata/script/mod_sumdb_file_path.txt create mode 100644 src/cmd/go/testdata/script/mod_sumdb_golang.txt create mode 100644 src/cmd/go/testdata/script/mod_sumdb_proxy.txt create mode 100644 src/cmd/go/testdata/script/mod_symlink.txt create mode 100644 src/cmd/go/testdata/script/mod_symlink_dotgo.txt create mode 100644 src/cmd/go/testdata/script/mod_tagged_import_cycle.txt create mode 100644 src/cmd/go/testdata/script/mod_test.txt create mode 100644 src/cmd/go/testdata/script/mod_test_cached.txt create mode 100644 src/cmd/go/testdata/script/mod_test_files.txt create mode 100644 src/cmd/go/testdata/script/mod_tidy.txt create mode 100644 src/cmd/go/testdata/script/mod_tidy_cycle.txt create mode 100644 src/cmd/go/testdata/script/mod_tidy_error.txt create mode 100644 src/cmd/go/testdata/script/mod_tidy_old.txt create mode 100644 src/cmd/go/testdata/script/mod_tidy_quote.txt create mode 100644 src/cmd/go/testdata/script/mod_tidy_replace.txt create mode 100644 src/cmd/go/testdata/script/mod_tidy_sum.txt create mode 100644 src/cmd/go/testdata/script/mod_tidy_too_new.txt create mode 100644 src/cmd/go/testdata/script/mod_upgrade_patch.txt create mode 100644 src/cmd/go/testdata/script/mod_vcs_missing.txt create mode 100644 src/cmd/go/testdata/script/mod_vendor.txt create mode 100644 src/cmd/go/testdata/script/mod_vendor_auto.txt create mode 100644 src/cmd/go/testdata/script/mod_vendor_build.txt create mode 100644 src/cmd/go/testdata/script/mod_vendor_embed.txt create mode 100644 src/cmd/go/testdata/script/mod_vendor_nodeps.txt create mode 100644 src/cmd/go/testdata/script/mod_vendor_replace.txt create mode 100644 src/cmd/go/testdata/script/mod_vendor_trimpath.txt create mode 100644 src/cmd/go/testdata/script/mod_vendor_unused.txt create mode 100644 src/cmd/go/testdata/script/mod_vendor_unused_only.txt create mode 100644 src/cmd/go/testdata/script/mod_verify.txt create mode 100644 src/cmd/go/testdata/script/mod_versions.txt create mode 100644 src/cmd/go/testdata/script/mod_why.txt create mode 100644 src/cmd/go/testdata/script/modfile_flag.txt create mode 100644 src/cmd/go/testdata/script/noncanonical_import.txt create mode 100644 src/cmd/go/testdata/script/pattern_syntax_error.txt create mode 100644 src/cmd/go/testdata/script/prevent_sys_unix_import.txt create mode 100644 src/cmd/go/testdata/script/run_dirs.txt create mode 100644 src/cmd/go/testdata/script/run_hello.txt create mode 100644 src/cmd/go/testdata/script/run_hello_pkg.txt create mode 100644 src/cmd/go/testdata/script/run_internal.txt create mode 100644 src/cmd/go/testdata/script/run_issue11709.txt create mode 100644 src/cmd/go/testdata/script/run_set_executable_name.txt create mode 100644 src/cmd/go/testdata/script/run_vendor.txt create mode 100644 src/cmd/go/testdata/script/run_wildcard.txt create mode 100644 src/cmd/go/testdata/script/script_wait.txt create mode 100644 src/cmd/go/testdata/script/std_vendor.txt create mode 100644 src/cmd/go/testdata/script/test_bad_example.txt create mode 100644 src/cmd/go/testdata/script/test_badtest.txt create mode 100644 src/cmd/go/testdata/script/test_benchmark_chatty_fail.txt create mode 100644 src/cmd/go/testdata/script/test_benchmark_chatty_success.txt create mode 100644 src/cmd/go/testdata/script/test_benchmark_fatal.txt create mode 100644 src/cmd/go/testdata/script/test_benchmark_labels.txt create mode 100644 src/cmd/go/testdata/script/test_benchmark_timeout.txt create mode 100644 src/cmd/go/testdata/script/test_build_failure.txt create mode 100644 src/cmd/go/testdata/script/test_cache_inputs.txt create mode 100644 src/cmd/go/testdata/script/test_chatty_fail.txt create mode 100644 src/cmd/go/testdata/script/test_chatty_parallel_fail.txt create mode 100644 src/cmd/go/testdata/script/test_chatty_parallel_success.txt create mode 100644 src/cmd/go/testdata/script/test_chatty_parallel_success_sleepy.txt create mode 100644 src/cmd/go/testdata/script/test_chatty_success.txt create mode 100644 src/cmd/go/testdata/script/test_cleanup_failnow.txt create mode 100644 src/cmd/go/testdata/script/test_compile_binary.txt create mode 100644 src/cmd/go/testdata/script/test_compile_tempfile.txt create mode 100644 src/cmd/go/testdata/script/test_deadline.txt create mode 100644 src/cmd/go/testdata/script/test_empty.txt create mode 100644 src/cmd/go/testdata/script/test_env_term.txt create mode 100644 src/cmd/go/testdata/script/test_example_goexit.txt create mode 100644 src/cmd/go/testdata/script/test_exit.txt create mode 100644 src/cmd/go/testdata/script/test_fail_fast.txt create mode 100644 src/cmd/go/testdata/script/test_flag.txt create mode 100644 src/cmd/go/testdata/script/test_flags.txt create mode 100644 src/cmd/go/testdata/script/test_generated_main.txt create mode 100644 src/cmd/go/testdata/script/test_go111module_cache.txt create mode 100644 src/cmd/go/testdata/script/test_import_error_stack.txt create mode 100644 src/cmd/go/testdata/script/test_json.txt create mode 100644 src/cmd/go/testdata/script/test_json_exit.txt create mode 100644 src/cmd/go/testdata/script/test_json_interleaved.txt create mode 100644 src/cmd/go/testdata/script/test_json_panic_exit.txt create mode 100644 src/cmd/go/testdata/script/test_main.txt create mode 100644 src/cmd/go/testdata/script/test_main_archive.txt create mode 100644 src/cmd/go/testdata/script/test_main_panic.txt create mode 100644 src/cmd/go/testdata/script/test_main_twice.txt create mode 100644 src/cmd/go/testdata/script/test_match_benchmark_labels.txt create mode 100644 src/cmd/go/testdata/script/test_match_no_benchmarks.txt create mode 100644 src/cmd/go/testdata/script/test_match_no_subtests.txt create mode 100644 src/cmd/go/testdata/script/test_match_no_subtests_failure.txt create mode 100644 src/cmd/go/testdata/script/test_match_no_subtests_parallel.txt create mode 100644 src/cmd/go/testdata/script/test_match_no_tests.txt create mode 100644 src/cmd/go/testdata/script/test_match_no_tests_build_failure.txt create mode 100644 src/cmd/go/testdata/script/test_match_no_tests_with_subtests.txt create mode 100644 src/cmd/go/testdata/script/test_match_only_benchmarks.txt create mode 100644 src/cmd/go/testdata/script/test_match_only_example.txt create mode 100644 src/cmd/go/testdata/script/test_match_only_subtests.txt create mode 100644 src/cmd/go/testdata/script/test_match_only_subtests_parallel.txt create mode 100644 src/cmd/go/testdata/script/test_match_only_tests.txt create mode 100644 src/cmd/go/testdata/script/test_minus_n.txt create mode 100644 src/cmd/go/testdata/script/test_no_run_example.txt create mode 100644 src/cmd/go/testdata/script/test_no_tests.txt create mode 100644 src/cmd/go/testdata/script/test_parallel_number.txt create mode 100644 src/cmd/go/testdata/script/test_profile.txt create mode 100644 src/cmd/go/testdata/script/test_race.txt create mode 100644 src/cmd/go/testdata/script/test_race_cover_mode_issue20435.txt create mode 100644 src/cmd/go/testdata/script/test_race_install.txt create mode 100644 src/cmd/go/testdata/script/test_race_install_cgo.txt create mode 100644 src/cmd/go/testdata/script/test_rebuildall.txt create mode 100644 src/cmd/go/testdata/script/test_regexps.txt create mode 100644 src/cmd/go/testdata/script/test_relative_cmdline.txt create mode 100644 src/cmd/go/testdata/script/test_relative_import.txt create mode 100644 src/cmd/go/testdata/script/test_relative_import_dash_i.txt create mode 100644 src/cmd/go/testdata/script/test_source_order.txt create mode 100644 src/cmd/go/testdata/script/test_status.txt create mode 100644 src/cmd/go/testdata/script/test_syntax_error_says_fail.txt create mode 100644 src/cmd/go/testdata/script/test_timeout.txt create mode 100644 src/cmd/go/testdata/script/test_vendor.txt create mode 100644 src/cmd/go/testdata/script/test_vet.txt create mode 100644 src/cmd/go/testdata/script/test_write_profiles_on_timeout.txt create mode 100644 src/cmd/go/testdata/script/test_xtestonly_works.txt create mode 100644 src/cmd/go/testdata/script/testing_issue40908.txt create mode 100644 src/cmd/go/testdata/script/toolexec.txt create mode 100644 src/cmd/go/testdata/script/vendor_complex.txt create mode 100644 src/cmd/go/testdata/script/vendor_gopath_issue11409.txt create mode 100644 src/cmd/go/testdata/script/vendor_import.txt create mode 100644 src/cmd/go/testdata/script/vendor_import_missing.txt create mode 100644 src/cmd/go/testdata/script/vendor_import_wrong.txt create mode 100644 src/cmd/go/testdata/script/vendor_issue12156.txt create mode 100644 src/cmd/go/testdata/script/vendor_list_issue11977.txt create mode 100644 src/cmd/go/testdata/script/vendor_resolve.txt create mode 100644 src/cmd/go/testdata/script/vendor_test_issue11864.txt create mode 100644 src/cmd/go/testdata/script/vendor_test_issue14613.txt create mode 100644 src/cmd/go/testdata/script/version.txt create mode 100644 src/cmd/go/testdata/script/version_replace.txt create mode 100644 src/cmd/go/testdata/script/vet.txt create mode 100644 src/cmd/go/testdata/script/vet_asm.txt create mode 100644 src/cmd/go/testdata/script/vet_deps.txt create mode 100644 src/cmd/go/testdata/script/vet_flags.txt create mode 100644 src/cmd/go/testdata/script/vet_internal.txt create mode 100644 src/cmd/go/testdata/testterminal18153/terminal_test.go create mode 100644 src/cmd/go/testdata/vendormod.txt (limited to 'src/cmd/go') diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go new file mode 100644 index 0000000..84f89c9 --- /dev/null +++ b/src/cmd/go/alldocs.go @@ -0,0 +1,2935 @@ +// Copyright 2011 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. + +// 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 [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 +// fix update packages to use new APIs +// fmt gofmt (reformat) package sources +// generate generate Go files by processing source +// get add dependencies to current module and install them +// install compile and install packages and dependencies +// 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 " for more information about a command. +// +// Additional help topics: +// +// buildconstraint build constraints +// 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 +// gopath-get legacy GOPATH go get +// goproxy module proxy protocol +// importpath import path syntax +// modules modules, module versions, and more +// module-get module-aware go get +// module-auth module authentication using go.sum +// packages package lists and patterns +// private configuration for downloading non-public code +// testflag testing flags +// testfunc testing functions +// vcs controlling version control with GOVCS +// +// Use "go help " 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 +// +// Usage: +// +// go build [-o output] [build flags] [packages] +// +// Build compiles the packages named by the import paths, +// along with their dependencies, but it does not install the results. +// +// If the arguments to build are a list of .go files from a single directory, +// build treats them as a list of source files specifying a single package. +// +// When compiling packages, build ignores files that end in '_test.go'. +// +// When compiling a single main package, build writes +// the resulting executable to an output file named after +// the first source file ('go build ed.go rx.go' writes 'ed' or 'ed.exe') +// or the source code directory ('go build unix/sam' writes 'sam' or 'sam.exe'). +// The '.exe' suffix is added when writing a Windows executable. +// +// When compiling multiple packages or a single non-main package, +// build compiles the packages but discards the resulting object, +// serving only as a check that the packages can be built. +// +// The -o flag forces build to write the resulting executable or object +// to the named output file or directory, instead of the default behavior described +// in the last two paragraphs. If the named output is an existing directory or +// ends with a slash or backslash, then any resulting executables +// will be written to that directory. +// +// The -i flag installs the packages that are dependencies of the target. +// The -i flag is deprecated. Compiled packages are cached automatically. +// +// The build flags are shared by the build, clean, get, install, list, run, +// and test commands: +// +// -a +// force rebuilding of packages that are already up-to-date. +// -n +// print the commands but do not run them. +// -p n +// the number of programs, such as build commands or +// test binaries, that can be run in parallel. +// The default is the number of CPUs available. +// -race +// enable data race detection. +// Supported only on linux/amd64, freebsd/amd64, darwin/amd64, windows/amd64, +// linux/ppc64le and linux/arm64 (only for 48-bit VMA). +// -msan +// enable interoperation with memory sanitizer. +// Supported only on linux/amd64, linux/arm64 +// and only with Clang/LLVM as the host C compiler. +// On linux/arm64, pie build mode will be used. +// -v +// print the names of packages as they are compiled. +// -work +// print the name of the temporary work directory and +// do not delete it when exiting. +// -x +// print the commands. +// +// -asmflags '[pattern=]arg list' +// arguments to pass on each go tool asm invocation. +// -buildmode mode +// build mode to use. See 'go help buildmode' for more. +// -compiler name +// name of compiler to use, as in runtime.Compiler (gccgo or gc). +// -gccgoflags '[pattern=]arg list' +// arguments to pass on each gccgo compiler/linker invocation. +// -gcflags '[pattern=]arg list' +// arguments to pass on each go tool compile invocation. +// -installsuffix suffix +// a suffix to use in the name of the package installation directory, +// in order to keep output separate from default builds. +// If using the -race flag, the install suffix is automatically set to race +// or, if set explicitly, has _race appended to it. Likewise for the -msan +// flag. Using a -buildmode option that requires non-default compile flags +// has a similar effect. +// -ldflags '[pattern=]arg list' +// arguments to pass on each go tool link invocation. +// -linkshared +// build code that will be linked against shared libraries previously +// created with -buildmode=shared. +// -mod mode +// module download mode to use: readonly, vendor, or mod. +// By default, if a vendor directory is present and the go version in go.mod +// is 1.14 or higher, the go command acts as if -mod=vendor were set. +// Otherwise, the go command acts as if -mod=readonly were set. +// See https://golang.org/ref/mod#build-commands for details. +// -modcacherw +// leave newly-created directories in the module cache read-write +// instead of making them read-only. +// -modfile file +// in module aware mode, read (and possibly write) an alternate go.mod +// file instead of the one in the module root directory. A file named +// "go.mod" must still be present in order to determine the module root +// directory, but it is not accessed. When -modfile is specified, an +// alternate go.sum file is also used: its path is derived from the +// -modfile flag by trimming the ".mod" extension and appending ".sum". +// -overlay file +// read a JSON config file that provides an overlay for build operations. +// The file is a JSON struct with a single field, named 'Replace', that +// maps each disk file path (a string) to its backing file path, so that +// a build will run as if the disk file path exists with the contents +// given by the backing file paths, or as if the disk file path does not +// exist if its backing file path is empty. Support for the -overlay flag +// has some limitations:importantly, cgo files included from outside the +// include path must be in the same directory as the Go package they are +// included from, and overlays will not appear when binaries and tests are +// run through go run and go test respectively. +// -pkgdir dir +// install and load all packages from dir instead of the usual locations. +// For example, when building with a non-standard configuration, +// use -pkgdir to keep generated packages in a separate location. +// -tags tag,list +// a comma-separated list of build tags to consider satisfied during the +// build. For more information about build tags, see the description of +// build constraints in the documentation for the go/build package. +// (Earlier versions of Go used a space-separated list, and that form +// is deprecated but still recognized.) +// -trimpath +// remove all file system paths from the resulting executable. +// Instead of absolute file system paths, the recorded file names +// will begin with either "go" (for the standard library), +// or a module path@version (when using modules), +// or a plain import path (when using GOPATH). +// -toolexec 'cmd args' +// a program to use to invoke toolchain programs like vet and asm. +// For example, instead of running asm, the go command will run +// 'cmd args /path/to/asm '. +// +// The -asmflags, -gccgoflags, -gcflags, and -ldflags flags accept a +// space-separated list of arguments to pass to an underlying tool +// during the build. To embed spaces in an element in the list, surround +// it with either single or double quotes. The argument list may be +// preceded by a package pattern and an equal sign, which restricts +// the use of that argument list to the building of packages matching +// that pattern (see 'go help packages' for a description of package +// patterns). Without a pattern, the argument list applies only to the +// packages named on the command line. The flags may be repeated +// with different patterns in order to specify different arguments for +// different sets of packages. If a package matches patterns given in +// multiple flags, the latest match on the command line wins. +// For example, 'go build -gcflags=-S fmt' prints the disassembly +// only for package fmt, while 'go build -gcflags=all=-S fmt' +// prints the disassembly for fmt and all its dependencies. +// +// For more about specifying packages, see 'go help packages'. +// For more about where packages and binaries are installed, +// run 'go help gopath'. +// For more about calling between Go and C/C++, run 'go help c'. +// +// Note: Build adheres to certain conventions such as those described +// by 'go help gopath'. Not all projects can follow these conventions, +// however. Installations that have their own conventions or that use +// a separate software build system may choose to use lower-level +// invocations such as 'go tool compile' and 'go tool link' to avoid +// some of the overheads and design decisions of the build tool. +// +// See also: go install, go get, go clean. +// +// +// Remove object files and cached files +// +// Usage: +// +// 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, +// so go clean is mainly concerned with object files left by other +// tools or by manual invocations of go build. +// +// If a package argument is given or the -i or -r flag is set, +// clean removes the following files from each of the +// source directories corresponding to the import paths: +// +// _obj/ old object directory, left from Makefiles +// _test/ old test directory, left from Makefiles +// _testmain.go old gotest file, left from Makefiles +// test.out old test log, left from Makefiles +// build.out old test log, left from Makefiles +// *.[568ao] object files, left from Makefiles +// +// DIR(.exe) from go build +// DIR.test(.exe) from go test -c +// MAINFILE(.exe) from go build MAINFILE.go +// *.so from SWIG +// +// In the list, DIR represents the final path element of the +// directory, and MAINFILE is the base name of any Go source +// file in the directory that is not included when building +// the package. +// +// The -i flag causes clean to remove the corresponding installed +// archive or binary (what 'go install' would create). +// +// The -n flag causes clean to print the remove commands it would execute, +// but not run them. +// +// The -r flag causes clean to be applied recursively to all the +// dependencies of the packages named by the import paths. +// +// The -x flag causes clean to print remove commands as it executes them. +// +// 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'. +// +// +// Show documentation for package or symbol +// +// Usage: +// +// go doc [-u] [-c] [package|[package.]symbol[.methodOrField]] +// +// Doc prints the documentation comments associated with the item identified by its +// arguments (a package, const, func, type, var, method, or struct field) +// followed by a one-line summary of each of the first-level items "under" +// that item (package-level declarations for a package, methods for a type, +// etc.). +// +// Doc accepts zero, one, or two arguments. +// +// Given no arguments, that is, when run as +// +// go doc +// +// it prints the package documentation for the package in the current directory. +// If the package is a command (package main), the exported symbols of the package +// are elided from the presentation unless the -cmd flag is provided. +// +// When run with one argument, the argument is treated as a Go-syntax-like +// representation of the item to be documented. What the argument selects depends +// on what is installed in GOROOT and GOPATH, as well as the form of the argument, +// which is schematically one of these: +// +// go doc +// go doc [.] +// go doc [.][.] +// go doc [.][.] +// +// The first item in this list matched by the argument is the one whose documentation +// is printed. (See the examples below.) However, if the argument starts with a capital +// letter it is assumed to identify a symbol or method in the current directory. +// +// For packages, the order of scanning is determined lexically in breadth-first order. +// That is, the package presented is the one that matches the search and is nearest +// the root and lexically first at its level of the hierarchy. The GOROOT tree is +// always scanned in its entirety before GOPATH. +// +// If there is no package specified or matched, the package in the current +// directory is selected, so "go doc Foo" shows the documentation for symbol Foo in +// the current package. +// +// The package path must be either a qualified path or a proper suffix of a +// path. The go tool's usual package mechanism does not apply: package path +// elements like . and ... are not implemented by go doc. +// +// When run with two arguments, the first must be a full package path (not just a +// suffix), and the second is a symbol, or symbol with method or struct field. +// This is similar to the syntax accepted by godoc: +// +// go doc [.] +// +// In all forms, when matching symbols, lower-case letters in the argument match +// either case but upper-case letters match exactly. This means that there may be +// multiple matches of a lower-case argument in a package if different symbols have +// different cases. If this occurs, documentation for all matches is printed. +// +// Examples: +// go doc +// Show documentation for current package. +// go doc Foo +// Show documentation for Foo in the current package. +// (Foo starts with a capital letter so it cannot match +// a package path.) +// go doc encoding/json +// Show documentation for the encoding/json package. +// go doc json +// Shorthand for encoding/json. +// go doc json.Number (or go doc json.number) +// Show documentation and method summary for json.Number. +// go doc json.Number.Int64 (or go doc json.number.int64) +// Show documentation for json.Number's Int64 method. +// go doc cmd/doc +// Show package docs for the doc command. +// go doc -cmd cmd/doc +// Show package docs and exported symbols within the doc command. +// go doc template.new +// Show documentation for html/template's New function. +// (html/template is lexically before text/template) +// go doc text/template.new # One argument +// Show documentation for text/template's New function. +// go doc text/template new # Two arguments +// Show documentation for text/template's New function. +// +// At least in the current tree, these invocations all print the +// documentation for json.Decoder's Decode method: +// +// go doc json.Decoder.Decode +// go doc json.decoder.decode +// go doc json.decode +// cd go/src/encoding/json; go doc decode +// +// Flags: +// -all +// Show all the documentation for the package. +// -c +// Respect case when matching symbols. +// -cmd +// Treat a command (package main) like a regular package. +// Otherwise package main's exported symbols are hidden +// when showing the package's top-level documentation. +// -short +// One-line representation for each symbol. +// -src +// Show the full source code for the symbol. This will +// display the full Go source of its declaration and +// definition, such as a function definition (including +// the body), type declaration or enclosing const +// block. The output may therefore include unexported +// details. +// -u +// Show documentation for unexported as well as exported +// symbols, methods, and fields. +// +// +// Print Go environment information +// +// Usage: +// +// go env [-json] [-u] [-w] [var ...] +// +// Env prints Go environment information. +// +// By default env prints information as a shell script +// (on Windows, a batch file). If one or more variable +// names is given as arguments, env prints the value of +// each named variable on its own line. +// +// The -json flag prints the environment in JSON format +// instead of as a shell script. +// +// The -u flag requires one or more arguments and unsets +// the default setting for the named environment variables, +// if one has been set with 'go env -w'. +// +// The -w flag requires one or more arguments of the +// form NAME=VALUE and changes the default settings +// of the named environment variables to the given values. +// +// For more about environment variables, see 'go help environment'. +// +// +// Update packages to use new APIs +// +// Usage: +// +// go fix [packages] +// +// Fix runs the Go fix command on the packages named by the import paths. +// +// For more about fix, see 'go doc cmd/fix'. +// For more about specifying packages, see 'go help packages'. +// +// To run fix with specific options, run 'go tool fix'. +// +// See also: go fmt, go vet. +// +// +// Gofmt (reformat) package sources +// +// Usage: +// +// go fmt [-n] [-x] [packages] +// +// Fmt runs the command 'gofmt -l -w' on the packages named +// by the import paths. It prints the names of the files that are modified. +// +// For more about gofmt, see 'go doc cmd/gofmt'. +// For more about specifying packages, see 'go help packages'. +// +// The -n flag prints commands that would be executed. +// The -x flag prints commands as they are executed. +// +// The -mod flag's value sets which module download mode +// to use: readonly or vendor. See 'go help modules' for more. +// +// To run gofmt with specific options, run gofmt itself. +// +// See also: go fix, go vet. +// +// +// Generate Go files by processing source +// +// Usage: +// +// go generate [-run regexp] [-n] [-v] [-x] [build flags] [file.go... | packages] +// +// Generate runs commands described by directives within existing +// files. Those commands can run any process but the intent is to +// create or update Go source files. +// +// Go generate is never run automatically by go build, go get, go test, +// and so on. It must be run explicitly. +// +// Go generate scans the file for directives, which are lines of +// the form, +// +// //go:generate command argument... +// +// (note: no leading spaces and no space in "//go") where command +// is the generator to be run, corresponding to an executable file +// 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. +// +// 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. +// +// The arguments to the directive are space-separated tokens or +// double-quoted strings passed to the generator as individual +// arguments when it is run. +// +// Quoted strings use Go syntax and are evaluated before execution; a +// quoted string appears as a single argument to the generator. +// +// To convey to humans and machine tools that code is generated, +// generated source should have a line that matches the following +// regular expression (in Go syntax): +// +// ^// Code generated .* DO NOT EDIT\.$ +// +// This line must appear before the first non-comment, non-blank +// text in the file. +// +// Go generate sets several variables when it runs the generator: +// +// $GOARCH +// The execution architecture (arm, amd64, etc.) +// $GOOS +// The execution operating system (linux, windows, etc.) +// $GOFILE +// The base name of the file. +// $GOLINE +// The line number of the directive in the source file. +// $GOPACKAGE +// The name of the package of the file containing the directive. +// $DOLLAR +// A dollar sign. +// +// Other than variable substitution and quoted-string evaluation, no +// special processing such as "globbing" is performed on the command +// line. +// +// As a last step before running the command, any invocations of any +// environment variables with alphanumeric names, such as $GOFILE or +// $HOME, are expanded throughout the command line. The syntax for +// variable expansion is $NAME on all operating systems. Due to the +// order of evaluation, variables are expanded even inside quoted +// strings. If the variable NAME is not set, $NAME expands to the +// empty string. +// +// A directive of the form, +// +// //go:generate -command xxx args... +// +// specifies, for the remainder of this source file only, that the +// string xxx represents the command identified by the arguments. This +// can be used to create aliases or to handle multiword generators. +// For example, +// +// //go:generate -command foo go tool foo +// +// specifies that the command "foo" represents the generator +// "go tool foo". +// +// Generate processes packages in the order given on the command line, +// one at a time. If the command line lists .go files from a single directory, +// they are treated as a single package. Within a package, generate processes the +// source files in a package in file name order, one at a time. Within +// a source file, generate runs generators in the order they appear +// in the file, one at a time. The go generate tool also sets the build +// tag "generate" so that files may be examined by go generate but ignored +// during build. +// +// For packages with invalid code, generate processes only source files with a +// valid package clause. +// +// If any generator returns an error exit status, "go generate" skips +// all further processing for that package. +// +// The generator is run in the package's source directory. +// +// Go generate accepts one specific flag: +// +// -run="" +// if non-empty, specifies a regular expression to select +// directives whose full original source text (excluding +// any trailing spaces and final newline) matches the +// expression. +// +// It also accepts the standard build flags including -v, -n, and -x. +// The -v flag prints the names of packages and files as they are +// processed. +// The -n flag prints commands that would be executed. +// The -x flag prints commands as they are executed. +// +// For more about build flags, see 'go help build'. +// +// For more about specifying packages, see 'go help packages'. +// +// +// Add dependencies to current module and install them +// +// Usage: +// +// go get [-d] [-t] [-u] [-v] [-insecure] [build flags] [packages] +// +// Get resolves its command-line arguments to packages at specific module versions, +// updates go.mod to require those versions, downloads source code into the +// module cache, then builds and installs the named packages. +// +// To add a dependency for a package or upgrade it to its latest version: +// +// go get example.com/pkg +// +// To upgrade or downgrade a package to a specific version: +// +// go get example.com/pkg@v1.2.3 +// +// To remove a dependency on a module and downgrade modules that require it: +// +// go get example.com/mod@none +// +// See https://golang.org/ref/mod#go-get for details. +// +// The 'go install' command may be used to build and install packages. When a +// version is specified, 'go install' runs in module-aware mode and ignores +// the go.mod file in the current directory. For example: +// +// go install example.com/pkg@v1.2.3 +// go install example.com/pkg@latest +// +// See 'go help install' or https://golang.org/ref/mod#go-install for details. +// +// In addition to build flags (listed in 'go help build') 'go get' accepts the +// following flags. +// +// The -t flag instructs get to consider modules needed to build tests of +// packages specified on the command line. +// +// The -u flag instructs get to update modules providing dependencies +// of packages named on the command line to use newer minor or patch +// releases when available. +// +// The -u=patch flag (not -u patch) also instructs get to update dependencies, +// but changes the default to select patch releases. +// +// When the -t and -u flags are used together, get will update +// test dependencies as well. +// +// The -insecure flag permits fetching from repositories and resolving +// custom domains using insecure schemes such as HTTP, and also bypassess +// module sum validation using the checksum database. Use with caution. +// This flag is deprecated and will be removed in a future version of go. +// To permit the use of insecure schemes, use the GOINSECURE environment +// variable instead. To bypass module sum validation, use GOPRIVATE or +// GONOSUMDB. See 'go help environment' for details. +// +// The -d flag instructs get not to build or install packages. get will only +// update go.mod and download source code needed to build packages. +// +// Building and installing packages with get is deprecated. In a future release, +// the -d flag will be enabled by default, and 'go get' will be only be used to +// adjust dependencies of the current module. To install a package using +// dependencies from the current module, use 'go install'. To install a package +// ignoring the current module, use 'go install' with an @version suffix like +// "@latest" after each argument. +// +// For more about modules, see https://golang.org/ref/mod. +// +// 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 gopath-get'. +// +// See also: go build, go install, go clean, go mod. +// +// +// Compile and install packages and dependencies +// +// Usage: +// +// go install [build flags] [packages] +// +// Install compiles and installs the packages named by the import paths. +// +// Executables are installed in the directory named by the GOBIN environment +// variable, which defaults to $GOPATH/bin or $HOME/go/bin if the GOPATH +// environment variable is not set. Executables in $GOROOT +// are installed in $GOROOT/bin or $GOTOOLDIR instead of $GOBIN. +// +// If the arguments have version suffixes (like @latest or @v1.0.0), "go install" +// builds packages in module-aware mode, ignoring the go.mod file in the current +// directory or any parent directory, if there is one. This is useful for +// installing executables without affecting the dependencies of the main module. +// To eliminate ambiguity about which module versions are used in the build, the +// arguments must satisfy the following constraints: +// +// - Arguments must be package paths or package patterns (with "..." wildcards). +// They must not be standard packages (like fmt), meta-patterns (std, cmd, +// all), or relative or absolute file paths. +// +// - All arguments must have the same version suffix. Different queries are not +// allowed, even if they refer to the same version. +// +// - All arguments must refer to packages in the same module at the same version. +// +// - No module is considered the "main" module. If the module containing +// packages named on the command line has a go.mod file, it must not contain +// directives (replace and exclude) that would cause it to be interpreted +// differently than if it were the main module. The module must not require +// a higher version of itself. +// +// - Package path arguments must refer to main packages. Pattern arguments +// will only match main packages. +// +// If the arguments don't have version suffixes, "go install" may run in +// module-aware mode or GOPATH mode, depending on the GO111MODULE environment +// variable and the presence of a go.mod file. See 'go help modules' for details. +// If module-aware mode is enabled, "go install" runs in the context of the main +// module. +// +// When module-aware mode is disabled, other packages are installed in the +// directory $GOPATH/pkg/$GOOS_$GOARCH. When module-aware mode is enabled, +// other packages are built and cached but not installed. +// +// The -i flag installs the dependencies of the named packages as well. +// The -i flag is deprecated. Compiled packages are cached automatically. +// +// For more about the build flags, see 'go help build'. +// For more about specifying packages, see 'go help packages'. +// +// See also: go build, go get, go clean. +// +// +// List packages or modules +// +// Usage: +// +// go list [-f format] [-json] [-m] [list flags] [build flags] [packages] +// +// 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: +// +// bytes +// encoding/json +// github.com/gorilla/mux +// 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: +// +// 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 (no longer supported) +// ForTest string // package is only for use in named test +// Export string // file containing export data (when using -export) +// BuildID string // build ID of the compiled package (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 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 +// IgnoredOtherFiles []string // non-.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 +// +// // Embedded files +// EmbedPatterns []string // //go:embed patterns +// EmbedFiles []string // files matched by EmbedPatterns +// TestEmbedPatterns []string // //go:embed patterns in TestGoFiles +// TestEmbedFiles []string // files matched by TestEmbedPatterns +// XTestEmbedPatterns []string // //go:embed patterns in XTestGoFiles +// XTestEmbedFiles []string // files matched by XTestEmbedPatterns +// +// // Cgo directives +// CgoCFLAGS []string // cgo: flags for C compiler +// CgoCPPFLAGS []string // cgo: flags for C preprocessor +// CgoCXXFLAGS []string // cgo: flags for C++ compiler +// CgoFFLAGS []string // cgo: flags for Fortran compiler +// CgoLDFLAGS []string // cgo: flags for linker +// CgoPkgConfig []string // cgo: pkg-config names +// +// // Dependency information +// 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 +// Error *PackageError // error loading package +// DepsErrors []*PackageError // errors loading dependencies +// } +// +// 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 import paths. See golang.org/s/go15vendor for more about vendoring. +// +// The error information, if any, is +// +// type PackageError struct { +// ImportStack []string // shortest path from package named on command line to this one +// Pos string // position of error (if present, file:line:col) +// 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 +// } +// +// For more information about the meaning of these fields see the documentation +// 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 +// omits the packages from consideration during the usual printing. +// With the -e flag, the list command never prints errors to standard +// error and instead processes the erroneous packages with the usual +// 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 used when loading this module, if any +// GoVersion string // go version used in module +// Retracted string // retraction information, if any (with -retracted or -u) +// Error *ModuleError // error loading module +// } +// +// type ModuleError struct { +// Err string // the error itself +// } +// +// The file GoMod refers to may be outside the module directory if the +// module is in the module cache or if the -modfile flag is used. +// +// 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. list -u will also set +// the module's Retracted field if the current version is retracted. +// The Module's String method indicates an available upgrade by +// formatting the newer version in brackets after the current version. +// If a version is retracted, the string "(retracted)" will follow it. +// 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 (retracted) [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 -retracted flag causes list to report information about retracted +// module versions. When -retracted is used with -f or -json, the Retracted +// field will be set to a string explaining why the version was retracted. +// The string is taken from comments on the retract directive in the +// module's go.mod file. When -retracted is used with -versions, retracted +// versions are listed together with unretracted versions. The -retracted +// flag may be used with or without -m. +// +// 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 https://golang.org/ref/mod. +// +// +// 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 [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 " for more information about a command. +// +// Download modules to local cache +// +// Usage: +// +// go mod download [-x] [-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 +// (equivalent to 'go mod download all'). +// +// 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 writes nothing to standard output. It may print progress +// messages and errors to standard error. +// +// 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) +// } +// +// The -x flag causes download to print the commands download executes. +// +// See https://golang.org/ref/mod#go-mod-download for more about 'go mod download'. +// +// See https://golang.org/ref/mod#version-queries for more about version 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] flag adds a replacement of the given +// module path and version pair. If the @v in old@v is omitted, a +// replacement without a version on the left side is added, which applies +// to all versions of 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 redundant replacements for old[@v], +// so omitting @v will drop existing replacements for specific versions. +// +// The -dropreplace=old[@v] flag drops a replacement of the given +// module path and version pair. If the @v is omitted, a replacement without +// a version on the left side is dropped. +// +// The -retract=version and -dropretract=version flags add and drop a +// retraction on the given version. The version may be a single version +// like "v1.2.3" or a closed interval like "[v1.1.0,v1.1.9]". Note that +// -retract=version is a no-op if that retraction already exists. +// +// The -require, -droprequire, -exclude, -dropexclude, -replace, +// -dropreplace, -retract, and -dropretract editing flags may be repeated, +// and the changes are applied in the order given. +// +// The -go=version flag sets the expected Go language version. +// +// 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 +// Go string +// Require []Require +// Exclude []Module +// Replace []Replace +// Retract []Retract +// } +// +// type Require struct { +// Path string +// Version string +// Indirect bool +// } +// +// type Replace struct { +// Old Module +// New Module +// } +// +// type Retract struct { +// Low string +// High string +// Rationale string +// } +// +// Retract entries representing a single version (not an interval) will have +// the "Low" and "High" fields set to the same value. +// +// 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'. +// +// See https://golang.org/ref/mod#go-mod-edit for more about 'go mod edit'. +// +// +// 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. +// +// See https://golang.org/ref/mod#go-mod-graph for more about 'go mod graph'. +// +// +// Initialize new module in current directory +// +// Usage: +// +// go mod init [module] +// +// Init initializes and writes a new go.mod file in the current directory, in +// effect creating a new module rooted at the current directory. The go.mod file +// must not already exist. +// +// Init accepts one optional argument, the module path for the new module. If the +// module path argument is omitted, init will attempt to infer the module path +// using import comments in .go files, vendoring tool configuration files (like +// Gopkg.lock), and the current directory (if in GOPATH). +// +// If a configuration file for a vendoring tool is present, init will attempt to +// import module requirements from it. +// +// See https://golang.org/ref/mod#go-mod-init for more about 'go mod init'. +// +// +// Add missing and remove unused modules +// +// Usage: +// +// go mod tidy [-e] [-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. +// +// The -e flag causes tidy to attempt to proceed despite errors +// encountered while loading packages. +// +// See https://golang.org/ref/mod#go-mod-tidy for more about 'go mod tidy'. +// +// +// Make vendored copy of dependencies +// +// Usage: +// +// go mod vendor [-e] [-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. +// +// The -e flag causes vendor to attempt to proceed despite errors +// encountered while loading packages. +// +// See https://golang.org/ref/mod#go-mod-vendor for more about 'go mod vendor'. +// +// +// 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. +// +// See https://golang.org/ref/mod#go-mod-verify for more about 'go mod verify'. +// +// +// 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) +// $ +// +// See https://golang.org/ref/mod#go-mod-why for more about 'go mod why'. +// +// +// Compile and run Go program +// +// Usage: +// +// go run [build flags] [-exec xprog] package [arguments...] +// +// Run compiles and runs the named main Go package. +// Typically the package is specified as a list of .go source files from a single directory, +// 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: +// 'xprog a.out arguments...'. +// If the -exec flag is not given, GOOS or GOARCH is different from the system +// default, and a program named go_$GOOS_$GOARCH_exec can be found +// on the current search path, 'go run' invokes the binary using that program, +// for example 'go_js_wasm_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. +// +// +// Test packages +// +// Usage: +// +// go test [build/test flags] [packages] [build/test flags & test binary flags] +// +// 'Go test' automates testing the packages named by the import paths. +// It prints a summary of the test results in the format: +// +// ok archive/tar 0.011s +// FAIL archive/zip 0.022s +// ok compress/gzip 0.033s +// ... +// +// followed by detailed output for each failed package. +// +// 'Go test' recompiles each package along with any files with names matching +// the file pattern "*_test.go". +// These additional files can contain test functions, benchmark functions, and +// example functions. See 'go help testfunc' for more. +// Each listed package causes the execution of a separate test binary. +// Files whose names begin with "_" (including "_test.go") or "." are ignored. +// +// Test files that declare a package with the suffix "_test" will be compiled as a +// separate package, and then linked and run with the main test binary. +// +// The go tool will ignore a directory named "testdata", making it available +// 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. That subset is: 'atomic', 'bool', 'buildtags', 'errorsas', +// 'ifaceassert', 'nilfunc', 'printf', and 'stringintconv'. 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 +// error. (The go command's standard error is reserved for printing +// errors building the tests.) +// +// Go test runs in two different modes: +// +// The first, called local directory mode, occurs when go test is +// invoked with no package arguments (for example, 'go test' or 'go +// test -v'). In this mode, go test compiles the package sources and +// tests found in the current directory and then runs the resulting +// test binary. In this mode, caching (discussed below) is disabled. +// After the package test finishes, go test prints a summary line +// showing the test status ('ok' or 'FAIL'), package name, and elapsed +// time. +// +// The second, called package list mode, occurs when go test is invoked +// with explicit package arguments (for example 'go test math', 'go +// test ./...', and even 'go test .'). In this mode, go test compiles +// and tests each of the packages listed on the command line. If a +// package test passes, go test prints only the final 'ok' summary +// line. If a package test fails, go test prints the full test output. +// If invoked with the -bench or -v flag, go test prints the full +// output even for passing package tests, in order to display the +// requested benchmark results or verbose logging. After the package +// tests for all of the listed packages finish, and their output is +// printed, go test prints a final 'FAIL' status if any package test +// has failed. +// +// In package list mode only, go test caches successful package test +// results to avoid unnecessary repeated running of tests. When the +// result of a test can be recovered from the cache, go test will +// redisplay the previous output instead of running the test binary +// again. When this happens, go test prints '(cached)' in place of the +// elapsed time in the summary line. +// +// The rule for a match in the cache is that the run involves the same +// test binary and the flags on the command line come entirely from a +// restricted set of 'cacheable' test flags, defined as -cpu, -list, +// -parallel, -run, -short, and -v. If a run of go test has any test +// or non-test flags outside this set, the result is not cached. 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. Tests that open files within the package's source +// root (usually $GOPATH) or that consult environment variables only +// match future runs in which the files and environment variables are unchanged. +// A cached test result is treated as executing in no time at all, +// so a successful package test result will be cached and reused +// regardless of -timeout setting. +// +// In addition to the build flags, the flags handled by 'go test' itself are: +// +// -args +// Pass the remainder of the command line (everything after -args) +// to the test binary, uninterpreted and unchanged. +// Because this flag consumes the remainder of the command line, +// the package list (if present) must appear before this flag. +// +// -c +// Compile the test binary to pkg.test but do not run it +// (where pkg is the last element of the package's import path). +// The file name can be changed with the -o flag. +// +// -exec xprog +// Run the test binary using xprog. The behavior is the same as +// in 'go run'. See 'go help run' for details. +// +// -i +// Install packages that are dependencies of the test. +// Do not run the test. +// The -i flag is deprecated. Compiled packages are cached automatically. +// +// -json +// Convert test output to JSON suitable for automated processing. +// See 'go doc test2json' for the encoding details. +// +// -o file +// Compile the test binary to the named file. +// The test still runs (unless -c or -i is specified). +// +// The test binary also accepts flags that control execution of the test; these +// flags are also accessible by 'go test'. See 'go help testflag' for details. +// +// For more about build flags, see 'go help build'. +// For more about specifying packages, see 'go help packages'. +// +// See also: go build, go vet. +// +// +// Run specified go tool +// +// Usage: +// +// go tool [-n] command [args...] +// +// Tool runs the go tool command identified by the arguments. +// With no arguments it prints the list of known tools. +// +// The -n flag causes tool to print the command that would be +// executed but not execute it. +// +// For more about each tool command, see 'go doc cmd/'. +// +// +// Print Go version +// +// Usage: +// +// go version [-m] [-v] [file ...] +// +// Version prints the build information for Go executables. +// +// Go version reports the Go version used to build each of the named +// executable files. +// +// If no files are named on the command line, go version prints its own +// version information. +// +// If a directory is named, go version walks that directory, recursively, +// looking for recognized Go binaries and reporting their versions. +// By default, go version does not report unrecognized files found +// during a directory scan. The -v flag causes it to report unrecognized files. +// +// The -m flag causes go version to print each executable's embedded +// module version information, when available. In the output, the module +// information consists of multiple lines following the version line, each +// indented by a leading tab character. +// +// See also: go doc runtime/debug.BuildInfo. +// +// +// Report likely mistakes in packages +// +// Usage: +// +// go vet [-n] [-x] [-vettool prog] [build flags] [vet flags] [packages] +// +// Vet runs the Go vet command on the packages named by the import paths. +// +// For more about vet and its flags, see 'go doc cmd/vet'. +// For more about specifying packages, see 'go help packages'. +// For a list of checkers and their flags, see 'go tool vet help'. +// For details of a specific checker such as 'printf', see 'go tool vet help printf'. +// +// The -n flag prints commands that would be executed. +// The -x flag prints commands as they are executed. +// +// The -vettool=prog flag selects a different analysis tool with alternative +// or additional checks. +// For example, the 'shadow' analyzer can be built and run using these commands: +// +// go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow +// go vet -vettool=$(which shadow) +// +// The build flags supported by go vet are those that control package resolution +// and execution, such as -n, -x, -v, -tags, and -toolexec. +// For more about these flags, see 'go help build'. +// +// See also: go fmt, go fix. +// +// +// Build constraints +// +// A build constraint, also known as a build tag, is a line comment that begins +// +// // +build +// +// that lists the conditions under which a file should be included in the package. +// Constraints may appear in any kind of source file (not just Go), but +// they must appear near the top of the file, preceded +// only by blank lines and other line comments. These rules mean that in Go +// files a build constraint must appear before the package clause. +// +// To distinguish build constraints from package documentation, a series of +// build constraints must be followed by a blank line. +// +// A build constraint is evaluated as the OR of space-separated options. +// Each option evaluates as the AND of its comma-separated terms. +// Each term consists of letters, digits, underscores, and dots. +// A term may be negated with a preceding !. +// For example, the build constraint: +// +// // +build linux,386 darwin,!cgo +// +// corresponds to the boolean formula: +// +// (linux AND 386) OR (darwin AND (NOT cgo)) +// +// A file may have multiple build constraints. The overall constraint is the AND +// of the individual constraints. That is, the build constraints: +// +// // +build linux darwin +// // +build amd64 +// +// corresponds to the boolean formula: +// +// (linux OR darwin) AND amd64 +// +// During a particular build, the following words are satisfied: +// +// - the target operating system, as spelled by runtime.GOOS, set with the +// GOOS environment variable. +// - the target architecture, as spelled by runtime.GOARCH, set with the +// GOARCH environment variable. +// - the compiler being used, either "gc" or "gccgo" +// - "cgo", if the cgo command is supported (see CGO_ENABLED in +// 'go help environment'). +// - a term for each Go major release, through the current version: +// "go1.1" from Go version 1.1 onward, "go1.12" from Go 1.12, and so on. +// - any additional tags given by the -tags flag (see 'go help build'). +// +// There are no separate build tags for beta or minor releases. +// +// If a file's name, after stripping the extension and a possible _test suffix, +// matches any of the following patterns: +// *_GOOS +// *_GOARCH +// *_GOOS_GOARCH +// (example: source_windows_amd64.go) where GOOS and GOARCH represent +// any known operating system and architecture values respectively, then +// the file is considered to have an implicit build constraint requiring +// those terms (in addition to any explicit constraints in the file). +// +// Using GOOS=android matches build tags and files as for GOOS=linux +// in addition to android tags and files. +// +// Using GOOS=illumos matches build tags and files as for GOOS=solaris +// in addition to illumos tags and files. +// +// Using GOOS=ios matches build tags and files as for GOOS=darwin +// in addition to ios tags and files. +// +// To keep a file from being considered for the build: +// +// // +build ignore +// +// (any other unsatisfied word will work as well, but "ignore" is conventional.) +// +// To build a file only when using cgo, and only on Linux and OS X: +// +// // +build linux,cgo darwin,cgo +// +// Such a file is usually paired with another file implementing the +// default functionality for other systems, which in this case would +// carry the constraint: +// +// // +build !linux,!darwin !cgo +// +// Naming a file dns_windows.go will cause it to be included only when +// building the package for Windows; similarly, math_386.s will be included +// only when building the package for 32-bit x86. +// +// +// Build modes +// +// The 'go build' and 'go install' commands take a -buildmode argument which +// indicates which kind of object file is to be built. Currently supported values +// are: +// +// -buildmode=archive +// Build the listed non-main packages into .a files. Packages named +// main are ignored. +// +// -buildmode=c-archive +// Build the listed main package, plus all packages it imports, +// into a C archive file. The only callable symbols will be those +// functions exported using a cgo //export comment. Requires +// exactly one main package to be listed. +// +// -buildmode=c-shared +// Build the listed main package, plus all packages it imports, +// into a C shared library. The only callable symbols will +// be those functions exported using a cgo //export comment. +// Requires exactly one main package to be listed. +// +// -buildmode=default +// Listed main packages are built into executables and listed +// non-main packages are built into .a files (the default +// behavior). +// +// -buildmode=shared +// Combine all the listed non-main packages into a single shared +// library that will be used when building with the -linkshared +// option. Packages named main are ignored. +// +// -buildmode=exe +// Build the listed main packages and everything they import into +// executables. Packages not named main are ignored. +// +// -buildmode=pie +// Build the listed main packages and everything they import into +// position independent executables (PIE). Packages not named +// main are ignored. +// +// -buildmode=plugin +// Build the listed main packages, plus all packages that they +// import, into a Go plugin. Packages not named main are ignored. +// +// On AIX, when linking a C program that uses a Go archive built with +// -buildmode=c-archive, you must pass -Wl,-bnoobjreorder to the C compiler. +// +// +// 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, .S +// or .sx 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. +// 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. +// +// The go command periodically deletes cached data that has not been +// used recently. Running 'go clean -cache' deletes all cached data. +// +// The build cache correctly accounts for changes to Go source files, +// compilers, compiler options, and so on: cleaning the cache explicitly +// should not be necessary in typical use. However, the build cache +// does not detect changes to C libraries imported with cgo. +// If you have made changes to the C libraries on your system, you +// will need to clean the cache explicitly or else use the -a build flag +// (see 'go help build') to force rebuilding of packages that +// depend on the updated C libraries. +// +// The go command also caches successful package test results. +// See 'go help test' for details. Running 'go clean -testcache' removes +// all cached test results (but not cached build results). +// +// The GODEBUG environment variable can enable printing of debugging +// information about the state of the cache: +// +// GODEBUG=gocacheverify=1 causes the go command to bypass the +// use of any cache entries and instead rebuild everything and check +// that the results match existing cache entries. +// +// GODEBUG=gocachehash=1 causes the go command to print the inputs +// for all of the content hashes it uses to construct cache lookup keys. +// The output is voluminous but can be useful for debugging the cache. +// +// GODEBUG=gocachetest=1 causes the go command to print details of its +// decisions about whether to reuse a cached test result. +// +// +// Environment variables +// +// The go command and the tools it invokes consult environment variables +// for configuration. If an environment variable is unset, the go command +// uses a sensible default setting. To see the effective setting of the +// variable , run 'go env '. To change the default setting, +// run 'go env -w ='. Defaults changed using 'go env -w' +// are recorded in a Go environment configuration file stored in the +// per-user configuration directory, as reported by os.UserConfigDir. +// The location of the configuration file can be changed by setting +// the environment variable GOENV, and 'go env GOENV' prints the +// effective location, but 'go env -w' cannot change the default location. +// See 'go help env' for details. +// +// General-purpose environment variables: +// +// GO111MODULE +// Controls whether the go command runs in module-aware mode or GOPATH mode. +// May be "off", "on", or "auto". +// See https://golang.org/ref/mod#mod-commands. +// 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. +// GOMODCACHE +// The directory where the go command will store downloaded modules. +// GODEBUG +// Enable various debugging facilities. See 'go doc runtime' +// for details. +// GOENV +// The location of the Go environment configuration file. +// Cannot be set using 'go env -w'. +// 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. Each entry must be a standalone flag. +// Because the entries are space-separated, flag values must +// not contain spaces. Flags listed on the command line +// are applied after this list and therefore override it. +// GOINSECURE +// Comma-separated list of glob patterns (in the syntax of Go's path.Match) +// of module path prefixes that should always be fetched in an insecure +// manner. Only applies to dependencies that are being fetched directly. +// Unlike the -insecure flag on 'go get', GOINSECURE does not disable +// checksum database validation. GOPRIVATE or GONOSUMDB may be used +// to achieve that. +// 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 https://golang.org/ref/mod#environment-variables +// and https://golang.org/ref/mod#module-proxy for details. +// GOPRIVATE, GONOPROXY, GONOSUMDB +// Comma-separated list of glob patterns (in the syntax of Go's path.Match) +// of module path prefixes that should always be fetched directly +// or that should not be compared against the checksum database. +// See https://golang.org/ref/mod#private-modules. +// GOROOT +// The root of the go tree. +// GOSUMDB +// The name of checksum database to use and optionally its public key and +// URL. See https://golang.org/ref/mod#authenticating. +// GOTMPDIR +// The directory where the go command will write +// temporary source files, packages, and binaries. +// GOVCS +// Lists version control commands that may be used with matching servers. +// See 'go help vcs'. +// +// Environment variables for use with cgo: +// +// AR +// The command to use to manipulate library archives when +// building with the gccgo compiler. +// The default is 'ar'. +// 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. +// FC +// The command to use to compile Fortran 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, how to implement floating point instructions. +// Valid values are sse2 (default), softfloat. +// 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. +// GOWASM +// For GOARCH=wasm, comma-separated list of experimental WebAssembly features to use. +// Valid values are satconv, signext. +// +// 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'. +// Because the variable is defined by Git, the default value cannot +// be set using 'go env -w'. +// +// Additional information available from 'go env' but not read from the environment: +// +// GOEXE +// The executable file name suffix (".exe" on Windows, "" on other systems). +// GOGCCFLAGS +// A space-separated list of arguments supplied to the CC command. +// 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. +// If module-aware mode is enabled, but there is no go.mod, GOMOD will be +// os.DevNull ("/dev/null" on Unix-like systems, "NUL" on Windows). +// If module-aware mode is disabled, GOMOD will be the empty string. +// GOTOOLDIR +// The directory where the go tools (compile, cover, doc, etc...) are installed. +// GOVERSION +// The version of the installed Go tree, as reported by runtime.Version. +// +// +// File types +// +// The go command examines the contents of a restricted set of files +// in each directory. It identifies which files to examine based on +// the extension of the file name. These extensions are: +// +// .go +// Go source files. +// .c, .h +// C source files. +// If the package uses cgo or SWIG, these will be compiled with the +// OS-native compiler (typically gcc); otherwise they will +// trigger an error. +// .cc, .cpp, .cxx, .hh, .hpp, .hxx +// C++ source files. Only useful with cgo or SWIG, and always +// compiled with the OS-native compiler. +// .m +// Objective-C source files. Only useful with cgo, and always +// compiled with the OS-native compiler. +// .s, .S, .sx +// Assembler source files. +// If the package uses cgo or SWIG, these will be assembled with the +// OS-native assembler (typically gcc (sic)); otherwise they +// will be assembled with the Go assembler. +// .swig, .swigcxx +// SWIG definition files. +// .syso +// System object files. +// +// Files of each of these types except .syso may contain build +// constraints, but the go command stops scanning for build constraints +// at the first item in the file that is not a blank line or //-style +// line comment. See the go/build package documentation for +// more details. +// +// +// 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 format is described in detail at +// https://golang.org/ref/mod#go-mod-file. +// +// To create a new go.mod file, use 'go help init'. For details see +// 'go help mod init' or https://golang.org/ref/mod#go-mod-init. +// +// To add missing module requirements or remove unneeded requirements, +// use 'go mod tidy'. For details, see 'go help mod tidy' or +// https://golang.org/ref/mod#go-mod-tidy. +// +// To add, upgrade, downgrade, or remove a specific module requirement, use +// 'go get'. For details, see 'go help module-get' or +// https://golang.org/ref/mod#go-get. +// +// To make other changes or to parse go.mod as JSON for use by other tools, +// use 'go mod edit'. See 'go help mod edit' or +// https://golang.org/ref/mod#go-mod-edit. +// +// +// GOPATH environment variable +// +// The Go path is used to resolve import statements. +// It is implemented by and documented in the go/build package. +// +// The GOPATH environment variable lists places to look for Go code. +// On Unix, the value is a colon-separated string. +// On Windows, the value is a semicolon-separated string. +// On Plan 9, the value is a list. +// +// If the environment variable is unset, GOPATH defaults +// to a subdirectory named "go" in the user's home directory +// ($HOME/go on Unix, %USERPROFILE%\go on Windows), +// unless that directory holds a Go distribution. +// Run "go env GOPATH" to see the current GOPATH. +// +// See https://golang.org/wiki/SettingGOPATH to set a custom GOPATH. +// +// Each directory listed in GOPATH must have a prescribed structure: +// +// The src directory holds source code. The path below src +// determines the import path or executable name. +// +// The pkg directory holds installed package objects. +// As in the Go tree, each target operating system and +// architecture pair has its own subdirectory of pkg +// (pkg/GOOS_GOARCH). +// +// If DIR is a directory listed in the GOPATH, a package with +// source in DIR/src/foo/bar can be imported as "foo/bar" and +// has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a". +// +// The bin directory holds compiled commands. +// Each command is named for its source directory, but only +// the final element, not the entire path. That is, the +// command with source in DIR/src/foo/quux is installed into +// DIR/bin/quux, not DIR/bin/foo/quux. The "foo/" prefix is stripped +// so that you can add DIR/bin to your PATH to get at the +// installed commands. If the GOBIN environment variable is +// set, commands are installed to the directory it names instead +// of DIR/bin. GOBIN must be an absolute path. +// +// Here's an example directory layout: +// +// GOPATH=/home/user/go +// +// /home/user/go/ +// src/ +// foo/ +// bar/ (go code in package bar) +// x.go +// quux/ (go code in package main) +// y.go +// bin/ +// quux (installed command) +// pkg/ +// linux_amd64/ +// foo/ +// bar.a (installed package object) +// +// Go searches each directory listed in GOPATH to find source code, +// but new packages are always downloaded into the first directory +// 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 +// by code in the directory tree rooted at the parent of "internal". +// Here's an extended version of the directory layout above: +// +// /home/user/go/ +// src/ +// crash/ +// bang/ (go code in package bang) +// b.go +// foo/ (go code in package foo) +// f.go +// bar/ (go code in package bar) +// x.go +// internal/ +// baz/ (go code in package baz) +// z.go +// quux/ (go code in package main) +// y.go +// +// +// The code in z.go is imported as "foo/internal/baz", but that +// import statement can only appear in source files in the subtree +// rooted at foo. The source files foo/f.go, foo/bar/x.go, and +// foo/quux/y.go can all import "foo/internal/baz", but the source file +// crash/bang/b.go cannot. +// +// See https://golang.org/s/go14internal for details. +// +// Vendor Directories +// +// Go 1.6 includes support for using local copies of external dependencies +// to satisfy imports of those dependencies, often referred to as vendoring. +// +// Code below a directory named "vendor" is importable only +// by code in the directory tree rooted at the parent of "vendor", +// and only using an import path that omits the prefix up to and +// including the vendor element. +// +// Here's the example from the previous section, +// but with the "internal" directory renamed to "vendor" +// and a new foo/vendor/crash/bang directory added: +// +// /home/user/go/ +// src/ +// crash/ +// bang/ (go code in package bang) +// b.go +// foo/ (go code in package foo) +// f.go +// bar/ (go code in package bar) +// x.go +// vendor/ +// crash/ +// bang/ (go code in package bang) +// b.go +// baz/ (go code in package baz) +// z.go +// quux/ (go code in package main) +// y.go +// +// The same visibility rules apply as for internal, but the code +// in z.go is imported as "baz", not as "foo/vendor/baz". +// +// Code in vendor directories deeper in the source tree shadows +// code in higher directories. Within the subtree rooted at foo, an import +// of "crash/bang" resolves to "foo/vendor/crash/bang", not the +// top-level "crash/bang". +// +// Code in vendor directories is not subject to import path +// checking (see 'go help importpath'). +// +// When 'go get' checks out or updates a git repository, it now also +// updates submodules. +// +// Vendor directories do not affect the placement of new repositories +// being checked out for the first time by 'go get': those are always +// placed in the main GOPATH, never in a vendor subtree. +// +// See https://golang.org/s/go15vendor for details. +// +// +// Legacy GOPATH 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 gopath-get' even in module-aware mode, +// describes 'go get' as it operates in legacy GOPATH mode. +// +// Usage: 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'. +// +// The -d flag instructs get to stop after downloading the packages; that is, +// it instructs get not to install the packages. +// +// The -f flag, valid only when -u is set, forces get -u not to verify that +// each package has been checked out from the source control repository +// implied by its import path. This can be useful if the source is a local fork +// of the original. +// +// The -fix flag instructs get to run the fix tool on the downloaded packages +// before resolving dependencies or building the code. +// +// The -insecure flag permits fetching from repositories and resolving +// custom domains using insecure schemes such as HTTP. Use with caution. +// This flag is deprecated and will be removed in a future version of go. +// The GOINSECURE environment variable should be used instead, since it +// provides control over which packages may be retrieved using an insecure +// scheme. See 'go help environment' for details. +// +// The -t flag instructs get to also download the packages required to build +// the tests for the specified packages. +// +// The -u flag instructs get to use the network to update the named packages +// and their dependencies. By default, get uses the network to check out +// missing packages but does not use it to look for updates to existing packages. +// +// The -v flag enables verbose progress and debug output. +// +// Get also accepts build flags to control the installation. See 'go help build'. +// +// When checking out a new package, get creates the target directory +// GOPATH/src/. If the GOPATH contains multiple entries, +// get uses the first one. For more details see: 'go help gopath'. +// +// When checking out or updating a package, get looks for a branch or tag +// that matches the locally installed version of Go. The most important +// rule is that if the local installation is running version "go1", get +// searches for a branch or tag named "go1". If no such version exists +// it retrieves the default branch of the package. +// +// When go get checks out or updates a Git repository, +// it also updates any git submodules referenced by the repository. +// +// Get never checks out or updates code stored in vendor directories. +// +// 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. +// +// +// Module proxy protocol +// +// 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. +// +// For details on the GOPROXY protocol, see +// https://golang.org/ref/mod#goproxy-protocol. +// +// +// Import path syntax +// +// An import path (see 'go help packages') denotes a package stored in the local +// file system. In general, an import path denotes either a standard package (such +// as "unicode/utf8") or a package found in one of the work spaces (For more +// details see: 'go help gopath'). +// +// Relative import paths +// +// An import path beginning with ./ or ../ is called a relative path. +// The toolchain supports relative import paths as a shortcut in two ways. +// +// First, a relative path can be used as a shorthand on the command line. +// If you are working in the directory containing the code imported as +// "unicode" and want to run the tests for "unicode/utf8", you can type +// "go test ./utf8" instead of needing to specify the full path. +// Similarly, in the reverse situation, "go test .." will test "unicode" from +// the "unicode/utf8" directory. Relative patterns are also allowed, like +// "go test ./..." to test all subdirectories. See 'go help packages' for details +// on the pattern syntax. +// +// Second, if you are compiling a Go program not in a work space, +// you can use a relative path in an import statement in that program +// to refer to nearby code also not in a work space. +// This makes it easy to experiment with small multipackage programs +// outside of the usual work spaces, but such programs cannot be +// installed with "go install" (there is no work space in which to install them), +// so they are rebuilt from scratch each time they are built. +// To avoid ambiguity, Go programs cannot use relative import paths +// within a work space. +// +// Remote import paths +// +// Certain import paths also +// describe how to obtain the source code for the package using +// a revision control system. +// +// A few common code hosting sites have special syntax: +// +// Bitbucket (Git, Mercurial) +// +// import "bitbucket.org/user/project" +// import "bitbucket.org/user/project/sub/directory" +// +// GitHub (Git) +// +// import "github.com/user/project" +// import "github.com/user/project/sub/directory" +// +// Launchpad (Bazaar) +// +// import "launchpad.net/project" +// import "launchpad.net/project/series" +// import "launchpad.net/project/series/sub/directory" +// +// import "launchpad.net/~user/project/branch" +// import "launchpad.net/~user/project/branch/sub/directory" +// +// IBM DevOps Services (Git) +// +// import "hub.jazz.net/git/user/project" +// import "hub.jazz.net/git/user/project/sub/directory" +// +// For code hosted on other servers, import paths may either be qualified +// with the version control type, or the go tool can dynamically fetch +// the import path over https/http and discover where the code resides +// from a tag in the HTML. +// +// To declare the code location, an import path of the form +// +// repository.vcs/path +// +// specifies the given repository, with or without the .vcs suffix, +// 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 +// +// For example, +// +// import "example.org/user/foo.hg" +// +// denotes the root directory of the Mercurial repository at +// example.org/user/foo or foo.hg, and +// +// import "example.org/repo.git/foo/bar" +// +// denotes the foo/bar directory of the Git repository at +// example.org/repo or repo.git. +// +// When a version control system supports multiple protocols, +// each is tried in turn when downloading. For example, a Git +// download tries https://, then git+ssh://. +// +// By default, downloads are restricted to known secure protocols +// (e.g. https, ssh). To override this setting for Git downloads, the +// GIT_ALLOW_PROTOCOL environment variable can be set (For more details see: +// 'go help environment'). +// +// If the import path is not a known code hosting site and also lacks a +// version control qualifier, the go tool attempts to fetch the import +// over https/http and looks for a tag in the document's HTML +// . +// +// The meta tag has the form: +// +// +// +// The import-prefix is the import path corresponding to the repository +// root. It must be a prefix or an exact match of the package being +// fetched with "go get". If it's not an exact match, another http +// request is made at the prefix to verify the tags match. +// +// 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 "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. +// +// For example, +// +// import "example.org/pkg/foo" +// +// will result in the following requests: +// +// https://example.org/pkg/foo?go-get=1 (preferred) +// http://example.org/pkg/foo?go-get=1 (fallback, only with -insecure) +// +// If that page contains the meta tag +// +// +// +// 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. +// +// 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 https://golang.org/ref/mod#module-cache. +// +// 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: +// +// +// +// 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 https://golang.org/ref/mod#goproxy-protocol for details about the +// proxy protocol. +// +// Import path checking +// +// When the custom import path feature described above redirects to a +// known code hosting site, each of the resulting packages has two possible +// import paths, using the custom domain or the known hosting site. +// +// A package statement is said to have an "import comment" if it is immediately +// followed (before the next newline) by a comment of one of these two forms: +// +// package math // import "path" +// package math /* import "path" */ +// +// The go command will refuse to install a package with an import comment +// unless it is being referred to by that import path. In this way, import comments +// let package authors make sure the custom import path is used and not a +// direct path to the underlying code hosting site. +// +// 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. +// +// +// Modules, module versions, and more +// +// Modules are how Go manages dependencies. +// +// A module is a collection of packages that are released, versioned, and +// distributed together. Modules may be downloaded directly from version control +// repositories or from module proxy servers. +// +// For a series of tutorials on modules, see +// https://golang.org/doc/tutorial/create-module. +// +// For a detailed reference on modules, see https://golang.org/ref/mod. +// +// By default, the go command may download modules from https://proxy.golang.org. +// It may authenticate modules using the checksum database at +// https://sum.golang.org. Both services are operated by the Go team at Google. +// The privacy policies for these services are available at +// https://proxy.golang.org/privacy and https://sum.golang.org/privacy, +// respectively. +// +// The go command's download behavior may be configured using GOPROXY, GOSUMDB, +// GOPRIVATE, and other environment variables. See 'go help environment' +// and https://golang.org/ref/mod#private-module-privacy for more information. +// +// +// Module authentication using go.sum +// +// When the go command downloads a module zip file or go.mod file into the +// module cache, it computes a cryptographic hash and compares it with a known +// value to verify the file hasn't changed since it was first downloaded. Known +// hashes are stored in a file in the module root directory named go.sum. Hashes +// may also be downloaded from the checksum database depending on the values of +// GOSUMDB, GOPRIVATE, and GONOSUMDB. +// +// For details, see https://golang.org/ref/mod#authenticating. +// +// +// Package lists and patterns +// +// Many commands apply to a set of packages: +// +// go action [packages] +// +// Usually, [packages] is a list of import paths. +// +// An import path that is a rooted path or that begins with +// a . or .. element is interpreted as a file system path and +// denotes the package in that directory. +// +// Otherwise, the import path P denotes the package found in +// the directory DIR/src/P for some DIR listed in the GOPATH +// environment variable (For more details see: 'go help gopath'). +// +// If no import paths are given, the action applies to the +// package in the current directory. +// +// There are four reserved names for paths that should not be used +// for packages to be built with the go tool: +// +// - "main" denotes the top-level package in a stand-alone executable. +// +// - "all" expands to all packages found in all the GOPATH +// trees. For example, 'go list all' lists all the packages on the local +// 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. +// +// - "cmd" expands to the Go repository's commands and their +// internal libraries. +// +// Import paths beginning with "cmd/" only match source code in +// the Go repository. +// +// An import path is a pattern if it includes one or more "..." wildcards, +// each of which can match any string, including the empty string and +// strings containing slashes. Such a pattern expands to all package +// directories found in the GOPATH trees with names matching the +// patterns. +// +// To make common patterns more convenient, there are two special cases. +// 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-separated 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. +// See golang.org/s/go15vendor for more about vendoring. +// +// An import path can also name a package to be downloaded from +// a remote repository. Run 'go help importpath' for details. +// +// Every package in a program must have a unique import path. +// By convention, this is arranged by starting each path with a +// unique prefix that belongs to you. For example, paths used +// internally at Google all begin with 'google', and paths +// denoting remote repositories begin with the path to the code, +// such as 'github.com/user/repo'. +// +// Packages in a program need not have unique package names, +// but there are two reserved package names with special meaning. +// The name main indicates a command, not a library. +// Commands are built into binaries and cannot be imported. +// The name documentation indicates documentation for +// a non-Go program in the directory. Files in package documentation +// are ignored by the go command. +// +// As a special case, if the package list is a list of .go files from a +// single directory, the command is applied to a single synthesized +// package made up of exactly those files, ignoring any build constraints +// in those files and ignoring any other files in the directory. +// +// Directory and file names that begin with "." or "_" are ignored +// by the go tool, as are directories named "testdata". +// +// +// Configuration for downloading non-public code +// +// The go command defaults to downloading modules from the public Go module +// mirror at proxy.golang.org. It also defaults to validating downloaded modules, +// regardless of source, against the public Go checksum database at sum.golang.org. +// These defaults work well for publicly available source code. +// +// The GOPRIVATE environment variable controls which modules the go command +// considers to be private (not available publicly) and should therefore not use +// the proxy or checksum database. The variable is a comma-separated list of +// glob patterns (in the syntax of Go's path.Match) of module path prefixes. +// For example, +// +// GOPRIVATE=*.corp.example.com,rsc.io/private +// +// causes the go command to treat as private any module with a path prefix +// matching either pattern, including git.corp.example.com/xyzzy, rsc.io/private, +// and rsc.io/private/quux. +// +// For fine-grained control over module download and validation, the GONOPROXY +// and GONOSUMDB environment variables accept the same kind of glob list +// and override GOPRIVATE for the specific decision of whether to use the proxy +// and checksum database, respectively. +// +// For example, if a company ran a module proxy serving private modules, +// users would configure go using: +// +// GOPRIVATE=*.corp.example.com +// GOPROXY=proxy.example.com +// GONOPROXY=none +// +// The GOPRIVATE variable is also used to define the "public" and "private" +// patterns for the GOVCS variable; see 'go help vcs'. For that usage, +// GOPRIVATE applies even in GOPATH mode. In that case, it matches import paths +// instead of module paths. +// +// The 'go env -w' command (see 'go help env') can be used to set these variables +// for future go command invocations. +// +// For more details, see https://golang.org/ref/mod#private-modules. +// +// +// Testing flags +// +// The 'go test' command takes both flags that apply to 'go test' itself +// and flags that apply to the resulting test binary. +// +// Several of the flags control profiling and write an execution profile +// suitable for "go tool pprof"; run "go tool pprof -h" for more +// information. The --alloc_space, --alloc_objects, and --show_bytes +// options of pprof control how the information is presented. +// +// The following flags are recognized by the 'go test' command and +// control the execution of any test: +// +// -bench regexp +// Run only those benchmarks matching a regular expression. +// By default, no benchmarks are run. +// To run all benchmarks, use '-bench .' or '-bench=.'. +// The regular expression is split by unbracketed slash (/) +// characters into a sequence of regular expressions, and each +// part of a benchmark's identifier must match the corresponding +// element in the sequence, if any. Possible parents of matches +// are run with b.N=1 to identify sub-benchmarks. For example, +// given -bench=X/Y, top-level benchmarks matching X are run +// with b.N=1 to find any sub-benchmarks matching Y, which are +// then run in full. +// +// -benchtime t +// Run enough iterations of each benchmark to take t, specified +// as a time.Duration (for example, -benchtime 1h30s). +// The default is 1 second (1s). +// The special syntax Nx means to run the benchmark N times +// (for example, -benchtime 100x). +// +// -count n +// Run each test and benchmark n times (default 1). +// If -cpu is set, run n times for each GOMAXPROCS value. +// Examples are always run once. +// +// -cover +// Enable coverage analysis. +// Note that because coverage works by annotating the source +// code before compilation, compilation and test failures with +// coverage enabled may report line numbers that don't correspond +// to the original sources. +// +// -covermode set,count,atomic +// Set the mode for coverage analysis for the package[s] +// being tested. The default is "set" unless -race is enabled, +// in which case it is "atomic". +// The values: +// set: bool: does this statement run? +// count: int: how many times does this statement run? +// atomic: int: count, but correct in multithreaded tests; +// significantly more expensive. +// Sets -cover. +// +// -coverpkg pattern1,pattern2,pattern3 +// Apply coverage analysis in each test to packages matching the patterns. +// The default is for each test to analyze only the package being tested. +// See 'go help packages' for a description of package patterns. +// Sets -cover. +// +// -cpu 1,2,4 +// Specify a list of GOMAXPROCS values for which the tests or +// benchmarks should be executed. The default is the current value +// of GOMAXPROCS. +// +// -failfast +// Do not start new tests after the first test failure. +// +// -list regexp +// List tests, benchmarks, or examples matching the regular expression. +// No tests, benchmarks or examples will be run. This will only +// list top-level tests. No subtest or subbenchmarks will be shown. +// +// -parallel n +// Allow parallel execution of test functions that call t.Parallel. +// The value of this flag is the maximum number of tests to run +// simultaneously; by default, it is set to the value of GOMAXPROCS. +// Note that -parallel only applies within a single test binary. +// The 'go test' command may run tests for different packages +// in parallel as well, according to the setting of the -p flag +// (see 'go help build'). +// +// -run regexp +// Run only those tests and examples matching the regular expression. +// For tests, the regular expression is split by unbracketed slash (/) +// characters into a sequence of regular expressions, and each part +// of a test's identifier must match the corresponding element in +// the sequence, if any. Note that possible parents of matches are +// run too, so that -run=X/Y matches and runs and reports the result +// of all tests matching X, even those without sub-tests matching Y, +// because it must run them to look for those sub-tests. +// +// -short +// Tell long-running tests to shorten their run time. +// It is off by default but set during all.bash so that installing +// the Go tree can run a sanity check but not spend time running +// exhaustive tests. +// +// -timeout d +// If a test binary runs longer than duration d, panic. +// If d is 0, the timeout is disabled. +// The default is 10 minutes (10m). +// +// -v +// Verbose output: log all tests as they are run. Also print all +// text from Log and Logf calls even if the test succeeds. +// +// -vet list +// Configure the invocation of "go vet" during "go test" +// to use the comma-separated list of vet checks. +// If list is empty, "go test" runs "go vet" with a curated list of +// checks believed to be always worth addressing. +// If list is "off", "go test" does not run "go vet" at all. +// +// The following flags are also recognized by 'go test' and can be used to +// profile the tests during execution: +// +// -benchmem +// Print memory allocation statistics for benchmarks. +// +// -blockprofile block.out +// Write a goroutine blocking profile to the specified file +// when all tests are complete. +// Writes test binary as -c would. +// +// -blockprofilerate n +// Control the detail provided in goroutine blocking profiles by +// calling runtime.SetBlockProfileRate with n. +// See 'go doc runtime.SetBlockProfileRate'. +// The profiler aims to sample, on average, one blocking event every +// n nanoseconds the program spends blocked. By default, +// if -test.blockprofile is set without this flag, all blocking events +// are recorded, equivalent to -test.blockprofilerate=1. +// +// -coverprofile cover.out +// Write a coverage profile to the file after all tests have passed. +// Sets -cover. +// +// -cpuprofile cpu.out +// Write a CPU profile to the specified file before exiting. +// Writes test binary as -c would. +// +// -memprofile mem.out +// 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 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 +// when all tests are complete. +// Writes test binary as -c would. +// +// -mutexprofilefraction n +// Sample 1 in n stack traces of goroutines holding a +// contended mutex. +// +// -outputdir directory +// Place output files from profiling in the specified directory, +// by default the directory in which "go test" is running. +// +// -trace trace.out +// Write an execution trace to the specified file before exiting. +// +// Each of these flags is also recognized with an optional 'test.' prefix, +// as in -test.v. When invoking the generated test binary (the result of +// 'go test -c') directly, however, the prefix is mandatory. +// +// The 'go test' command rewrites or removes recognized flags, +// as appropriate, both before and after the optional package list, +// before invoking the test binary. +// +// For instance, the command +// +// go test -v -myflag testdata -cpuprofile=prof.out -x +// +// will compile the test binary and then run it as +// +// pkg.test -test.v -myflag testdata -test.cpuprofile=prof.out +// +// (The -x flag is removed because it applies only to the go command's +// execution, not to the test itself.) +// +// The test flags that generate profiles (other than for coverage) also +// leave the test binary in pkg.test for use when analyzing the profiles. +// +// When 'go test' runs a test binary, it does so from within the +// corresponding package's source code directory. Depending on the test, +// it may be necessary to do the same when invoking a generated test +// binary directly. +// +// The command-line package list, if present, must appear before any +// 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 +// uninterpreted and unaltered. +// +// For instance, the command +// +// go test -v -args -x -v +// +// will compile the test binary and then run it as +// +// pkg.test -test.v -x -v +// +// Similarly, +// +// go test -args math +// +// will compile the test binary and then run it as +// +// pkg.test math +// +// In the first example, the -x and the second -v are passed through to the +// test binary unchanged and with no effect on the go command itself. +// In the second example, the argument math is passed through to the test +// binary, instead of being interpreted as the package list. +// +// +// Testing functions +// +// The 'go test' command expects to find test, benchmark, and example functions +// in the "*_test.go" files corresponding to the package under test. +// +// A test function is one named TestXxx (where Xxx does not start with a +// lower case letter) and should have the signature, +// +// func TestXxx(t *testing.T) { ... } +// +// A benchmark function is one named BenchmarkXxx and should have the signature, +// +// func BenchmarkXxx(b *testing.B) { ... } +// +// An example function is similar to a test function but, instead of using +// *testing.T to report success or failure, prints output to os.Stdout. +// If the last comment in the function starts with "Output:" then the output +// is compared exactly against the comment (see examples below). If the last +// comment begins with "Unordered output:" then the output is compared to the +// comment, however the order of the lines is ignored. An example with no such +// comment is compiled but not executed. An example with no text after +// "Output:" is compiled, executed, and expected to produce no output. +// +// Godoc displays the body of ExampleXxx to demonstrate the use +// of the function, constant, or variable Xxx. An example of a method M with +// receiver type T or *T is named ExampleT_M. There may be multiple examples +// for a given function, constant, or variable, distinguished by a trailing _xxx, +// where xxx is a suffix not beginning with an upper case letter. +// +// Here is an example of an example: +// +// func ExamplePrintln() { +// Println("The output of\nthis example.") +// // Output: The output of +// // this example. +// } +// +// Here is another example where the ordering of the output is ignored: +// +// func ExamplePerm() { +// for _, value := range Perm(4) { +// fmt.Println(value) +// } +// +// // Unordered output: 4 +// // 2 +// // 1 +// // 3 +// // 0 +// } +// +// The entire test file is presented as the example when it contains a single +// example function, at least one other function, type, variable, or constant +// declaration, and no test or benchmark functions. +// +// See the documentation of the testing package for more information. +// +// +// Controlling version control with GOVCS +// +// The 'go get' command can run version control commands like git +// to download imported code. This functionality is critical to the decentralized +// Go package ecosystem, in which code can be imported from any server, +// but it is also a potential security problem, if a malicious server finds a +// way to cause the invoked version control command to run unintended code. +// +// To balance the functionality and security concerns, the 'go get' command +// by default will only use git and hg to download code from public servers. +// But it will use any known version control system (bzr, fossil, git, hg, svn) +// to download code from private servers, defined as those hosting packages +// matching the GOPRIVATE variable (see 'go help private'). The rationale behind +// allowing only Git and Mercurial is that these two systems have had the most +// attention to issues of being run as clients of untrusted servers. In contrast, +// Bazaar, Fossil, and Subversion have primarily been used in trusted, +// authenticated environments and are not as well scrutinized as attack surfaces. +// +// The version control command restrictions only apply when using direct version +// control access to download code. When downloading modules from a proxy, +// 'go get' uses the proxy protocol instead, which is always permitted. +// By default, the 'go get' command uses the Go module mirror (proxy.golang.org) +// for public packages and only falls back to version control for private +// packages or when the mirror refuses to serve a public package (typically for +// legal reasons). Therefore, clients can still access public code served from +// Bazaar, Fossil, or Subversion repositories by default, because those downloads +// use the Go module mirror, which takes on the security risk of running the +// version control commands using a custom sandbox. +// +// The GOVCS variable can be used to change the allowed version control systems +// for specific packages (identified by a module or import path). +// The GOVCS variable applies when building package in both module-aware mode +// and GOPATH mode. When using modules, the patterns match against the module path. +// When using GOPATH, the patterns match against the import path corresponding to +// the root of the version control repository. +// +// The general form of the GOVCS setting is a comma-separated list of +// pattern:vcslist rules. The pattern is a glob pattern that must match +// one or more leading elements of the module or import path. The vcslist +// is a pipe-separated list of allowed version control commands, or "all" +// to allow use of any known command, or "off" to disallow all commands. +// Note that if a module matches a pattern with vcslist "off", it may still be +// downloaded if the origin server uses the "mod" scheme, which instructs the +// go command to download the module using the GOPROXY protocol. +// The earliest matching pattern in the list applies, even if later patterns +// might also match. +// +// For example, consider: +// +// GOVCS=github.com:git,evil.com:off,*:git|hg +// +// With this setting, code with a module or import path beginning with +// github.com/ can only use git; paths on evil.com cannot use any version +// control command, and all other paths (* matches everything) can use +// only git or hg. +// +// The special patterns "public" and "private" match public and private +// module or import paths. A path is private if it matches the GOPRIVATE +// variable; otherwise it is public. +// +// If no rules in the GOVCS variable match a particular module or import path, +// the 'go get' command applies its default rule, which can now be summarized +// in GOVCS notation as 'public:git|hg,private:all'. +// +// To allow unfettered use of any version control system for any package, use: +// +// GOVCS=*:all +// +// To disable all use of version control, use: +// +// GOVCS=*:off +// +// The 'go env -w' command (see 'go help env') can be used to set the GOVCS +// variable for future go command invocations. +// +// +package main diff --git a/src/cmd/go/go11.go b/src/cmd/go/go11.go new file mode 100644 index 0000000..7e383f4 --- /dev/null +++ b/src/cmd/go/go11.go @@ -0,0 +1,10 @@ +// Copyright 2013 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 go1.1 + +package main + +// Test that go1.1 tag above is included in builds. main.go refers to this definition. +const go11tag = true diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go new file mode 100644 index 0000000..3ce3238 --- /dev/null +++ b/src/cmd/go/go_test.go @@ -0,0 +1,2832 @@ +// Copyright 2015 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 ( + "bytes" + "debug/elf" + "debug/macho" + "debug/pe" + "encoding/binary" + "flag" + "fmt" + "go/format" + "internal/race" + "internal/testenv" + "io" + "io/fs" + "log" + "os" + "os/exec" + "path/filepath" + "regexp" + "runtime" + "strconv" + "strings" + "testing" + "time" + + "cmd/go/internal/cache" + "cmd/go/internal/cfg" + "cmd/go/internal/robustio" + "cmd/go/internal/work" + "cmd/internal/sys" +) + +func init() { + // GOVCS defaults to public:git|hg,private:all, + // which breaks many tests here - they can't use non-git, non-hg VCS at all! + // Change to fully permissive. + // The tests of the GOVCS setting itself are in ../../testdata/script/govcs.txt. + os.Setenv("GOVCS", "*:all") +} + +var ( + canRace = false // whether we can run the race detector + canCgo = false // whether we can use cgo + canMSan = false // whether we can run the memory sanitizer +) + +var exeSuffix string = func() string { + if runtime.GOOS == "windows" { + return ".exe" + } + return "" +}() + +func tooSlow(t *testing.T) { + if testing.Short() { + // In -short mode; skip test, except run it on the {darwin,linux,windows}/amd64 builders. + if testenv.Builder() != "" && runtime.GOARCH == "amd64" && (runtime.GOOS == "linux" || runtime.GOOS == "darwin" || runtime.GOOS == "windows") { + return + } + t.Helper() + t.Skip("skipping test in -short mode") + } +} + +// testGOROOT is the GOROOT to use when running testgo, a cmd/go binary +// build from this process's current GOROOT, but run from a different +// (temp) directory. +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. +func TestMain(m *testing.M) { + // $GO_GCFLAGS a compiler debug flag known to cmd/dist, make.bash, etc. + // It is not a standard go command flag; use os.Getenv, not cfg.Getenv. + if os.Getenv("GO_GCFLAGS") != "" { + fmt.Fprintf(os.Stderr, "testing: warning: no tests to run\n") // magic string for cmd/go + fmt.Printf("cmd/go test is not compatible with $GO_GCFLAGS being set\n") + fmt.Printf("SKIP\n") + return + } + + flag.Parse() + + if *proxyAddr != "" { + StartProxy() + select {} + } + + // Run with a temporary TMPDIR to check that the tests don't + // leave anything behind. + topTmpdir, err := os.MkdirTemp("", "cmd-go-test-") + if err != nil { + log.Fatal(err) + } + if !*testWork { + defer removeAll(topTmpdir) + } + os.Setenv(tempEnvName(), topTmpdir) + + dir, err := os.MkdirTemp(topTmpdir, "tmpdir") + if err != nil { + log.Fatal(err) + } + testTmpDir = dir + if !*testWork { + defer removeAll(testTmpDir) + } + + testGOCACHE = cache.DefaultDir() + if testenv.HasGoBuild() { + 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") + } + gotool, err := testenv.GoTool() + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(2) + } + + goEnv := func(name string) string { + out, err := exec.Command(gotool, "env", name).CombinedOutput() + if err != nil { + fmt.Fprintf(os.Stderr, "go env %s: %v\n%s", name, err, out) + os.Exit(2) + } + return strings.TrimSpace(string(out)) + } + testGOROOT = goEnv("GOROOT") + os.Setenv("TESTGO_GOROOT", testGOROOT) + // Ensure that GOROOT is set explicitly. + // Otherwise, if the toolchain was built with GOROOT_FINAL set but has not + // yet been moved to its final location, programs that invoke runtime.GOROOT + // may accidentally use the wrong path. + os.Setenv("GOROOT", testGOROOT) + + // The whole GOROOT/pkg tree was installed using the GOHOSTOS/GOHOSTARCH + // toolchain (installed in GOROOT/pkg/tool/GOHOSTOS_GOHOSTARCH). + // The testgo.exe we are about to create will be built for GOOS/GOARCH, + // which means it will use the GOOS/GOARCH toolchain + // (installed in GOROOT/pkg/tool/GOOS_GOARCH). + // If these are not the same toolchain, then the entire standard library + // will look out of date (the compilers in those two different tool directories + // are built for different architectures and have different build IDs), + // which will cause many tests to do unnecessary rebuilds and some + // tests to attempt to overwrite the installed standard library. + // Bail out entirely in this case. + hostGOOS := goEnv("GOHOSTOS") + hostGOARCH := goEnv("GOHOSTARCH") + if hostGOOS != runtime.GOOS || hostGOARCH != runtime.GOARCH { + fmt.Fprintf(os.Stderr, "testing: warning: no tests to run\n") // magic string for cmd/go + fmt.Printf("cmd/go test is not compatible with GOOS/GOARCH != GOHOSTOS/GOHOSTARCH (%s/%s != %s/%s)\n", runtime.GOOS, runtime.GOARCH, hostGOOS, hostGOARCH) + fmt.Printf("SKIP\n") + return + } + + buildCmd := exec.Command(gotool, args...) + buildCmd.Env = append(os.Environ(), "GOFLAGS=-mod=vendor") + out, err := buildCmd.CombinedOutput() + if err != nil { + fmt.Fprintf(os.Stderr, "building testgo failed: %v\n%s", err, out) + os.Exit(2) + } + + out, err = exec.Command(gotool, "env", "CC").CombinedOutput() + if err != nil { + fmt.Fprintf(os.Stderr, "could not find testing CC: %v\n%s", err, out) + os.Exit(2) + } + testCC = strings.TrimSpace(string(out)) + + cmd := exec.Command(testGo, "env", "CGO_ENABLED") + cmd.Stderr = new(strings.Builder) + if out, err := cmd.Output(); err != nil { + fmt.Fprintf(os.Stderr, "running testgo failed: %v\n%s", err, cmd.Stderr) + os.Exit(2) + } else { + canCgo, err = strconv.ParseBool(strings.TrimSpace(string(out))) + if err != nil { + fmt.Fprintf(os.Stderr, "can't parse go env CGO_ENABLED output: %v\n", strings.TrimSpace(string(out))) + } + } + + 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)) + + canMSan = canCgo && sys.MSanSupported(runtime.GOOS, runtime.GOARCH) + canRace = canCgo && sys.RaceDetectorSupported(runtime.GOOS, runtime.GOARCH) + // The race detector doesn't work on Alpine Linux: + // golang.org/issue/14481 + // gccgo does not support the race detector. + if isAlpineLinux() || runtime.Compiler == "gccgo" { + canRace = false + } + } + // Don't let these environment variables confuse the test. + os.Setenv("GOENV", "off") + os.Unsetenv("GOFLAGS") + os.Unsetenv("GOBIN") + os.Unsetenv("GOPATH") + os.Unsetenv("GIT_ALLOW_PROTOCOL") + 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 cfg.Getenv("GOCACHE") == "" { + os.Setenv("GOCACHE", testGOCACHE) // because $HOME is gone + } + + r := m.Run() + if !*testWork { + removeAll(testTmpDir) // os.Exit won't run defer + } + + if !*testWork { + // There shouldn't be anything left in topTmpdir. + dirf, err := os.Open(topTmpdir) + if err != nil { + log.Fatal(err) + } + names, err := dirf.Readdirnames(0) + if err != nil { + log.Fatal(err) + } + if len(names) > 0 { + log.Fatalf("unexpected files left in tmpdir: %v", names) + } + + removeAll(topTmpdir) + } + + os.Exit(r) +} + +func isAlpineLinux() bool { + if runtime.GOOS != "linux" { + return false + } + fi, err := os.Lstat("/etc/alpine-release") + return err == nil && fi.Mode().IsRegular() +} + +// The length of an mtime tick on this system. This is an estimate of +// how long we need to sleep to ensure that the mtime of two files is +// different. +// We used to try to be clever but that didn't always work (see golang.org/issue/12205). +var mtimeTick time.Duration = 1 * time.Second + +// Manage a single run of the testgo binary. +type testgoData struct { + t *testing.T + temps []string + env []string + tempdir string + ran bool + inParallel bool + stdout, stderr bytes.Buffer + execDir string // dir for tg.run +} + +// skipIfGccgo skips the test if using gccgo. +func skipIfGccgo(t *testing.T, msg string) { + if runtime.Compiler == "gccgo" { + t.Skipf("skipping test not supported on gccgo: %s", msg) + } +} + +// testgo sets up for a test that runs testgo. +func testgo(t *testing.T) *testgoData { + t.Helper() + testenv.MustHaveGoBuild(t) + testenv.SkipIfShortAndSlow(t) + + return &testgoData{t: t} +} + +// must gives a fatal error if err is not nil. +func (tg *testgoData) must(err error) { + tg.t.Helper() + if err != nil { + tg.t.Fatal(err) + } +} + +// check gives a test non-fatal error if err is not nil. +func (tg *testgoData) check(err error) { + tg.t.Helper() + if err != nil { + tg.t.Error(err) + } +} + +// parallel runs the test in parallel by calling t.Parallel. +func (tg *testgoData) parallel() { + tg.t.Helper() + if tg.ran { + tg.t.Fatal("internal testsuite error: call to parallel after run") + } + for _, e := range tg.env { + if strings.HasPrefix(e, "GOROOT=") || strings.HasPrefix(e, "GOPATH=") || strings.HasPrefix(e, "GOBIN=") { + val := e[strings.Index(e, "=")+1:] + if strings.HasPrefix(val, "testdata") || strings.HasPrefix(val, "./testdata") { + tg.t.Fatalf("internal testsuite error: call to parallel with testdata in environment (%s)", e) + } + } + } + tg.inParallel = true + tg.t.Parallel() +} + +// pwd returns the current directory. +func (tg *testgoData) pwd() string { + tg.t.Helper() + wd, err := os.Getwd() + if err != nil { + tg.t.Fatalf("could not get working directory: %v", err) + } + return wd +} + +// sleep sleeps for one tick, where a tick is a conservative estimate +// of how long it takes for a file modification to get a different +// mtime. +func (tg *testgoData) sleep() { + time.Sleep(mtimeTick) +} + +// setenv sets an environment variable to use when running the test go +// command. +func (tg *testgoData) setenv(name, val string) { + tg.t.Helper() + if tg.inParallel && (name == "GOROOT" || name == "GOPATH" || name == "GOBIN") && (strings.HasPrefix(val, "testdata") || strings.HasPrefix(val, "./testdata")) { + tg.t.Fatalf("internal testsuite error: call to setenv with testdata (%s=%s) after parallel", name, val) + } + tg.unsetenv(name) + tg.env = append(tg.env, name+"="+val) +} + +// unsetenv removes an environment variable. +func (tg *testgoData) unsetenv(name string) { + if tg.env == nil { + tg.env = append([]string(nil), os.Environ()...) + tg.env = append(tg.env, "GO111MODULE=off") + } + for i, v := range tg.env { + if strings.HasPrefix(v, name+"=") { + tg.env = append(tg.env[:i], tg.env[i+1:]...) + break + } + } +} + +func (tg *testgoData) goTool() string { + return testGo +} + +// doRun runs the test go command, recording stdout and stderr and +// returning exit status. +func (tg *testgoData) doRun(args []string) error { + tg.t.Helper() + if tg.inParallel { + for _, arg := range args { + if strings.HasPrefix(arg, "testdata") || strings.HasPrefix(arg, "./testdata") { + tg.t.Fatal("internal testsuite error: parallel run using testdata") + } + } + } + + hasGoroot := false + for _, v := range tg.env { + if strings.HasPrefix(v, "GOROOT=") { + hasGoroot = true + break + } + } + prog := tg.goTool() + if !hasGoroot { + tg.setenv("GOROOT", testGOROOT) + } + + tg.t.Logf("running testgo %v", args) + 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 + status := cmd.Run() + if tg.stdout.Len() > 0 { + tg.t.Log("standard output:") + tg.t.Log(tg.stdout.String()) + } + if tg.stderr.Len() > 0 { + tg.t.Log("standard error:") + tg.t.Log(tg.stderr.String()) + } + tg.ran = true + return status +} + +// run runs the test go command, and expects it to succeed. +func (tg *testgoData) run(args ...string) { + tg.t.Helper() + if status := tg.doRun(args); status != nil { + wd, _ := os.Getwd() + tg.t.Logf("go %v failed unexpectedly in %s: %v", args, wd, status) + tg.t.FailNow() + } +} + +// runFail runs the test go command, and expects it to fail. +func (tg *testgoData) runFail(args ...string) { + tg.t.Helper() + if status := tg.doRun(args); status == nil { + tg.t.Fatal("testgo succeeded unexpectedly") + } else { + tg.t.Log("testgo failed as expected:", status) + } +} + +// runGit runs a git command, and expects it to succeed. +func (tg *testgoData) runGit(dir string, args ...string) { + tg.t.Helper() + cmd := exec.Command("git", args...) + tg.stdout.Reset() + tg.stderr.Reset() + cmd.Stdout = &tg.stdout + cmd.Stderr = &tg.stderr + cmd.Dir = dir + cmd.Env = tg.env + status := cmd.Run() + if tg.stdout.Len() > 0 { + tg.t.Log("git standard output:") + tg.t.Log(tg.stdout.String()) + } + if tg.stderr.Len() > 0 { + tg.t.Log("git standard error:") + tg.t.Log(tg.stderr.String()) + } + if status != nil { + tg.t.Logf("git %v failed unexpectedly: %v", args, status) + tg.t.FailNow() + } +} + +// getStdout returns standard output of the testgo run as a string. +func (tg *testgoData) getStdout() string { + tg.t.Helper() + if !tg.ran { + tg.t.Fatal("internal testsuite error: stdout called before run") + } + return tg.stdout.String() +} + +// getStderr returns standard error of the testgo run as a string. +func (tg *testgoData) getStderr() string { + tg.t.Helper() + if !tg.ran { + tg.t.Fatal("internal testsuite error: stdout called before run") + } + return tg.stderr.String() +} + +// doGrepMatch looks for a regular expression in a buffer, and returns +// whether it is found. The regular expression is matched against +// each line separately, as with the grep command. +func (tg *testgoData) doGrepMatch(match string, b *bytes.Buffer) bool { + tg.t.Helper() + if !tg.ran { + tg.t.Fatal("internal testsuite error: grep called before run") + } + re := regexp.MustCompile(match) + for _, ln := range bytes.Split(b.Bytes(), []byte{'\n'}) { + if re.Match(ln) { + return true + } + } + return false +} + +// doGrep looks for a regular expression in a buffer and fails if it +// is not found. The name argument is the name of the output we are +// searching, "output" or "error". The msg argument is logged on +// failure. +func (tg *testgoData) doGrep(match string, b *bytes.Buffer, name, msg string) { + tg.t.Helper() + if !tg.doGrepMatch(match, b) { + tg.t.Log(msg) + tg.t.Logf("pattern %v not found in standard %s", match, name) + tg.t.FailNow() + } +} + +// grepStdout looks for a regular expression in the test run's +// standard output and fails, logging msg, if it is not found. +func (tg *testgoData) grepStdout(match, msg string) { + tg.t.Helper() + tg.doGrep(match, &tg.stdout, "output", msg) +} + +// grepStderr looks for a regular expression in the test run's +// standard error and fails, logging msg, if it is not found. +func (tg *testgoData) grepStderr(match, msg string) { + tg.t.Helper() + tg.doGrep(match, &tg.stderr, "error", msg) +} + +// grepBoth looks for a regular expression in the test run's standard +// output or stand error and fails, logging msg, if it is not found. +func (tg *testgoData) grepBoth(match, msg string) { + tg.t.Helper() + if !tg.doGrepMatch(match, &tg.stdout) && !tg.doGrepMatch(match, &tg.stderr) { + tg.t.Log(msg) + tg.t.Logf("pattern %v not found in standard output or standard error", match) + tg.t.FailNow() + } +} + +// doGrepNot looks for a regular expression in a buffer and fails if +// it is found. The name and msg arguments are as for doGrep. +func (tg *testgoData) doGrepNot(match string, b *bytes.Buffer, name, msg string) { + tg.t.Helper() + if tg.doGrepMatch(match, b) { + tg.t.Log(msg) + tg.t.Logf("pattern %v found unexpectedly in standard %s", match, name) + tg.t.FailNow() + } +} + +// grepStdoutNot looks for a regular expression in the test run's +// standard output and fails, logging msg, if it is found. +func (tg *testgoData) grepStdoutNot(match, msg string) { + tg.t.Helper() + tg.doGrepNot(match, &tg.stdout, "output", msg) +} + +// grepStderrNot looks for a regular expression in the test run's +// standard error and fails, logging msg, if it is found. +func (tg *testgoData) grepStderrNot(match, msg string) { + tg.t.Helper() + tg.doGrepNot(match, &tg.stderr, "error", msg) +} + +// grepBothNot looks for a regular expression in the test run's +// standard output or standard error and fails, logging msg, if it is +// found. +func (tg *testgoData) grepBothNot(match, msg string) { + tg.t.Helper() + if tg.doGrepMatch(match, &tg.stdout) || tg.doGrepMatch(match, &tg.stderr) { + tg.t.Log(msg) + tg.t.Fatalf("pattern %v found unexpectedly in standard output or standard error", match) + } +} + +// doGrepCount counts the number of times a regexp is seen in a buffer. +func (tg *testgoData) doGrepCount(match string, b *bytes.Buffer) int { + tg.t.Helper() + if !tg.ran { + tg.t.Fatal("internal testsuite error: doGrepCount called before run") + } + re := regexp.MustCompile(match) + c := 0 + for _, ln := range bytes.Split(b.Bytes(), []byte{'\n'}) { + if re.Match(ln) { + c++ + } + } + return c +} + +// grepCountBoth returns the number of times a regexp is seen in both +// standard output and standard error. +func (tg *testgoData) grepCountBoth(match string) int { + tg.t.Helper() + return tg.doGrepCount(match, &tg.stdout) + tg.doGrepCount(match, &tg.stderr) +} + +// creatingTemp records that the test plans to create a temporary file +// or directory. If the file or directory exists already, it will be +// removed. When the test completes, the file or directory will be +// removed if it exists. +func (tg *testgoData) creatingTemp(path string) { + tg.t.Helper() + if filepath.IsAbs(path) && !strings.HasPrefix(path, tg.tempdir) { + tg.t.Fatalf("internal testsuite error: creatingTemp(%q) with absolute path not in temporary directory", path) + } + tg.must(robustio.RemoveAll(path)) + tg.temps = append(tg.temps, path) +} + +// makeTempdir makes a temporary directory for a run of testgo. If +// the temporary directory was already created, this does nothing. +func (tg *testgoData) makeTempdir() { + tg.t.Helper() + if tg.tempdir == "" { + var err error + tg.tempdir, err = os.MkdirTemp("", "gotest") + tg.must(err) + } +} + +// tempFile adds a temporary file for a run of testgo. +func (tg *testgoData) tempFile(path, contents string) { + tg.t.Helper() + tg.makeTempdir() + tg.must(os.MkdirAll(filepath.Join(tg.tempdir, filepath.Dir(path)), 0755)) + bytes := []byte(contents) + if strings.HasSuffix(path, ".go") { + formatted, err := format.Source(bytes) + if err == nil { + bytes = formatted + } + } + tg.must(os.WriteFile(filepath.Join(tg.tempdir, path), bytes, 0644)) +} + +// tempDir adds a temporary directory for a run of testgo. +func (tg *testgoData) tempDir(path string) { + tg.t.Helper() + tg.makeTempdir() + if err := os.MkdirAll(filepath.Join(tg.tempdir, path), 0755); err != nil && !os.IsExist(err) { + tg.t.Fatal(err) + } +} + +// path returns the absolute pathname to file with the temporary +// directory. +func (tg *testgoData) path(name string) string { + tg.t.Helper() + if tg.tempdir == "" { + tg.t.Fatalf("internal testsuite error: path(%q) with no tempdir", name) + } + if name == "." { + return tg.tempdir + } + return filepath.Join(tg.tempdir, name) +} + +// mustExist fails if path does not exist. +func (tg *testgoData) mustExist(path string) { + tg.t.Helper() + if _, err := os.Stat(path); err != nil { + if os.IsNotExist(err) { + tg.t.Fatalf("%s does not exist but should", path) + } + tg.t.Fatalf("%s stat failed: %v", path, err) + } +} + +// mustNotExist fails if path exists. +func (tg *testgoData) mustNotExist(path string) { + tg.t.Helper() + if _, err := os.Stat(path); err == nil || !os.IsNotExist(err) { + tg.t.Fatalf("%s exists but should not (%v)", path, err) + } +} + +// mustHaveContent succeeds if filePath is a path to a file, +// and that file is readable and not empty. +func (tg *testgoData) mustHaveContent(filePath string) { + tg.mustExist(filePath) + f, err := os.Stat(filePath) + if err != nil { + tg.t.Fatal(err) + } + if f.Size() == 0 { + tg.t.Fatalf("expected %s to have data, but is empty", filePath) + } +} + +// wantExecutable fails with msg if path is not executable. +func (tg *testgoData) wantExecutable(path, msg string) { + tg.t.Helper() + if st, err := os.Stat(path); err != nil { + if !os.IsNotExist(err) { + tg.t.Log(err) + } + tg.t.Fatal(msg) + } else { + if runtime.GOOS != "windows" && st.Mode()&0111 == 0 { + tg.t.Fatalf("binary %s exists but is not executable", path) + } + } +} + +// isStale reports whether pkg is stale, and why +func (tg *testgoData) isStale(pkg string) (bool, string) { + tg.t.Helper() + tg.run("list", "-f", "{{.Stale}}:{{.StaleReason}}", pkg) + v := strings.TrimSpace(tg.getStdout()) + f := strings.SplitN(v, ":", 2) + if len(f) == 2 { + switch f[0] { + case "true": + return true, f[1] + case "false": + return false, f[1] + } + } + tg.t.Fatalf("unexpected output checking staleness of package %v: %v", pkg, v) + panic("unreachable") +} + +// wantStale fails with msg if pkg is not stale. +func (tg *testgoData) wantStale(pkg, reason, msg string) { + tg.t.Helper() + stale, why := tg.isStale(pkg) + if !stale { + tg.t.Fatal(msg) + } + // 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) + } +} + +// wantNotStale fails with msg if pkg is stale. +func (tg *testgoData) wantNotStale(pkg, reason, msg string) { + tg.t.Helper() + stale, why := tg.isStale(pkg) + if stale { + tg.t.Fatal(msg) + } + if reason == "" && why != "" || !strings.Contains(why, reason) { + tg.t.Errorf("wrong reason for Stale=false: %q, want %q", why, reason) + } +} + +// 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 *testWork { + tg.t.Logf("TESTWORK=%s\n", tg.path(".")) + return + } + for _, path := range tg.temps { + tg.check(removeAll(path)) + } + if 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.WalkDir(dir, func(path string, info fs.DirEntry, err error) error { + // chmod not only directories, but also things that we couldn't even stat + // due to permission errors: they may also be unreadable directories. + if err != nil || info.IsDir() { + os.Chmod(path, 0777) + } + return nil + }) + return robustio.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() { + tg.t.Helper() + wd, err := os.Getwd() + if err != nil { + tg.t.Fatal(err) + } + fail := filepath.Join(wd, "testdata/failssh") + tg.setenv("PATH", fmt.Sprintf("%v%c%v", fail, filepath.ListSeparator, os.Getenv("PATH"))) +} + +func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) { + if testing.Short() { + t.Skip("skipping lengthy test in short mode") + } + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + + // Copy the runtime packages into a temporary GOROOT + // so that we can change files. + for _, copydir := range []string{ + "src/runtime", + "src/internal/bytealg", + "src/internal/cpu", + "src/math/bits", + "src/unsafe", + filepath.Join("pkg", runtime.GOOS+"_"+runtime.GOARCH), + filepath.Join("pkg/tool", runtime.GOOS+"_"+runtime.GOARCH), + "pkg/include", + } { + srcdir := filepath.Join(testGOROOT, copydir) + tg.tempDir(filepath.Join("goroot", copydir)) + err := filepath.WalkDir(srcdir, + func(path string, info fs.DirEntry, err error) error { + if err != nil { + return err + } + if info.IsDir() { + return nil + } + srcrel, err := filepath.Rel(srcdir, path) + if err != nil { + return err + } + dest := filepath.Join("goroot", copydir, srcrel) + data, err := os.ReadFile(path) + if err != nil { + return err + } + tg.tempFile(dest, string(data)) + if strings.Contains(copydir, filepath.Join("pkg", "tool")) { + os.Chmod(tg.path(dest), 0777) + } + return nil + }) + if err != nil { + t.Fatal(err) + } + } + tg.setenv("GOROOT", tg.path("goroot")) + + addVar := func(name string, idx int) (restore func()) { + data, err := os.ReadFile(name) + if err != nil { + t.Fatal(err) + } + old := data + data = append(data, fmt.Sprintf("var DummyUnusedVar%d bool\n", idx)...) + if err := os.WriteFile(name, append(data, '\n'), 0666); err != nil { + t.Fatal(err) + } + tg.sleep() + return func() { + if err := os.WriteFile(name, old, 0666); err != nil { + t.Fatal(err) + } + } + } + + // Every main package depends on the "runtime". + tg.tempFile("d1/src/p1/p1.go", `package main; func main(){}`) + tg.setenv("GOPATH", tg.path("d1")) + // 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 + // should have no effect: only the content matters. + // In fact this should be true even outside a release branch. + sys := tg.path("goroot/src/runtime/internal/sys/sys.go") + tg.sleep() + 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 = 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") + addVar(sys, 2) + tg.wantStale("p1", "stale dependency: runtime", "./testgo list claims p1 is NOT stale, incorrectly, after changing sys.go again") + 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", "-i", "p1") + tg.wantNotStale("p1", "", "./testgo list claims p1 is stale after building with old release") +} + +// cmd/go: custom import path checking should not apply to Go packages without import comment. +func TestIssue10952(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + testenv.MustHaveExecPath(t, "git") + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempDir("src") + tg.setenv("GOPATH", tg.path(".")) + const importPath = "github.com/zombiezen/go-get-issue-10952" + tg.run("get", "-d", "-u", importPath) + repoDir := tg.path("src/" + importPath) + tg.runGit(repoDir, "remote", "set-url", "origin", "https://"+importPath+".git") + tg.run("get", "-d", "-u", importPath) +} + +func TestIssue16471(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + testenv.MustHaveExecPath(t, "git") + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempDir("src") + tg.setenv("GOPATH", tg.path(".")) + tg.must(os.MkdirAll(tg.path("src/rsc.io/go-get-issue-10952"), 0755)) + tg.runGit(tg.path("src/rsc.io"), "clone", "https://github.com/zombiezen/go-get-issue-10952") + tg.runFail("get", "-u", "rsc.io/go-get-issue-10952") + tg.grepStderr("rsc.io/go-get-issue-10952 is a custom import path for https://github.com/rsc/go-get-issue-10952, but .* is checked out from https://github.com/zombiezen/go-get-issue-10952", "did not detect updated import path") +} + +// Test git clone URL that uses SCP-like syntax and custom import path checking. +func TestIssue11457(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + testenv.MustHaveExecPath(t, "git") + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempDir("src") + tg.setenv("GOPATH", tg.path(".")) + const importPath = "rsc.io/go-get-issue-11457" + tg.run("get", "-d", "-u", importPath) + repoDir := tg.path("src/" + importPath) + tg.runGit(repoDir, "remote", "set-url", "origin", "git@github.com:rsc/go-get-issue-11457") + + // At this time, custom import path checking compares remotes verbatim (rather than + // just the host and path, skipping scheme and user), so we expect go get -u to fail. + // However, the goal of this test is to verify that gitRemoteRepo correctly parsed + // the SCP-like syntax, and we expect it to appear in the error message. + tg.runFail("get", "-d", "-u", importPath) + want := " is checked out from ssh://git@github.com/rsc/go-get-issue-11457" + if !strings.HasSuffix(strings.TrimSpace(tg.getStderr()), want) { + t.Error("expected clone URL to appear in stderr") + } +} + +func TestGetGitDefaultBranch(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + testenv.MustHaveExecPath(t, "git") + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempDir("src") + tg.setenv("GOPATH", tg.path(".")) + + // This repo has two branches, master and another-branch. + // The another-branch is the default that you get from 'git clone'. + // The go get command variants should not override this. + const importPath = "github.com/rsc/go-get-default-branch" + + tg.run("get", "-d", importPath) + repoDir := tg.path("src/" + importPath) + tg.runGit(repoDir, "branch", "--contains", "HEAD") + tg.grepStdout(`\* another-branch`, "not on correct default branch") + + tg.run("get", "-d", "-u", importPath) + tg.runGit(repoDir, "branch", "--contains", "HEAD") + 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) + testenv.MustHaveExecPath(t, "git") + testenv.MustHaveExecPath(t, "svn") + + tg := testgo(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") + + 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 TestPackageMainTestCompilerFlags(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.setenv("GOPATH", tg.path(".")) + tg.tempFile("src/p1/p1.go", "package main\n") + tg.tempFile("src/p1/p1_test.go", "package main\nimport \"testing\"\nfunc Test(t *testing.T){}\n") + tg.run("test", "-c", "-n", "p1") + tg.grepBothNot(`([\\/]compile|gccgo).* (-p main|-fgo-pkgpath=main).*p1\.go`, "should not have run compile -p main p1.go") + tg.grepStderr(`([\\/]compile|gccgo).* (-p p1|-fgo-pkgpath=p1).*p1\.go`, "should have run compile -p p1 p1.go") +} + +// Issue 4104. +func TestGoTestWithPackageListedMultipleTimes(t *testing.T) { + tooSlow(t) + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.run("test", "errors", "errors", "errors", "errors", "errors") + if strings.Contains(strings.TrimSpace(tg.getStdout()), "\n") { + t.Error("go test errors errors errors errors errors tested the same package multiple times") + } +} + +func TestGoListHasAConsistentOrder(t *testing.T) { + tooSlow(t) + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.run("list", "std") + first := tg.getStdout() + tg.run("list", "std") + if first != tg.getStdout() { + t.Error("go list std ordering is inconsistent") + } +} + +func TestGoListStdDoesNotIncludeCommands(t *testing.T) { + tooSlow(t) + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.run("list", "std") + tg.grepStdoutNot("cmd/", "go list std shows commands") +} + +func TestGoListCmdOnlyShowsCommands(t *testing.T) { + skipIfGccgo(t, "gccgo does not have GOROOT") + tooSlow(t) + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.run("list", "cmd") + out := strings.TrimSpace(tg.getStdout()) + for _, line := range strings.Split(out, "\n") { + if !strings.Contains(line, "cmd/") { + t.Error("go list cmd shows non-commands") + break + } + } +} + +func TestGoListDeps(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempDir("src/p1/p2/p3/p4") + tg.setenv("GOPATH", tg.path(".")) + tg.tempFile("src/p1/p.go", "package p1\nimport _ \"p1/p2\"\n") + tg.tempFile("src/p1/p2/p.go", "package p2\nimport _ \"p1/p2/p3\"\n") + tg.tempFile("src/p1/p2/p3/p.go", "package p3\nimport _ \"p1/p2/p3/p4\"\n") + 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/bits\nmath\n" + out := tg.stdout.String() + if !strings.Contains(out, "internal/cpu") { + // Some systems don't use internal/cpu. + want = "unsafe\nmath/bits\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(`^internal/reflectlite$`, "missing internal/reflectlite") + tg.grepStdoutNot(`^sort`, "unexpected sort") +} + +func TestGoListCompiledCgo(t *testing.T) { + tooSlow(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) + } + + tg.run("list", "-export", "-f", "{{.BuildID}}", "strings") + buildID := strings.TrimSpace(tg.stdout.String()) + if buildID == "" { + t.Fatalf(".BuildID with -export was empty") + } + + tg.run("tool", "buildid", file) + toolBuildID := strings.TrimSpace(tg.stdout.String()) + if buildID != toolBuildID { + t.Fatalf(".BuildID with -export %q disagrees with 'go tool buildid' %q", buildID, toolBuildID) + } +} + +// Issue 4096. Validate the output of unsuccessful go install foo/quxx. +func TestUnsuccessfulGoInstallShouldMentionMissingPackage(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.runFail("install", "foo/quxx") + if tg.grepCountBoth(`cannot find package "foo/quxx" in any of`) != 1 { + t.Error(`go install foo/quxx expected error: .*cannot find package "foo/quxx" in any of`) + } +} + +func TestGOROOTSearchFailureReporting(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.runFail("install", "foo/quxx") + if tg.grepCountBoth(regexp.QuoteMeta(filepath.Join("foo", "quxx"))+` \(from \$GOROOT\)$`) != 1 { + t.Error(`go install foo/quxx expected error: .*foo/quxx (from $GOROOT)`) + } +} + +func TestMultipleGOPATHEntriesReportedSeparately(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + sep := string(filepath.ListSeparator) + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b")) + tg.runFail("install", "foo/quxx") + if tg.grepCountBoth(`testdata[/\\].[/\\]src[/\\]foo[/\\]quxx`) != 2 { + t.Error(`go install foo/quxx expected error: .*testdata/a/src/foo/quxx (from $GOPATH)\n.*testdata/b/src/foo/quxx`) + } +} + +// Test (from $GOPATH) annotation is reported for the first GOPATH entry, +func TestMentionGOPATHInFirstGOPATHEntry(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + sep := string(filepath.ListSeparator) + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b")) + tg.runFail("install", "foo/quxx") + if tg.grepCountBoth(regexp.QuoteMeta(filepath.Join("testdata", "a", "src", "foo", "quxx"))+` \(from \$GOPATH\)$`) != 1 { + t.Error(`go install foo/quxx expected error: .*testdata/a/src/foo/quxx (from $GOPATH)`) + } +} + +// but not on the second. +func TestMentionGOPATHNotOnSecondEntry(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + sep := string(filepath.ListSeparator) + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b")) + tg.runFail("install", "foo/quxx") + if tg.grepCountBoth(regexp.QuoteMeta(filepath.Join("testdata", "b", "src", "foo", "quxx"))+`$`) != 1 { + t.Error(`go install foo/quxx expected error: .*testdata/b/src/foo/quxx`) + } +} + +func homeEnvName() string { + switch runtime.GOOS { + case "windows": + return "USERPROFILE" + case "plan9": + return "home" + default: + return "HOME" + } +} + +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() + tg.parallel() + tg.tempDir("home/go") + tg.setenv(homeEnvName(), tg.path("home")) + + tg.run("env", "GOPATH") + tg.grepStdout(regexp.QuoteMeta(tg.path("home/go")), "want GOPATH=$HOME/go") + + tg.setenv("GOROOT", tg.path("home/go")) + tg.run("env", "GOPATH") + tg.grepStdoutNot(".", "want unset GOPATH because GOROOT=$HOME/go") + + tg.setenv("GOROOT", tg.path("home/go")+"/") + tg.run("env", "GOPATH") + tg.grepStdoutNot(".", "want unset GOPATH because GOROOT=$HOME/go/") +} + +func TestDefaultGOPATHGet(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + testenv.MustHaveExecPath(t, "git") + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.setenv("GOPATH", "") + tg.tempDir("home") + tg.setenv(homeEnvName(), tg.path("home")) + + // warn for creating directory + tg.run("get", "-v", "github.com/golang/example/hello") + tg.grepStderr("created GOPATH="+regexp.QuoteMeta(tg.path("home/go"))+"; see 'go help gopath'", "did not create GOPATH") + + // no warning if directory already exists + tg.must(robustio.RemoveAll(tg.path("home/go"))) + tg.tempDir("home/go") + tg.run("get", "github.com/golang/example/hello") + tg.grepStderrNot(".", "expected no output on standard error") + + // error if $HOME/go is a file + tg.must(robustio.RemoveAll(tg.path("home/go"))) + tg.tempFile("home/go", "") + tg.runFail("get", "github.com/golang/example/hello") + tg.grepStderr(`mkdir .*[/\\]go: .*(not a directory|cannot find the path)`, "expected error because $HOME/go is a file") +} + +func TestDefaultGOPATHPrintedSearchList(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.setenv("GOPATH", "") + tg.tempDir("home") + tg.setenv(homeEnvName(), tg.path("home")) + + tg.runFail("install", "github.com/golang/example/hello") + tg.grepStderr(regexp.QuoteMeta(tg.path("home/go/src/github.com/golang/example/hello"))+`.*from \$GOPATH`, "expected default GOPATH") +} + +func TestLdflagsArgumentsWithSpacesIssue3941(t *testing.T) { + skipIfGccgo(t, "gccgo does not support -ldflags -X") + tooSlow(t) + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempFile("main.go", `package main + var extern string + func main() { + println(extern) + }`) + tg.run("run", "-ldflags", `-X "main.extern=hello world"`, tg.path("main.go")) + tg.grepStderr("^hello world", `ldflags -X "main.extern=hello world"' failed`) +} + +func TestLdFlagsLongArgumentsIssue42295(t *testing.T) { + // Test the extremely long command line arguments that contain '\n' characters + // get encoded and passed correctly. + skipIfGccgo(t, "gccgo does not support -ldflags -X") + tooSlow(t) + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempFile("main.go", `package main + var extern string + func main() { + print(extern) + }`) + testStr := "test test test test test \n\\ " + var buf bytes.Buffer + for buf.Len() < work.ArgLengthForResponseFile+1 { + buf.WriteString(testStr) + } + tg.run("run", "-ldflags", fmt.Sprintf(`-X "main.extern=%s"`, buf.String()), tg.path("main.go")) + if tg.stderr.String() != buf.String() { + t.Errorf("strings differ") + } +} + +func TestGoTestDashCDashOControlsBinaryLocation(t *testing.T) { + skipIfGccgo(t, "gccgo has no standard packages") + tooSlow(t) + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.run("test", "-c", "-o", tg.path("myerrors.test"+exeSuffix), "errors") + tg.wantExecutable(tg.path("myerrors.test"+exeSuffix), "go test -c -o myerrors.test did not create myerrors.test") +} + +func TestGoTestDashOWritesBinary(t *testing.T) { + skipIfGccgo(t, "gccgo has no standard packages") + tooSlow(t) + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.run("test", "-o", tg.path("myerrors.test"+exeSuffix), "errors") + tg.wantExecutable(tg.path("myerrors.test"+exeSuffix), "go test -o myerrors.test did not create myerrors.test") +} + +func TestGoTestDashIDashOWritesBinary(t *testing.T) { + skipIfGccgo(t, "gccgo has no standard packages") + tooSlow(t) + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + + // don't let test -i overwrite runtime + tg.wantNotStale("runtime", "", "must be non-stale before test -i") + + tg.run("test", "-v", "-i", "-o", tg.path("myerrors.test"+exeSuffix), "errors") + tg.grepBothNot("PASS|FAIL", "test should not have run") + tg.wantExecutable(tg.path("myerrors.test"+exeSuffix), "go test -o myerrors.test did not create myerrors.test") +} + +// Issue 4515. +func TestInstallWithTags(t *testing.T) { + tooSlow(t) + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempDir("bin") + tg.tempFile("src/example/a/main.go", `package main + func main() {}`) + tg.tempFile("src/example/b/main.go", `// +build mytag + + package main + func main() {}`) + tg.setenv("GOPATH", tg.path(".")) + tg.run("install", "-tags", "mytag", "example/a", "example/b") + tg.wantExecutable(tg.path("bin/a"+exeSuffix), "go install example/a example/b did not install binaries") + tg.wantExecutable(tg.path("bin/b"+exeSuffix), "go install example/a example/b did not install binaries") + tg.must(os.Remove(tg.path("bin/a" + exeSuffix))) + tg.must(os.Remove(tg.path("bin/b" + exeSuffix))) + tg.run("install", "-tags", "mytag", "example/...") + tg.wantExecutable(tg.path("bin/a"+exeSuffix), "go install example/... did not install binaries") + tg.wantExecutable(tg.path("bin/b"+exeSuffix), "go install example/... did not install binaries") + tg.run("list", "-tags", "mytag", "example/b...") + if strings.TrimSpace(tg.getStdout()) != "example/b" { + t.Error("go list example/b did not find example/b") + } +} + +// Issue 17451, 17662. +func TestSymlinkWarning(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.setenv("GOPATH", tg.path(".")) + + tg.tempDir("src/example/xx") + tg.tempDir("yy/zz") + tg.tempFile("yy/zz/zz.go", "package zz\n") + if err := os.Symlink(tg.path("yy"), tg.path("src/example/xx/yy")); err != nil { + t.Skipf("symlink failed: %v", err) + } + tg.run("list", "example/xx/z...") + tg.grepStdoutNot(".", "list should not have matched anything") + tg.grepStderr("matched no packages", "list should have reported that pattern matched no packages") + tg.grepStderrNot("symlink", "list should not have reported symlink") + + tg.run("list", "example/xx/...") + tg.grepStdoutNot(".", "list should not have matched anything") + tg.grepStderr("matched no packages", "list should have reported that pattern matched no packages") + tg.grepStderr("ignoring symlink", "list should have reported symlink") +} + +func TestCgoShowsFullPathNames(t *testing.T) { + if !canCgo { + t.Skip("skipping because cgo not enabled") + } + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempFile("src/x/y/dirname/foo.go", ` + package foo + import "C" + func f() {`) + tg.setenv("GOPATH", tg.path(".")) + tg.runFail("build", "x/y/dirname") + tg.grepBoth("x/y/dirname", "error did not use full path") +} + +func TestCgoHandlesWlORIGIN(t *testing.T) { + tooSlow(t) + if !canCgo { + t.Skip("skipping because cgo not enabled") + } + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempFile("src/origin/origin.go", `package origin + // #cgo !darwin LDFLAGS: -Wl,-rpath,$ORIGIN + // void f(void) {} + import "C" + func f() { C.f() }`) + tg.setenv("GOPATH", tg.path(".")) + tg.run("build", "origin") +} + +func TestCgoPkgConfig(t *testing.T) { + tooSlow(t) + if !canCgo { + t.Skip("skipping because cgo not enabled") + } + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + + tg.run("env", "PKG_CONFIG") + pkgConfig := strings.TrimSpace(tg.getStdout()) + testenv.MustHaveExecPath(t, pkgConfig) + if out, err := exec.Command(pkgConfig, "--atleast-pkgconfig-version", "0.24").CombinedOutput(); err != nil { + t.Skipf("%s --atleast-pkgconfig-version 0.24: %v\n%s", pkgConfig, err, out) + } + + // 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 https://man.openbsd.org/pkg-config.1 + tg.tempFile("foo.pc", ` +Name: foo +Description: The foo library +Version: 1.0.0 +Cflags: -Dhello=10 -Dworld=+32 -DDEFINED_FROM_PKG_CONFIG=hello\ world +`) + tg.tempFile("foo.go", `package main + +/* +#cgo pkg-config: foo +int value() { + return DEFINED_FROM_PKG_CONFIG; +} +*/ +import "C" +import "os" + +func main() { + if C.value() != 42 { + println("value() =", C.value(), "wanted 42") + os.Exit(1) + } +} +`) + tg.setenv("PKG_CONFIG_PATH", tg.path(".")) + tg.run("run", tg.path("foo.go")) +} + +func TestListTemplateContextFunction(t *testing.T) { + t.Parallel() + for _, tt := range []struct { + v string + want string + }{ + {"GOARCH", runtime.GOARCH}, + {"GOOS", runtime.GOOS}, + {"GOROOT", filepath.Clean(runtime.GOROOT())}, + {"GOPATH", os.Getenv("GOPATH")}, + {"CgoEnabled", ""}, + {"UseAllFiles", ""}, + {"Compiler", ""}, + {"BuildTags", ""}, + {"ReleaseTags", ""}, + {"InstallSuffix", ""}, + } { + tt := tt + t.Run(tt.v, func(t *testing.T) { + tg := testgo(t) + tg.parallel() + defer tg.cleanup() + tmpl := "{{context." + tt.v + "}}" + tg.run("list", "-f", tmpl) + if tt.want == "" { + return + } + if got := strings.TrimSpace(tg.getStdout()); got != tt.want { + t.Errorf("go list -f %q: got %q; want %q", tmpl, got, tt.want) + } + }) + } +} + +// Test that you cannot use a local import in a package +// accessed by a non-local import (found in a GOPATH/GOROOT). +// See golang.org/issue/17475. +func TestImportLocal(t *testing.T) { + tooSlow(t) + + tg := testgo(t) + tg.parallel() + defer tg.cleanup() + + tg.tempFile("src/dir/x/x.go", `package x + var X int + `) + tg.setenv("GOPATH", tg.path(".")) + tg.run("build", "dir/x") + + // Ordinary import should work. + tg.tempFile("src/dir/p0/p.go", `package p0 + import "dir/x" + var _ = x.X + `) + tg.run("build", "dir/p0") + + // Relative import should not. + tg.tempFile("src/dir/p1/p.go", `package p1 + import "../x" + var _ = x.X + `) + tg.runFail("build", "dir/p1") + tg.grepStderr("local import.*in non-local package", "did not diagnose local import") + + // ... even in a test. + tg.tempFile("src/dir/p2/p.go", `package p2 + `) + tg.tempFile("src/dir/p2/p_test.go", `package p2 + import "../x" + import "testing" + var _ = x.X + func TestFoo(t *testing.T) {} + `) + tg.run("build", "dir/p2") + tg.runFail("test", "dir/p2") + tg.grepStderr("local import.*in non-local package", "did not diagnose local import") + + // ... even in an xtest. + tg.tempFile("src/dir/p2/p_test.go", `package p2_test + import "../x" + import "testing" + var _ = x.X + func TestFoo(t *testing.T) {} + `) + tg.run("build", "dir/p2") + tg.runFail("test", "dir/p2") + tg.grepStderr("local import.*in non-local package", "did not diagnose local import") + + // Relative import starting with ./ should not work either. + tg.tempFile("src/dir/d.go", `package dir + import "./x" + var _ = x.X + `) + tg.runFail("build", "dir") + tg.grepStderr("local import.*in non-local package", "did not diagnose local import") + + // ... even in a test. + tg.tempFile("src/dir/d.go", `package dir + `) + tg.tempFile("src/dir/d_test.go", `package dir + import "./x" + import "testing" + var _ = x.X + func TestFoo(t *testing.T) {} + `) + tg.run("build", "dir") + tg.runFail("test", "dir") + tg.grepStderr("local import.*in non-local package", "did not diagnose local import") + + // ... even in an xtest. + tg.tempFile("src/dir/d_test.go", `package dir_test + import "./x" + import "testing" + var _ = x.X + func TestFoo(t *testing.T) {} + `) + tg.run("build", "dir") + tg.runFail("test", "dir") + tg.grepStderr("local import.*in non-local package", "did not diagnose local import") + + // Relative import plain ".." should not work. + tg.tempFile("src/dir/x/y/y.go", `package dir + import ".." + var _ = x.X + `) + tg.runFail("build", "dir/x/y") + tg.grepStderr("local import.*in non-local package", "did not diagnose local import") + + // ... even in a test. + tg.tempFile("src/dir/x/y/y.go", `package y + `) + tg.tempFile("src/dir/x/y/y_test.go", `package y + import ".." + import "testing" + var _ = x.X + func TestFoo(t *testing.T) {} + `) + tg.run("build", "dir/x/y") + tg.runFail("test", "dir/x/y") + tg.grepStderr("local import.*in non-local package", "did not diagnose local import") + + // ... even in an x test. + tg.tempFile("src/dir/x/y/y_test.go", `package y_test + import ".." + import "testing" + var _ = x.X + func TestFoo(t *testing.T) {} + `) + tg.run("build", "dir/x/y") + tg.runFail("test", "dir/x/y") + tg.grepStderr("local import.*in non-local package", "did not diagnose local import") + + // Relative import "." should not work. + tg.tempFile("src/dir/x/xx.go", `package x + import "." + var _ = x.X + `) + tg.runFail("build", "dir/x") + tg.grepStderr("cannot import current directory", "did not diagnose import current directory") + + // ... even in a test. + tg.tempFile("src/dir/x/xx.go", `package x + `) + tg.tempFile("src/dir/x/xx_test.go", `package x + import "." + import "testing" + var _ = x.X + func TestFoo(t *testing.T) {} + `) + tg.run("build", "dir/x") + tg.runFail("test", "dir/x") + tg.grepStderr("cannot import current directory", "did not diagnose import current directory") + + // ... even in an xtest. + tg.tempFile("src/dir/x/xx.go", `package x + `) + tg.tempFile("src/dir/x/xx_test.go", `package x_test + import "." + import "testing" + var _ = x.X + func TestFoo(t *testing.T) {} + `) + tg.run("build", "dir/x") + tg.runFail("test", "dir/x") + tg.grepStderr("cannot import current directory", "did not diagnose import current directory") +} + +func TestGoInstallPkgdir(t *testing.T) { + skipIfGccgo(t, "gccgo has no standard packages") + tooSlow(t) + + tg := testgo(t) + tg.parallel() + defer tg.cleanup() + tg.makeTempdir() + pkg := tg.path(".") + tg.run("install", "-pkgdir", pkg, "sync") + tg.mustExist(filepath.Join(pkg, "sync.a")) + tg.mustNotExist(filepath.Join(pkg, "sync/atomic.a")) + tg.run("install", "-i", "-pkgdir", pkg, "sync") + tg.mustExist(filepath.Join(pkg, "sync.a")) + tg.mustExist(filepath.Join(pkg, "sync/atomic.a")) +} + +// For issue 14337. +func TestParallelTest(t *testing.T) { + tooSlow(t) + tg := testgo(t) + tg.parallel() + defer tg.cleanup() + tg.makeTempdir() + const testSrc = `package package_test + import ( + "testing" + ) + func TestTest(t *testing.T) { + }` + tg.tempFile("src/p1/p1_test.go", strings.Replace(testSrc, "package_test", "p1_test", 1)) + tg.tempFile("src/p2/p2_test.go", strings.Replace(testSrc, "package_test", "p2_test", 1)) + tg.tempFile("src/p3/p3_test.go", strings.Replace(testSrc, "package_test", "p3_test", 1)) + tg.tempFile("src/p4/p4_test.go", strings.Replace(testSrc, "package_test", "p4_test", 1)) + tg.setenv("GOPATH", tg.path(".")) + tg.run("test", "-p=4", "p1", "p2", "p3", "p4") +} + +func TestBinaryOnlyPackages(t *testing.T) { + tooSlow(t) + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.setenv("GOPATH", tg.path(".")) + + tg.tempFile("src/p1/p1.go", `//go:binary-only-package + + package p1 + `) + tg.wantStale("p1", "binary-only packages are no longer supported", "p1 is binary-only, and this message should always be printed") + tg.runFail("install", "p1") + tg.grepStderr("binary-only packages are no longer supported", "did not report attempt to compile binary-only package") + + tg.tempFile("src/p1/p1.go", ` + package p1 + import "fmt" + func F(b bool) { fmt.Printf("hello from p1\n"); if b { F(false) } } + `) + tg.run("install", "p1") + os.Remove(tg.path("src/p1/p1.go")) + tg.mustNotExist(tg.path("src/p1/p1.go")) + + tg.tempFile("src/p2/p2.go", `//go:binary-only-packages-are-not-great + + package p2 + import "p1" + func F() { p1.F(true) } + `) + tg.runFail("install", "p2") + tg.grepStderr("no Go files", "did not complain about missing sources") + + tg.tempFile("src/p1/missing.go", `//go:binary-only-package + + package p1 + import _ "fmt" + func G() + `) + tg.wantStale("p1", "binary-only package", "should NOT want to rebuild p1 (first)") + tg.runFail("install", "p2") + tg.grepStderr("p1: binary-only packages are no longer supported", "did not report error for binary-only p1") + + tg.run("list", "-deps", "-f", "{{.ImportPath}}: {{.BinaryOnly}}", "p2") + tg.grepStdout("p1: true", "p1 not listed as BinaryOnly") + tg.grepStdout("p2: false", "p2 listed as BinaryOnly") +} + +// Issue 16050. +func TestAlwaysLinkSysoFiles(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempDir("src/syso") + tg.tempFile("src/syso/a.syso", ``) + tg.tempFile("src/syso/b.go", `package syso`) + tg.setenv("GOPATH", tg.path(".")) + + // We should see the .syso file regardless of the setting of + // CGO_ENABLED. + + tg.setenv("CGO_ENABLED", "1") + tg.run("list", "-f", "{{.SysoFiles}}", "syso") + tg.grepStdout("a.syso", "missing syso file with CGO_ENABLED=1") + + tg.setenv("CGO_ENABLED", "0") + tg.run("list", "-f", "{{.SysoFiles}}", "syso") + tg.grepStdout("a.syso", "missing syso file with CGO_ENABLED=0") +} + +// Issue 16120. +func TestGenerateUsesBuildContext(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("this test won't run under Windows") + } + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempDir("src/gen") + tg.tempFile("src/gen/gen.go", "package gen\n//go:generate echo $GOOS $GOARCH\n") + tg.setenv("GOPATH", tg.path(".")) + + tg.setenv("GOOS", "linux") + tg.setenv("GOARCH", "amd64") + tg.run("generate", "gen") + tg.grepStdout("linux amd64", "unexpected GOOS/GOARCH combination") + + tg.setenv("GOOS", "darwin") + tg.setenv("GOARCH", "arm64") + tg.run("generate", "gen") + tg.grepStdout("darwin arm64", "unexpected GOOS/GOARCH combination") +} + +func TestGoEnv(t *testing.T) { + tg := testgo(t) + tg.parallel() + defer tg.cleanup() + tg.setenv("GOOS", "freebsd") // to avoid invalid pair errors + tg.setenv("GOARCH", "arm") + tg.run("env", "GOARCH") + tg.grepStdout("^arm$", "GOARCH not honored") + + tg.run("env", "GCCGO") + tg.grepStdout(".", "GCCGO unexpectedly empty") + + tg.run("env", "CGO_CFLAGS") + tg.grepStdout(".", "default CGO_CFLAGS unexpectedly empty") + + tg.setenv("CGO_CFLAGS", "-foobar") + tg.run("env", "CGO_CFLAGS") + tg.grepStdout("^-foobar$", "CGO_CFLAGS not honored") + + tg.setenv("CC", "gcc -fmust -fgo -ffaster") + tg.run("env", "CC") + tg.grepStdout("gcc", "CC not found") + tg.run("env", "GOGCCFLAGS") + tg.grepStdout("-ffaster", "CC arguments not found") + + tg.run("env", "GOVERSION") + envVersion := strings.TrimSpace(tg.stdout.String()) + + tg.run("version") + cmdVersion := strings.TrimSpace(tg.stdout.String()) + + // If 'go version' is "go version /", then + // 'go env GOVERSION' is just "". + if cmdVersion == envVersion || !strings.Contains(cmdVersion, envVersion) { + t.Fatalf("'go env GOVERSION' %q should be a shorter substring of 'go version' %q", envVersion, cmdVersion) + } +} + +const ( + noMatchesPattern = `(?m)^ok.*\[no tests to run\]` + okPattern = `(?m)^ok` +) + +// Issue 18044. +func TestLdBindNow(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.setenv("LD_BIND_NOW", "1") + tg.run("help") +} + +// Issue 18225. +// This is really a cmd/asm issue but this is a convenient place to test it. +func TestConcurrentAsm(t *testing.T) { + skipIfGccgo(t, "gccgo does not use cmd/asm") + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + asm := `DATA ·constants<>+0x0(SB)/8,$0 +GLOBL ·constants<>(SB),8,$8 +` + tg.tempFile("go/src/p/a.s", asm) + tg.tempFile("go/src/p/b.s", asm) + tg.tempFile("go/src/p/p.go", `package p`) + tg.setenv("GOPATH", tg.path("go")) + tg.run("build", "p") +} + +// Issue 18975. +func TestFFLAGS(t *testing.T) { + if !canCgo { + t.Skip("skipping because cgo not enabled") + } + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + + tg.tempFile("p/src/p/main.go", `package main + // #cgo FFLAGS: -no-such-fortran-flag + import "C" + func main() {} + `) + tg.tempFile("p/src/p/a.f", `! comment`) + tg.setenv("GOPATH", tg.path("p")) + + // This should normally fail because we are passing an unknown flag, + // but issue #19080 points to Fortran compilers that succeed anyhow. + // To work either way we call doRun directly rather than run or runFail. + tg.doRun([]string{"build", "-x", "p"}) + + tg.grepStderr("no-such-fortran-flag", `missing expected "-no-such-fortran-flag"`) +} + +// Issue 19198. +// This is really a cmd/link issue but this is a convenient place to test it. +func TestDuplicateGlobalAsmSymbols(t *testing.T) { + skipIfGccgo(t, "gccgo does not use cmd/asm") + tooSlow(t) + if runtime.GOARCH != "386" && runtime.GOARCH != "amd64" { + t.Skipf("skipping test on %s", runtime.GOARCH) + } + if !canCgo { + t.Skip("skipping because cgo not enabled") + } + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + + asm := ` +#include "textflag.h" + +DATA sym<>+0x0(SB)/8,$0 +GLOBL sym<>(SB),(NOPTR+RODATA),$8 + +TEXT ·Data(SB),NOSPLIT,$0 + MOVB sym<>(SB), AX + MOVB AX, ret+0(FP) + RET +` + tg.tempFile("go/src/a/a.s", asm) + tg.tempFile("go/src/a/a.go", `package a; func Data() uint8`) + tg.tempFile("go/src/b/b.s", asm) + tg.tempFile("go/src/b/b.go", `package b; func Data() uint8`) + tg.tempFile("go/src/p/p.go", ` +package main +import "a" +import "b" +import "C" +func main() { + _ = a.Data() + b.Data() +} +`) + tg.setenv("GOPATH", tg.path("go")) + exe := tg.path("p.exe") + tg.creatingTemp(exe) + tg.run("build", "-o", exe, "p") +} + +func copyFile(src, dst string, perm fs.FileMode) error { + sf, err := os.Open(src) + if err != nil { + return err + } + defer sf.Close() + + df, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) + if err != nil { + return err + } + + _, err = io.Copy(df, sf) + err2 := df.Close() + if err != nil { + return err + } + return err2 +} + +func TestNeedVersion(t *testing.T) { + skipIfGccgo(t, "gccgo does not use cmd/compile") + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempFile("goversion.go", `package main; func main() {}`) + path := tg.path("goversion.go") + tg.setenv("TESTGO_VERSION", "go1.testgo") + tg.runFail("run", path) + tg.grepStderr("compile", "does not match go tool version") +} + +func TestBuildmodePIE(t *testing.T) { + if testing.Short() && testenv.Builder() == "" { + t.Skipf("skipping in -short mode on non-builder") + } + + platform := fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH) + switch platform { + case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/riscv64", "linux/s390x", + "android/amd64", "android/arm", "android/arm64", "android/386", + "freebsd/amd64", + "windows/386", "windows/amd64", "windows/arm": + case "darwin/amd64": + default: + t.Skipf("skipping test because buildmode=pie is not supported on %s", platform) + } + t.Run("non-cgo", func(t *testing.T) { + testBuildmodePIE(t, false, true) + }) + if canCgo { + switch runtime.GOOS { + case "darwin", "freebsd", "linux", "windows": + t.Run("cgo", func(t *testing.T) { + testBuildmodePIE(t, true, true) + }) + } + } +} + +func TestWindowsDefaultBuildmodIsPIE(t *testing.T) { + if testing.Short() && testenv.Builder() == "" { + t.Skipf("skipping in -short mode on non-builder") + } + + if runtime.GOOS != "windows" { + t.Skip("skipping windows only test") + } + + t.Run("non-cgo", func(t *testing.T) { + testBuildmodePIE(t, false, false) + }) + if canCgo { + t.Run("cgo", func(t *testing.T) { + testBuildmodePIE(t, true, false) + }) + } +} + +func testBuildmodePIE(t *testing.T, useCgo, setBuildmodeToPIE bool) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + + var s string + if useCgo { + s = `import "C";` + } + tg.tempFile("main.go", fmt.Sprintf(`package main;%s func main() { print("hello") }`, s)) + src := tg.path("main.go") + obj := tg.path("main.exe") + args := []string{"build"} + if setBuildmodeToPIE { + args = append(args, "-buildmode=pie") + } + args = append(args, "-o", obj, src) + tg.run(args...) + + switch runtime.GOOS { + case "linux", "android", "freebsd": + f, err := elf.Open(obj) + if err != nil { + t.Fatal(err) + } + defer f.Close() + if f.Type != elf.ET_DYN { + t.Errorf("PIE type must be ET_DYN, but %s", f.Type) + } + case "darwin": + f, err := macho.Open(obj) + if err != nil { + t.Fatal(err) + } + defer f.Close() + if f.Flags&macho.FlagDyldLink == 0 { + t.Error("PIE must have DyldLink flag, but not") + } + if f.Flags&macho.FlagPIE == 0 { + t.Error("PIE must have PIE flag, but not") + } + case "windows": + f, err := pe.Open(obj) + if err != nil { + t.Fatal(err) + } + defer f.Close() + if f.Section(".reloc") == nil { + t.Error(".reloc section is not present") + } + if (f.FileHeader.Characteristics & pe.IMAGE_FILE_RELOCS_STRIPPED) != 0 { + t.Error("IMAGE_FILE_RELOCS_STRIPPED flag is set") + } + var dc uint16 + switch oh := f.OptionalHeader.(type) { + case *pe.OptionalHeader32: + dc = oh.DllCharacteristics + case *pe.OptionalHeader64: + dc = oh.DllCharacteristics + if (dc & pe.IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA) == 0 { + t.Error("IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA flag is not set") + } + default: + t.Fatalf("unexpected optional header type of %T", f.OptionalHeader) + } + if (dc & pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) == 0 { + t.Error("IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE flag is not set") + } + if useCgo { + // Test that only one symbol is exported (#40795). + // PIE binaries don´t require .edata section but unfortunately + // binutils doesn´t generate a .reloc section unless there is + // at least one symbol exported. + // See https://sourceware.org/bugzilla/show_bug.cgi?id=19011 + section := f.Section(".edata") + if section == nil { + t.Fatalf(".edata section is not present") + } + // TODO: deduplicate this struct from cmd/link/internal/ld/pe.go + type IMAGE_EXPORT_DIRECTORY struct { + _ [2]uint32 + _ [2]uint16 + _ [2]uint32 + NumberOfFunctions uint32 + NumberOfNames uint32 + _ [3]uint32 + } + var e IMAGE_EXPORT_DIRECTORY + if err := binary.Read(section.Open(), binary.LittleEndian, &e); err != nil { + t.Fatalf("binary.Read failed: %v", err) + } + + // Only _cgo_dummy_export should be exported + if e.NumberOfFunctions != 1 { + t.Fatalf("got %d exported functions; want 1", e.NumberOfFunctions) + } + if e.NumberOfNames != 1 { + t.Fatalf("got %d exported names; want 1", e.NumberOfNames) + } + } + default: + panic("unreachable") + } + + out, err := exec.Command(obj).CombinedOutput() + if err != nil { + t.Fatal(err) + } + + if string(out) != "hello" { + t.Errorf("got %q; want %q", out, "hello") + } +} + +func TestUpxCompression(t *testing.T) { + if runtime.GOOS != "linux" || + (runtime.GOARCH != "amd64" && runtime.GOARCH != "386") { + t.Skipf("skipping upx test on %s/%s", runtime.GOOS, runtime.GOARCH) + } + + testenv.MustHaveExecPath(t, "upx") + out, err := exec.Command("upx", "--version").CombinedOutput() + if err != nil { + t.Fatalf("upx --version failed: %v", err) + } + + // upx --version prints `upx ` in the first line of output: + // upx 3.94 + // [...] + re := regexp.MustCompile(`([[:digit:]]+)\.([[:digit:]]+)`) + upxVersion := re.FindStringSubmatch(string(out)) + if len(upxVersion) != 3 { + t.Fatalf("bad upx version string: %s", upxVersion) + } + + major, err1 := strconv.Atoi(upxVersion[1]) + minor, err2 := strconv.Atoi(upxVersion[2]) + if err1 != nil || err2 != nil { + t.Fatalf("bad upx version string: %s", upxVersion[0]) + } + + // Anything below 3.94 is known not to work with go binaries + if (major < 3) || (major == 3 && minor < 94) { + t.Skipf("skipping because upx version %v.%v is too old", major, minor) + } + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + + tg.tempFile("main.go", `package main; import "fmt"; func main() { fmt.Print("hello upx") }`) + src := tg.path("main.go") + obj := tg.path("main") + tg.run("build", "-o", obj, src) + + out, err = exec.Command("upx", obj).CombinedOutput() + if err != nil { + t.Logf("executing upx\n%s\n", out) + t.Fatalf("upx failed with %v", err) + } + + out, err = exec.Command(obj).CombinedOutput() + if err != nil { + t.Logf("%s", out) + t.Fatalf("running compressed go binary failed with error %s", err) + } + if string(out) != "hello upx" { + t.Fatalf("bad output from compressed go binary:\ngot %q; want %q", out, "hello upx") + } +} + +func TestCacheListStale(t *testing.T) { + tooSlow(t) + if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") { + t.Skip("GODEBUG gocacheverify") + } + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.setenv("GOCACHE", tg.path("cache")) + tg.tempFile("gopath/src/p/p.go", "package p; import _ \"q\"; func F(){}\n") + tg.tempFile("gopath/src/q/q.go", "package q; func F(){}\n") + tg.tempFile("gopath/src/m/m.go", "package main; import _ \"q\"; func main(){}\n") + + tg.setenv("GOPATH", tg.path("gopath")) + tg.run("install", "p", "m") + tg.run("list", "-f={{.ImportPath}} {{.Stale}}", "m", "q", "p") + tg.grepStdout("^m false", "m should not be stale") + tg.grepStdout("^q true", "q should be stale") + tg.grepStdout("^p false", "p should not be stale") +} + +func TestCacheCoverage(t *testing.T) { + tooSlow(t) + + if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") { + t.Skip("GODEBUG gocacheverify") + } + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.makeTempdir() + + tg.setenv("GOCACHE", tg.path("c1")) + tg.run("test", "-cover", "-short", "strings") + tg.run("test", "-cover", "-short", "math", "strings") +} + +func TestIssue22588(t *testing.T) { + // Don't get confused by stderr coming from tools. + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + + if _, err := os.Stat("/usr/bin/time"); err != nil { + t.Skip(err) + } + + tg.run("list", "-f={{.Stale}}", "runtime") + tg.run("list", "-toolexec=/usr/bin/time", "-f={{.Stale}}", "runtime") + tg.grepStdout("false", "incorrectly reported runtime as stale") +} + +func TestIssue22531(t *testing.T) { + tooSlow(t) + if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") { + t.Skip("GODEBUG gocacheverify") + } + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.setenv("GOPATH", tg.tempdir) + tg.setenv("GOCACHE", tg.path("cache")) + tg.tempFile("src/m/main.go", "package main /* c1 */; func main() {}\n") + tg.run("install", "-x", "m") + tg.run("list", "-f", "{{.Stale}}", "m") + tg.grepStdout("false", "reported m as stale after install") + tg.run("tool", "buildid", tg.path("bin/m"+exeSuffix)) + + // The link action ID did not include the full main build ID, + // even though the full main build ID is written into the + // eventual binary. That caused the following install to + // be a no-op, thinking the gofmt binary was up-to-date, + // even though .Stale could see it was not. + tg.tempFile("src/m/main.go", "package main /* c2 */; func main() {}\n") + tg.run("install", "-x", "m") + tg.run("list", "-f", "{{.Stale}}", "m") + tg.grepStdout("false", "reported m as stale after reinstall") + tg.run("tool", "buildid", tg.path("bin/m"+exeSuffix)) +} + +func TestIssue22596(t *testing.T) { + tooSlow(t) + if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") { + t.Skip("GODEBUG gocacheverify") + } + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.setenv("GOCACHE", tg.path("cache")) + tg.tempFile("gopath1/src/p/p.go", "package p; func F(){}\n") + tg.tempFile("gopath2/src/p/p.go", "package p; func F(){}\n") + + tg.setenv("GOPATH", tg.path("gopath1")) + tg.run("list", "-f={{.Target}}", "p") + target1 := strings.TrimSpace(tg.getStdout()) + tg.run("install", "p") + tg.wantNotStale("p", "", "p stale after install") + + tg.setenv("GOPATH", tg.path("gopath2")) + tg.run("list", "-f={{.Target}}", "p") + target2 := strings.TrimSpace(tg.getStdout()) + tg.must(os.MkdirAll(filepath.Dir(target2), 0777)) + tg.must(copyFile(target1, target2, 0666)) + tg.wantStale("p", "build ID mismatch", "p not stale after copy from gopath1") + tg.run("install", "p") + tg.wantNotStale("p", "", "p stale after install2") +} + +func TestTestCache(t *testing.T) { + tooSlow(t) + + if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") { + t.Skip("GODEBUG gocacheverify") + } + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.setenv("GOPATH", tg.tempdir) + tg.setenv("GOCACHE", tg.path("cache")) + + // The -p=1 in the commands below just makes the -x output easier to read. + + t.Log("\n\nINITIAL\n\n") + + tg.tempFile("src/p1/p1.go", "package p1\nvar X = 1\n") + tg.tempFile("src/p2/p2.go", "package p2\nimport _ \"p1\"\nvar X = 1\n") + tg.tempFile("src/t/t1/t1_test.go", "package t\nimport \"testing\"\nfunc Test1(*testing.T) {}\n") + tg.tempFile("src/t/t2/t2_test.go", "package t\nimport _ \"p1\"\nimport \"testing\"\nfunc Test2(*testing.T) {}\n") + tg.tempFile("src/t/t3/t3_test.go", "package t\nimport \"p1\"\nimport \"testing\"\nfunc Test3(t *testing.T) {t.Log(p1.X)}\n") + tg.tempFile("src/t/t4/t4_test.go", "package t\nimport \"p2\"\nimport \"testing\"\nfunc Test4(t *testing.T) {t.Log(p2.X)}") + tg.run("test", "-x", "-v", "-short", "t/...") + + t.Log("\n\nREPEAT\n\n") + + tg.run("test", "-x", "-v", "-short", "t/...") + tg.grepStdout(`ok \tt/t1\t\(cached\)`, "did not cache t1") + tg.grepStdout(`ok \tt/t2\t\(cached\)`, "did not cache t2") + tg.grepStdout(`ok \tt/t3\t\(cached\)`, "did not cache t3") + tg.grepStdout(`ok \tt/t4\t\(cached\)`, "did not cache t4") + tg.grepStderrNot(`[\\/](compile|gccgo) `, "incorrectly ran compiler") + tg.grepStderrNot(`[\\/](link|gccgo) `, "incorrectly ran linker") + tg.grepStderrNot(`p[0-9]\.test`, "incorrectly ran test") + + t.Log("\n\nCOMMENT\n\n") + + // Changing the program text without affecting the compiled package + // should result in the package being rebuilt but nothing more. + tg.tempFile("src/p1/p1.go", "package p1\nvar X = 01\n") + tg.run("test", "-p=1", "-x", "-v", "-short", "t/...") + tg.grepStdout(`ok \tt/t1\t\(cached\)`, "did not cache t1") + tg.grepStdout(`ok \tt/t2\t\(cached\)`, "did not cache t2") + tg.grepStdout(`ok \tt/t3\t\(cached\)`, "did not cache t3") + tg.grepStdout(`ok \tt/t4\t\(cached\)`, "did not cache t4") + tg.grepStderrNot(`([\\/](compile|gccgo) ).*t[0-9]_test\.go`, "incorrectly ran compiler") + tg.grepStderrNot(`[\\/](link|gccgo) `, "incorrectly ran linker") + tg.grepStderrNot(`t[0-9]\.test.*test\.short`, "incorrectly ran test") + + t.Log("\n\nCHANGE\n\n") + + // Changing the actual package should have limited effects. + tg.tempFile("src/p1/p1.go", "package p1\nvar X = 02\n") + tg.run("test", "-p=1", "-x", "-v", "-short", "t/...") + + // p2 should have been rebuilt. + tg.grepStderr(`([\\/]compile|gccgo).*p2.go`, "did not recompile p2") + + // t1 does not import anything, should not have been rebuilt. + tg.grepStderrNot(`([\\/]compile|gccgo).*t1_test.go`, "incorrectly recompiled t1") + tg.grepStderrNot(`([\\/]link|gccgo).*t1_test`, "incorrectly relinked t1_test") + tg.grepStdout(`ok \tt/t1\t\(cached\)`, "did not cache t/t1") + + // t2 imports p1 and must be rebuilt and relinked, + // but the change should not have any effect on the test binary, + // so the test should not have been rerun. + tg.grepStderr(`([\\/]compile|gccgo).*t2_test.go`, "did not recompile t2") + tg.grepStderr(`([\\/]link|gccgo).*t2\.test`, "did not relink t2_test") + // This check does not currently work with gccgo, as garbage + // collection of unused variables is not turned on by default. + if runtime.Compiler != "gccgo" { + tg.grepStdout(`ok \tt/t2\t\(cached\)`, "did not cache t/t2") + } + + // t3 imports p1, and changing X changes t3's test binary. + tg.grepStderr(`([\\/]compile|gccgo).*t3_test.go`, "did not recompile t3") + tg.grepStderr(`([\\/]link|gccgo).*t3\.test`, "did not relink t3_test") + tg.grepStderr(`t3\.test.*-test.short`, "did not rerun t3_test") + tg.grepStdoutNot(`ok \tt/t3\t\(cached\)`, "reported cached t3_test result") + + // t4 imports p2, but p2 did not change, so t4 should be relinked, not recompiled, + // and not rerun. + tg.grepStderrNot(`([\\/]compile|gccgo).*t4_test.go`, "incorrectly recompiled t4") + tg.grepStderr(`([\\/]link|gccgo).*t4\.test`, "did not relink t4_test") + // This check does not currently work with gccgo, as garbage + // collection of unused variables is not turned on by default. + if runtime.Compiler != "gccgo" { + tg.grepStdout(`ok \tt/t4\t\(cached\)`, "did not cache t/t4") + } +} + +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 TestTestVetRebuild(t *testing.T) { + tooSlow(t) + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + + // golang.org/issue/23701. + // b_test imports b with augmented method from export_test.go. + // b_test also imports a, which imports b. + // Must not accidentally see un-augmented b propagate through a to b_test. + tg.tempFile("src/a/a.go", `package a + import "b" + type Type struct{} + func (*Type) M() b.T {return 0} + `) + tg.tempFile("src/b/b.go", `package b + type T int + type I interface {M() T} + `) + tg.tempFile("src/b/export_test.go", `package b + func (*T) Method() *T { return nil } + `) + tg.tempFile("src/b/b_test.go", `package b_test + import ( + "testing" + "a" + . "b" + ) + func TestBroken(t *testing.T) { + x := new(T) + x.Method() + _ = new(a.Type) + } + `) + + tg.setenv("GOPATH", tg.path(".")) + tg.run("test", "b") + tg.run("vet", "b") +} + +func TestInstallDeps(t *testing.T) { + tooSlow(t) + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.setenv("GOPATH", tg.tempdir) + + tg.tempFile("src/p1/p1.go", "package p1\nvar X = 1\n") + tg.tempFile("src/p2/p2.go", "package p2\nimport _ \"p1\"\n") + tg.tempFile("src/main1/main.go", "package main\nimport _ \"p2\"\nfunc main() {}\n") + + tg.run("list", "-f={{.Target}}", "p1") + p1 := strings.TrimSpace(tg.getStdout()) + tg.run("list", "-f={{.Target}}", "p2") + p2 := strings.TrimSpace(tg.getStdout()) + tg.run("list", "-f={{.Target}}", "main1") + main1 := strings.TrimSpace(tg.getStdout()) + + tg.run("install", "main1") + + tg.mustExist(main1) + tg.mustNotExist(p2) + tg.mustNotExist(p1) + + tg.run("install", "p2") + tg.mustExist(p2) + tg.mustNotExist(p1) + + // don't let install -i overwrite runtime + tg.wantNotStale("runtime", "", "must be non-stale before install -i") + + tg.run("install", "-i", "main1") + tg.mustExist(p1) + tg.must(os.Remove(p1)) + + tg.run("install", "-i", "p2") + tg.mustExist(p1) +} + +// Issue 22986. +func TestImportPath(t *testing.T) { + tooSlow(t) + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + + tg.tempFile("src/a/a.go", ` +package main + +import ( + "log" + p "a/p-1.0" +) + +func main() { + if !p.V { + log.Fatal("false") + } +}`) + + tg.tempFile("src/a/a_test.go", ` +package main_test + +import ( + p "a/p-1.0" + "testing" +) + +func TestV(t *testing.T) { + if !p.V { + t.Fatal("false") + } +}`) + + tg.tempFile("src/a/p-1.0/p.go", ` +package p + +var V = true + +func init() {} +`) + + tg.setenv("GOPATH", tg.path(".")) + tg.run("build", "-o", tg.path("a.exe"), "a") + tg.run("test", "a") +} + +func TestBadCommandLines(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + + tg.tempFile("src/x/x.go", "package x\n") + tg.setenv("GOPATH", tg.path(".")) + + tg.run("build", "x") + + tg.tempFile("src/x/@y.go", "package x\n") + tg.runFail("build", "x") + tg.grepStderr("invalid input file name \"@y.go\"", "did not reject @y.go") + tg.must(os.Remove(tg.path("src/x/@y.go"))) + + tg.tempFile("src/x/-y.go", "package x\n") + tg.runFail("build", "x") + tg.grepStderr("invalid input file name \"-y.go\"", "did not reject -y.go") + tg.must(os.Remove(tg.path("src/x/-y.go"))) + + if runtime.Compiler == "gccgo" { + tg.runFail("build", "-gccgoflags=all=@x", "x") + } else { + tg.runFail("build", "-gcflags=all=@x", "x") + } + tg.grepStderr("invalid command-line argument @x in command", "did not reject @x during exec") + + 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\"|can only use path@version syntax with 'go get' and 'go install' in module-aware mode", "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\"|can only use path@version syntax with 'go get' and 'go install' in module-aware mode", "did not reject @x/y import path") + + tg.tempFile("src/-x/x.go", "package x\n") + tg.setenv("GOPATH", tg.path(".")) + tg.runFail("build", "--", "-x") + tg.grepStderr("invalid import path \"-x\"", "did not reject -x import path") + + 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") +} + +func TestTwoPkgConfigs(t *testing.T) { + if !canCgo { + t.Skip("no cgo") + } + if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { + t.Skipf("no shell scripts on %s", runtime.GOOS) + } + tooSlow(t) + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempFile("src/x/a.go", `package x + // #cgo pkg-config: --static a + import "C" + `) + tg.tempFile("src/x/b.go", `package x + // #cgo pkg-config: --static a + import "C" + `) + tg.tempFile("pkg-config.sh", `#!/bin/sh +echo $* >>`+tg.path("pkg-config.out")) + tg.must(os.Chmod(tg.path("pkg-config.sh"), 0755)) + tg.setenv("GOPATH", tg.path(".")) + tg.setenv("PKG_CONFIG", tg.path("pkg-config.sh")) + tg.run("build", "x") + out, err := os.ReadFile(tg.path("pkg-config.out")) + tg.must(err) + out = bytes.TrimSpace(out) + want := "--cflags --static --static -- a a\n--libs --static --static -- a a" + if !bytes.Equal(out, []byte(want)) { + t.Errorf("got %q want %q", out, want) + } +} + +func TestCgoCache(t *testing.T) { + if !canCgo { + t.Skip("no cgo") + } + tooSlow(t) + + 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.parallel() + 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 24704. +func TestLinkerTmpDirIsDeleted(t *testing.T) { + skipIfGccgo(t, "gccgo does not use cmd/link") + if !canCgo { + t.Skip("skipping because cgo not enabled") + } + tooSlow(t) + + 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) + } +} + +// Issue 25093. +func TestCoverpkgTestOnly(t *testing.T) { + skipIfGccgo(t, "gccgo has no cover tool") + tooSlow(t) + 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/src/cmd/go/go_unix_test.go b/src/cmd/go/go_unix_test.go new file mode 100644 index 0000000..f6e10ca --- /dev/null +++ b/src/cmd/go/go_unix_test.go @@ -0,0 +1,35 @@ +// Copyright 2015 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 darwin dragonfly freebsd linux netbsd openbsd solaris + +package main_test + +import ( + "os" + "syscall" + "testing" +) + +func TestGoBuildUmask(t *testing.T) { + // Do not use tg.parallel; avoid other tests seeing umask manipulation. + mask := syscall.Umask(0077) // prohibit low bits + defer syscall.Umask(mask) + tg := testgo(t) + defer tg.cleanup() + tg.tempFile("x.go", `package main; func main() {}`) + // Make sure artifact will be output to /tmp/... in case the user + // has POSIX acl's on their go source tree. + // See issue 17909. + exe := tg.path("x") + tg.creatingTemp(exe) + tg.run("build", "-o", exe, tg.path("x.go")) + fi, err := os.Stat(exe) + if err != nil { + t.Fatal(err) + } + if mode := fi.Mode(); mode&0077 != 0 { + t.Fatalf("wrote x with mode=%v, wanted no 0077 bits", mode) + } +} diff --git a/src/cmd/go/go_windows_test.go b/src/cmd/go/go_windows_test.go new file mode 100644 index 0000000..3094212 --- /dev/null +++ b/src/cmd/go/go_windows_test.go @@ -0,0 +1,50 @@ +// Copyright 2014 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 ( + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + + "cmd/go/internal/robustio" +) + +func TestAbsolutePath(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + + tmp, err := os.MkdirTemp("", "TestAbsolutePath") + if err != nil { + t.Fatal(err) + } + defer robustio.RemoveAll(tmp) + + file := filepath.Join(tmp, "a.go") + err = os.WriteFile(file, []byte{}, 0644) + if err != nil { + t.Fatal(err) + } + dir := filepath.Join(tmp, "dir") + err = os.Mkdir(dir, 0777) + if err != nil { + t.Fatal(err) + } + + noVolume := file[len(filepath.VolumeName(file)):] + wrongPath := filepath.Join(dir, noVolume) + cmd := exec.Command(tg.goTool(), "build", noVolume) + cmd.Dir = dir + output, err := cmd.CombinedOutput() + if err == nil { + t.Fatal("build should fail") + } + if strings.Contains(string(output), wrongPath) { + t.Fatalf("wrong output found: %v %v", err, string(output)) + } +} diff --git a/src/cmd/go/help_test.go b/src/cmd/go/help_test.go new file mode 100644 index 0000000..abfc3db --- /dev/null +++ b/src/cmd/go/help_test.go @@ -0,0 +1,33 @@ +// 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 ( + "bytes" + "os" + "testing" + + "cmd/go/internal/help" + "cmd/go/internal/modload" +) + +func TestDocsUpToDate(t *testing.T) { + t.Parallel() + + if !modload.Enabled() { + t.Skipf("help.Help in GOPATH mode is configured by main.main") + } + + buf := new(bytes.Buffer) + // Match the command in mkalldocs.sh that generates alldocs.go. + help.Help(buf, []string{"documentation"}) + data, err := os.ReadFile("alldocs.go") + if err != nil { + t.Fatalf("error reading alldocs.go: %v", err) + } + if !bytes.Equal(data, buf.Bytes()) { + t.Errorf("alldocs.go is not up to date; run mkalldocs.sh to regenerate it") + } +} diff --git a/src/cmd/go/init_test.go b/src/cmd/go/init_test.go new file mode 100644 index 0000000..5a5cbe5 --- /dev/null +++ b/src/cmd/go/init_test.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 main_test + +import ( + "internal/testenv" + "os/exec" + "sync/atomic" + "testing" +) + +// BenchmarkExecGoEnv measures how long it takes for 'go env GOARCH' to run. +// Since 'go' is executed, remember to run 'go install cmd/go' before running +// the benchmark if any changes were done. +func BenchmarkExecGoEnv(b *testing.B) { + testenv.MustHaveExec(b) + gotool, err := testenv.GoTool() + if err != nil { + b.Fatal(err) + } + + // We collect extra metrics. + var n, userTime, systemTime int64 + + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + cmd := exec.Command(gotool, "env", "GOARCH") + + if err := cmd.Run(); err != nil { + b.Fatal(err) + } + atomic.AddInt64(&n, 1) + atomic.AddInt64(&userTime, int64(cmd.ProcessState.UserTime())) + atomic.AddInt64(&systemTime, int64(cmd.ProcessState.SystemTime())) + } + }) + b.ReportMetric(float64(userTime)/float64(n), "user-ns/op") + b.ReportMetric(float64(systemTime)/float64(n), "sys-ns/op") +} diff --git a/src/cmd/go/internal/auth/auth.go b/src/cmd/go/internal/auth/auth.go new file mode 100644 index 0000000..fe5a89d --- /dev/null +++ b/src/cmd/go/internal/auth/auth.go @@ -0,0 +1,25 @@ +// Copyright 2019 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 auth provides access to user-provided authentication credentials. +package auth + +import "net/http" + +// AddCredentials fills in the user's credentials for req, if any. +// The return value reports whether any matching credentials were found. +func AddCredentials(req *http.Request) (added bool) { + host := req.URL.Hostname() + + // TODO(golang.org/issue/26232): Support arbitrary user-provided credentials. + netrcOnce.Do(readNetrc) + for _, l := range netrc { + if l.machine == host { + req.SetBasicAuth(l.login, l.password) + return true + } + } + + return false +} diff --git a/src/cmd/go/internal/auth/netrc.go b/src/cmd/go/internal/auth/netrc.go new file mode 100644 index 0000000..0107f20 --- /dev/null +++ b/src/cmd/go/internal/auth/netrc.go @@ -0,0 +1,110 @@ +// Copyright 2019 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 auth + +import ( + "os" + "path/filepath" + "runtime" + "strings" + "sync" +) + +type netrcLine struct { + machine string + login string + password string +} + +var ( + netrcOnce sync.Once + netrc []netrcLine + netrcErr error +) + +func parseNetrc(data string) []netrcLine { + // See https://www.gnu.org/software/inetutils/manual/html_node/The-_002enetrc-file.html + // for documentation on the .netrc format. + var nrc []netrcLine + var l netrcLine + inMacro := false + for _, line := range strings.Split(data, "\n") { + if inMacro { + if line == "" { + inMacro = false + } + continue + } + + f := strings.Fields(line) + i := 0 + for ; i < len(f)-1; i += 2 { + // Reset at each "machine" token. + // “The auto-login process searches the .netrc file for a machine token + // that matches […]. Once a match is made, the subsequent .netrc tokens + // are processed, stopping when the end of file is reached or another + // machine or a default token is encountered.” + switch f[i] { + case "machine": + l = netrcLine{machine: f[i+1]} + case "default": + break + case "login": + l.login = f[i+1] + case "password": + l.password = f[i+1] + case "macdef": + // “A macro is defined with the specified name; its contents begin with + // the next .netrc line and continue until a null line (consecutive + // new-line characters) is encountered.” + inMacro = true + } + if l.machine != "" && l.login != "" && l.password != "" { + nrc = append(nrc, l) + l = netrcLine{} + } + } + + if i < len(f) && f[i] == "default" { + // “There can be only one default token, and it must be after all machine tokens.” + break + } + } + + return nrc +} + +func netrcPath() (string, error) { + if env := os.Getenv("NETRC"); env != "" { + return env, nil + } + dir, err := os.UserHomeDir() + if err != nil { + return "", err + } + base := ".netrc" + if runtime.GOOS == "windows" { + base = "_netrc" + } + return filepath.Join(dir, base), nil +} + +func readNetrc() { + path, err := netrcPath() + if err != nil { + netrcErr = err + return + } + + data, err := os.ReadFile(path) + if err != nil { + if !os.IsNotExist(err) { + netrcErr = err + } + return + } + + netrc = parseNetrc(string(data)) +} diff --git a/src/cmd/go/internal/auth/netrc_test.go b/src/cmd/go/internal/auth/netrc_test.go new file mode 100644 index 0000000..e06c545 --- /dev/null +++ b/src/cmd/go/internal/auth/netrc_test.go @@ -0,0 +1,58 @@ +// 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 auth + +import ( + "reflect" + "testing" +) + +var testNetrc = ` +machine incomplete +password none + +machine api.github.com + login user + password pwd + +machine incomlete.host + login justlogin + +machine test.host +login user2 +password pwd2 + +machine oneline login user3 password pwd3 + +machine ignore.host macdef ignore + login nobody + password nothing + +machine hasmacro.too macdef ignore-next-lines login user4 password pwd4 + login nobody + password nothing + +default +login anonymous +password gopher@golang.org + +machine after.default +login oops +password too-late-in-file +` + +func TestParseNetrc(t *testing.T) { + lines := parseNetrc(testNetrc) + want := []netrcLine{ + {"api.github.com", "user", "pwd"}, + {"test.host", "user2", "pwd2"}, + {"oneline", "user3", "pwd3"}, + {"hasmacro.too", "user4", "pwd4"}, + } + + if !reflect.DeepEqual(lines, want) { + t.Errorf("parseNetrc:\nhave %q\nwant %q", lines, want) + } +} diff --git a/src/cmd/go/internal/base/base.go b/src/cmd/go/internal/base/base.go new file mode 100644 index 0000000..954ce47 --- /dev/null +++ b/src/cmd/go/internal/base/base.go @@ -0,0 +1,186 @@ +// 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 base defines shared basic pieces of the go command, +// in particular logging and the Command structure. +package base + +import ( + "context" + "flag" + "fmt" + exec "internal/execabs" + "log" + "os" + "strings" + "sync" + + "cmd/go/internal/cfg" + "cmd/go/internal/str" +) + +// A Command is an implementation of a go command +// like go build or go fix. +type Command struct { + // Run runs the command. + // The args are the arguments after the command name. + Run func(ctx context.Context, cmd *Command, args []string) + + // UsageLine is the one-line usage message. + // The words between "go" and the first flag or argument in the line are taken to be the command name. + UsageLine string + + // Short is the short description shown in the 'go help' output. + Short string + + // Long is the long message shown in the 'go help ' output. + Long string + + // Flag is a set of flags specific to this command. + Flag flag.FlagSet + + // 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 +} + +var Go = &Command{ + UsageLine: "go", + Long: `Go is a tool for managing Go source code.`, + // Commands initialized in package main +} + +// hasFlag reports whether a command or any of its subcommands contain the given +// flag. +func hasFlag(c *Command, name string) bool { + if f := c.Flag.Lookup(name); f != nil { + return true + } + for _, sub := range c.Commands { + if hasFlag(sub, name) { + return true + } + } + return false +} + +// 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 + 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.LongName()) + SetExitStatus(2) + Exit() +} + +// Runnable reports whether the command can be run; otherwise +// it is a documentation pseudo-command such as importpath. +func (c *Command) Runnable() bool { + return c.Run != nil +} + +var atExitFuncs []func() + +func AtExit(f func()) { + atExitFuncs = append(atExitFuncs, f) +} + +func Exit() { + for _, f := range atExitFuncs { + f() + } + os.Exit(exitStatus) +} + +func Fatalf(format string, args ...interface{}) { + Errorf(format, args...) + Exit() +} + +func Errorf(format string, args ...interface{}) { + log.Printf(format, args...) + SetExitStatus(1) +} + +func ExitIfErrors() { + if exitStatus != 0 { + Exit() + } +} + +var exitStatus = 0 +var exitMu sync.Mutex + +func SetExitStatus(n int) { + exitMu.Lock() + if exitStatus < n { + exitStatus = n + } + exitMu.Unlock() +} + +func GetExitStatus() int { + return exitStatus +} + +// Run runs the command, with stdout and stderr +// connected to the go command's own stdout and stderr. +// If the command fails, Run reports the error using Errorf. +func Run(cmdargs ...interface{}) { + cmdline := str.StringList(cmdargs...) + if cfg.BuildN || cfg.BuildX { + fmt.Printf("%s\n", strings.Join(cmdline, " ")) + if cfg.BuildN { + return + } + } + + cmd := exec.Command(cmdline[0], cmdline[1:]...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + Errorf("%v", err) + } +} + +// RunStdin is like run but connects Stdin. +func RunStdin(cmdline []string) { + cmd := exec.Command(cmdline[0], cmdline[1:]...) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Env = cfg.OrigEnv + StartSigHandlers() + if err := cmd.Run(); err != nil { + Errorf("%v", err) + } +} + +// Usage is the usage-reporting function, filled in by package main +// but here for reference by other packages. +var Usage func() diff --git a/src/cmd/go/internal/base/env.go b/src/cmd/go/internal/base/env.go new file mode 100644 index 0000000..5f2665d --- /dev/null +++ b/src/cmd/go/internal/base/env.go @@ -0,0 +1,15 @@ +// 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 base + +// AppendPWD returns the result of appending PWD=dir to the environment base. +// +// The resulting environment makes os.Getwd more efficient for a subprocess +// running in dir. +func AppendPWD(base []string, dir string) []string { + // Internally we only use absolute paths, so dir is absolute. + // Even if dir is not absolute, no harm done. + return append(base, "PWD="+dir) +} diff --git a/src/cmd/go/internal/base/flag.go b/src/cmd/go/internal/base/flag.go new file mode 100644 index 0000000..677f819 --- /dev/null +++ b/src/cmd/go/internal/base/flag.go @@ -0,0 +1,71 @@ +// 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 base + +import ( + "flag" + + "cmd/go/internal/cfg" + "cmd/go/internal/fsys" + "cmd/go/internal/str" +) + +// A StringsFlag is a command-line flag that interprets its argument +// as a space-separated list of possibly-quoted strings. +type StringsFlag []string + +func (v *StringsFlag) Set(s string) error { + var err error + *v, err = str.SplitQuotedFields(s) + if *v == nil { + *v = []string{} + } + return err +} + +func (v *StringsFlag) String() string { + return "" +} + +// explicitStringFlag is like a regular string flag, but it also tracks whether +// the string was set explicitly to a non-empty value. +type explicitStringFlag struct { + value *string + explicit *bool +} + +func (f explicitStringFlag) String() string { + if f.value == nil { + return "" + } + return *f.value +} + +func (f explicitStringFlag) Set(v string) error { + *f.value = v + if v != "" { + *f.explicit = true + } + return nil +} + +// AddBuildFlagsNX adds the -n and -x build flags to the flag set. +func AddBuildFlagsNX(flags *flag.FlagSet) { + flags.BoolVar(&cfg.BuildN, "n", false, "") + flags.BoolVar(&cfg.BuildX, "x", false, "") +} + +// AddModFlag adds the -mod build flag to the flag set. +func AddModFlag(flags *flag.FlagSet) { + flags.Var(explicitStringFlag{value: &cfg.BuildMod, explicit: &cfg.BuildModExplicit}, "mod", "") +} + +// AddModCommonFlags adds the module-related flags common to build commands +// and 'go mod' subcommands. +func AddModCommonFlags(flags *flag.FlagSet) { + flags.BoolVar(&cfg.ModCacheRW, "modcacherw", false, "") + flags.StringVar(&cfg.ModFile, "modfile", "", "") + flags.StringVar(&fsys.OverlayFile, "overlay", "", "") +} diff --git a/src/cmd/go/internal/base/goflags.go b/src/cmd/go/internal/base/goflags.go new file mode 100644 index 0000000..267006b --- /dev/null +++ b/src/cmd/go/internal/base/goflags.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 base + +import ( + "flag" + "fmt" + "runtime" + "strings" + + "cmd/go/internal/cfg" +) + +var goflags []string // cached $GOFLAGS list; can be -x or --x form + +// 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 + } + + goflags = strings.Fields(cfg.Getenv("GOFLAGS")) + if len(goflags) == 0 { + // nothing to do; avoid work on later InitGOFLAGS call + goflags = []string{} + return + } + + // 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" + + // 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 !hasFlag(Go, 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 + // Ignore invalid flags like '=' or '=value'. + // If it is not reported in InitGOFlags it means we don't want to report it. + if i := strings.Index(goflag, "="); i == 0 { + continue + } else if 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 + } + + // Use flags.Set consistently (instead of f.Value.Set) so that a subsequent + // call to flags.Visit will correctly visit the flags that have been set. + + if fb, ok := f.Value.(boolFlag); ok && fb.IsBoolFlag() { + if hasValue { + if err := flags.Set(f.Name, 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 := flags.Set(f.Name, "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 := flags.Set(f.Name, value); err != nil { + fmt.Fprintf(flags.Output(), "go: invalid value %q for flag %s (from %s): %v\n", value, name, where, err) + flags.Usage() + } + } + } +} + +// InGOFLAGS returns whether GOFLAGS contains the given flag, such as "-mod". +func InGOFLAGS(flag string) bool { + for _, goflag := range 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/src/cmd/go/internal/base/path.go b/src/cmd/go/internal/base/path.go new file mode 100644 index 0000000..7a51181 --- /dev/null +++ b/src/cmd/go/internal/base/path.go @@ -0,0 +1,52 @@ +// 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 base + +import ( + "os" + "path/filepath" + "strings" +) + +func getwd() string { + wd, err := os.Getwd() + if err != nil { + Fatalf("cannot determine current directory: %v", err) + } + return wd +} + +var Cwd = getwd() + +// ShortPath returns an absolute or relative name for path, whatever is shorter. +func ShortPath(path string) string { + if rel, err := filepath.Rel(Cwd, path); err == nil && len(rel) < len(path) { + return rel + } + return path +} + +// RelPaths returns a copy of paths with absolute paths +// made relative to the current directory if they would be shorter. +func RelPaths(paths []string) []string { + var out []string + // TODO(rsc): Can this use Cwd from above? + pwd, _ := os.Getwd() + for _, p := range paths { + rel, err := filepath.Rel(pwd, p) + if err == nil && len(rel) < len(p) { + p = rel + } + out = append(out, p) + } + return out +} + +// IsTestFile reports whether the source file is a set of tests and should therefore +// be excluded from coverage analysis. +func IsTestFile(file string) bool { + // We don't cover tests, only the code they test. + return strings.HasSuffix(file, "_test.go") +} diff --git a/src/cmd/go/internal/base/signal.go b/src/cmd/go/internal/base/signal.go new file mode 100644 index 0000000..05befcf --- /dev/null +++ b/src/cmd/go/internal/base/signal.go @@ -0,0 +1,31 @@ +// 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. + +package base + +import ( + "os" + "os/signal" + "sync" +) + +// Interrupted is closed when the go command receives an interrupt signal. +var Interrupted = make(chan struct{}) + +// processSignals setups signal handler. +func processSignals() { + sig := make(chan os.Signal, 1) + signal.Notify(sig, signalsToIgnore...) + go func() { + <-sig + close(Interrupted) + }() +} + +var onceProcessSignals sync.Once + +// StartSigHandlers starts the signal handlers. +func StartSigHandlers() { + onceProcessSignals.Do(processSignals) +} diff --git a/src/cmd/go/internal/base/signal_notunix.go b/src/cmd/go/internal/base/signal_notunix.go new file mode 100644 index 0000000..9e869b0 --- /dev/null +++ b/src/cmd/go/internal/base/signal_notunix.go @@ -0,0 +1,17 @@ +// 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. + +// +build plan9 windows + +package base + +import ( + "os" +) + +var signalsToIgnore = []os.Signal{os.Interrupt} + +// SignalTrace is the signal to send to make a Go program +// crash with a stack trace (no such signal in this case). +var SignalTrace os.Signal = nil diff --git a/src/cmd/go/internal/base/signal_unix.go b/src/cmd/go/internal/base/signal_unix.go new file mode 100644 index 0000000..342775a --- /dev/null +++ b/src/cmd/go/internal/base/signal_unix.go @@ -0,0 +1,18 @@ +// 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. + +// +build aix darwin dragonfly freebsd js linux netbsd openbsd solaris + +package base + +import ( + "os" + "syscall" +) + +var signalsToIgnore = []os.Signal{os.Interrupt, syscall.SIGQUIT} + +// SignalTrace is the signal to send to make a Go program +// crash with a stack trace. +var SignalTrace os.Signal = syscall.SIGQUIT diff --git a/src/cmd/go/internal/base/tool.go b/src/cmd/go/internal/base/tool.go new file mode 100644 index 0000000..d0da65e --- /dev/null +++ b/src/cmd/go/internal/base/tool.go @@ -0,0 +1,44 @@ +// 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 base + +import ( + "fmt" + "go/build" + "os" + "path/filepath" + "runtime" + + "cmd/go/internal/cfg" +) + +// Configuration for finding tool binaries. +var ( + ToolGOOS = runtime.GOOS + ToolGOARCH = runtime.GOARCH + ToolIsWindows = ToolGOOS == "windows" + ToolDir = build.ToolDir +) + +const ToolWindowsExtension = ".exe" + +// Tool returns the path to the named tool (for example, "vet"). +// If the tool cannot be found, Tool exits the process. +func Tool(toolName string) string { + toolPath := filepath.Join(ToolDir, toolName) + if ToolIsWindows { + toolPath += ToolWindowsExtension + } + if len(cfg.BuildToolexec) > 0 { + return toolPath + } + // Give a nice message if there is no tool with that name. + if _, err := os.Stat(toolPath); err != nil { + fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName) + SetExitStatus(2) + Exit() + } + return toolPath +} diff --git a/src/cmd/go/internal/bug/bug.go b/src/cmd/go/internal/bug/bug.go new file mode 100644 index 0000000..4aa08b4 --- /dev/null +++ b/src/cmd/go/internal/bug/bug.go @@ -0,0 +1,211 @@ +// Copyright 2016 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 bug implements the ``go bug'' command. +package bug + +import ( + "bytes" + "context" + "fmt" + exec "internal/execabs" + "io" + urlpkg "net/url" + "os" + "path/filepath" + "regexp" + "runtime" + "strings" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/web" +) + +var CmdBug = &base.Command{ + Run: runBug, + UsageLine: "go bug", + Short: "start a bug report", + Long: ` +Bug opens the default browser and starts a new bug report. +The report includes useful system information. + `, +} + +func init() { + CmdBug.Flag.BoolVar(&cfg.BuildV, "v", false, "") +} + +func runBug(ctx context.Context, cmd *base.Command, args []string) { + if len(args) > 0 { + base.Fatalf("go bug: bug takes no arguments") + } + var buf bytes.Buffer + buf.WriteString(bugHeader) + printGoVersion(&buf) + buf.WriteString("### Does this issue reproduce with the latest release?\n\n\n") + printEnvDetails(&buf) + buf.WriteString(bugFooter) + + body := buf.String() + url := "https://github.com/golang/go/issues/new?body=" + urlpkg.QueryEscape(body) + if !web.OpenBrowser(url) { + fmt.Print("Please file a new issue at golang.org/issue/new using this template:\n\n") + fmt.Print(body) + } +} + +const bugHeader = ` + +` +const bugFooter = `### What did you do? + + + + + +### What did you expect to see? + + + +### What did you see instead? + +` + +func printGoVersion(w io.Writer) { + fmt.Fprintf(w, "### What version of Go are you using (`go version`)?\n\n") + fmt.Fprintf(w, "
\n")
+	fmt.Fprintf(w, "$ go version\n")
+	printCmdOut(w, "", "go", "version")
+	fmt.Fprintf(w, "
\n") + fmt.Fprintf(w, "\n") +} + +func printEnvDetails(w io.Writer) { + fmt.Fprintf(w, "### What operating system and processor architecture are you using (`go env`)?\n\n") + fmt.Fprintf(w, "
go env Output
\n")
+	fmt.Fprintf(w, "$ go env\n")
+	printCmdOut(w, "", "go", "env")
+	printGoDetails(w)
+	printOSDetails(w)
+	printCDetails(w)
+	fmt.Fprintf(w, "
\n\n") +} + +func printGoDetails(w io.Writer) { + printCmdOut(w, "GOROOT/bin/go version: ", filepath.Join(runtime.GOROOT(), "bin/go"), "version") + printCmdOut(w, "GOROOT/bin/go tool compile -V: ", filepath.Join(runtime.GOROOT(), "bin/go"), "tool", "compile", "-V") +} + +func printOSDetails(w io.Writer) { + switch runtime.GOOS { + case "darwin", "ios": + printCmdOut(w, "uname -v: ", "uname", "-v") + printCmdOut(w, "", "sw_vers") + case "linux": + printCmdOut(w, "uname -sr: ", "uname", "-sr") + printCmdOut(w, "", "lsb_release", "-a") + printGlibcVersion(w) + case "openbsd", "netbsd", "freebsd", "dragonfly": + printCmdOut(w, "uname -v: ", "uname", "-v") + case "illumos", "solaris": + // Be sure to use the OS-supplied uname, in "/usr/bin": + printCmdOut(w, "uname -srv: ", "/usr/bin/uname", "-srv") + out, err := os.ReadFile("/etc/release") + if err == nil { + fmt.Fprintf(w, "/etc/release: %s\n", out) + } else { + if cfg.BuildV { + fmt.Printf("failed to read /etc/release: %v\n", err) + } + } + } +} + +func printCDetails(w io.Writer) { + printCmdOut(w, "lldb --version: ", "lldb", "--version") + cmd := exec.Command("gdb", "--version") + out, err := cmd.Output() + if err == nil { + // There's apparently no combination of command line flags + // to get gdb to spit out its version without the license and warranty. + // Print up to the first newline. + fmt.Fprintf(w, "gdb --version: %s\n", firstLine(out)) + } else { + if cfg.BuildV { + fmt.Printf("failed to run gdb --version: %v\n", err) + } + } +} + +// printCmdOut prints the output of running the given command. +// It ignores failures; 'go bug' is best effort. +func printCmdOut(w io.Writer, prefix, path string, args ...string) { + cmd := exec.Command(path, args...) + out, err := cmd.Output() + if err != nil { + if cfg.BuildV { + fmt.Printf("%s %s: %v\n", path, strings.Join(args, " "), err) + } + return + } + fmt.Fprintf(w, "%s%s\n", prefix, bytes.TrimSpace(out)) +} + +// firstLine returns the first line of a given byte slice. +func firstLine(buf []byte) []byte { + idx := bytes.IndexByte(buf, '\n') + if idx > 0 { + buf = buf[:idx] + } + return bytes.TrimSpace(buf) +} + +// printGlibcVersion prints information about the glibc version. +// It ignores failures. +func printGlibcVersion(w io.Writer) { + tempdir := os.TempDir() + if tempdir == "" { + return + } + src := []byte(`int main() {}`) + srcfile := filepath.Join(tempdir, "go-bug.c") + outfile := filepath.Join(tempdir, "go-bug") + err := os.WriteFile(srcfile, src, 0644) + if err != nil { + return + } + defer os.Remove(srcfile) + cmd := exec.Command("gcc", "-o", outfile, srcfile) + if _, err = cmd.CombinedOutput(); err != nil { + return + } + defer os.Remove(outfile) + + cmd = exec.Command("ldd", outfile) + out, err := cmd.CombinedOutput() + if err != nil { + return + } + re := regexp.MustCompile(`libc\.so[^ ]* => ([^ ]+)`) + m := re.FindStringSubmatch(string(out)) + if m == nil { + return + } + cmd = exec.Command(m[1]) + out, err = cmd.Output() + if err != nil { + return + } + fmt.Fprintf(w, "%s: %s\n", m[1], firstLine(out)) + + // print another line (the one containing version string) in case of musl libc + if idx := bytes.IndexByte(out, '\n'); bytes.Index(out, []byte("musl")) != -1 && idx > -1 { + fmt.Fprintf(w, "%s\n", firstLine(out[idx+1:])) + } +} diff --git a/src/cmd/go/internal/cache/cache.go b/src/cmd/go/internal/cache/cache.go new file mode 100644 index 0000000..41f9216 --- /dev/null +++ b/src/cmd/go/internal/cache/cache.go @@ -0,0 +1,524 @@ +// 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 cache implements a build artifact cache. +package cache + +import ( + "bytes" + "crypto/sha256" + "encoding/hex" + "errors" + "fmt" + "io" + "io/fs" + "os" + "path/filepath" + "strconv" + "strings" + "time" + + "cmd/go/internal/renameio" +) + +// An ActionID is a cache action key, the hash of a complete description of a +// repeatable computation (command line, environment variables, +// input file contents, executable contents). +type ActionID [HashSize]byte + +// An OutputID is a cache output key, the hash of an output of a computation. +type OutputID [HashSize]byte + +// A Cache is a package cache, backed by a file system directory tree. +type Cache struct { + dir string + now func() time.Time +} + +// Open opens and returns the cache in the given directory. +// +// It is safe for multiple processes on a single machine to use the +// same cache directory in a local file system simultaneously. +// They will coordinate using operating system file locks and may +// duplicate effort but will not corrupt the cache. +// +// However, it is NOT safe for multiple processes on different machines +// to share a cache directory (for example, if the directory were stored +// in a network file system). File locking is notoriously unreliable in +// network file systems and may not suffice to protect the cache. +// +func Open(dir string) (*Cache, error) { + info, err := os.Stat(dir) + if err != nil { + return nil, err + } + if !info.IsDir() { + return nil, &fs.PathError{Op: "open", Path: dir, Err: fmt.Errorf("not a directory")} + } + for i := 0; i < 256; i++ { + name := filepath.Join(dir, fmt.Sprintf("%02x", i)) + if err := os.MkdirAll(name, 0777); err != nil { + return nil, err + } + } + c := &Cache{ + dir: dir, + now: time.Now, + } + return c, nil +} + +// fileName returns the name of the file corresponding to the given id. +func (c *Cache) fileName(id [HashSize]byte, key string) string { + return filepath.Join(c.dir, fmt.Sprintf("%02x", id[0]), fmt.Sprintf("%x", id)+"-"+key) +} + +// An entryNotFoundError indicates that a cache entry was not found, with an +// optional underlying reason. +type entryNotFoundError struct { + Err error +} + +func (e *entryNotFoundError) Error() string { + if e.Err == nil { + return "cache entry not found" + } + return fmt.Sprintf("cache entry not found: %v", e.Err) +} + +func (e *entryNotFoundError) Unwrap() error { + return e.Err +} + +const ( + // action entry file is "v1 \n" + hexSize = HashSize * 2 + entrySize = 2 + 1 + hexSize + 1 + hexSize + 1 + 20 + 1 + 20 + 1 +) + +// verify controls whether to run the cache in verify mode. +// In verify mode, the cache always returns errMissing from Get +// but then double-checks in Put that the data being written +// exactly matches any existing entry. This provides an easy +// way to detect program behavior that would have been different +// had the cache entry been returned from Get. +// +// verify is enabled by setting the environment variable +// GODEBUG=gocacheverify=1. +var verify = false + +var errVerifyMode = errors.New("gocacheverify=1") + +// DebugTest is set when GODEBUG=gocachetest=1 is in the environment. +var DebugTest = false + +func init() { initEnv() } + +func initEnv() { + verify = false + debugHash = false + debug := strings.Split(os.Getenv("GODEBUG"), ",") + for _, f := range debug { + if f == "gocacheverify=1" { + verify = true + } + if f == "gocachehash=1" { + debugHash = true + } + if f == "gocachetest=1" { + DebugTest = true + } + } +} + +// Get looks up the action ID in the cache, +// returning the corresponding output ID and file size, if any. +// Note that finding an output ID does not guarantee that the +// saved file for that output ID is still available. +func (c *Cache) Get(id ActionID) (Entry, error) { + if verify { + return Entry{}, &entryNotFoundError{Err: errVerifyMode} + } + return c.get(id) +} + +type Entry struct { + OutputID OutputID + Size int64 + Time time.Time +} + +// get is Get but does not respect verify mode, so that Put can use it. +func (c *Cache) get(id ActionID) (Entry, error) { + missing := func(reason error) (Entry, error) { + return Entry{}, &entryNotFoundError{Err: reason} + } + f, err := os.Open(c.fileName(id, "a")) + if err != nil { + return missing(err) + } + defer f.Close() + entry := make([]byte, entrySize+1) // +1 to detect whether f is too long + if n, err := io.ReadFull(f, entry); n > entrySize { + return missing(errors.New("too long")) + } else if err != io.ErrUnexpectedEOF { + if err == io.EOF { + return missing(errors.New("file is empty")) + } + return missing(err) + } else if n < entrySize { + return missing(errors.New("entry file incomplete")) + } + if entry[0] != 'v' || entry[1] != '1' || entry[2] != ' ' || entry[3+hexSize] != ' ' || entry[3+hexSize+1+hexSize] != ' ' || entry[3+hexSize+1+hexSize+1+20] != ' ' || entry[entrySize-1] != '\n' { + return missing(errors.New("invalid header")) + } + eid, entry := entry[3:3+hexSize], entry[3+hexSize:] + eout, entry := entry[1:1+hexSize], entry[1+hexSize:] + esize, entry := entry[1:1+20], entry[1+20:] + etime, entry := entry[1:1+20], entry[1+20:] + var buf [HashSize]byte + if _, err := hex.Decode(buf[:], eid); err != nil { + return missing(fmt.Errorf("decoding ID: %v", err)) + } else if buf != id { + return missing(errors.New("mismatched ID")) + } + if _, err := hex.Decode(buf[:], eout); err != nil { + return missing(fmt.Errorf("decoding output ID: %v", err)) + } + i := 0 + for i < len(esize) && esize[i] == ' ' { + i++ + } + size, err := strconv.ParseInt(string(esize[i:]), 10, 64) + if err != nil { + return missing(fmt.Errorf("parsing size: %v", err)) + } else if size < 0 { + return missing(errors.New("negative size")) + } + i = 0 + for i < len(etime) && etime[i] == ' ' { + i++ + } + tm, err := strconv.ParseInt(string(etime[i:]), 10, 64) + if err != nil { + return missing(fmt.Errorf("parsing timestamp: %v", err)) + } else if tm < 0 { + return missing(errors.New("negative timestamp")) + } + + c.used(c.fileName(id, "a")) + + 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 { + return "", Entry{}, &entryNotFoundError{Err: err} + } + if info.Size() != entry.Size { + return "", Entry{}, &entryNotFoundError{Err: errors.New("file incomplete")} + } + 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. +func (c *Cache) GetBytes(id ActionID) ([]byte, Entry, error) { + entry, err := c.Get(id) + if err != nil { + return nil, entry, err + } + data, _ := os.ReadFile(c.OutputFile(entry.OutputID)) + if sha256.Sum256(data) != entry.OutputID { + return nil, entry, &entryNotFoundError{Err: errors.New("bad checksum")} + } + return data, entry, nil +} + +// OutputFile returns the name of the cache file storing output with the given OutputID. +func (c *Cache) OutputFile(out OutputID) string { + file := c.fileName(out, "d") + c.used(file) + return file +} + +// Time constants for cache expiration. +// +// We set the mtime on a cache file on each use, but at most one per mtimeInterval (1 hour), +// to avoid causing many unnecessary inode updates. The mtimes therefore +// roughly reflect "time of last use" but may in fact be older by at most an hour. +// +// We scan the cache for entries to delete at most once per trimInterval (1 day). +// +// When we do scan the cache, we delete entries that have not been used for +// at least trimLimit (5 days). Statistics gathered from a month of usage by +// Go developers found that essentially all reuse of cached entries happened +// within 5 days of the previous reuse. See golang.org/issue/22990. +const ( + mtimeInterval = 1 * time.Hour + trimInterval = 24 * time.Hour + trimLimit = 5 * 24 * time.Hour +) + +// used makes a best-effort attempt to update mtime on file, +// so that mtime reflects cache access time. +// +// Because the reflection only needs to be approximate, +// and to reduce the amount of disk activity caused by using +// cache entries, used only updates the mtime if the current +// mtime is more than an hour old. This heuristic eliminates +// nearly all of the mtime updates that would otherwise happen, +// while still keeping the mtimes useful for cache trimming. +func (c *Cache) used(file string) { + info, err := os.Stat(file) + if err == nil && c.now().Sub(info.ModTime()) < mtimeInterval { + return + } + os.Chtimes(file, c.now(), c.now()) +} + +// Trim removes old cache entries that are likely not to be reused. +func (c *Cache) Trim() { + now := c.now() + + // We maintain in dir/trim.txt the time of the last completed cache trim. + // If the cache has been trimmed recently enough, do nothing. + // This is the common case. + data, _ := renameio.ReadFile(filepath.Join(c.dir, "trim.txt")) + t, err := strconv.ParseInt(strings.TrimSpace(string(data)), 10, 64) + if err == nil && now.Sub(time.Unix(t, 0)) < trimInterval { + return + } + + // Trim each of the 256 subdirectories. + // We subtract an additional mtimeInterval + // to account for the imprecision of our "last used" mtimes. + cutoff := now.Add(-trimLimit - mtimeInterval) + for i := 0; i < 256; i++ { + subdir := filepath.Join(c.dir, fmt.Sprintf("%02x", i)) + c.trimSubdir(subdir, cutoff) + } + + // Ignore errors from here: if we don't write the complete timestamp, the + // cache will appear older than it is, and we'll trim it again next time. + renameio.WriteFile(filepath.Join(c.dir, "trim.txt"), []byte(fmt.Sprintf("%d", now.Unix())), 0666) +} + +// trimSubdir trims a single cache subdirectory. +func (c *Cache) trimSubdir(subdir string, cutoff time.Time) { + // Read all directory entries from subdir before removing + // any files, in case removing files invalidates the file offset + // in the directory scan. Also, ignore error from f.Readdirnames, + // because we don't care about reporting the error and we still + // want to process any entries found before the error. + f, err := os.Open(subdir) + if err != nil { + return + } + names, _ := f.Readdirnames(-1) + f.Close() + + for _, name := range names { + // Remove only cache entries (xxxx-a and xxxx-d). + if !strings.HasSuffix(name, "-a") && !strings.HasSuffix(name, "-d") { + continue + } + entry := filepath.Join(subdir, name) + info, err := os.Stat(entry) + if err == nil && info.ModTime().Before(cutoff) { + os.Remove(entry) + } + } +} + +// putIndexEntry adds an entry to the cache recording that executing the action +// with the given id produces an output with the given output id (hash) and size. +func (c *Cache) putIndexEntry(id ActionID, out OutputID, size int64, allowVerify bool) error { + // Note: We expect that for one reason or another it may happen + // that repeating an action produces a different output hash + // (for example, if the output contains a time stamp or temp dir name). + // While not ideal, this is also not a correctness problem, so we + // don't make a big deal about it. In particular, we leave the action + // cache entries writable specifically so that they can be overwritten. + // + // Setting GODEBUG=gocacheverify=1 does make a big deal: + // in verify mode we are double-checking that the cache entries + // are entirely reproducible. As just noted, this may be unrealistic + // in some cases but the check is also useful for shaking out real bugs. + entry := fmt.Sprintf("v1 %x %x %20d %20d\n", id, out, size, time.Now().UnixNano()) + if verify && allowVerify { + old, err := c.get(id) + if err == nil && (old.OutputID != out || old.Size != size) { + // panic to show stack trace, so we can see what code is generating this cache entry. + msg := fmt.Sprintf("go: internal cache error: cache verify failed: id=%x changed:<<<\n%s\n>>>\nold: %x %d\nnew: %x %d", id, reverseHash(id), out, size, old.OutputID, old.Size) + panic(msg) + } + } + file := c.fileName(id, "a") + + // Copy file to cache directory. + mode := os.O_WRONLY | os.O_CREATE + f, err := os.OpenFile(file, mode, 0666) + if err != nil { + return err + } + _, err = f.WriteString(entry) + if err == nil { + // Truncate the file only *after* writing it. + // (This should be a no-op, but truncate just in case of previous corruption.) + // + // This differs from os.WriteFile, which truncates to 0 *before* writing + // via os.O_TRUNC. Truncating only after writing ensures that a second write + // of the same content to the same file is idempotent, and does not — even + // temporarily! — undo the effect of the first write. + err = f.Truncate(int64(len(entry))) + } + if closeErr := f.Close(); err == nil { + err = closeErr + } + if err != nil { + // TODO(bcmills): This Remove potentially races with another go command writing to file. + // Can we eliminate it? + os.Remove(file) + return err + } + os.Chtimes(file, c.now(), c.now()) // mainly for tests + + return nil +} + +// Put stores the given output in the cache as the output for the action ID. +// It may read file twice. The content of file must not change between the two passes. +func (c *Cache) Put(id ActionID, file io.ReadSeeker) (OutputID, int64, error) { + return c.put(id, file, true) +} + +// PutNoVerify is like Put but disables the verify check +// when GODEBUG=goverifycache=1 is set. +// It is meant for data that is OK to cache but that we expect to vary slightly from run to run, +// like test output containing times and the like. +func (c *Cache) PutNoVerify(id ActionID, file io.ReadSeeker) (OutputID, int64, error) { + return c.put(id, file, false) +} + +func (c *Cache) put(id ActionID, file io.ReadSeeker, allowVerify bool) (OutputID, int64, error) { + // Compute output ID. + h := sha256.New() + if _, err := file.Seek(0, 0); err != nil { + return OutputID{}, 0, err + } + size, err := io.Copy(h, file) + if err != nil { + return OutputID{}, 0, err + } + var out OutputID + h.Sum(out[:0]) + + // Copy to cached output file (if not already present). + if err := c.copyFile(file, out, size); err != nil { + return out, size, err + } + + // Add to cache index. + return out, size, c.putIndexEntry(id, out, size, allowVerify) +} + +// PutBytes stores the given bytes in the cache as the output for the action ID. +func (c *Cache) PutBytes(id ActionID, data []byte) error { + _, _, err := c.Put(id, bytes.NewReader(data)) + return err +} + +// copyFile copies file into the cache, expecting it to have the given +// output ID and size, if that file is not present already. +func (c *Cache) copyFile(file io.ReadSeeker, out OutputID, size int64) error { + name := c.fileName(out, "d") + info, err := os.Stat(name) + if err == nil && info.Size() == size { + // Check hash. + if f, err := os.Open(name); err == nil { + h := sha256.New() + io.Copy(h, f) + f.Close() + var out2 OutputID + h.Sum(out2[:0]) + if out == out2 { + return nil + } + } + // Hash did not match. Fall through and rewrite file. + } + + // Copy file to cache directory. + mode := os.O_RDWR | os.O_CREATE + if err == nil && info.Size() > size { // shouldn't happen but fix in case + mode |= os.O_TRUNC + } + f, err := os.OpenFile(name, mode, 0666) + if err != nil { + return err + } + defer f.Close() + if size == 0 { + // File now exists with correct size. + // Only one possible zero-length file, so contents are OK too. + // Early return here makes sure there's a "last byte" for code below. + return nil + } + + // From here on, if any of the I/O writing the file fails, + // we make a best-effort attempt to truncate the file f + // before returning, to avoid leaving bad bytes in the file. + + // Copy file to f, but also into h to double-check hash. + if _, err := file.Seek(0, 0); err != nil { + f.Truncate(0) + return err + } + h := sha256.New() + w := io.MultiWriter(f, h) + if _, err := io.CopyN(w, file, size-1); err != nil { + f.Truncate(0) + return err + } + // Check last byte before writing it; writing it will make the size match + // what other processes expect to find and might cause them to start + // using the file. + buf := make([]byte, 1) + if _, err := file.Read(buf); err != nil { + f.Truncate(0) + return err + } + h.Write(buf) + sum := h.Sum(nil) + if !bytes.Equal(sum, out[:]) { + f.Truncate(0) + return fmt.Errorf("file content changed underfoot") + } + + // Commit cache file entry. + if _, err := f.Write(buf); err != nil { + f.Truncate(0) + return err + } + if err := f.Close(); err != nil { + // Data might not have been written, + // but file may look like it is the right size. + // To be extra careful, remove cached file. + os.Remove(name) + return err + } + os.Chtimes(name, c.now(), c.now()) // mainly for tests + + return nil +} diff --git a/src/cmd/go/internal/cache/cache_test.go b/src/cmd/go/internal/cache/cache_test.go new file mode 100644 index 0000000..a865b97 --- /dev/null +++ b/src/cmd/go/internal/cache/cache_test.go @@ -0,0 +1,269 @@ +// 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 cache + +import ( + "bytes" + "encoding/binary" + "fmt" + "os" + "path/filepath" + "testing" + "time" +) + +func init() { + verify = false // even if GODEBUG is set +} + +func TestBasic(t *testing.T) { + dir, err := os.MkdirTemp("", "cachetest-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + _, err = Open(filepath.Join(dir, "notexist")) + if err == nil { + t.Fatal(`Open("tmp/notexist") succeeded, want failure`) + } + + cdir := filepath.Join(dir, "c1") + if err := os.Mkdir(cdir, 0777); err != nil { + t.Fatal(err) + } + + c1, err := Open(cdir) + if err != nil { + t.Fatalf("Open(c1) (create): %v", err) + } + if err := c1.putIndexEntry(dummyID(1), dummyID(12), 13, true); err != nil { + t.Fatalf("addIndexEntry: %v", err) + } + if err := c1.putIndexEntry(dummyID(1), dummyID(2), 3, true); err != nil { // overwrite entry + t.Fatalf("addIndexEntry: %v", err) + } + if entry, err := c1.Get(dummyID(1)); err != nil || entry.OutputID != dummyID(2) || entry.Size != 3 { + t.Fatalf("c1.Get(1) = %x, %v, %v, want %x, %v, nil", entry.OutputID, entry.Size, err, dummyID(2), 3) + } + + c2, err := Open(cdir) + if err != nil { + t.Fatalf("Open(c2) (reuse): %v", err) + } + if entry, err := c2.Get(dummyID(1)); err != nil || entry.OutputID != dummyID(2) || entry.Size != 3 { + t.Fatalf("c2.Get(1) = %x, %v, %v, want %x, %v, nil", entry.OutputID, entry.Size, err, dummyID(2), 3) + } + if err := c2.putIndexEntry(dummyID(2), dummyID(3), 4, true); err != nil { + t.Fatalf("addIndexEntry: %v", err) + } + if entry, err := c1.Get(dummyID(2)); err != nil || entry.OutputID != dummyID(3) || entry.Size != 4 { + t.Fatalf("c1.Get(2) = %x, %v, %v, want %x, %v, nil", entry.OutputID, entry.Size, err, dummyID(3), 4) + } +} + +func TestGrowth(t *testing.T) { + dir, err := os.MkdirTemp("", "cachetest-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + c, err := Open(dir) + if err != nil { + t.Fatalf("Open: %v", err) + } + + n := 10000 + if testing.Short() { + n = 10 + } + + for i := 0; i < n; i++ { + if err := c.putIndexEntry(dummyID(i), dummyID(i*99), int64(i)*101, true); err != nil { + t.Fatalf("addIndexEntry: %v", err) + } + id := ActionID(dummyID(i)) + entry, err := c.Get(id) + if err != nil { + t.Fatalf("Get(%x): %v", id, err) + } + if entry.OutputID != dummyID(i*99) || entry.Size != int64(i)*101 { + t.Errorf("Get(%x) = %x, %d, want %x, %d", id, entry.OutputID, entry.Size, dummyID(i*99), int64(i)*101) + } + } + for i := 0; i < n; i++ { + id := ActionID(dummyID(i)) + entry, err := c.Get(id) + if err != nil { + t.Fatalf("Get2(%x): %v", id, err) + } + if entry.OutputID != dummyID(i*99) || entry.Size != int64(i)*101 { + t.Errorf("Get2(%x) = %x, %d, want %x, %d", id, entry.OutputID, entry.Size, dummyID(i*99), int64(i)*101) + } + } +} + +func TestVerifyPanic(t *testing.T) { + os.Setenv("GODEBUG", "gocacheverify=1") + initEnv() + defer func() { + os.Unsetenv("GODEBUG") + verify = false + }() + + if !verify { + t.Fatal("initEnv did not set verify") + } + + dir, err := os.MkdirTemp("", "cachetest-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + c, err := Open(dir) + if err != nil { + t.Fatalf("Open: %v", err) + } + + id := ActionID(dummyID(1)) + if err := c.PutBytes(id, []byte("abc")); err != nil { + t.Fatal(err) + } + + defer func() { + if err := recover(); err != nil { + t.Log(err) + return + } + }() + c.PutBytes(id, []byte("def")) + t.Fatal("mismatched Put did not panic in verify mode") +} + +func dummyID(x int) [HashSize]byte { + var out [HashSize]byte + binary.LittleEndian.PutUint64(out[:], uint64(x)) + return out +} + +func TestCacheTrim(t *testing.T) { + dir, err := os.MkdirTemp("", "cachetest-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + c, err := Open(dir) + if err != nil { + t.Fatalf("Open: %v", err) + } + const start = 1000000000 + now := int64(start) + c.now = func() time.Time { return time.Unix(now, 0) } + + checkTime := func(name string, mtime int64) { + t.Helper() + file := filepath.Join(c.dir, name[:2], name) + info, err := os.Stat(file) + if err != nil { + t.Fatal(err) + } + if info.ModTime().Unix() != mtime { + t.Fatalf("%s mtime = %d, want %d", name, info.ModTime().Unix(), mtime) + } + } + + id := ActionID(dummyID(1)) + c.PutBytes(id, []byte("abc")) + entry, _ := c.Get(id) + c.PutBytes(ActionID(dummyID(2)), []byte("def")) + mtime := now + checkTime(fmt.Sprintf("%x-a", id), mtime) + checkTime(fmt.Sprintf("%x-d", entry.OutputID), mtime) + + // Get should not change recent mtimes. + now = start + 10 + c.Get(id) + checkTime(fmt.Sprintf("%x-a", id), mtime) + checkTime(fmt.Sprintf("%x-d", entry.OutputID), mtime) + + // Get should change distant mtimes. + now = start + 5000 + mtime2 := now + if _, err := c.Get(id); err != nil { + t.Fatal(err) + } + c.OutputFile(entry.OutputID) + checkTime(fmt.Sprintf("%x-a", id), mtime2) + checkTime(fmt.Sprintf("%x-d", entry.OutputID), mtime2) + + // Trim should leave everything alone: it's all too new. + c.Trim() + if _, err := c.Get(id); err != nil { + t.Fatal(err) + } + c.OutputFile(entry.OutputID) + data, err := os.ReadFile(filepath.Join(dir, "trim.txt")) + if err != nil { + t.Fatal(err) + } + checkTime(fmt.Sprintf("%x-a", dummyID(2)), start) + + // Trim less than a day later should not do any work at all. + now = start + 80000 + c.Trim() + if _, err := c.Get(id); err != nil { + t.Fatal(err) + } + c.OutputFile(entry.OutputID) + data2, err := os.ReadFile(filepath.Join(dir, "trim.txt")) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(data, data2) { + t.Fatalf("second trim did work: %q -> %q", data, data2) + } + + // Fast forward and do another trim just before the 5 day cutoff. + // Note that because of usedQuantum the cutoff is actually 5 days + 1 hour. + // We used c.Get(id) just now, so 5 days later it should still be kept. + // On the other hand almost a full day has gone by since we wrote dummyID(2) + // and we haven't looked at it since, so 5 days later it should be gone. + now += 5 * 86400 + checkTime(fmt.Sprintf("%x-a", dummyID(2)), start) + c.Trim() + if _, err := c.Get(id); err != nil { + t.Fatal(err) + } + c.OutputFile(entry.OutputID) + mtime3 := now + if _, err := c.Get(dummyID(2)); err == nil { // haven't done a Get for this since original write above + t.Fatalf("Trim did not remove dummyID(2)") + } + + // The c.Get(id) refreshed id's mtime again. + // Check that another 5 days later it is still not gone, + // but check by using checkTime, which doesn't bring mtime forward. + now += 5 * 86400 + c.Trim() + checkTime(fmt.Sprintf("%x-a", id), mtime3) + checkTime(fmt.Sprintf("%x-d", entry.OutputID), mtime3) + + // Half a day later Trim should still be a no-op, because there was a Trim recently. + // Even though the entry for id is now old enough to be trimmed, + // it gets a reprieve until the time comes for a new Trim scan. + now += 86400 / 2 + c.Trim() + checkTime(fmt.Sprintf("%x-a", id), mtime3) + checkTime(fmt.Sprintf("%x-d", entry.OutputID), mtime3) + + // Another half a day later, Trim should actually run, and it should remove id. + now += 86400/2 + 1 + c.Trim() + if _, err := c.Get(dummyID(1)); err == nil { + t.Fatal("Trim did not remove dummyID(1)") + } +} diff --git a/src/cmd/go/internal/cache/default.go b/src/cmd/go/internal/cache/default.go new file mode 100644 index 0000000..0b1c1e0 --- /dev/null +++ b/src/cmd/go/internal/cache/default.go @@ -0,0 +1,97 @@ +// 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 cache + +import ( + "fmt" + "os" + "path/filepath" + "sync" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" +) + +// Default returns the default cache to use, or nil if no cache should be used. +func Default() *Cache { + defaultOnce.Do(initDefaultCache) + return defaultCache +} + +var ( + defaultOnce sync.Once + defaultCache *Cache +) + +// cacheREADME is a message stored in a README in the cache directory. +// Because the cache lives outside the normal Go trees, we leave the +// README as a courtesy to explain where it came from. +const cacheREADME = `This directory holds cached build artifacts from the Go build system. +Run "go clean -cache" if the directory is getting too large. +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() + if dir == "off" { + if defaultDirErr != nil { + base.Fatalf("build cache is required, but could not be located: %v", defaultDirErr) + } + base.Fatalf("build cache is disabled by GOCACHE=off, but required as of Go 1.12") + } + if err := os.MkdirAll(dir, 0777); err != nil { + base.Fatalf("failed to initialize build cache at %s: %s\n", dir, err) + } + if _, err := os.Stat(filepath.Join(dir, "README")); err != nil { + // Best effort. + os.WriteFile(filepath.Join(dir, "README"), []byte(cacheREADME), 0666) + } + + c, err := Open(dir) + if err != nil { + base.Fatalf("failed to initialize build cache at %s: %s\n", dir, err) + } + defaultCache = c +} + +var ( + defaultDirOnce sync.Once + defaultDir string + defaultDirErr error +) + +// DefaultDir returns the effective GOCACHE setting. +// It returns "off" if the cache is disabled. +func DefaultDir() string { + // Save the result of the first call to DefaultDir for later use in + // initDefaultCache. cmd/go/main.go explicitly sets GOCACHE so that + // subprocesses will inherit it, but that means initDefaultCache can't + // otherwise distinguish between an explicit "off" and a UserCacheDir error. + + defaultDirOnce.Do(func() { + defaultDir = cfg.Getenv("GOCACHE") + if filepath.IsAbs(defaultDir) || defaultDir == "off" { + return + } + if defaultDir != "" { + defaultDir = "off" + defaultDirErr = fmt.Errorf("GOCACHE is not an absolute path") + return + } + + // Compute default location. + dir, err := os.UserCacheDir() + if err != nil { + defaultDir = "off" + defaultDirErr = fmt.Errorf("GOCACHE is not defined and %v", err) + return + } + defaultDir = filepath.Join(dir, "go-build") + }) + + return defaultDir +} diff --git a/src/cmd/go/internal/cache/hash.go b/src/cmd/go/internal/cache/hash.go new file mode 100644 index 0000000..e4bb2a3 --- /dev/null +++ b/src/cmd/go/internal/cache/hash.go @@ -0,0 +1,174 @@ +// 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 cache + +import ( + "bytes" + "crypto/sha256" + "fmt" + "hash" + "io" + "os" + "runtime" + "sync" +) + +var debugHash = false // set when GODEBUG=gocachehash=1 + +// HashSize is the number of bytes in a hash. +const HashSize = 32 + +// A Hash provides access to the canonical hash function used to index the cache. +// The current implementation uses salted SHA256, but clients must not assume this. +type Hash struct { + h hash.Hash + name string // for debugging + buf *bytes.Buffer // for verify +} + +// hashSalt is a salt string added to the beginning of every hash +// created by NewHash. Using the Go version makes sure that different +// versions of the go command (or even different Git commits during +// work on the development branch) do not address the same cache +// entries, so that a bug in one version does not affect the execution +// of other versions. This salt will result in additional ActionID files +// in the cache, but not additional copies of the large output files, +// which are still addressed by unsalted SHA256. +var hashSalt = []byte(runtime.Version()) + +// Subkey returns an action ID corresponding to mixing a parent +// action ID with a string description of the subkey. +func Subkey(parent ActionID, desc string) ActionID { + h := sha256.New() + h.Write([]byte("subkey:")) + h.Write(parent[:]) + h.Write([]byte(desc)) + var out ActionID + h.Sum(out[:0]) + if debugHash { + fmt.Fprintf(os.Stderr, "HASH subkey %x %q = %x\n", parent, desc, out) + } + if verify { + hashDebug.Lock() + hashDebug.m[out] = fmt.Sprintf("subkey %x %q", parent, desc) + hashDebug.Unlock() + } + return out +} + +// NewHash returns a new Hash. +// The caller is expected to Write data to it and then call Sum. +func NewHash(name string) *Hash { + h := &Hash{h: sha256.New(), name: name} + if debugHash { + fmt.Fprintf(os.Stderr, "HASH[%s]\n", h.name) + } + h.Write(hashSalt) + if verify { + h.buf = new(bytes.Buffer) + } + return h +} + +// Write writes data to the running hash. +func (h *Hash) Write(b []byte) (int, error) { + if debugHash { + fmt.Fprintf(os.Stderr, "HASH[%s]: %q\n", h.name, b) + } + if h.buf != nil { + h.buf.Write(b) + } + return h.h.Write(b) +} + +// Sum returns the hash of the data written previously. +func (h *Hash) Sum() [HashSize]byte { + var out [HashSize]byte + h.h.Sum(out[:0]) + if debugHash { + fmt.Fprintf(os.Stderr, "HASH[%s]: %x\n", h.name, out) + } + if h.buf != nil { + hashDebug.Lock() + if hashDebug.m == nil { + hashDebug.m = make(map[[HashSize]byte]string) + } + hashDebug.m[out] = h.buf.String() + hashDebug.Unlock() + } + return out +} + +// In GODEBUG=gocacheverify=1 mode, +// hashDebug holds the input to every computed hash ID, +// so that we can work backward from the ID involved in a +// cache entry mismatch to a description of what should be there. +var hashDebug struct { + sync.Mutex + m map[[HashSize]byte]string +} + +// reverseHash returns the input used to compute the hash id. +func reverseHash(id [HashSize]byte) string { + hashDebug.Lock() + s := hashDebug.m[id] + hashDebug.Unlock() + return s +} + +var hashFileCache struct { + sync.Mutex + m map[string][HashSize]byte +} + +// FileHash returns the hash of the named file. +// It caches repeated lookups for a given file, +// and the cache entry for a file can be initialized +// using SetFileHash. +// The hash used by FileHash is not the same as +// the hash used by NewHash. +func FileHash(file string) ([HashSize]byte, error) { + hashFileCache.Lock() + out, ok := hashFileCache.m[file] + hashFileCache.Unlock() + + if ok { + return out, nil + } + + h := sha256.New() + f, err := os.Open(file) + if err != nil { + if debugHash { + fmt.Fprintf(os.Stderr, "HASH %s: %v\n", file, err) + } + return [HashSize]byte{}, err + } + _, err = io.Copy(h, f) + f.Close() + if err != nil { + if debugHash { + fmt.Fprintf(os.Stderr, "HASH %s: %v\n", file, err) + } + return [HashSize]byte{}, err + } + h.Sum(out[:0]) + if debugHash { + fmt.Fprintf(os.Stderr, "HASH %s: %x\n", file, out) + } + + SetFileHash(file, out) + return out, nil +} + +// SetFileHash sets the hash returned by FileHash for file. +func SetFileHash(file string, sum [HashSize]byte) { + hashFileCache.Lock() + if hashFileCache.m == nil { + hashFileCache.m = make(map[string][HashSize]byte) + } + hashFileCache.m[file] = sum + hashFileCache.Unlock() +} diff --git a/src/cmd/go/internal/cache/hash_test.go b/src/cmd/go/internal/cache/hash_test.go new file mode 100644 index 0000000..a035677 --- /dev/null +++ b/src/cmd/go/internal/cache/hash_test.go @@ -0,0 +1,51 @@ +// 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 cache + +import ( + "fmt" + "os" + "testing" +) + +func TestHash(t *testing.T) { + oldSalt := hashSalt + hashSalt = nil + defer func() { + hashSalt = oldSalt + }() + + h := NewHash("alice") + h.Write([]byte("hello world")) + sum := fmt.Sprintf("%x", h.Sum()) + want := "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9" + if sum != want { + t.Errorf("hash(hello world) = %v, want %v", sum, want) + } +} + +func TestHashFile(t *testing.T) { + f, err := os.CreateTemp("", "cmd-go-test-") + if err != nil { + t.Fatal(err) + } + name := f.Name() + fmt.Fprintf(f, "hello world") + defer os.Remove(name) + if err := f.Close(); err != nil { + t.Fatal(err) + } + + var h ActionID // make sure hash result is assignable to ActionID + h, err = FileHash(name) + if err != nil { + t.Fatal(err) + } + sum := fmt.Sprintf("%x", h) + want := "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9" + if sum != want { + t.Errorf("hash(hello world) = %v, want %v", sum, want) + } +} diff --git a/src/cmd/go/internal/cfg/cfg.go b/src/cmd/go/internal/cfg/cfg.go new file mode 100644 index 0000000..c48904e --- /dev/null +++ b/src/cmd/go/internal/cfg/cfg.go @@ -0,0 +1,393 @@ +// 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 cfg holds configuration shared by multiple parts +// of the go command. +package cfg + +import ( + "bytes" + "fmt" + "go/build" + "internal/cfg" + "io" + "os" + "path/filepath" + "runtime" + "strings" + "sync" + + "cmd/go/internal/fsys" + + "cmd/internal/objabi" +) + +// These are general "build flags" used by build and other commands. +var ( + BuildA bool // -a flag + BuildBuildmode string // -buildmode flag + BuildContext = defaultContext() + BuildMod string // -mod flag + BuildModExplicit bool // whether -mod was set explicitly + BuildModReason string // reason -mod was set, if set by default + BuildI bool // -i flag + BuildLinkshared bool // -linkshared flag + BuildMSan bool // -msan flag + BuildN bool // -n flag + BuildO string // -o flag + BuildP = runtime.NumCPU() // -p flag + BuildPkgdir string // -pkgdir flag + BuildRace bool // -race flag + BuildToolexec []string // -toolexec flag + BuildToolchainName string + BuildToolchainCompiler func() string + BuildToolchainLinker func() string + BuildTrimpath bool // -trimpath flag + BuildV bool // -v flag + BuildWork bool // -work flag + BuildX bool // -x flag + + ModCacheRW bool // -modcacherw flag + ModFile string // -modfile flag + + Insecure bool // -insecure flag + + CmdName string // "build", "install", "list", "mod tidy", etc. + + DebugActiongraph string // -debug-actiongraph flag (undocumented, unstable) + DebugTrace string // -debug-trace flag +) + +func defaultContext() build.Context { + ctxt := build.Default + ctxt.JoinPath = filepath.Join // back door to say "do not use go command" + + ctxt.GOROOT = findGOROOT() + if runtime.Compiler != "gccgo" { + // Note that we must use runtime.GOOS and runtime.GOARCH here, + // as the tool directory does not move based on environment + // variables. This matches the initialization of ToolDir in + // go/build, except for using ctxt.GOROOT rather than + // runtime.GOROOT. + build.ToolDir = filepath.Join(ctxt.GOROOT, "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH) + } + + ctxt.GOPATH = envOr("GOPATH", ctxt.GOPATH) + + // Override defaults computed in go/build with defaults + // from go environment configuration file, if known. + ctxt.GOOS = envOr("GOOS", ctxt.GOOS) + ctxt.GOARCH = envOr("GOARCH", ctxt.GOARCH) + + // The go/build rule for whether cgo is enabled is: + // 1. If $CGO_ENABLED is set, respect it. + // 2. Otherwise, if this is a cross-compile, disable cgo. + // 3. Otherwise, use built-in default for GOOS/GOARCH. + // Recreate that logic here with the new GOOS/GOARCH setting. + if v := Getenv("CGO_ENABLED"); v == "0" || v == "1" { + ctxt.CgoEnabled = v[0] == '1' + } else if ctxt.GOOS != runtime.GOOS || ctxt.GOARCH != runtime.GOARCH { + ctxt.CgoEnabled = false + } else { + // Use built-in default cgo setting for GOOS/GOARCH. + // Note that ctxt.GOOS/GOARCH are derived from the preference list + // (1) environment, (2) go/env file, (3) runtime constants, + // while go/build.Default.GOOS/GOARCH are derived from the preference list + // (1) environment, (2) runtime constants. + // We know ctxt.GOOS/GOARCH == runtime.GOOS/GOARCH; + // no matter how that happened, go/build.Default will make the + // same decision (either the environment variables are set explicitly + // to match the runtime constants, or else they are unset, in which + // case go/build falls back to the runtime constants), so + // go/build.Default.GOOS/GOARCH == runtime.GOOS/GOARCH. + // So ctxt.CgoEnabled (== go/build.Default.CgoEnabled) is correct + // as is and can be left unmodified. + // Nothing to do here. + } + + ctxt.OpenFile = func(path string) (io.ReadCloser, error) { + return fsys.Open(path) + } + ctxt.ReadDir = fsys.ReadDir + ctxt.IsDir = func(path string) bool { + isDir, err := fsys.IsDir(path) + return err == nil && isDir + } + + return ctxt +} + +func init() { + BuildToolchainCompiler = func() string { return "missing-compiler" } + BuildToolchainLinker = func() string { return "missing-linker" } +} + +// An EnvVar is an environment variable Name=Value. +type EnvVar struct { + Name string + Value string +} + +// OrigEnv is the original environment of the program at startup. +var OrigEnv []string + +// CmdEnv is the new environment for running go tool commands. +// User binaries (during go test or go run) are run with OrigEnv, +// not CmdEnv. +var CmdEnv []EnvVar + +// Global build parameters (used during package load) +var ( + Goarch = BuildContext.GOARCH + Goos = BuildContext.GOOS + + ExeSuffix = exeSuffix() + + // 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 +) + +func exeSuffix() string { + if Goos == "windows" { + return ".exe" + } + return "" +} + +var envCache struct { + once sync.Once + m map[string]string +} + +// EnvFile returns the name of the Go environment configuration file. +func EnvFile() (string, error) { + if file := os.Getenv("GOENV"); file != "" { + if file == "off" { + return "", fmt.Errorf("GOENV=off") + } + return file, nil + } + dir, err := os.UserConfigDir() + if err != nil { + return "", err + } + if dir == "" { + return "", fmt.Errorf("missing user-config dir") + } + return filepath.Join(dir, "go/env"), nil +} + +func initEnvCache() { + envCache.m = make(map[string]string) + file, _ := EnvFile() + if file == "" { + return + } + data, err := os.ReadFile(file) + if err != nil { + return + } + + for len(data) > 0 { + // Get next line. + line := data + i := bytes.IndexByte(data, '\n') + if i >= 0 { + line, data = line[:i], data[i+1:] + } else { + data = nil + } + + i = bytes.IndexByte(line, '=') + if i < 0 || line[0] < 'A' || 'Z' < line[0] { + // Line is missing = (or empty) or a comment or not a valid env name. Ignore. + // (This should not happen, since the file should be maintained almost + // exclusively by "go env -w", but better to silently ignore than to make + // the go command unusable just because somehow the env file has + // gotten corrupted.) + continue + } + key, val := line[:i], line[i+1:] + envCache.m[string(key)] = string(val) + } +} + +// Getenv gets the value for the configuration key. +// It consults the operating system environment +// and then the go/env file. +// If Getenv is called for a key that cannot be set +// in the go/env file (for example GODEBUG), it panics. +// This ensures that CanGetenv is accurate, so that +// 'go env -w' stays in sync with what Getenv can retrieve. +func Getenv(key string) string { + if !CanGetenv(key) { + switch key { + case "CGO_TEST_ALLOW", "CGO_TEST_DISALLOW", "CGO_test_ALLOW", "CGO_test_DISALLOW": + // used by internal/work/security_test.go; allow + default: + panic("internal error: invalid Getenv " + key) + } + } + val := os.Getenv(key) + if val != "" { + return val + } + envCache.once.Do(initEnvCache) + return envCache.m[key] +} + +// CanGetenv reports whether key is a valid go/env configuration key. +func CanGetenv(key string) bool { + return strings.Contains(cfg.KnownEnv, "\t"+key+"\n") +} + +var ( + GOROOT = BuildContext.GOROOT + GOBIN = Getenv("GOBIN") + GOROOTbin = filepath.Join(GOROOT, "bin") + GOROOTpkg = filepath.Join(GOROOT, "pkg") + GOROOTsrc = filepath.Join(GOROOT, "src") + GOROOT_FINAL = findGOROOT_FINAL() + GOMODCACHE = envOr("GOMODCACHE", gopathDir("pkg/mod")) + + // Used in envcmd.MkEnv and build ID computations. + GOARM = envOr("GOARM", fmt.Sprint(objabi.GOARM)) + GO386 = envOr("GO386", objabi.GO386) + GOMIPS = envOr("GOMIPS", objabi.GOMIPS) + GOMIPS64 = envOr("GOMIPS64", objabi.GOMIPS64) + GOPPC64 = envOr("GOPPC64", fmt.Sprintf("%s%d", "power", objabi.GOPPC64)) + GOWASM = envOr("GOWASM", fmt.Sprint(objabi.GOWASM)) + + GOPROXY = envOr("GOPROXY", "https://proxy.golang.org,direct") + GOSUMDB = envOr("GOSUMDB", "sum.golang.org") + GOPRIVATE = Getenv("GOPRIVATE") + GONOPROXY = envOr("GONOPROXY", GOPRIVATE) + GONOSUMDB = envOr("GONOSUMDB", GOPRIVATE) + GOINSECURE = Getenv("GOINSECURE") + GOVCS = Getenv("GOVCS") +) + +var SumdbDir = gopathDir("pkg/sumdb") + +// GetArchEnv returns the name and setting of the +// GOARCH-specific architecture environment variable. +// If the current architecture has no GOARCH-specific variable, +// GetArchEnv returns empty key and value. +func GetArchEnv() (key, val string) { + switch Goarch { + case "arm": + return "GOARM", GOARM + case "386": + return "GO386", GO386 + case "mips", "mipsle": + return "GOMIPS", GOMIPS + case "mips64", "mips64le": + return "GOMIPS64", GOMIPS64 + case "ppc64", "ppc64le": + return "GOPPC64", GOPPC64 + case "wasm": + return "GOWASM", GOWASM + } + return "", "" +} + +// envOr returns Getenv(key) if set, or else def. +func envOr(key, def string) string { + val := Getenv(key) + if val == "" { + val = def + } + return val +} + +// 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 := Getenv("GOROOT"); env != "" { + return filepath.Clean(env) + } + def := filepath.Clean(runtime.GOROOT()) + if runtime.Compiler == "gccgo" { + // gccgo has no real GOROOT, and it certainly doesn't + // depend on the executable's location. + return def + } + exe, err := os.Executable() + if err == nil { + exe, err = filepath.Abs(exe) + if err == nil { + if dir := filepath.Join(exe, "../.."); isGOROOT(dir) { + // If def (runtime.GOROOT()) and dir are the same + // directory, prefer the spelling used in def. + if isSameDir(def, dir) { + return def + } + return dir + } + exe, err = filepath.EvalSymlinks(exe) + if err == nil { + if dir := filepath.Join(exe, "../.."); isGOROOT(dir) { + if isSameDir(def, dir) { + return def + } + return dir + } + } + } + } + return def +} + +func findGOROOT_FINAL() string { + // $GOROOT_FINAL is only for use during make.bash + // so it is not settable using go/env, so we use os.Getenv here. + def := GOROOT + if env := os.Getenv("GOROOT_FINAL"); env != "" { + def = filepath.Clean(env) + } + return def +} + +// isSameDir reports whether dir1 and dir2 are the same directory. +func isSameDir(dir1, dir2 string) bool { + if dir1 == dir2 { + return true + } + info1, err1 := os.Stat(dir1) + info2, err2 := os.Stat(dir2) + return err1 == nil && err2 == nil && os.SameFile(info1, info2) +} + +// isGOROOT reports whether path looks like a GOROOT. +// +// 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 { + return false + } + return stat.IsDir() +} + +func gopathDir(rel string) string { + list := filepath.SplitList(BuildContext.GOPATH) + if len(list) == 0 || list[0] == "" { + return "" + } + return filepath.Join(list[0], rel) +} diff --git a/src/cmd/go/internal/clean/clean.go b/src/cmd/go/internal/clean/clean.go new file mode 100644 index 0000000..b1d40fe --- /dev/null +++ b/src/cmd/go/internal/clean/clean.go @@ -0,0 +1,390 @@ +// 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. + +// Package clean implements the ``go clean'' command. +package clean + +import ( + "context" + "fmt" + "io" + "os" + "path/filepath" + "strconv" + "strings" + "time" + + "cmd/go/internal/base" + "cmd/go/internal/cache" + "cmd/go/internal/cfg" + "cmd/go/internal/load" + "cmd/go/internal/lockedfile" + "cmd/go/internal/modfetch" + "cmd/go/internal/modload" + "cmd/go/internal/work" +) + +var CmdClean = &base.Command{ + UsageLine: "go clean [clean flags] [build flags] [packages]", + Short: "remove object files and cached files", + Long: ` +Clean removes object files from package source directories. +The go command builds most objects in a temporary directory, +so go clean is mainly concerned with object files left by other +tools or by manual invocations of go build. + +If a package argument is given or the -i or -r flag is set, +clean removes the following files from each of the +source directories corresponding to the import paths: + + _obj/ old object directory, left from Makefiles + _test/ old test directory, left from Makefiles + _testmain.go old gotest file, left from Makefiles + test.out old test log, left from Makefiles + build.out old test log, left from Makefiles + *.[568ao] object files, left from Makefiles + + DIR(.exe) from go build + DIR.test(.exe) from go test -c + MAINFILE(.exe) from go build MAINFILE.go + *.so from SWIG + +In the list, DIR represents the final path element of the +directory, and MAINFILE is the base name of any Go source +file in the directory that is not included when building +the package. + +The -i flag causes clean to remove the corresponding installed +archive or binary (what 'go install' would create). + +The -n flag causes clean to print the remove commands it would execute, +but not run them. + +The -r flag causes clean to be applied recursively to all the +dependencies of the packages named by the import paths. + +The -x flag causes clean to print remove commands as it executes them. + +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'. + `, +} + +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 +) + +func init() { + // break init cycle + CmdClean.Run = runClean + + 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 + // mentioned explicitly in the docs but they + // are part of the build flags. + + work.AddBuildFlags(CmdClean, work.DefaultBuildFlags) +} + +func runClean(ctx context.Context, cmd *base.Command, args []string) { + // golang.org/issue/29925: only load packages before cleaning if + // either the flags and arguments explicitly imply a package, + // or no other target (such as a cache) was requested to be cleaned. + cleanPkg := len(args) > 0 || cleanI || cleanR + if (!modload.Enabled() || modload.HasModRoot()) && + !cleanCache && !cleanModcache && !cleanTestcache { + cleanPkg = true + } + + if cleanPkg { + for _, pkg := range load.PackagesAndErrors(ctx, args) { + clean(pkg) + } + } + + var b work.Builder + b.Print = fmt.Print + + if cleanCache { + dir := cache.DefaultDir() + if dir != "off" { + // Remove the cache subdirectories but not the top cache directory. + // The top cache directory may have been created with special permissions + // and not something that we want to remove. Also, we'd like to preserve + // the access log for future analysis, even if the cache is cleared. + subdirs, _ := filepath.Glob(filepath.Join(dir, "[0-9a-f][0-9a-f]")) + printedErrors := false + if len(subdirs) > 0 { + if cfg.BuildN || cfg.BuildX { + b.Showcmd("", "rm -r %s", strings.Join(subdirs, " ")) + } + if !cfg.BuildN { + for _, d := range subdirs { + // Only print the first error - there may be many. + // This also mimics what os.RemoveAll(dir) would do. + if err := os.RemoveAll(d); err != nil && !printedErrors { + printedErrors = true + base.Errorf("go clean -cache: %v", err) + } + } + } + } + + logFile := filepath.Join(dir, "log.txt") + if cfg.BuildN || cfg.BuildX { + b.Showcmd("", "rm -f %s", logFile) + } + if !cfg.BuildN { + if err := os.RemoveAll(logFile); err != nil && !printedErrors { + printedErrors = true + base.Errorf("go clean -cache: %v", err) + } + } + } + } + + if cleanTestcache && !cleanCache { + // Instead of walking through the entire cache looking for test results, + // we write a file to the cache indicating that all test results from before + // right now are to be ignored. + dir := cache.DefaultDir() + if dir != "off" { + f, err := lockedfile.Edit(filepath.Join(dir, "testexpire.txt")) + if err == nil { + now := time.Now().UnixNano() + buf, _ := io.ReadAll(f) + prev, _ := strconv.ParseInt(strings.TrimSpace(string(buf)), 10, 64) + if now > prev { + if err = f.Truncate(0); err == nil { + if _, err = f.Seek(0, 0); err == nil { + _, err = fmt.Fprintf(f, "%d\n", now) + } + } + } + if closeErr := f.Close(); err == nil { + err = closeErr + } + } + if err != nil { + if _, statErr := os.Stat(dir); !os.IsNotExist(statErr) { + base.Errorf("go clean -testcache: %v", err) + } + } + } + } + + if cleanModcache { + if cfg.GOMODCACHE == "" { + base.Fatalf("go clean -modcache: no module cache") + } + if cfg.BuildN || cfg.BuildX { + b.Showcmd("", "rm -rf %s", cfg.GOMODCACHE) + } + if !cfg.BuildN { + if err := modfetch.RemoveAll(cfg.GOMODCACHE); err != nil { + base.Errorf("go clean -modcache: %v", err) + } + } + } +} + +var cleaned = map[*load.Package]bool{} + +// TODO: These are dregs left by Makefile-based builds. +// Eventually, can stop deleting these. +var cleanDir = map[string]bool{ + "_test": true, + "_obj": true, +} + +var cleanFile = map[string]bool{ + "_testmain.go": true, + "test.out": true, + "build.out": true, + "a.out": true, +} + +var cleanExt = map[string]bool{ + ".5": true, + ".6": true, + ".8": true, + ".a": true, + ".o": true, + ".so": true, +} + +func clean(p *load.Package) { + if cleaned[p] { + return + } + cleaned[p] = true + + if p.Dir == "" { + base.Errorf("%v", p.Error) + return + } + dirs, err := os.ReadDir(p.Dir) + if err != nil { + base.Errorf("go clean %s: %v", p.Dir, err) + return + } + + var b work.Builder + b.Print = fmt.Print + + packageFile := map[string]bool{} + if p.Name != "main" { + // Record which files are not in package main. + // The others are. + keep := func(list []string) { + for _, f := range list { + packageFile[f] = true + } + } + keep(p.GoFiles) + keep(p.CgoFiles) + keep(p.TestGoFiles) + keep(p.XTestGoFiles) + } + + _, elem := filepath.Split(p.Dir) + var allRemove []string + + // Remove dir-named executable only if this is package main. + if p.Name == "main" { + allRemove = append(allRemove, + elem, + elem+".exe", + p.DefaultExecName(), + p.DefaultExecName()+".exe", + ) + } + + // Remove package test executables. + allRemove = append(allRemove, + elem+".test", + elem+".test.exe", + p.DefaultExecName()+".test", + p.DefaultExecName()+".test.exe", + ) + + // Remove a potential executable, test executable for each .go file in the directory that + // is not part of the directory's package. + for _, dir := range dirs { + name := dir.Name() + if packageFile[name] { + continue + } + + if dir.IsDir() { + continue + } + + if strings.HasSuffix(name, "_test.go") { + base := name[:len(name)-len("_test.go")] + allRemove = append(allRemove, base+".test", base+".test.exe") + } + + if strings.HasSuffix(name, ".go") { + // TODO(adg,rsc): check that this .go file is actually + // in "package main", and therefore capable of building + // to an executable file. + base := name[:len(name)-len(".go")] + allRemove = append(allRemove, base, base+".exe") + } + } + + if cfg.BuildN || cfg.BuildX { + b.Showcmd(p.Dir, "rm -f %s", strings.Join(allRemove, " ")) + } + + toRemove := map[string]bool{} + for _, name := range allRemove { + toRemove[name] = true + } + for _, dir := range dirs { + name := dir.Name() + if dir.IsDir() { + // TODO: Remove once Makefiles are forgotten. + if cleanDir[name] { + if cfg.BuildN || cfg.BuildX { + b.Showcmd(p.Dir, "rm -r %s", name) + if cfg.BuildN { + continue + } + } + if err := os.RemoveAll(filepath.Join(p.Dir, name)); err != nil { + base.Errorf("go clean: %v", err) + } + } + continue + } + + if cfg.BuildN { + continue + } + + if cleanFile[name] || cleanExt[filepath.Ext(name)] || toRemove[name] { + removeFile(filepath.Join(p.Dir, name)) + } + } + + if cleanI && p.Target != "" { + if cfg.BuildN || cfg.BuildX { + b.Showcmd("", "rm -f %s", p.Target) + } + if !cfg.BuildN { + removeFile(p.Target) + } + } + + if cleanR { + for _, p1 := range p.Internal.Imports { + clean(p1) + } + } +} + +// removeFile tries to remove file f, if error other than file doesn't exist +// occurs, it will report the error. +func removeFile(f string) { + err := os.Remove(f) + if err == nil || os.IsNotExist(err) { + return + } + // Windows does not allow deletion of a binary file while it is executing. + if base.ToolIsWindows { + // Remove lingering ~ file from last attempt. + if _, err2 := os.Stat(f + "~"); err2 == nil { + os.Remove(f + "~") + } + // Try to move it out of the way. If the move fails, + // which is likely, we'll try again the + // next time we do an install of this binary. + if err2 := os.Rename(f, f+"~"); err2 == nil { + os.Remove(f + "~") + return + } + } + base.Errorf("go clean: %v", err) +} diff --git a/src/cmd/go/internal/cmdflag/flag.go b/src/cmd/go/internal/cmdflag/flag.go new file mode 100644 index 0000000..8abb7e5 --- /dev/null +++ b/src/cmd/go/internal/cmdflag/flag.go @@ -0,0 +1,129 @@ +// 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 cmdflag handles flag processing common to several go tools. +package cmdflag + +import ( + "errors" + "flag" + "fmt" + "strings" +) + +// The flag handling part of go commands such as test is large and distracting. +// We can't use the standard flag package because some of the flags from +// our command line are for us, and some are for the binary we're running, +// and some are for both. + +// ErrFlagTerminator indicates the distinguished token "--", which causes the +// flag package to treat all subsequent arguments as non-flags. +var ErrFlagTerminator = errors.New("flag terminator") + +// A FlagNotDefinedError indicates a flag-like argument that does not correspond +// to any registered flag in a FlagSet. +type FlagNotDefinedError struct { + RawArg string // the original argument, like --foo or -foo=value + Name string + HasValue bool // is this the -foo=value or --foo=value form? + Value string // only provided if HasValue is true +} + +func (e FlagNotDefinedError) Error() string { + return fmt.Sprintf("flag provided but not defined: -%s", e.Name) +} + +// A NonFlagError indicates an argument that is not a syntactically-valid flag. +type NonFlagError struct { + RawArg string +} + +func (e NonFlagError) Error() string { + return fmt.Sprintf("not a flag: %q", e.RawArg) +} + +// ParseOne sees if args[0] is present in the given flag set and if so, +// sets its value and returns the flag along with the remaining (unused) arguments. +// +// ParseOne always returns either a non-nil Flag or a non-nil error, +// and always consumes at least one argument (even on error). +// +// Unlike (*flag.FlagSet).Parse, ParseOne does not log its own errors. +func ParseOne(fs *flag.FlagSet, args []string) (f *flag.Flag, remainingArgs []string, err error) { + // This function is loosely derived from (*flag.FlagSet).parseOne. + + raw, args := args[0], args[1:] + arg := raw + if strings.HasPrefix(arg, "--") { + if arg == "--" { + return nil, args, ErrFlagTerminator + } + arg = arg[1:] // reduce two minuses to one + } + + switch arg { + case "-?", "-h", "-help": + return nil, args, flag.ErrHelp + } + if len(arg) < 2 || arg[0] != '-' || arg[1] == '-' || arg[1] == '=' { + return nil, args, NonFlagError{RawArg: raw} + } + + name := arg[1:] + hasValue := false + value := "" + if i := strings.Index(name, "="); i >= 0 { + value = name[i+1:] + hasValue = true + name = name[0:i] + } + + f = fs.Lookup(name) + if f == nil { + return nil, args, FlagNotDefinedError{ + RawArg: raw, + Name: name, + HasValue: hasValue, + Value: value, + } + } + + // Use fs.Set instead of f.Value.Set below so that any subsequent call to + // fs.Visit will correctly visit the flags that have been set. + + failf := func(format string, a ...interface{}) (*flag.Flag, []string, error) { + return f, args, fmt.Errorf(format, a...) + } + + if fv, ok := f.Value.(boolFlag); ok && fv.IsBoolFlag() { // special case: doesn't need an arg + if hasValue { + if err := fs.Set(name, value); err != nil { + return failf("invalid boolean value %q for -%s: %v", value, name, err) + } + } else { + if err := fs.Set(name, "true"); err != nil { + return failf("invalid boolean flag %s: %v", name, err) + } + } + } else { + // It must have a value, which might be the next argument. + if !hasValue && len(args) > 0 { + // value is the next arg + hasValue = true + value, args = args[0], args[1:] + } + if !hasValue { + return failf("flag needs an argument: -%s", name) + } + if err := fs.Set(name, value); err != nil { + return failf("invalid value %q for flag -%s: %v", value, name, err) + } + } + + return f, args, nil +} + +type boolFlag interface { + IsBoolFlag() bool +} diff --git a/src/cmd/go/internal/doc/doc.go b/src/cmd/go/internal/doc/doc.go new file mode 100644 index 0000000..67f76e2 --- /dev/null +++ b/src/cmd/go/internal/doc/doc.go @@ -0,0 +1,135 @@ +// Copyright 2015 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 doc implements the ``go doc'' command. +package doc + +import ( + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "context" +) + +var CmdDoc = &base.Command{ + Run: runDoc, + UsageLine: "go doc [-u] [-c] [package|[package.]symbol[.methodOrField]]", + CustomFlags: true, + Short: "show documentation for package or symbol", + Long: ` +Doc prints the documentation comments associated with the item identified by its +arguments (a package, const, func, type, var, method, or struct field) +followed by a one-line summary of each of the first-level items "under" +that item (package-level declarations for a package, methods for a type, +etc.). + +Doc accepts zero, one, or two arguments. + +Given no arguments, that is, when run as + + go doc + +it prints the package documentation for the package in the current directory. +If the package is a command (package main), the exported symbols of the package +are elided from the presentation unless the -cmd flag is provided. + +When run with one argument, the argument is treated as a Go-syntax-like +representation of the item to be documented. What the argument selects depends +on what is installed in GOROOT and GOPATH, as well as the form of the argument, +which is schematically one of these: + + go doc + go doc [.] + go doc [.][.] + go doc [.][.] + +The first item in this list matched by the argument is the one whose documentation +is printed. (See the examples below.) However, if the argument starts with a capital +letter it is assumed to identify a symbol or method in the current directory. + +For packages, the order of scanning is determined lexically in breadth-first order. +That is, the package presented is the one that matches the search and is nearest +the root and lexically first at its level of the hierarchy. The GOROOT tree is +always scanned in its entirety before GOPATH. + +If there is no package specified or matched, the package in the current +directory is selected, so "go doc Foo" shows the documentation for symbol Foo in +the current package. + +The package path must be either a qualified path or a proper suffix of a +path. The go tool's usual package mechanism does not apply: package path +elements like . and ... are not implemented by go doc. + +When run with two arguments, the first must be a full package path (not just a +suffix), and the second is a symbol, or symbol with method or struct field. +This is similar to the syntax accepted by godoc: + + go doc [.] + +In all forms, when matching symbols, lower-case letters in the argument match +either case but upper-case letters match exactly. This means that there may be +multiple matches of a lower-case argument in a package if different symbols have +different cases. If this occurs, documentation for all matches is printed. + +Examples: + go doc + Show documentation for current package. + go doc Foo + Show documentation for Foo in the current package. + (Foo starts with a capital letter so it cannot match + a package path.) + go doc encoding/json + Show documentation for the encoding/json package. + go doc json + Shorthand for encoding/json. + go doc json.Number (or go doc json.number) + Show documentation and method summary for json.Number. + go doc json.Number.Int64 (or go doc json.number.int64) + Show documentation for json.Number's Int64 method. + go doc cmd/doc + Show package docs for the doc command. + go doc -cmd cmd/doc + Show package docs and exported symbols within the doc command. + go doc template.new + Show documentation for html/template's New function. + (html/template is lexically before text/template) + go doc text/template.new # One argument + Show documentation for text/template's New function. + go doc text/template new # Two arguments + Show documentation for text/template's New function. + + At least in the current tree, these invocations all print the + documentation for json.Decoder's Decode method: + + go doc json.Decoder.Decode + go doc json.decoder.decode + go doc json.decode + cd go/src/encoding/json; go doc decode + +Flags: + -all + Show all the documentation for the package. + -c + Respect case when matching symbols. + -cmd + Treat a command (package main) like a regular package. + Otherwise package main's exported symbols are hidden + when showing the package's top-level documentation. + -short + One-line representation for each symbol. + -src + Show the full source code for the symbol. This will + display the full Go source of its declaration and + definition, such as a function definition (including + the body), type declaration or enclosing const + block. The output may therefore include unexported + details. + -u + Show documentation for unexported as well as exported + symbols, methods, and fields. +`, +} + +func runDoc(ctx context.Context, cmd *base.Command, args []string) { + base.Run(cfg.BuildToolexec, base.Tool("doc"), args) +} diff --git a/src/cmd/go/internal/envcmd/env.go b/src/cmd/go/internal/envcmd/env.go new file mode 100644 index 0000000..6937187 --- /dev/null +++ b/src/cmd/go/internal/envcmd/env.go @@ -0,0 +1,537 @@ +// 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. + +// Package envcmd implements the ``go env'' command. +package envcmd + +import ( + "context" + "encoding/json" + "fmt" + "go/build" + "os" + "path/filepath" + "runtime" + "sort" + "strings" + "unicode/utf8" + + "cmd/go/internal/base" + "cmd/go/internal/cache" + "cmd/go/internal/cfg" + "cmd/go/internal/fsys" + "cmd/go/internal/load" + "cmd/go/internal/modload" + "cmd/go/internal/work" +) + +var CmdEnv = &base.Command{ + UsageLine: "go env [-json] [-u] [-w] [var ...]", + Short: "print Go environment information", + Long: ` +Env prints Go environment information. + +By default env prints information as a shell script +(on Windows, a batch file). If one or more variable +names is given as arguments, env prints the value of +each named variable on its own line. + +The -json flag prints the environment in JSON format +instead of as a shell script. + +The -u flag requires one or more arguments and unsets +the default setting for the named environment variables, +if one has been set with 'go env -w'. + +The -w flag requires one or more arguments of the +form NAME=VALUE and changes the default settings +of the named environment variables to the given values. + +For more about environment variables, see 'go help environment'. + `, +} + +func init() { + CmdEnv.Run = runEnv // break init cycle +} + +var ( + envJson = CmdEnv.Flag.Bool("json", false, "") + envU = CmdEnv.Flag.Bool("u", false, "") + envW = CmdEnv.Flag.Bool("w", false, "") +) + +func MkEnv() []cfg.EnvVar { + envFile, _ := cfg.EnvFile() + env := []cfg.EnvVar{ + {Name: "GO111MODULE", Value: cfg.Getenv("GO111MODULE")}, + {Name: "GOARCH", Value: cfg.Goarch}, + {Name: "GOBIN", Value: cfg.GOBIN}, + {Name: "GOCACHE", Value: cache.DefaultDir()}, + {Name: "GOENV", Value: envFile}, + {Name: "GOEXE", Value: cfg.ExeSuffix}, + {Name: "GOFLAGS", Value: cfg.Getenv("GOFLAGS")}, + {Name: "GOHOSTARCH", Value: runtime.GOARCH}, + {Name: "GOHOSTOS", Value: runtime.GOOS}, + {Name: "GOINSECURE", Value: cfg.GOINSECURE}, + {Name: "GOMODCACHE", Value: cfg.GOMODCACHE}, + {Name: "GONOPROXY", Value: cfg.GONOPROXY}, + {Name: "GONOSUMDB", Value: cfg.GONOSUMDB}, + {Name: "GOOS", Value: cfg.Goos}, + {Name: "GOPATH", Value: cfg.BuildContext.GOPATH}, + {Name: "GOPRIVATE", Value: cfg.GOPRIVATE}, + {Name: "GOPROXY", Value: cfg.GOPROXY}, + {Name: "GOROOT", Value: cfg.GOROOT}, + {Name: "GOSUMDB", Value: cfg.GOSUMDB}, + {Name: "GOTMPDIR", Value: cfg.Getenv("GOTMPDIR")}, + {Name: "GOTOOLDIR", Value: base.ToolDir}, + {Name: "GOVCS", Value: cfg.GOVCS}, + {Name: "GOVERSION", Value: runtime.Version()}, + } + + if work.GccgoBin != "" { + env = append(env, cfg.EnvVar{Name: "GCCGO", Value: work.GccgoBin}) + } else { + env = append(env, cfg.EnvVar{Name: "GCCGO", Value: work.GccgoName}) + } + + key, val := cfg.GetArchEnv() + if key != "" { + env = append(env, cfg.EnvVar{Name: key, Value: val}) + } + + cc := cfg.DefaultCC(cfg.Goos, cfg.Goarch) + if env := strings.Fields(cfg.Getenv("CC")); len(env) > 0 { + cc = env[0] + } + cxx := cfg.DefaultCXX(cfg.Goos, cfg.Goarch) + if env := strings.Fields(cfg.Getenv("CXX")); len(env) > 0 { + cxx = env[0] + } + env = append(env, cfg.EnvVar{Name: "AR", Value: envOr("AR", "ar")}) + env = append(env, cfg.EnvVar{Name: "CC", Value: cc}) + env = append(env, cfg.EnvVar{Name: "CXX", Value: cxx}) + + if cfg.BuildContext.CgoEnabled { + env = append(env, cfg.EnvVar{Name: "CGO_ENABLED", Value: "1"}) + } else { + env = append(env, cfg.EnvVar{Name: "CGO_ENABLED", Value: "0"}) + } + + return env +} + +func envOr(name, def string) string { + val := cfg.Getenv(name) + if val != "" { + return val + } + return def +} + +func findEnv(env []cfg.EnvVar, name string) string { + for _, e := range env { + if e.Name == name { + return e.Value + } + } + return "" +} + +// ExtraEnvVars returns environment variables that should not leak into child processes. +func ExtraEnvVars() []cfg.EnvVar { + gomod := "" + if modload.HasModRoot() { + gomod = filepath.Join(modload.ModRoot(), "go.mod") + } else if modload.Enabled() { + gomod = os.DevNull + } + 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{}) + if err != nil { + // Should not happen - b.CFlags was given an empty package. + fmt.Fprintf(os.Stderr, "go: invalid cflags: %v\n", err) + 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, " ")}, + {Name: "CGO_CPPFLAGS", Value: strings.Join(cppflags, " ")}, + {Name: "CGO_CXXFLAGS", Value: strings.Join(cxxflags, " ")}, + {Name: "CGO_FFLAGS", Value: strings.Join(fflags, " ")}, + {Name: "CGO_LDFLAGS", Value: strings.Join(ldflags, " ")}, + {Name: "PKG_CONFIG", Value: b.PkgconfigCmd()}, + {Name: "GOGCCFLAGS", Value: strings.Join(cmd[3:], " ")}, + } +} + +// argKey returns the KEY part of the arg KEY=VAL, or else arg itself. +func argKey(arg string) string { + i := strings.Index(arg, "=") + if i < 0 { + return arg + } + return arg[:i] +} + +func runEnv(ctx context.Context, cmd *base.Command, args []string) { + if *envJson && *envU { + base.Fatalf("go env: cannot use -json with -u") + } + if *envJson && *envW { + base.Fatalf("go env: cannot use -json with -w") + } + if *envU && *envW { + base.Fatalf("go env: cannot use -u with -w") + } + env := cfg.CmdEnv + env = append(env, ExtraEnvVars()...) + + if err := fsys.Init(base.Cwd); err != nil { + base.Fatalf("go: %v", err) + } + + // Do we need to call ExtraEnvVarsCostly, which is a bit expensive? + needCostly := false + if *envU || *envW { + // We're overwriting or removing default settings, + // so it doesn't really matter what the existing settings are. + // + // Moreover, we haven't validated the new settings yet, so it is + // important that we NOT perform any actions based on them, + // such as initializing the builder to compute other variables. + } else if len(args) == 0 { + // We're listing all environment variables ("go env"), + // including the expensive ones. + needCostly = true + } else { + needCostly = false + checkCostly: + for _, arg := range args { + switch argKey(arg) { + case "CGO_CFLAGS", + "CGO_CPPFLAGS", + "CGO_CXXFLAGS", + "CGO_FFLAGS", + "CGO_LDFLAGS", + "PKG_CONFIG", + "GOGCCFLAGS": + needCostly = true + break checkCostly + } + } + } + if needCostly { + env = append(env, ExtraEnvVarsCostly()...) + } + + if *envW { + // Process and sanity-check command line. + if len(args) == 0 { + base.Fatalf("go env -w: no KEY=VALUE arguments given") + } + osEnv := make(map[string]string) + for _, e := range cfg.OrigEnv { + if i := strings.Index(e, "="); i >= 0 { + osEnv[e[:i]] = e[i+1:] + } + } + add := make(map[string]string) + for _, arg := range args { + i := strings.Index(arg, "=") + if i < 0 { + base.Fatalf("go env -w: arguments must be KEY=VALUE: invalid argument: %s", arg) + } + key, val := arg[:i], arg[i+1:] + if err := checkEnvWrite(key, val); err != nil { + base.Fatalf("go env -w: %v", err) + } + if _, ok := add[key]; ok { + base.Fatalf("go env -w: multiple values for key: %s", key) + } + add[key] = val + if osVal := osEnv[key]; osVal != "" && osVal != val { + fmt.Fprintf(os.Stderr, "warning: go env -w %s=... does not override conflicting OS environment variable\n", key) + } + } + + goos, okGOOS := add["GOOS"] + goarch, okGOARCH := add["GOARCH"] + if okGOOS || okGOARCH { + if !okGOOS { + goos = cfg.Goos + } + if !okGOARCH { + goarch = cfg.Goarch + } + if err := work.CheckGOOSARCHPair(goos, goarch); err != nil { + base.Fatalf("go env -w: %v", err) + } + } + + gotmp, okGOTMP := add["GOTMPDIR"] + if okGOTMP { + if !filepath.IsAbs(gotmp) && gotmp != "" { + base.Fatalf("go env -w: GOTMPDIR must be an absolute path") + } + } + + updateEnvFile(add, nil) + return + } + + if *envU { + // Process and sanity-check command line. + if len(args) == 0 { + base.Fatalf("go env -u: no arguments given") + } + del := make(map[string]bool) + for _, arg := range args { + if err := checkEnvWrite(arg, ""); err != nil { + base.Fatalf("go env -u: %v", err) + } + del[arg] = true + } + if del["GOOS"] || del["GOARCH"] { + goos, goarch := cfg.Goos, cfg.Goarch + if del["GOOS"] { + goos = getOrigEnv("GOOS") + if goos == "" { + goos = build.Default.GOOS + } + } + if del["GOARCH"] { + goarch = getOrigEnv("GOARCH") + if goarch == "" { + goarch = build.Default.GOARCH + } + } + if err := work.CheckGOOSARCHPair(goos, goarch); err != nil { + base.Fatalf("go env -u: %v", err) + } + } + updateEnvFile(nil, del) + return + } + + if len(args) > 0 { + if *envJson { + var es []cfg.EnvVar + for _, name := range args { + e := cfg.EnvVar{Name: name, Value: findEnv(env, name)} + es = append(es, e) + } + printEnvAsJSON(es) + } else { + for _, name := range args { + fmt.Printf("%s\n", findEnv(env, name)) + } + } + return + } + + if *envJson { + printEnvAsJSON(env) + return + } + + for _, e := range env { + if e.Name != "TERM" { + switch runtime.GOOS { + default: + fmt.Printf("%s=\"%s\"\n", e.Name, e.Value) + case "plan9": + if strings.IndexByte(e.Value, '\x00') < 0 { + fmt.Printf("%s='%s'\n", e.Name, strings.ReplaceAll(e.Value, "'", "''")) + } else { + v := strings.Split(e.Value, "\x00") + fmt.Printf("%s=(", e.Name) + for x, s := range v { + if x > 0 { + fmt.Printf(" ") + } + fmt.Printf("%s", s) + } + fmt.Printf(")\n") + } + case "windows": + fmt.Printf("set %s=%s\n", e.Name, e.Value) + } + } + } +} + +func printEnvAsJSON(env []cfg.EnvVar) { + m := make(map[string]string) + for _, e := range env { + if e.Name == "TERM" { + continue + } + m[e.Name] = e.Value + } + enc := json.NewEncoder(os.Stdout) + enc.SetIndent("", "\t") + if err := enc.Encode(m); err != nil { + base.Fatalf("go env -json: %s", err) + } +} + +func getOrigEnv(key string) string { + for _, v := range cfg.OrigEnv { + if strings.HasPrefix(v, key+"=") { + return strings.TrimPrefix(v, key+"=") + } + } + return "" +} + +func checkEnvWrite(key, val string) error { + switch key { + case "GOEXE", "GOGCCFLAGS", "GOHOSTARCH", "GOHOSTOS", "GOMOD", "GOTOOLDIR", "GOVERSION": + return fmt.Errorf("%s cannot be modified", key) + case "GOENV": + return fmt.Errorf("%s can only be set using the OS environment", key) + } + + // To catch typos and the like, check that we know the variable. + if !cfg.CanGetenv(key) { + return fmt.Errorf("unknown go command variable %s", key) + } + + // Some variables can only have one of a few valid values. If set to an + // invalid value, the next cmd/go invocation might fail immediately, + // even 'go env -w' itself. + switch key { + case "GO111MODULE": + switch val { + case "", "auto", "on", "off": + default: + return fmt.Errorf("invalid %s value %q", key, val) + } + case "GOPATH": + if strings.HasPrefix(val, "~") { + return fmt.Errorf("GOPATH entry cannot start with shell metacharacter '~': %q", val) + } + if !filepath.IsAbs(val) && val != "" { + return fmt.Errorf("GOPATH entry is relative; must be absolute path: %q", val) + } + // Make sure CC and CXX are absolute paths + case "CC", "CXX": + if !filepath.IsAbs(val) && val != "" && val != filepath.Base(val) { + return fmt.Errorf("%s entry is relative; must be absolute path: %q", key, val) + } + } + + if !utf8.ValidString(val) { + return fmt.Errorf("invalid UTF-8 in %s=... value", key) + } + if strings.Contains(val, "\x00") { + return fmt.Errorf("invalid NUL in %s=... value", key) + } + if strings.ContainsAny(val, "\v\r\n") { + return fmt.Errorf("invalid newline in %s=... value", key) + } + return nil +} + +func updateEnvFile(add map[string]string, del map[string]bool) { + file, err := cfg.EnvFile() + if file == "" { + base.Fatalf("go env: cannot find go env config: %v", err) + } + data, err := os.ReadFile(file) + if err != nil && (!os.IsNotExist(err) || len(add) == 0) { + base.Fatalf("go env: reading go env config: %v", err) + } + + lines := strings.SplitAfter(string(data), "\n") + if lines[len(lines)-1] == "" { + lines = lines[:len(lines)-1] + } else { + lines[len(lines)-1] += "\n" + } + + // Delete all but last copy of any duplicated variables, + // since the last copy is the one that takes effect. + prev := make(map[string]int) + for l, line := range lines { + if key := lineToKey(line); key != "" { + if p, ok := prev[key]; ok { + lines[p] = "" + } + prev[key] = l + } + } + + // Add variables (go env -w). Update existing lines in file if present, add to end otherwise. + for key, val := range add { + if p, ok := prev[key]; ok { + lines[p] = key + "=" + val + "\n" + delete(add, key) + } + } + for key, val := range add { + lines = append(lines, key+"="+val+"\n") + } + + // Delete requested variables (go env -u). + for key := range del { + if p, ok := prev[key]; ok { + lines[p] = "" + } + } + + // Sort runs of KEY=VALUE lines + // (that is, blocks of lines where blocks are separated + // by comments, blank lines, or invalid lines). + start := 0 + for i := 0; i <= len(lines); i++ { + if i == len(lines) || lineToKey(lines[i]) == "" { + sortKeyValues(lines[start:i]) + start = i + 1 + } + } + + data = []byte(strings.Join(lines, "")) + err = os.WriteFile(file, data, 0666) + if err != nil { + // Try creating directory. + os.MkdirAll(filepath.Dir(file), 0777) + err = os.WriteFile(file, data, 0666) + if err != nil { + base.Fatalf("go env: writing go env config: %v", err) + } + } +} + +// lineToKey returns the KEY part of the line KEY=VALUE or else an empty string. +func lineToKey(line string) string { + i := strings.Index(line, "=") + if i < 0 || strings.Contains(line[:i], "#") { + return "" + } + return line[:i] +} + +// sortKeyValues sorts a sequence of lines by key. +// It differs from sort.Strings in that keys which are GOx where x is an ASCII +// character smaller than = sort after GO=. +// (There are no such keys currently. It used to matter for GO386 which was +// removed in Go 1.16.) +func sortKeyValues(lines []string) { + sort.Slice(lines, func(i, j int) bool { + return lineToKey(lines[i]) < lineToKey(lines[j]) + }) +} diff --git a/src/cmd/go/internal/fix/fix.go b/src/cmd/go/internal/fix/fix.go new file mode 100644 index 0000000..c7588c6 --- /dev/null +++ b/src/cmd/go/internal/fix/fix.go @@ -0,0 +1,63 @@ +// Copyright 2011 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 fix implements the ``go fix'' command. +package fix + +import ( + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/load" + "cmd/go/internal/modload" + "cmd/go/internal/str" + "context" + "fmt" + "os" +) + +var CmdFix = &base.Command{ + Run: runFix, + 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. + +For more about fix, see 'go doc cmd/fix'. +For more about specifying packages, see 'go help packages'. + +To run fix with specific options, run 'go tool fix'. + +See also: go fmt, go vet. + `, +} + +func runFix(ctx context.Context, cmd *base.Command, args []string) { + pkgs := load.PackagesAndErrors(ctx, args) + w := 0 + for _, pkg := range pkgs { + if pkg.Error != nil { + base.Errorf("%v", pkg.Error) + continue + } + pkgs[w] = pkg + w++ + } + pkgs = pkgs[:w] + + printed := false + for _, pkg := range pkgs { + if modload.Enabled() && pkg.Module != nil && !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. + files := base.RelPaths(pkg.InternalAllGoFiles()) + base.Run(str.StringList(cfg.BuildToolexec, base.Tool("fix"), files)) + } +} diff --git a/src/cmd/go/internal/fmtcmd/fmt.go b/src/cmd/go/internal/fmtcmd/fmt.go new file mode 100644 index 0000000..6b98f0c --- /dev/null +++ b/src/cmd/go/internal/fmtcmd/fmt.go @@ -0,0 +1,117 @@ +// Copyright 2011 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 fmtcmd implements the ``go fmt'' command. +package fmtcmd + +import ( + "context" + "errors" + "fmt" + "os" + "path/filepath" + "runtime" + "sync" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/load" + "cmd/go/internal/modload" + "cmd/go/internal/str" +) + +func init() { + base.AddBuildFlagsNX(&CmdFmt.Flag) + base.AddModFlag(&CmdFmt.Flag) + base.AddModCommonFlags(&CmdFmt.Flag) +} + +var CmdFmt = &base.Command{ + Run: runFmt, + UsageLine: "go fmt [-n] [-x] [packages]", + Short: "gofmt (reformat) package sources", + Long: ` +Fmt runs the command 'gofmt -l -w' on the packages named +by the import paths. It prints the names of the files that are modified. + +For more about gofmt, see 'go doc cmd/gofmt'. +For more about specifying packages, see 'go help packages'. + +The -n flag prints commands that would be executed. +The -x flag prints commands as they are executed. + +The -mod flag's value sets which module download mode +to use: readonly or vendor. See 'go help modules' for more. + +To run gofmt with specific options, run gofmt itself. + +See also: go fix, go vet. + `, +} + +func runFmt(ctx context.Context, cmd *base.Command, args []string) { + printed := false + gofmt := gofmtPath() + procs := runtime.GOMAXPROCS(0) + var wg sync.WaitGroup + wg.Add(procs) + fileC := make(chan string, 2*procs) + for i := 0; i < procs; i++ { + go func() { + defer wg.Done() + for file := range fileC { + base.Run(str.StringList(gofmt, "-l", "-w", file)) + } + }() + } + for _, pkg := range load.PackagesAndErrors(ctx, 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 { + var nogo *load.NoGoError + var embed *load.EmbedError + if (errors.As(pkg.Error, &nogo) || errors.As(pkg.Error, &embed)) && len(pkg.InternalAllGoFiles()) > 0 { + // Skip this error, as we will format + // all files regardless. + } else { + base.Errorf("%v", pkg.Error) + continue + } + } + // Use pkg.gofiles instead of pkg.Dir so that + // the command only applies to this package, + // not to packages in subdirectories. + files := base.RelPaths(pkg.InternalAllGoFiles()) + for _, file := range files { + fileC <- file + } + } + close(fileC) + wg.Wait() +} + +func gofmtPath() string { + gofmt := "gofmt" + if base.ToolIsWindows { + gofmt += base.ToolWindowsExtension + } + + gofmtPath := filepath.Join(cfg.GOBIN, gofmt) + if _, err := os.Stat(gofmtPath); err == nil { + return gofmtPath + } + + gofmtPath = filepath.Join(cfg.GOROOT, "bin", gofmt) + if _, err := os.Stat(gofmtPath); err == nil { + return gofmtPath + } + + // fallback to looking for gofmt in $PATH + return "gofmt" +} diff --git a/src/cmd/go/internal/fsys/fsys.go b/src/cmd/go/internal/fsys/fsys.go new file mode 100644 index 0000000..7b06c3c --- /dev/null +++ b/src/cmd/go/internal/fsys/fsys.go @@ -0,0 +1,689 @@ +// Package fsys is an abstraction for reading files that +// allows for virtual overlays on top of the files on disk. +package fsys + +import ( + "encoding/json" + "errors" + "fmt" + "io/fs" + "io/ioutil" + "os" + "path/filepath" + "runtime" + "sort" + "strings" + "time" +) + +// OverlayFile is the path to a text file in the OverlayJSON format. +// It is the value of the -overlay flag. +var OverlayFile string + +// OverlayJSON is the format overlay files are expected to be in. +// The Replace map maps from overlaid paths to replacement paths: +// the Go command will forward all reads trying to open +// each overlaid path to its replacement path, or consider the overlaid +// path not to exist if the replacement path is empty. +type OverlayJSON struct { + Replace map[string]string +} + +type node struct { + actualFilePath string // empty if a directory + children map[string]*node // path element → file or directory +} + +func (n *node) isDir() bool { + return n.actualFilePath == "" && n.children != nil +} + +func (n *node) isDeleted() bool { + return n.actualFilePath == "" && n.children == nil +} + +// TODO(matloob): encapsulate these in an io/fs-like interface +var overlay map[string]*node // path -> file or directory node +var cwd string // copy of base.Cwd to avoid dependency + +// Canonicalize a path for looking it up in the overlay. +// Important: filepath.Join(cwd, path) doesn't always produce +// the correct absolute path if path is relative, because on +// Windows producing the correct absolute path requires making +// a syscall. So this should only be used when looking up paths +// in the overlay, or canonicalizing the paths in the overlay. +func canonicalize(path string) string { + if path == "" { + return "" + } + if filepath.IsAbs(path) { + return filepath.Clean(path) + } + + if v := filepath.VolumeName(cwd); v != "" && path[0] == filepath.Separator { + // On Windows filepath.Join(cwd, path) doesn't always work. In general + // filepath.Abs needs to make a syscall on Windows. Elsewhere in cmd/go + // use filepath.Join(cwd, path), but cmd/go specifically supports Windows + // paths that start with "\" which implies the path is relative to the + // volume of the working directory. See golang.org/issue/8130. + return filepath.Join(v, path) + } + + // Make the path absolute. + return filepath.Join(cwd, path) +} + +// Init initializes the overlay, if one is being used. +func Init(wd string) error { + if overlay != nil { + // already initialized + return nil + } + + cwd = wd + + if OverlayFile == "" { + return nil + } + + b, err := os.ReadFile(OverlayFile) + if err != nil { + return fmt.Errorf("reading overlay file: %v", err) + } + + var overlayJSON OverlayJSON + if err := json.Unmarshal(b, &overlayJSON); err != nil { + return fmt.Errorf("parsing overlay JSON: %v", err) + } + + return initFromJSON(overlayJSON) +} + +func initFromJSON(overlayJSON OverlayJSON) error { + // Canonicalize the paths in in the overlay map. + // Use reverseCanonicalized to check for collisions: + // no two 'from' paths should canonicalize to the same path. + overlay = make(map[string]*node) + reverseCanonicalized := make(map[string]string) // inverse of canonicalize operation, to check for duplicates + // Build a table of file and directory nodes from the replacement map. + + // Remove any potential non-determinism from iterating over map by sorting it. + replaceFrom := make([]string, 0, len(overlayJSON.Replace)) + for k := range overlayJSON.Replace { + replaceFrom = append(replaceFrom, k) + } + sort.Strings(replaceFrom) + + for _, from := range replaceFrom { + to := overlayJSON.Replace[from] + // Canonicalize paths and check for a collision. + if from == "" { + return fmt.Errorf("empty string key in overlay file Replace map") + } + cfrom := canonicalize(from) + if to != "" { + // Don't canonicalize "", meaning to delete a file, because then it will turn into ".". + to = canonicalize(to) + } + if otherFrom, seen := reverseCanonicalized[cfrom]; seen { + return fmt.Errorf( + "paths %q and %q both canonicalize to %q in overlay file Replace map", otherFrom, from, cfrom) + } + reverseCanonicalized[cfrom] = from + from = cfrom + + // Create node for overlaid file. + dir, base := filepath.Dir(from), filepath.Base(from) + if n, ok := overlay[from]; ok { + // All 'from' paths in the overlay are file paths. Since the from paths + // are in a map, they are unique, so if the node already exists we added + // it below when we create parent directory nodes. That is, that + // both a file and a path to one of its parent directories exist as keys + // in the Replace map. + // + // This only applies if the overlay directory has any files or directories + // in it: placeholder directories that only contain deleted files don't + // count. They are safe to be overwritten with actual files. + for _, f := range n.children { + if !f.isDeleted() { + return fmt.Errorf("invalid overlay: path %v is used as both file and directory", from) + } + } + } + overlay[from] = &node{actualFilePath: to} + + // Add parent directory nodes to overlay structure. + childNode := overlay[from] + for { + dirNode := overlay[dir] + if dirNode == nil || dirNode.isDeleted() { + dirNode = &node{children: make(map[string]*node)} + overlay[dir] = dirNode + } + if childNode.isDeleted() { + // Only create one parent for a deleted file: + // the directory only conditionally exists if + // there are any non-deleted children, so + // we don't create their parents. + if dirNode.isDir() { + dirNode.children[base] = childNode + } + break + } + if !dirNode.isDir() { + // This path already exists as a file, so it can't be a parent + // directory. See comment at error above. + return fmt.Errorf("invalid overlay: path %v is used as both file and directory", dir) + } + dirNode.children[base] = childNode + parent := filepath.Dir(dir) + if parent == dir { + break // reached the top; there is no parent + } + dir, base = parent, filepath.Base(dir) + childNode = dirNode + } + } + + return nil +} + +// IsDir returns true if path is a directory on disk or in the +// overlay. +func IsDir(path string) (bool, error) { + path = canonicalize(path) + + if _, ok := parentIsOverlayFile(path); ok { + return false, nil + } + + if n, ok := overlay[path]; ok { + return n.isDir(), nil + } + + fi, err := os.Stat(path) + if err != nil { + return false, err + } + + return fi.IsDir(), nil +} + +// parentIsOverlayFile returns whether name or any of +// its parents are files in the overlay, and the first parent found, +// including name itself, that's a file in the overlay. +func parentIsOverlayFile(name string) (string, bool) { + if overlay != nil { + // Check if name can't possibly be a directory because + // it or one of its parents is overlaid with a file. + // TODO(matloob): Maybe save this to avoid doing it every time? + prefix := name + for { + node := overlay[prefix] + if node != nil && !node.isDir() { + return prefix, true + } + parent := filepath.Dir(prefix) + if parent == prefix { + break + } + prefix = parent + } + } + + return "", false +} + +// errNotDir is used to communicate from ReadDir to IsDirWithGoFiles +// that the argument is not a directory, so that IsDirWithGoFiles doesn't +// return an error. +var errNotDir = errors.New("not a directory") + +// readDir reads a dir on disk, returning an error that is errNotDir if the dir is not a directory. +// Unfortunately, the error returned by ioutil.ReadDir if dir is not a directory +// can vary depending on the OS (Linux, Mac, Windows return ENOTDIR; BSD returns EINVAL). +func readDir(dir string) ([]fs.FileInfo, error) { + fis, err := ioutil.ReadDir(dir) + if err == nil { + return fis, nil + } + + if os.IsNotExist(err) { + return nil, err + } + if dirfi, staterr := os.Stat(dir); staterr == nil && !dirfi.IsDir() { + return nil, &fs.PathError{Op: "ReadDir", Path: dir, Err: errNotDir} + } + return nil, err +} + +// ReadDir provides a slice of fs.FileInfo entries corresponding +// to the overlaid files in the directory. +func ReadDir(dir string) ([]fs.FileInfo, error) { + dir = canonicalize(dir) + if _, ok := parentIsOverlayFile(dir); ok { + return nil, &fs.PathError{Op: "ReadDir", Path: dir, Err: errNotDir} + } + + dirNode := overlay[dir] + if dirNode == nil { + return readDir(dir) + } + if dirNode.isDeleted() { + return nil, &fs.PathError{Op: "ReadDir", Path: dir, Err: fs.ErrNotExist} + } + diskfis, err := readDir(dir) + if err != nil && !os.IsNotExist(err) && !errors.Is(err, errNotDir) { + return nil, err + } + + // Stat files in overlay to make composite list of fileinfos + files := make(map[string]fs.FileInfo) + for _, f := range diskfis { + files[f.Name()] = f + } + for name, to := range dirNode.children { + switch { + case to.isDir(): + files[name] = fakeDir(name) + case to.isDeleted(): + delete(files, name) + default: + // This is a regular file. + f, err := os.Lstat(to.actualFilePath) + if err != nil { + files[name] = missingFile(name) + continue + } else if f.IsDir() { + return nil, fmt.Errorf("for overlay of %q to %q: overlay Replace entries can't point to dirctories", + filepath.Join(dir, name), to.actualFilePath) + } + // Add a fileinfo for the overlaid file, so that it has + // the original file's name, but the overlaid file's metadata. + files[name] = fakeFile{name, f} + } + } + sortedFiles := diskfis[:0] + for _, f := range files { + sortedFiles = append(sortedFiles, f) + } + sort.Slice(sortedFiles, func(i, j int) bool { return sortedFiles[i].Name() < sortedFiles[j].Name() }) + return sortedFiles, nil +} + +// OverlayPath returns the path to the overlaid contents of the +// file, the empty string if the overlay deletes the file, or path +// itself if the file is not in the overlay, the file is a directory +// in the overlay, or there is no overlay. +// It returns true if the path is overlaid with a regular file +// or deleted, and false otherwise. +func OverlayPath(path string) (string, bool) { + if p, ok := overlay[canonicalize(path)]; ok && !p.isDir() { + return p.actualFilePath, ok + } + + return path, false +} + +// Open opens the file at or overlaid on the given path. +func Open(path string) (*os.File, error) { + return OpenFile(path, os.O_RDONLY, 0) +} + +// OpenFile opens the file at or overlaid on the given path with the flag and perm. +func OpenFile(path string, flag int, perm os.FileMode) (*os.File, error) { + cpath := canonicalize(path) + if node, ok := overlay[cpath]; ok { + // Opening a file in the overlay. + if node.isDir() { + return nil, &fs.PathError{Op: "OpenFile", Path: path, Err: errors.New("fsys.OpenFile doesn't support opening directories yet")} + } + // We can't open overlaid paths for write. + if perm != os.FileMode(os.O_RDONLY) { + return nil, &fs.PathError{Op: "OpenFile", Path: path, Err: errors.New("overlaid files can't be opened for write")} + } + return os.OpenFile(node.actualFilePath, flag, perm) + } + if parent, ok := parentIsOverlayFile(filepath.Dir(cpath)); ok { + // The file is deleted explicitly in the Replace map, + // or implicitly because one of its parent directories was + // replaced by a file. + return nil, &fs.PathError{ + Op: "Open", + Path: path, + Err: fmt.Errorf("file %s does not exist: parent directory %s is replaced by a file in overlay", path, parent), + } + } + return os.OpenFile(cpath, flag, perm) +} + +// IsDirWithGoFiles reports whether dir is a directory containing Go files +// either on disk or in the overlay. +func IsDirWithGoFiles(dir string) (bool, error) { + fis, err := ReadDir(dir) + if os.IsNotExist(err) || errors.Is(err, errNotDir) { + return false, nil + } + if err != nil { + return false, err + } + + var firstErr error + for _, fi := range fis { + if fi.IsDir() { + continue + } + + // TODO(matloob): this enforces that the "from" in the map + // has a .go suffix, but the actual destination file + // doesn't need to have a .go suffix. Is this okay with the + // compiler? + if !strings.HasSuffix(fi.Name(), ".go") { + continue + } + if fi.Mode().IsRegular() { + return true, nil + } + + // fi is the result of an Lstat, so it doesn't follow symlinks. + // But it's okay if the file is a symlink pointing to a regular + // file, so use os.Stat to follow symlinks and check that. + actualFilePath, _ := OverlayPath(filepath.Join(dir, fi.Name())) + fi, err := os.Stat(actualFilePath) + if err == nil && fi.Mode().IsRegular() { + return true, nil + } + if err != nil && firstErr == nil { + firstErr = err + } + } + + // No go files found in directory. + return false, firstErr +} + +// walk recursively descends path, calling walkFn. Copied, with some +// modifications from path/filepath.walk. +func walk(path string, info fs.FileInfo, walkFn filepath.WalkFunc) error { + if !info.IsDir() { + return walkFn(path, info, nil) + } + + fis, readErr := ReadDir(path) + walkErr := walkFn(path, info, readErr) + // If readErr != nil, walk can't walk into this directory. + // walkErr != nil means walkFn want walk to skip this directory or stop walking. + // Therefore, if one of readErr and walkErr isn't nil, walk will return. + if readErr != nil || walkErr != nil { + // The caller's behavior is controlled by the return value, which is decided + // by walkFn. walkFn may ignore readErr and return nil. + // If walkFn returns SkipDir, it will be handled by the caller. + // So walk should return whatever walkFn returns. + return walkErr + } + + for _, fi := range fis { + filename := filepath.Join(path, fi.Name()) + if walkErr = walk(filename, fi, walkFn); walkErr != nil { + if !fi.IsDir() || walkErr != filepath.SkipDir { + return walkErr + } + } + } + return nil +} + +// Walk walks the file tree rooted at root, calling walkFn for each file or +// directory in the tree, including root. +func Walk(root string, walkFn filepath.WalkFunc) error { + info, err := Lstat(root) + if err != nil { + err = walkFn(root, nil, err) + } else { + err = walk(root, info, walkFn) + } + if err == filepath.SkipDir { + return nil + } + return err +} + +// lstat implements a version of os.Lstat that operates on the overlay filesystem. +func Lstat(path string) (fs.FileInfo, error) { + return overlayStat(path, os.Lstat, "lstat") +} + +// Stat implements a version of os.Stat that operates on the overlay filesystem. +func Stat(path string) (fs.FileInfo, error) { + return overlayStat(path, os.Stat, "stat") +} + +// overlayStat implements lstat or Stat (depending on whether os.Lstat or os.Stat is passed in). +func overlayStat(path string, osStat func(string) (fs.FileInfo, error), opName string) (fs.FileInfo, error) { + cpath := canonicalize(path) + + if _, ok := parentIsOverlayFile(filepath.Dir(cpath)); ok { + return nil, &fs.PathError{Op: opName, Path: cpath, Err: fs.ErrNotExist} + } + + node, ok := overlay[cpath] + if !ok { + // The file or directory is not overlaid. + return osStat(path) + } + + switch { + case node.isDeleted(): + return nil, &fs.PathError{Op: "lstat", Path: cpath, Err: fs.ErrNotExist} + case node.isDir(): + return fakeDir(filepath.Base(path)), nil + default: + fi, err := osStat(node.actualFilePath) + if err != nil { + return nil, err + } + return fakeFile{name: filepath.Base(path), real: fi}, nil + } +} + +// fakeFile provides an fs.FileInfo implementation for an overlaid file, +// so that the file has the name of the overlaid file, but takes all +// other characteristics of the replacement file. +type fakeFile struct { + name string + real fs.FileInfo +} + +func (f fakeFile) Name() string { return f.name } +func (f fakeFile) Size() int64 { return f.real.Size() } +func (f fakeFile) Mode() fs.FileMode { return f.real.Mode() } +func (f fakeFile) ModTime() time.Time { return f.real.ModTime() } +func (f fakeFile) IsDir() bool { return f.real.IsDir() } +func (f fakeFile) Sys() interface{} { return f.real.Sys() } + +// missingFile provides an fs.FileInfo for an overlaid file where the +// destination file in the overlay doesn't exist. It returns zero values +// for the fileInfo methods other than Name, set to the file's name, and Mode +// set to ModeIrregular. +type missingFile string + +func (f missingFile) Name() string { return string(f) } +func (f missingFile) Size() int64 { return 0 } +func (f missingFile) Mode() fs.FileMode { return fs.ModeIrregular } +func (f missingFile) ModTime() time.Time { return time.Unix(0, 0) } +func (f missingFile) IsDir() bool { return false } +func (f missingFile) Sys() interface{} { return nil } + +// fakeDir provides an fs.FileInfo implementation for directories that are +// implicitly created by overlaid files. Each directory in the +// path of an overlaid file is considered to exist in the overlay filesystem. +type fakeDir string + +func (f fakeDir) Name() string { return string(f) } +func (f fakeDir) Size() int64 { return 0 } +func (f fakeDir) Mode() fs.FileMode { return fs.ModeDir | 0500 } +func (f fakeDir) ModTime() time.Time { return time.Unix(0, 0) } +func (f fakeDir) IsDir() bool { return true } +func (f fakeDir) Sys() interface{} { return nil } + +// Glob is like filepath.Glob but uses the overlay file system. +func Glob(pattern string) (matches []string, err error) { + // Check pattern is well-formed. + if _, err := filepath.Match(pattern, ""); err != nil { + return nil, err + } + if !hasMeta(pattern) { + if _, err = Lstat(pattern); err != nil { + return nil, nil + } + return []string{pattern}, nil + } + + dir, file := filepath.Split(pattern) + volumeLen := 0 + if runtime.GOOS == "windows" { + volumeLen, dir = cleanGlobPathWindows(dir) + } else { + dir = cleanGlobPath(dir) + } + + if !hasMeta(dir[volumeLen:]) { + return glob(dir, file, nil) + } + + // Prevent infinite recursion. See issue 15879. + if dir == pattern { + return nil, filepath.ErrBadPattern + } + + var m []string + m, err = Glob(dir) + if err != nil { + return + } + for _, d := range m { + matches, err = glob(d, file, matches) + if err != nil { + return + } + } + return +} + +// cleanGlobPath prepares path for glob matching. +func cleanGlobPath(path string) string { + switch path { + case "": + return "." + case string(filepath.Separator): + // do nothing to the path + return path + default: + return path[0 : len(path)-1] // chop off trailing separator + } +} + +func volumeNameLen(path string) int { + isSlash := func(c uint8) bool { + return c == '\\' || c == '/' + } + if len(path) < 2 { + return 0 + } + // with drive letter + c := path[0] + if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') { + return 2 + } + // is it UNC? https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx + if l := len(path); l >= 5 && isSlash(path[0]) && isSlash(path[1]) && + !isSlash(path[2]) && path[2] != '.' { + // first, leading `\\` and next shouldn't be `\`. its server name. + for n := 3; n < l-1; n++ { + // second, next '\' shouldn't be repeated. + if isSlash(path[n]) { + n++ + // third, following something characters. its share name. + if !isSlash(path[n]) { + if path[n] == '.' { + break + } + for ; n < l; n++ { + if isSlash(path[n]) { + break + } + } + return n + } + break + } + } + } + return 0 +} + +// cleanGlobPathWindows is windows version of cleanGlobPath. +func cleanGlobPathWindows(path string) (prefixLen int, cleaned string) { + vollen := volumeNameLen(path) + switch { + case path == "": + return 0, "." + case vollen+1 == len(path) && os.IsPathSeparator(path[len(path)-1]): // /, \, C:\ and C:/ + // do nothing to the path + return vollen + 1, path + case vollen == len(path) && len(path) == 2: // C: + return vollen, path + "." // convert C: into C:. + default: + if vollen >= len(path) { + vollen = len(path) - 1 + } + return vollen, path[0 : len(path)-1] // chop off trailing separator + } +} + +// glob searches for files matching pattern in the directory dir +// and appends them to matches. If the directory cannot be +// opened, it returns the existing matches. New matches are +// added in lexicographical order. +func glob(dir, pattern string, matches []string) (m []string, e error) { + m = matches + fi, err := Stat(dir) + if err != nil { + return // ignore I/O error + } + if !fi.IsDir() { + return // ignore I/O error + } + + list, err := ReadDir(dir) + if err != nil { + return // ignore I/O error + } + + var names []string + for _, info := range list { + names = append(names, info.Name()) + } + sort.Strings(names) + + for _, n := range names { + matched, err := filepath.Match(pattern, n) + if err != nil { + return m, err + } + if matched { + m = append(m, filepath.Join(dir, n)) + } + } + return +} + +// hasMeta reports whether path contains any of the magic characters +// recognized by filepath.Match. +func hasMeta(path string) bool { + magicChars := `*?[` + if runtime.GOOS != "windows" { + magicChars = `*?[\` + } + return strings.ContainsAny(path, magicChars) +} diff --git a/src/cmd/go/internal/fsys/fsys_test.go b/src/cmd/go/internal/fsys/fsys_test.go new file mode 100644 index 0000000..7f175c7 --- /dev/null +++ b/src/cmd/go/internal/fsys/fsys_test.go @@ -0,0 +1,1094 @@ +package fsys + +import ( + "cmd/go/internal/txtar" + "encoding/json" + "errors" + "fmt" + "internal/testenv" + "io" + "io/fs" + "os" + "path/filepath" + "reflect" + "testing" +) + +// initOverlay resets the overlay state to reflect the config. +// config should be a text archive string. The comment is the overlay config +// json, and the files, in the archive are laid out in a temp directory +// that cwd is set to. +func initOverlay(t *testing.T, config string) { + t.Helper() + + // Create a temporary directory and chdir to it. + prevwd, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + cwd = filepath.Join(t.TempDir(), "root") + if err := os.Mkdir(cwd, 0777); err != nil { + t.Fatal(err) + } + if err := os.Chdir(cwd); err != nil { + t.Fatal(err) + } + t.Cleanup(func() { + overlay = nil + if err := os.Chdir(prevwd); err != nil { + t.Fatal(err) + } + }) + + a := txtar.Parse([]byte(config)) + for _, f := range a.Files { + name := filepath.Join(cwd, f.Name) + if err := os.MkdirAll(filepath.Dir(name), 0777); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(name, f.Data, 0666); err != nil { + t.Fatal(err) + } + } + + var overlayJSON OverlayJSON + if err := json.Unmarshal(a.Comment, &overlayJSON); err != nil { + t.Fatal(fmt.Errorf("parsing overlay JSON: %v", err)) + } + + initFromJSON(overlayJSON) +} + +func TestIsDir(t *testing.T) { + initOverlay(t, ` +{ + "Replace": { + "subdir2/file2.txt": "overlayfiles/subdir2_file2.txt", + "subdir4": "overlayfiles/subdir4", + "subdir3/file3b.txt": "overlayfiles/subdir3_file3b.txt", + "subdir5": "", + "subdir6": "" + } +} +-- subdir1/file1.txt -- + +-- subdir3/file3a.txt -- +33 +-- subdir4/file4.txt -- +444 +-- overlayfiles/subdir2_file2.txt -- +2 +-- overlayfiles/subdir3_file3b.txt -- +66666 +-- overlayfiles/subdir4 -- +x +-- subdir6/file6.txt -- +six +`) + + testCases := []struct { + path string + want, wantErr bool + }{ + {"", true, true}, + {".", true, false}, + {cwd, true, false}, + {cwd + string(filepath.Separator), true, false}, + // subdir1 is only on disk + {filepath.Join(cwd, "subdir1"), true, false}, + {"subdir1", true, false}, + {"subdir1" + string(filepath.Separator), true, false}, + {"subdir1/file1.txt", false, false}, + {"subdir1/doesntexist.txt", false, true}, + {"doesntexist", false, true}, + // subdir2 is only in overlay + {filepath.Join(cwd, "subdir2"), true, false}, + {"subdir2", true, false}, + {"subdir2" + string(filepath.Separator), true, false}, + {"subdir2/file2.txt", false, false}, + {"subdir2/doesntexist.txt", false, true}, + // subdir3 has files on disk and in overlay + {filepath.Join(cwd, "subdir3"), true, false}, + {"subdir3", true, false}, + {"subdir3" + string(filepath.Separator), true, false}, + {"subdir3/file3a.txt", false, false}, + {"subdir3/file3b.txt", false, false}, + {"subdir3/doesntexist.txt", false, true}, + // subdir4 is overlaid with a file + {filepath.Join(cwd, "subdir4"), false, false}, + {"subdir4", false, false}, + {"subdir4" + string(filepath.Separator), false, false}, + {"subdir4/file4.txt", false, false}, + {"subdir4/doesntexist.txt", false, false}, + // subdir5 doesn't exist, and is overlaid with a "delete" entry + {filepath.Join(cwd, "subdir5"), false, false}, + {"subdir5", false, false}, + {"subdir5" + string(filepath.Separator), false, false}, + {"subdir5/file5.txt", false, false}, + {"subdir5/doesntexist.txt", false, false}, + // subdir6 does exist, and is overlaid with a "delete" entry + {filepath.Join(cwd, "subdir6"), false, false}, + {"subdir6", false, false}, + {"subdir6" + string(filepath.Separator), false, false}, + {"subdir6/file6.txt", false, false}, + {"subdir6/doesntexist.txt", false, false}, + } + + for _, tc := range testCases { + got, err := IsDir(tc.path) + if err != nil { + if !tc.wantErr { + t.Errorf("IsDir(%q): got error with string %q, want no error", tc.path, err.Error()) + } + continue + } + if tc.wantErr { + t.Errorf("IsDir(%q): got no error, want error", tc.path) + } + if tc.want != got { + t.Errorf("IsDir(%q) = %v, want %v", tc.path, got, tc.want) + } + } +} + +const readDirOverlay = ` +{ + "Replace": { + "subdir2/file2.txt": "overlayfiles/subdir2_file2.txt", + "subdir4": "overlayfiles/subdir4", + "subdir3/file3b.txt": "overlayfiles/subdir3_file3b.txt", + "subdir5": "", + "subdir6/asubsubdir/afile.txt": "overlayfiles/subdir6_asubsubdir_afile.txt", + "subdir6/asubsubdir/zfile.txt": "overlayfiles/subdir6_asubsubdir_zfile.txt", + "subdir6/zsubsubdir/file.txt": "overlayfiles/subdir6_zsubsubdir_file.txt", + "subdir7/asubsubdir/file.txt": "overlayfiles/subdir7_asubsubdir_file.txt", + "subdir7/zsubsubdir/file.txt": "overlayfiles/subdir7_zsubsubdir_file.txt", + "subdir8/doesntexist": "this_file_doesnt_exist_anywhere", + "other/pointstodir": "overlayfiles/this_is_a_directory", + "parentoverwritten/subdir1": "overlayfiles/parentoverwritten_subdir1", + "subdir9/this_file_is_overlaid.txt": "overlayfiles/subdir9_this_file_is_overlaid.txt", + "subdir10/only_deleted_file.txt": "", + "subdir11/deleted.txt": "", + "subdir11": "overlayfiles/subdir11", + "textfile.txt/file.go": "overlayfiles/textfile_txt_file.go" + } +} +-- subdir1/file1.txt -- + +-- subdir3/file3a.txt -- +33 +-- subdir4/file4.txt -- +444 +-- subdir6/file.txt -- +-- subdir6/asubsubdir/file.txt -- +-- subdir6/anothersubsubdir/file.txt -- +-- subdir9/this_file_is_overlaid.txt -- +-- subdir10/only_deleted_file.txt -- +this will be deleted in overlay +-- subdir11/deleted.txt -- +-- parentoverwritten/subdir1/subdir2/subdir3/file.txt -- +-- textfile.txt -- +this will be overridden by textfile.txt/file.go +-- overlayfiles/subdir2_file2.txt -- +2 +-- overlayfiles/subdir3_file3b.txt -- +66666 +-- overlayfiles/subdir4 -- +x +-- overlayfiles/subdir6_asubsubdir_afile.txt -- +-- overlayfiles/subdir6_asubsubdir_zfile.txt -- +-- overlayfiles/subdir6_zsubsubdir_file.txt -- +-- overlayfiles/subdir7_asubsubdir_file.txt -- +-- overlayfiles/subdir7_zsubsubdir_file.txt -- +-- overlayfiles/parentoverwritten_subdir1 -- +x +-- overlayfiles/subdir9_this_file_is_overlaid.txt -- +99999999 +-- overlayfiles/subdir11 -- +-- overlayfiles/this_is_a_directory/file.txt -- +-- overlayfiles/textfile_txt_file.go -- +x +` + +func TestReadDir(t *testing.T) { + initOverlay(t, readDirOverlay) + + type entry struct { + name string + size int64 + isDir bool + } + + testCases := []struct { + dir string + want []entry + }{ + { + ".", []entry{ + {"other", 0, true}, + {"overlayfiles", 0, true}, + {"parentoverwritten", 0, true}, + {"subdir1", 0, true}, + {"subdir10", 0, true}, + {"subdir11", 0, false}, + {"subdir2", 0, true}, + {"subdir3", 0, true}, + {"subdir4", 2, false}, + // no subdir5. + {"subdir6", 0, true}, + {"subdir7", 0, true}, + {"subdir8", 0, true}, + {"subdir9", 0, true}, + {"textfile.txt", 0, true}, + }, + }, + { + "subdir1", []entry{ + {"file1.txt", 1, false}, + }, + }, + { + "subdir2", []entry{ + {"file2.txt", 2, false}, + }, + }, + { + "subdir3", []entry{ + {"file3a.txt", 3, false}, + {"file3b.txt", 6, false}, + }, + }, + { + "subdir6", []entry{ + {"anothersubsubdir", 0, true}, + {"asubsubdir", 0, true}, + {"file.txt", 0, false}, + {"zsubsubdir", 0, true}, + }, + }, + { + "subdir6/asubsubdir", []entry{ + {"afile.txt", 0, false}, + {"file.txt", 0, false}, + {"zfile.txt", 0, false}, + }, + }, + { + "subdir8", []entry{ + {"doesntexist", 0, false}, // entry is returned even if destination file doesn't exist + }, + }, + { + // check that read dir actually redirects files that already exist + // the original this_file_is_overlaid.txt is empty + "subdir9", []entry{ + {"this_file_is_overlaid.txt", 9, false}, + }, + }, + { + "subdir10", []entry{}, + }, + { + "parentoverwritten", []entry{ + {"subdir1", 2, false}, + }, + }, + { + "textfile.txt", []entry{ + {"file.go", 2, false}, + }, + }, + } + + for _, tc := range testCases { + dir, want := tc.dir, tc.want + infos, err := ReadDir(dir) + if err != nil { + t.Errorf("ReadDir(%q): %v", dir, err) + continue + } + // Sorted diff of want and infos. + for len(infos) > 0 || len(want) > 0 { + switch { + case len(want) == 0 || len(infos) > 0 && infos[0].Name() < want[0].name: + t.Errorf("ReadDir(%q): unexpected entry: %s IsDir=%v Size=%v", dir, infos[0].Name(), infos[0].IsDir(), infos[0].Size()) + infos = infos[1:] + case len(infos) == 0 || len(want) > 0 && want[0].name < infos[0].Name(): + t.Errorf("ReadDir(%q): missing entry: %s IsDir=%v Size=%v", dir, want[0].name, want[0].isDir, want[0].size) + want = want[1:] + default: + infoSize := infos[0].Size() + if want[0].isDir { + infoSize = 0 + } + if infos[0].IsDir() != want[0].isDir || want[0].isDir && infoSize != want[0].size { + t.Errorf("ReadDir(%q): %s: IsDir=%v Size=%v, want IsDir=%v Size=%v", dir, want[0].name, infos[0].IsDir(), infoSize, want[0].isDir, want[0].size) + } + infos = infos[1:] + want = want[1:] + } + } + } + + errCases := []string{ + "subdir1/file1.txt", // regular file on disk + "subdir2/file2.txt", // regular file in overlay + "subdir4", // directory overlaid with regular file + "subdir5", // directory deleted in overlay + "parentoverwritten/subdir1/subdir2/subdir3", // parentoverwritten/subdir1 overlaid with regular file + "parentoverwritten/subdir1/subdir2", // parentoverwritten/subdir1 overlaid with regular file + "subdir11", // directory with deleted child, overlaid with regular file + "other/pointstodir", + } + + for _, dir := range errCases { + _, err := ReadDir(dir) + if _, ok := err.(*fs.PathError); !ok { + t.Errorf("ReadDir(%q): err = %T (%v), want fs.PathError", dir, err, err) + } + } +} + +func TestGlob(t *testing.T) { + initOverlay(t, readDirOverlay) + + testCases := []struct { + pattern string + match []string + }{ + { + "*o*", + []string{ + "other", + "overlayfiles", + "parentoverwritten", + }, + }, + { + "subdir2/file2.txt", + []string{ + "subdir2/file2.txt", + }, + }, + { + "*/*.txt", + []string{ + "overlayfiles/subdir2_file2.txt", + "overlayfiles/subdir3_file3b.txt", + "overlayfiles/subdir6_asubsubdir_afile.txt", + "overlayfiles/subdir6_asubsubdir_zfile.txt", + "overlayfiles/subdir6_zsubsubdir_file.txt", + "overlayfiles/subdir7_asubsubdir_file.txt", + "overlayfiles/subdir7_zsubsubdir_file.txt", + "overlayfiles/subdir9_this_file_is_overlaid.txt", + "subdir1/file1.txt", + "subdir2/file2.txt", + "subdir3/file3a.txt", + "subdir3/file3b.txt", + "subdir6/file.txt", + "subdir9/this_file_is_overlaid.txt", + }, + }, + } + + for _, tc := range testCases { + pattern := tc.pattern + match, err := Glob(pattern) + if err != nil { + t.Errorf("Glob(%q): %v", pattern, err) + continue + } + want := tc.match + for i, name := range want { + if name != tc.pattern { + want[i] = filepath.FromSlash(name) + } + } + for len(match) > 0 || len(want) > 0 { + switch { + case len(match) == 0 || len(want) > 0 && want[0] < match[0]: + t.Errorf("Glob(%q): missing match: %s", pattern, want[0]) + want = want[1:] + case len(want) == 0 || len(match) > 0 && match[0] < want[0]: + t.Errorf("Glob(%q): extra match: %s", pattern, match[0]) + match = match[1:] + default: + want = want[1:] + match = match[1:] + } + } + } +} + +func TestOverlayPath(t *testing.T) { + initOverlay(t, ` +{ + "Replace": { + "subdir2/file2.txt": "overlayfiles/subdir2_file2.txt", + "subdir3/doesntexist": "this_file_doesnt_exist_anywhere", + "subdir4/this_file_is_overlaid.txt": "overlayfiles/subdir4_this_file_is_overlaid.txt", + "subdir5/deleted.txt": "", + "parentoverwritten/subdir1": "" + } +} +-- subdir1/file1.txt -- +file 1 +-- subdir4/this_file_is_overlaid.txt -- +these contents are replaced by the overlay +-- parentoverwritten/subdir1/subdir2/subdir3/file.txt -- +-- subdir5/deleted.txt -- +deleted +-- overlayfiles/subdir2_file2.txt -- +file 2 +-- overlayfiles/subdir4_this_file_is_overlaid.txt -- +99999999 +`) + + testCases := []struct { + path string + wantPath string + wantOK bool + }{ + {"subdir1/file1.txt", "subdir1/file1.txt", false}, + // OverlayPath returns false for directories + {"subdir2", "subdir2", false}, + {"subdir2/file2.txt", filepath.Join(cwd, "overlayfiles/subdir2_file2.txt"), true}, + // OverlayPath doesn't stat a file to see if it exists, so it happily returns + // the 'to' path and true even if the 'to' path doesn't exist on disk. + {"subdir3/doesntexist", filepath.Join(cwd, "this_file_doesnt_exist_anywhere"), true}, + // Like the subdir2/file2.txt case above, but subdir4 exists on disk, but subdir2 does not. + {"subdir4/this_file_is_overlaid.txt", filepath.Join(cwd, "overlayfiles/subdir4_this_file_is_overlaid.txt"), true}, + {"subdir5", "subdir5", false}, + {"subdir5/deleted.txt", "", true}, + } + + for _, tc := range testCases { + gotPath, gotOK := OverlayPath(tc.path) + if gotPath != tc.wantPath || gotOK != tc.wantOK { + t.Errorf("OverlayPath(%q): got %v, %v; want %v, %v", + tc.path, gotPath, gotOK, tc.wantPath, tc.wantOK) + } + } +} + +func TestOpen(t *testing.T) { + initOverlay(t, ` +{ + "Replace": { + "subdir2/file2.txt": "overlayfiles/subdir2_file2.txt", + "subdir3/doesntexist": "this_file_doesnt_exist_anywhere", + "subdir4/this_file_is_overlaid.txt": "overlayfiles/subdir4_this_file_is_overlaid.txt", + "subdir5/deleted.txt": "", + "parentoverwritten/subdir1": "", + "childoverlay/subdir1.txt/child.txt": "overlayfiles/child.txt", + "subdir11/deleted.txt": "", + "subdir11": "overlayfiles/subdir11", + "parentdeleted": "", + "parentdeleted/file.txt": "overlayfiles/parentdeleted_file.txt" + } +} +-- subdir11/deleted.txt -- +-- subdir1/file1.txt -- +file 1 +-- subdir4/this_file_is_overlaid.txt -- +these contents are replaced by the overlay +-- parentoverwritten/subdir1/subdir2/subdir3/file.txt -- +-- childoverlay/subdir1.txt -- +this file doesn't exist because the path +childoverlay/subdir1.txt/child.txt is in the overlay +-- subdir5/deleted.txt -- +deleted +-- parentdeleted -- +this will be deleted so that parentdeleted/file.txt can exist +-- overlayfiles/subdir2_file2.txt -- +file 2 +-- overlayfiles/subdir4_this_file_is_overlaid.txt -- +99999999 +-- overlayfiles/child.txt -- +-- overlayfiles/subdir11 -- +11 +-- overlayfiles/parentdeleted_file.txt -- +this can exist because the parent directory is deleted +`) + + testCases := []struct { + path string + wantContents string + isErr bool + }{ + {"subdir1/file1.txt", "file 1\n", false}, + {"subdir2/file2.txt", "file 2\n", false}, + {"subdir3/doesntexist", "", true}, + {"subdir4/this_file_is_overlaid.txt", "99999999\n", false}, + {"subdir5/deleted.txt", "", true}, + {"parentoverwritten/subdir1/subdir2/subdir3/file.txt", "", true}, + {"childoverlay/subdir1.txt", "", true}, + {"subdir11", "11\n", false}, + {"parentdeleted/file.txt", "this can exist because the parent directory is deleted\n", false}, + } + + for _, tc := range testCases { + f, err := Open(tc.path) + if tc.isErr { + if err == nil { + f.Close() + t.Errorf("Open(%q): got no error, but want error", tc.path) + } + continue + } + if err != nil { + t.Errorf("Open(%q): got error %v, want nil", tc.path, err) + continue + } + contents, err := io.ReadAll(f) + if err != nil { + t.Errorf("unexpected error reading contents of file: %v", err) + } + if string(contents) != tc.wantContents { + t.Errorf("contents of file opened with Open(%q): got %q, want %q", + tc.path, contents, tc.wantContents) + } + f.Close() + } +} + +func TestIsDirWithGoFiles(t *testing.T) { + initOverlay(t, ` +{ + "Replace": { + "goinoverlay/file.go": "dummy", + "directory/removed/by/file": "dummy", + "directory_with_go_dir/dir.go/file.txt": "dummy", + "otherdirectory/deleted.go": "", + "nonexistentdirectory/deleted.go": "", + "textfile.txt/file.go": "dummy" + } +} +-- dummy -- +a destination file for the overlay entries to point to +contents don't matter for this test +-- nogo/file.txt -- +-- goondisk/file.go -- +-- goinoverlay/file.txt -- +-- directory/removed/by/file/in/overlay/file.go -- +-- otherdirectory/deleted.go -- +-- textfile.txt -- +`) + + testCases := []struct { + dir string + want bool + wantErr bool + }{ + {"nogo", false, false}, + {"goondisk", true, false}, + {"goinoverlay", true, false}, + {"directory/removed/by/file/in/overlay", false, false}, + {"directory_with_go_dir", false, false}, + {"otherdirectory", false, false}, + {"nonexistentdirectory", false, false}, + {"textfile.txt", true, false}, + } + + for _, tc := range testCases { + got, gotErr := IsDirWithGoFiles(tc.dir) + if tc.wantErr { + if gotErr == nil { + t.Errorf("IsDirWithGoFiles(%q): got %v, %v; want non-nil error", tc.dir, got, gotErr) + } + continue + } + if gotErr != nil { + t.Errorf("IsDirWithGoFiles(%q): got %v, %v; want nil error", tc.dir, got, gotErr) + } + if got != tc.want { + t.Errorf("IsDirWithGoFiles(%q) = %v; want %v", tc.dir, got, tc.want) + } + } +} + +func TestWalk(t *testing.T) { + // The root of the walk must be a name with an actual basename, not just ".". + // Walk uses Lstat to obtain the name of the root, and Lstat on platforms + // other than Plan 9 reports the name "." instead of the actual base name of + // the directory. (See https://golang.org/issue/42115.) + + type file struct { + path string + name string + size int64 + mode fs.FileMode + isDir bool + } + testCases := []struct { + name string + overlay string + root string + wantFiles []file + }{ + {"no overlay", ` +{} +-- dir/file.txt -- +`, + "dir", + []file{ + {"dir", "dir", 0, fs.ModeDir | 0700, true}, + {"dir/file.txt", "file.txt", 0, 0600, false}, + }, + }, + {"overlay with different file", ` +{ + "Replace": { + "dir/file.txt": "dir/other.txt" + } +} +-- dir/file.txt -- +-- dir/other.txt -- +contents of other file +`, + "dir", + []file{ + {"dir", "dir", 0, fs.ModeDir | 0500, true}, + {"dir/file.txt", "file.txt", 23, 0600, false}, + {"dir/other.txt", "other.txt", 23, 0600, false}, + }, + }, + {"overlay with new file", ` +{ + "Replace": { + "dir/file.txt": "dir/other.txt" + } +} +-- dir/other.txt -- +contents of other file +`, + "dir", + []file{ + {"dir", "dir", 0, fs.ModeDir | 0500, true}, + {"dir/file.txt", "file.txt", 23, 0600, false}, + {"dir/other.txt", "other.txt", 23, 0600, false}, + }, + }, + {"overlay with new directory", ` +{ + "Replace": { + "dir/subdir/file.txt": "dir/other.txt" + } +} +-- dir/other.txt -- +contents of other file +`, + "dir", + []file{ + {"dir", "dir", 0, fs.ModeDir | 0500, true}, + {"dir/other.txt", "other.txt", 23, 0600, false}, + {"dir/subdir", "subdir", 0, fs.ModeDir | 0500, true}, + {"dir/subdir/file.txt", "file.txt", 23, 0600, false}, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + initOverlay(t, tc.overlay) + + var got []file + Walk(tc.root, func(path string, info fs.FileInfo, err error) error { + got = append(got, file{path, info.Name(), info.Size(), info.Mode(), info.IsDir()}) + return nil + }) + + if len(got) != len(tc.wantFiles) { + t.Errorf("Walk: saw %#v in walk; want %#v", got, tc.wantFiles) + } + for i := 0; i < len(got) && i < len(tc.wantFiles); i++ { + wantPath := filepath.FromSlash(tc.wantFiles[i].path) + if got[i].path != wantPath { + t.Errorf("path of file #%v in walk, got %q, want %q", i, got[i].path, wantPath) + } + if got[i].name != tc.wantFiles[i].name { + t.Errorf("name of file #%v in walk, got %q, want %q", i, got[i].name, tc.wantFiles[i].name) + } + if got[i].mode&(fs.ModeDir|0700) != tc.wantFiles[i].mode { + t.Errorf("mode&(fs.ModeDir|0700) for mode of file #%v in walk, got %v, want %v", i, got[i].mode&(fs.ModeDir|0700), tc.wantFiles[i].mode) + } + if got[i].isDir != tc.wantFiles[i].isDir { + t.Errorf("isDir for file #%v in walk, got %v, want %v", i, got[i].isDir, tc.wantFiles[i].isDir) + } + if tc.wantFiles[i].isDir { + continue // don't check size for directories + } + if got[i].size != tc.wantFiles[i].size { + t.Errorf("size of file #%v in walk, got %v, want %v", i, got[i].size, tc.wantFiles[i].size) + } + } + }) + } +} + +func TestWalkSkipDir(t *testing.T) { + initOverlay(t, ` +{ + "Replace": { + "dir/skip/file.go": "dummy.txt", + "dir/dontskip/file.go": "dummy.txt", + "dir/dontskip/skip/file.go": "dummy.txt" + } +} +-- dummy.txt -- +`) + + var seen []string + Walk("dir", func(path string, info fs.FileInfo, err error) error { + seen = append(seen, filepath.ToSlash(path)) + if info.Name() == "skip" { + return filepath.SkipDir + } + return nil + }) + + wantSeen := []string{"dir", "dir/dontskip", "dir/dontskip/file.go", "dir/dontskip/skip", "dir/skip"} + + if len(seen) != len(wantSeen) { + t.Errorf("paths seen in walk: got %v entries; want %v entries", len(seen), len(wantSeen)) + } + + for i := 0; i < len(seen) && i < len(wantSeen); i++ { + if seen[i] != wantSeen[i] { + t.Errorf("path #%v seen walking tree: want %q, got %q", i, seen[i], wantSeen[i]) + } + } +} + +func TestWalkError(t *testing.T) { + initOverlay(t, "{}") + + alreadyCalled := false + err := Walk("foo", func(path string, info fs.FileInfo, err error) error { + if alreadyCalled { + t.Fatal("expected walk function to be called exactly once, but it was called more than once") + } + alreadyCalled = true + return errors.New("returned from function") + }) + if !alreadyCalled { + t.Fatal("expected walk function to be called exactly once, but it was never called") + + } + if err == nil { + t.Fatalf("Walk: got no error, want error") + } + if err.Error() != "returned from function" { + t.Fatalf("Walk: got error %v, want \"returned from function\" error", err) + } +} + +func TestWalkSymlink(t *testing.T) { + testenv.MustHaveSymlink(t) + + initOverlay(t, `{ + "Replace": {"overlay_symlink": "symlink"} +} +-- dir/file --`) + + // Create symlink + if err := os.Symlink("dir", "symlink"); err != nil { + t.Error(err) + } + + testCases := []struct { + name string + dir string + wantFiles []string + }{ + {"control", "dir", []string{"dir", "dir" + string(filepath.Separator) + "file"}}, + // ensure Walk doesn't walk into the directory pointed to by the symlink + // (because it's supposed to use Lstat instead of Stat). + {"symlink_to_dir", "symlink", []string{"symlink"}}, + {"overlay_to_symlink_to_dir", "overlay_symlink", []string{"overlay_symlink"}}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + var got []string + + err := Walk(tc.dir, func(path string, info fs.FileInfo, err error) error { + got = append(got, path) + if err != nil { + t.Errorf("walkfn: got non nil err argument: %v, want nil err argument", err) + } + return nil + }) + if err != nil { + t.Errorf("Walk: got error %q, want nil", err) + } + + if !reflect.DeepEqual(got, tc.wantFiles) { + t.Errorf("files examined by walk: got %v, want %v", got, tc.wantFiles) + } + }) + } + +} + +func TestLstat(t *testing.T) { + type file struct { + name string + size int64 + mode fs.FileMode // mode & (fs.ModeDir|0x700): only check 'user' permissions + isDir bool + } + + testCases := []struct { + name string + overlay string + path string + + want file + wantErr bool + }{ + { + "regular_file", + `{} +-- file.txt -- +contents`, + "file.txt", + file{"file.txt", 9, 0600, false}, + false, + }, + { + "new_file_in_overlay", + `{"Replace": {"file.txt": "dummy.txt"}} +-- dummy.txt -- +contents`, + "file.txt", + file{"file.txt", 9, 0600, false}, + false, + }, + { + "file_replaced_in_overlay", + `{"Replace": {"file.txt": "dummy.txt"}} +-- file.txt -- +-- dummy.txt -- +contents`, + "file.txt", + file{"file.txt", 9, 0600, false}, + false, + }, + { + "file_cant_exist", + `{"Replace": {"deleted": "dummy.txt"}} +-- deleted/file.txt -- +-- dummy.txt -- +`, + "deleted/file.txt", + file{}, + true, + }, + { + "deleted", + `{"Replace": {"deleted": ""}} +-- deleted -- +`, + "deleted", + file{}, + true, + }, + { + "dir_on_disk", + `{} +-- dir/foo.txt -- +`, + "dir", + file{"dir", 0, 0700 | fs.ModeDir, true}, + false, + }, + { + "dir_in_overlay", + `{"Replace": {"dir/file.txt": "dummy.txt"}} +-- dummy.txt -- +`, + "dir", + file{"dir", 0, 0500 | fs.ModeDir, true}, + false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + initOverlay(t, tc.overlay) + got, err := Lstat(tc.path) + if tc.wantErr { + if err == nil { + t.Errorf("lstat(%q): got no error, want error", tc.path) + } + return + } + if err != nil { + t.Fatalf("lstat(%q): got error %v, want no error", tc.path, err) + } + if got.Name() != tc.want.name { + t.Errorf("lstat(%q).Name(): got %q, want %q", tc.path, got.Name(), tc.want.name) + } + if got.Mode()&(fs.ModeDir|0700) != tc.want.mode { + t.Errorf("lstat(%q).Mode()&(fs.ModeDir|0700): got %v, want %v", tc.path, got.Mode()&(fs.ModeDir|0700), tc.want.mode) + } + if got.IsDir() != tc.want.isDir { + t.Errorf("lstat(%q).IsDir(): got %v, want %v", tc.path, got.IsDir(), tc.want.isDir) + } + if tc.want.isDir { + return // don't check size for directories + } + if got.Size() != tc.want.size { + t.Errorf("lstat(%q).Size(): got %v, want %v", tc.path, got.Size(), tc.want.size) + } + }) + } +} + +func TestStat(t *testing.T) { + testenv.MustHaveSymlink(t) + + type file struct { + name string + size int64 + mode os.FileMode // mode & (os.ModeDir|0x700): only check 'user' permissions + isDir bool + } + + testCases := []struct { + name string + overlay string + path string + + want file + wantErr bool + }{ + { + "regular_file", + `{} +-- file.txt -- +contents`, + "file.txt", + file{"file.txt", 9, 0600, false}, + false, + }, + { + "new_file_in_overlay", + `{"Replace": {"file.txt": "dummy.txt"}} +-- dummy.txt -- +contents`, + "file.txt", + file{"file.txt", 9, 0600, false}, + false, + }, + { + "file_replaced_in_overlay", + `{"Replace": {"file.txt": "dummy.txt"}} +-- file.txt -- +-- dummy.txt -- +contents`, + "file.txt", + file{"file.txt", 9, 0600, false}, + false, + }, + { + "file_cant_exist", + `{"Replace": {"deleted": "dummy.txt"}} +-- deleted/file.txt -- +-- dummy.txt -- +`, + "deleted/file.txt", + file{}, + true, + }, + { + "deleted", + `{"Replace": {"deleted": ""}} +-- deleted -- +`, + "deleted", + file{}, + true, + }, + { + "dir_on_disk", + `{} +-- dir/foo.txt -- +`, + "dir", + file{"dir", 0, 0700 | os.ModeDir, true}, + false, + }, + { + "dir_in_overlay", + `{"Replace": {"dir/file.txt": "dummy.txt"}} +-- dummy.txt -- +`, + "dir", + file{"dir", 0, 0500 | os.ModeDir, true}, + false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + initOverlay(t, tc.overlay) + got, err := Stat(tc.path) + if tc.wantErr { + if err == nil { + t.Errorf("Stat(%q): got no error, want error", tc.path) + } + return + } + if err != nil { + t.Fatalf("Stat(%q): got error %v, want no error", tc.path, err) + } + if got.Name() != tc.want.name { + t.Errorf("Stat(%q).Name(): got %q, want %q", tc.path, got.Name(), tc.want.name) + } + if got.Mode()&(os.ModeDir|0700) != tc.want.mode { + t.Errorf("Stat(%q).Mode()&(os.ModeDir|0700): got %v, want %v", tc.path, got.Mode()&(os.ModeDir|0700), tc.want.mode) + } + if got.IsDir() != tc.want.isDir { + t.Errorf("Stat(%q).IsDir(): got %v, want %v", tc.path, got.IsDir(), tc.want.isDir) + } + if tc.want.isDir { + return // don't check size for directories + } + if got.Size() != tc.want.size { + t.Errorf("Stat(%q).Size(): got %v, want %v", tc.path, got.Size(), tc.want.size) + } + }) + } +} + +func TestStatSymlink(t *testing.T) { + testenv.MustHaveSymlink(t) + + initOverlay(t, `{ + "Replace": {"file.go": "symlink"} +} +-- to.go -- +0123456789 +`) + + // Create symlink + if err := os.Symlink("to.go", "symlink"); err != nil { + t.Error(err) + } + + f := "file.go" + fi, err := Stat(f) + if err != nil { + t.Errorf("Stat(%q): got error %q, want nil error", f, err) + } + + if !fi.Mode().IsRegular() { + t.Errorf("Stat(%q).Mode(): got %v, want regular mode", f, fi.Mode()) + } + + if fi.Size() != 11 { + t.Errorf("Stat(%q).Size(): got %v, want 11", f, fi.Size()) + } +} diff --git a/src/cmd/go/internal/generate/generate.go b/src/cmd/go/internal/generate/generate.go new file mode 100644 index 0000000..a48311d --- /dev/null +++ b/src/cmd/go/internal/generate/generate.go @@ -0,0 +1,456 @@ +// Copyright 2011 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 generate implements the ``go generate'' command. +package generate + +import ( + "bufio" + "bytes" + "context" + "fmt" + "go/parser" + "go/token" + exec "internal/execabs" + "io" + "log" + "os" + "path/filepath" + "regexp" + "strconv" + "strings" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/load" + "cmd/go/internal/modload" + "cmd/go/internal/str" + "cmd/go/internal/work" +) + +var CmdGenerate = &base.Command{ + Run: runGenerate, + 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 +files. Those commands can run any process but the intent is to +create or update Go source files. + +Go generate is never run automatically by go build, go get, go test, +and so on. It must be run explicitly. + +Go generate scans the file for directives, which are lines of +the form, + + //go:generate command argument... + +(note: no leading spaces and no space in "//go") where command +is the generator to be run, corresponding to an executable file +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. + +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. + +The arguments to the directive are space-separated tokens or +double-quoted strings passed to the generator as individual +arguments when it is run. + +Quoted strings use Go syntax and are evaluated before execution; a +quoted string appears as a single argument to the generator. + +To convey to humans and machine tools that code is generated, +generated source should have a line that matches the following +regular expression (in Go syntax): + + ^// Code generated .* DO NOT EDIT\.$ + +This line must appear before the first non-comment, non-blank +text in the file. + +Go generate sets several variables when it runs the generator: + + $GOARCH + The execution architecture (arm, amd64, etc.) + $GOOS + The execution operating system (linux, windows, etc.) + $GOFILE + The base name of the file. + $GOLINE + The line number of the directive in the source file. + $GOPACKAGE + The name of the package of the file containing the directive. + $DOLLAR + A dollar sign. + +Other than variable substitution and quoted-string evaluation, no +special processing such as "globbing" is performed on the command +line. + +As a last step before running the command, any invocations of any +environment variables with alphanumeric names, such as $GOFILE or +$HOME, are expanded throughout the command line. The syntax for +variable expansion is $NAME on all operating systems. Due to the +order of evaluation, variables are expanded even inside quoted +strings. If the variable NAME is not set, $NAME expands to the +empty string. + +A directive of the form, + + //go:generate -command xxx args... + +specifies, for the remainder of this source file only, that the +string xxx represents the command identified by the arguments. This +can be used to create aliases or to handle multiword generators. +For example, + + //go:generate -command foo go tool foo + +specifies that the command "foo" represents the generator +"go tool foo". + +Generate processes packages in the order given on the command line, +one at a time. If the command line lists .go files from a single directory, +they are treated as a single package. Within a package, generate processes the +source files in a package in file name order, one at a time. Within +a source file, generate runs generators in the order they appear +in the file, one at a time. The go generate tool also sets the build +tag "generate" so that files may be examined by go generate but ignored +during build. + +For packages with invalid code, generate processes only source files with a +valid package clause. + +If any generator returns an error exit status, "go generate" skips +all further processing for that package. + +The generator is run in the package's source directory. + +Go generate accepts one specific flag: + + -run="" + if non-empty, specifies a regular expression to select + directives whose full original source text (excluding + any trailing spaces and final newline) matches the + expression. + +It also accepts the standard build flags including -v, -n, and -x. +The -v flag prints the names of packages and files as they are +processed. +The -n flag prints commands that would be executed. +The -x flag prints commands as they are executed. + +For more about build flags, see 'go help build'. + +For more about specifying packages, see 'go help packages'. + `, +} + +var ( + generateRunFlag string // generate -run flag + generateRunRE *regexp.Regexp // compiled expression for -run +) + +func init() { + work.AddBuildFlags(CmdGenerate, work.DefaultBuildFlags) + CmdGenerate.Flag.StringVar(&generateRunFlag, "run", "", "") +} + +func runGenerate(ctx context.Context, cmd *base.Command, args []string) { + load.IgnoreImports = true + + if generateRunFlag != "" { + var err error + generateRunRE, err = regexp.Compile(generateRunFlag) + if err != nil { + log.Fatalf("generate: %s", err) + } + } + + cfg.BuildContext.BuildTags = append(cfg.BuildContext.BuildTags, "generate") + + // Even if the arguments are .go files, this loop suffices. + printed := false + for _, pkg := range load.PackagesAndErrors(ctx, args) { + if modload.Enabled() && pkg.Module != nil && !pkg.Module.Main { + if !printed { + fmt.Fprintf(os.Stderr, "go: not generating in packages in dependency modules\n") + printed = true + } + continue + } + + for _, file := range pkg.InternalGoFiles() { + if !generate(file) { + break + } + } + + for _, file := range pkg.InternalXGoFiles() { + if !generate(file) { + break + } + } + } +} + +// generate runs the generation directives for a single file. +func generate(absFile string) bool { + src, err := os.ReadFile(absFile) + if err != nil { + log.Fatalf("generate: %s", err) + } + + // Parse package clause + filePkg, err := parser.ParseFile(token.NewFileSet(), "", src, parser.PackageClauseOnly) + if err != nil { + // Invalid package clause - ignore file. + return true + } + + g := &Generator{ + r: bytes.NewReader(src), + path: absFile, + pkg: filePkg.Name.String(), + commands: make(map[string][]string), + } + return g.run() +} + +// A Generator represents the state of a single Go source file +// being scanned for generator commands. +type Generator struct { + r io.Reader + path string // full rooted path name. + dir string // full rooted directory of file. + file string // base name of file. + pkg string + commands map[string][]string + lineNum int // current line number. + env []string +} + +// run runs the generators in the current file. +func (g *Generator) run() (ok bool) { + // Processing below here calls g.errorf on failure, which does panic(stop). + // If we encounter an error, we abort the package. + defer func() { + e := recover() + if e != nil { + ok = false + if e != stop { + panic(e) + } + base.SetExitStatus(1) + } + }() + g.dir, g.file = filepath.Split(g.path) + g.dir = filepath.Clean(g.dir) // No final separator please. + if cfg.BuildV { + fmt.Fprintf(os.Stderr, "%s\n", base.ShortPath(g.path)) + } + + // Scan for lines that start "//go:generate". + // Can't use bufio.Scanner because it can't handle long lines, + // which are likely to appear when using generate. + input := bufio.NewReader(g.r) + var err error + // One line per loop. + for { + g.lineNum++ // 1-indexed. + var buf []byte + buf, err = input.ReadSlice('\n') + if err == bufio.ErrBufferFull { + // Line too long - consume and ignore. + if isGoGenerate(buf) { + g.errorf("directive too long") + } + for err == bufio.ErrBufferFull { + _, err = input.ReadSlice('\n') + } + if err != nil { + break + } + continue + } + + if err != nil { + // Check for marker at EOF without final \n. + if err == io.EOF && isGoGenerate(buf) { + err = io.ErrUnexpectedEOF + } + break + } + + if !isGoGenerate(buf) { + continue + } + if generateRunFlag != "" { + if !generateRunRE.Match(bytes.TrimSpace(buf)) { + continue + } + } + + g.setEnv() + words := g.split(string(buf)) + if len(words) == 0 { + g.errorf("no arguments to directive") + } + if words[0] == "-command" { + g.setShorthand(words) + continue + } + // Run the command line. + if cfg.BuildN || cfg.BuildX { + fmt.Fprintf(os.Stderr, "%s\n", strings.Join(words, " ")) + } + if cfg.BuildN { + continue + } + g.exec(words) + } + if err != nil && err != io.EOF { + g.errorf("error reading %s: %s", base.ShortPath(g.path), err) + } + return true +} + +func isGoGenerate(buf []byte) bool { + return bytes.HasPrefix(buf, []byte("//go:generate ")) || bytes.HasPrefix(buf, []byte("//go:generate\t")) +} + +// setEnv sets the extra environment variables used when executing a +// single go:generate command. +func (g *Generator) setEnv() { + g.env = []string{ + "GOARCH=" + cfg.BuildContext.GOARCH, + "GOOS=" + cfg.BuildContext.GOOS, + "GOFILE=" + g.file, + "GOLINE=" + strconv.Itoa(g.lineNum), + "GOPACKAGE=" + g.pkg, + "DOLLAR=" + "$", + } +} + +// split breaks the line into words, evaluating quoted +// strings and evaluating environment variables. +// The initial //go:generate element is present in line. +func (g *Generator) split(line string) []string { + // Parse line, obeying quoted strings. + var words []string + line = line[len("//go:generate ") : len(line)-1] // Drop preamble and final newline. + // There may still be a carriage return. + if len(line) > 0 && line[len(line)-1] == '\r' { + line = line[:len(line)-1] + } + // One (possibly quoted) word per iteration. +Words: + for { + line = strings.TrimLeft(line, " \t") + if len(line) == 0 { + break + } + if line[0] == '"' { + for i := 1; i < len(line); i++ { + c := line[i] // Only looking for ASCII so this is OK. + switch c { + case '\\': + if i+1 == len(line) { + g.errorf("bad backslash") + } + i++ // Absorb next byte (If it's a multibyte we'll get an error in Unquote). + case '"': + word, err := strconv.Unquote(line[0 : i+1]) + if err != nil { + g.errorf("bad quoted string") + } + words = append(words, word) + line = line[i+1:] + // Check the next character is space or end of line. + if len(line) > 0 && line[0] != ' ' && line[0] != '\t' { + g.errorf("expect space after quoted argument") + } + continue Words + } + } + g.errorf("mismatched quoted string") + } + i := strings.IndexAny(line, " \t") + if i < 0 { + i = len(line) + } + words = append(words, line[0:i]) + line = line[i:] + } + // Substitute command if required. + if len(words) > 0 && g.commands[words[0]] != nil { + // Replace 0th word by command substitution. + // + // Force a copy of the command definition to + // ensure words doesn't end up as a reference + // to the g.commands content. + tmpCmdWords := append([]string(nil), (g.commands[words[0]])...) + words = append(tmpCmdWords, words[1:]...) + } + // Substitute environment variables. + for i, word := range words { + words[i] = os.Expand(word, g.expandVar) + } + return words +} + +var stop = fmt.Errorf("error in generation") + +// errorf logs an error message prefixed with the file and line number. +// It then exits the program (with exit status 1) because generation stops +// at the first error. +func (g *Generator) errorf(format string, args ...interface{}) { + fmt.Fprintf(os.Stderr, "%s:%d: %s\n", base.ShortPath(g.path), g.lineNum, + fmt.Sprintf(format, args...)) + panic(stop) +} + +// expandVar expands the $XXX invocation in word. It is called +// by os.Expand. +func (g *Generator) expandVar(word string) string { + w := word + "=" + for _, e := range g.env { + if strings.HasPrefix(e, w) { + return e[len(w):] + } + } + return os.Getenv(word) +} + +// setShorthand installs a new shorthand as defined by a -command directive. +func (g *Generator) setShorthand(words []string) { + // Create command shorthand. + if len(words) == 1 { + g.errorf("no command specified for -command") + } + command := words[1] + if g.commands[command] != nil { + g.errorf("command %q multiply defined", command) + } + g.commands[command] = words[2:len(words):len(words)] // force later append to make copy +} + +// exec runs the command specified by the argument. The first word is +// the command name itself. +func (g *Generator) exec(words []string) { + cmd := exec.Command(words[0], words[1:]...) + // Standard in and out of generator should be the usual. + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + // Run the command in the package directory. + cmd.Dir = g.dir + cmd.Env = str.StringList(cfg.OrigEnv, g.env) + err := cmd.Run() + if err != nil { + g.errorf("running %q: %s", words[0], err) + } +} diff --git a/src/cmd/go/internal/generate/generate_test.go b/src/cmd/go/internal/generate/generate_test.go new file mode 100644 index 0000000..b546218 --- /dev/null +++ b/src/cmd/go/internal/generate/generate_test.go @@ -0,0 +1,254 @@ +// Copyright 2011 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 generate + +import ( + "os" + "reflect" + "runtime" + "testing" +) + +type splitTest struct { + in string + out []string +} + +// Same as above, except including source line number to set +type splitTestWithLine struct { + in string + out []string + lineNumber int +} + +const anyLineNo = 0 + +var splitTests = []splitTest{ + {"", nil}, + {"x", []string{"x"}}, + {" a b\tc ", []string{"a", "b", "c"}}, + {` " a " `, []string{" a "}}, + {"$GOARCH", []string{runtime.GOARCH}}, + {"$GOOS", []string{runtime.GOOS}}, + {"$GOFILE", []string{"proc.go"}}, + {"$GOPACKAGE", []string{"sys"}}, + {"a $XXNOTDEFINEDXX b", []string{"a", "", "b"}}, + {"/$XXNOTDEFINED/", []string{"//"}}, + {"/$DOLLAR/", []string{"/$/"}}, + {"yacc -o $GOARCH/yacc_$GOFILE", []string{"go", "tool", "yacc", "-o", runtime.GOARCH + "/yacc_proc.go"}}, +} + +func TestGenerateCommandParse(t *testing.T) { + g := &Generator{ + r: nil, // Unused here. + path: "/usr/ken/sys/proc.go", + dir: "/usr/ken/sys", + file: "proc.go", + pkg: "sys", + commands: make(map[string][]string), + } + g.setEnv() + g.setShorthand([]string{"-command", "yacc", "go", "tool", "yacc"}) + for _, test := range splitTests { + // First with newlines. + got := g.split("//go:generate " + test.in + "\n") + if !reflect.DeepEqual(got, test.out) { + t.Errorf("split(%q): got %q expected %q", test.in, got, test.out) + } + // Then with CRLFs, thank you Windows. + got = g.split("//go:generate " + test.in + "\r\n") + if !reflect.DeepEqual(got, test.out) { + t.Errorf("split(%q): got %q expected %q", test.in, got, test.out) + } + } +} + +// These environment variables will be undefined before the splitTestWithLine tests +var undefEnvList = []string{ + "_XYZZY_", +} + +// These environment variables will be defined before the splitTestWithLine tests +var defEnvMap = map[string]string{ + "_PLUGH_": "SomeVal", + "_X": "Y", +} + +// TestGenerateCommandShortHand - similar to TestGenerateCommandParse, +// except: +// 1. if the result starts with -command, record that shorthand +// before moving on to the next test. +// 2. If a source line number is specified, set that in the parser +// before executing the test. i.e., execute the split as if it +// processing that source line. +func TestGenerateCommandShorthand(t *testing.T) { + g := &Generator{ + r: nil, // Unused here. + path: "/usr/ken/sys/proc.go", + dir: "/usr/ken/sys", + file: "proc.go", + pkg: "sys", + commands: make(map[string][]string), + } + + var inLine string + var expected, got []string + + g.setEnv() + + // Set up the system environment variables + for i := range undefEnvList { + os.Unsetenv(undefEnvList[i]) + } + for k := range defEnvMap { + os.Setenv(k, defEnvMap[k]) + } + + // simple command from environment variable + inLine = "//go:generate -command CMD0 \"ab${_X}cd\"" + expected = []string{"-command", "CMD0", "abYcd"} + got = g.split(inLine + "\n") + + if !reflect.DeepEqual(got, expected) { + t.Errorf("split(%q): got %q expected %q", inLine, got, expected) + } + + // try again, with an extra level of indirection (should leave variable in command) + inLine = "//go:generate -command CMD0 \"ab${DOLLAR}{_X}cd\"" + expected = []string{"-command", "CMD0", "ab${_X}cd"} + got = g.split(inLine + "\n") + + if !reflect.DeepEqual(got, expected) { + t.Errorf("split(%q): got %q expected %q", inLine, got, expected) + } + + // Now the interesting part, record that output as a command + g.setShorthand(got) + + // see that the command still substitutes correctly from env. variable + inLine = "//go:generate CMD0" + expected = []string{"abYcd"} + got = g.split(inLine + "\n") + + if !reflect.DeepEqual(got, expected) { + t.Errorf("split(%q): got %q expected %q", inLine, got, expected) + } + + // Now change the value of $X and see if the recorded definition is + // still intact (vs. having the $_X already substituted out) + + os.Setenv("_X", "Z") + inLine = "//go:generate CMD0" + expected = []string{"abZcd"} + got = g.split(inLine + "\n") + + if !reflect.DeepEqual(got, expected) { + t.Errorf("split(%q): got %q expected %q", inLine, got, expected) + } + + // What if the variable is now undefined? Should be empty substitution. + + os.Unsetenv("_X") + inLine = "//go:generate CMD0" + expected = []string{"abcd"} + got = g.split(inLine + "\n") + + if !reflect.DeepEqual(got, expected) { + t.Errorf("split(%q): got %q expected %q", inLine, got, expected) + } + + // Try another undefined variable as an extra check + os.Unsetenv("_Z") + inLine = "//go:generate -command CMD1 \"ab${_Z}cd\"" + expected = []string{"-command", "CMD1", "abcd"} + got = g.split(inLine + "\n") + + if !reflect.DeepEqual(got, expected) { + t.Errorf("split(%q): got %q expected %q", inLine, got, expected) + } + + g.setShorthand(got) + + inLine = "//go:generate CMD1" + expected = []string{"abcd"} + got = g.split(inLine + "\n") + + if !reflect.DeepEqual(got, expected) { + t.Errorf("split(%q): got %q expected %q", inLine, got, expected) + } + + const val = "someNewValue" + os.Setenv("_Z", val) + + // try again with the properly-escaped variable. + + inLine = "//go:generate -command CMD2 \"ab${DOLLAR}{_Z}cd\"" + expected = []string{"-command", "CMD2", "ab${_Z}cd"} + got = g.split(inLine + "\n") + + if !reflect.DeepEqual(got, expected) { + t.Errorf("split(%q): got %q expected %q", inLine, got, expected) + } + + g.setShorthand(got) + + inLine = "//go:generate CMD2" + expected = []string{"ab" + val + "cd"} + got = g.split(inLine + "\n") + + if !reflect.DeepEqual(got, expected) { + t.Errorf("split(%q): got %q expected %q", inLine, got, expected) + } +} + +// Command-related tests for TestGenerateCommandShortHand2 +// -- Note line numbers included to check substitutions from "build-in" variable - $GOLINE +var splitTestsLines = []splitTestWithLine{ + {"-command TEST1 $GOLINE", []string{"-command", "TEST1", "22"}, 22}, + {"-command TEST2 ${DOLLAR}GOLINE", []string{"-command", "TEST2", "$GOLINE"}, 26}, + {"TEST1", []string{"22"}, 33}, + {"TEST2", []string{"66"}, 66}, + {"TEST1 ''", []string{"22", "''"}, 99}, + {"TEST2 ''", []string{"44", "''"}, 44}, +} + +// TestGenerateCommandShortHand - similar to TestGenerateCommandParse, +// except: +// 1. if the result starts with -command, record that shorthand +// before moving on to the next test. +// 2. If a source line number is specified, set that in the parser +// before executing the test. i.e., execute the split as if it +// processing that source line. +func TestGenerateCommandShortHand2(t *testing.T) { + g := &Generator{ + r: nil, // Unused here. + path: "/usr/ken/sys/proc.go", + dir: "/usr/ken/sys", + file: "proc.go", + pkg: "sys", + commands: make(map[string][]string), + } + g.setEnv() + for _, test := range splitTestsLines { + // if the test specified a line number, reflect that + if test.lineNumber != anyLineNo { + g.lineNum = test.lineNumber + g.setEnv() + } + // First with newlines. + got := g.split("//go:generate " + test.in + "\n") + if !reflect.DeepEqual(got, test.out) { + t.Errorf("split(%q): got %q expected %q", test.in, got, test.out) + } + // Then with CRLFs, thank you Windows. + got = g.split("//go:generate " + test.in + "\r\n") + if !reflect.DeepEqual(got, test.out) { + t.Errorf("split(%q): got %q expected %q", test.in, got, test.out) + } + if got[0] == "-command" { // record commands + g.setShorthand(got) + } + } +} diff --git a/src/cmd/go/internal/get/get.go b/src/cmd/go/internal/get/get.go new file mode 100644 index 0000000..329a2f5 --- /dev/null +++ b/src/cmd/go/internal/get/get.go @@ -0,0 +1,621 @@ +// Copyright 2011 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 get implements the ``go get'' command. +package get + +import ( + "context" + "fmt" + "os" + "path/filepath" + "runtime" + "strings" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/load" + "cmd/go/internal/search" + "cmd/go/internal/str" + "cmd/go/internal/vcs" + "cmd/go/internal/web" + "cmd/go/internal/work" + + "golang.org/x/mod/module" +) + +var CmdGet = &base.Command{ + 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 +dependencies. It then installs the named packages, like 'go install'. + +The -d flag instructs get to stop after downloading the packages; that is, +it instructs get not to install the packages. + +The -f flag, valid only when -u is set, forces get -u not to verify that +each package has been checked out from the source control repository +implied by its import path. This can be useful if the source is a local fork +of the original. + +The -fix flag instructs get to run the fix tool on the downloaded packages +before resolving dependencies or building the code. + +The -insecure flag permits fetching from repositories and resolving +custom domains using insecure schemes such as HTTP. Use with caution. +This flag is deprecated and will be removed in a future version of go. +The GOINSECURE environment variable should be used instead, since it +provides control over which packages may be retrieved using an insecure +scheme. See 'go help environment' for details. + +The -t flag instructs get to also download the packages required to build +the tests for the specified packages. + +The -u flag instructs get to use the network to update the named packages +and their dependencies. By default, get uses the network to check out +missing packages but does not use it to look for updates to existing packages. + +The -v flag enables verbose progress and debug output. + +Get also accepts build flags to control the installation. See 'go help build'. + +When checking out a new package, get creates the target directory +GOPATH/src/. If the GOPATH contains multiple entries, +get uses the first one. For more details see: 'go help gopath'. + +When checking out or updating a package, get looks for a branch or tag +that matches the locally installed version of Go. The most important +rule is that if the local installation is running version "go1", get +searches for a branch or tag named "go1". If no such version exists +it retrieves the default branch of the package. + +When go get checks out or updates a Git repository, +it also updates any git submodules referenced by the repository. + +Get never checks out or updates code stored in vendor directories. + +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 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, "") +) + +func init() { + work.AddBuildFlags(CmdGet, work.OmitModFlag|work.OmitModCommonFlags) + CmdGet.Run = runGet // break init loop + CmdGet.Flag.BoolVar(&cfg.Insecure, "insecure", cfg.Insecure, "") +} + +func runGet(ctx context.Context, 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") + } + + work.BuildInit() + + if *getF && !*getU { + base.Fatalf("go get: cannot use -f flag without -u") + } + if cfg.Insecure { + fmt.Fprintf(os.Stderr, "go get: -insecure flag is deprecated; see 'go help get' for details\n") + } + + // 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") + } + + // Phase 1. Download/update. + var stk load.ImportStack + mode := 0 + if *getT { + mode |= load.GetTestDeps + } + for _, pkg := range downloadPaths(args) { + download(pkg, nil, &stk, mode) + } + base.ExitIfErrors() + + // Phase 2. Rescan packages and re-evaluate args list. + + // Code we downloaded and all code that depends on it + // needs to be evicted from the package cache so that + // the information will be recomputed. Instead of keeping + // track of the reverse dependency information, evict + // everything. + load.ClearPackageCache() + + pkgs := load.PackagesAndErrors(ctx, args) + load.CheckPackageErrors(pkgs) + + // Phase 3. Install. + if *getD { + // Download only. + // Check delayed until now so that downloadPaths + // and CheckPackageErrors have a chance to print errors. + return + } + + work.InstallPackages(ctx, args, pkgs) +} + +// downloadPaths prepares the list of paths to pass to download. +// It expands ... patterns that can be expanded. If there is no match +// 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(patterns []string) []string { + for _, arg := range patterns { + if strings.Contains(arg, "@") { + base.Fatalf("go: can only use path@version syntax with 'go get' and 'go install' in module-aware mode") + continue + } + + // Guard against 'go get x.go', a common mistake. + // Note that package and module paths may end with '.go', so only print an error + // if the argument has no slash or refers to an existing file. + if strings.HasSuffix(arg, ".go") { + if !strings.Contains(arg, "/") { + base.Errorf("go get %s: arguments must be package or module paths", arg) + continue + } + if fi, err := os.Stat(arg); err == nil && !fi.IsDir() { + base.Errorf("go get: %s exists as a file, but 'go get' requires package arguments", arg) + } + } + } + base.ExitIfErrors() + + 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...) + } + } + return pkgs +} + +// downloadCache records the import paths we have already +// considered during the download, to avoid duplicate work when +// there is more than one dependency sequence leading to +// a particular package. +var downloadCache = map[string]bool{} + +// downloadRootCache records the version control repository +// root directories we have already considered during the download. +// For example, all the packages in the github.com/google/codesearch repo +// share the same root (the directory for that path), and we only need +// to run the hg commands to consider each repository once. +var downloadRootCache = map[string]bool{} + +// download runs the download half of the get command +// for the package or pattern named by the argument. +func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) { + if mode&load.ResolveImport != 0 { + // Caller is responsible for expanding vendor paths. + panic("internal error: download mode has useVendor set") + } + load1 := func(path string, mode int) *load.Package { + if parent == nil { + mode := 0 // don't do module or vendor resolution + return load.LoadImport(context.TODO(), path, base.Cwd, nil, stk, nil, mode) + } + return load.LoadImport(context.TODO(), path, parent.Dir, parent, stk, nil, mode|load.ResolveModule) + } + + p := load1(arg, mode) + if p.Error != nil && p.Error.Hard { + base.Errorf("%s", p.Error) + return + } + + // loadPackage inferred the canonical ImportPath from arg. + // Use that in the following to prevent hysteresis effects + // in e.g. downloadCache and packageCache. + // This allows invocations such as: + // mkdir -p $GOPATH/src/github.com/user + // cd $GOPATH/src/github.com/user + // go get ./foo + // see: golang.org/issue/9767 + arg = p.ImportPath + + // There's nothing to do if this is a package in the standard library. + if p.Standard { + return + } + + // Only process each package once. + // (Unless we're fetching test dependencies for this package, + // in which case we want to process it again.) + if downloadCache[arg] && mode&load.GetTestDeps == 0 { + return + } + downloadCache[arg] = true + + pkgs := []*load.Package{p} + wildcardOkay := len(*stk) == 0 + isWildcard := false + + // Download if the package is missing, or update if we're using -u. + if p.Dir == "" || *getU { + // The actual download. + stk.Push(arg) + err := downloadPackage(p) + if err != nil { + base.Errorf("%s", &load.PackageError{ImportStack: stk.Copy(), Err: err}) + stk.Pop() + return + } + stk.Pop() + + args := []string{arg} + // If the argument has a wildcard in it, re-evaluate the wildcard. + // We delay this until after reloadPackage so that the old entry + // for p has been replaced in the package cache. + if wildcardOkay && strings.Contains(arg, "...") { + match := search.NewMatch(arg) + if match.IsLocal() { + match.MatchDirs() + args = match.Dirs + } else { + match.MatchPackages() + args = match.Pkgs + } + for _, err := range match.Errs { + base.Errorf("%s", err) + } + isWildcard = true + } + + // Clear all relevant package cache entries before + // doing any new loads. + load.ClearPackageCachePartial(args) + + pkgs = pkgs[:0] + for _, arg := range args { + // Note: load calls loadPackage or loadImport, + // which push arg onto stk already. + // Do not push here too, or else stk will say arg imports arg. + p := load1(arg, mode) + if p.Error != nil { + base.Errorf("%s", p.Error) + continue + } + pkgs = append(pkgs, p) + } + } + + // Process package, which might now be multiple packages + // due to wildcard expansion. + for _, p := range pkgs { + if *getFix { + files := base.RelPaths(p.InternalAllGoFiles()) + base.Run(cfg.BuildToolexec, str.StringList(base.Tool("fix"), files)) + + // The imports might have changed, so reload again. + p = load.ReloadPackageNoFlags(arg, stk) + if p.Error != nil { + base.Errorf("%s", p.Error) + return + } + } + + if isWildcard { + // Report both the real package and the + // wildcard in any error message. + stk.Push(p.ImportPath) + } + + // Process dependencies, now that we know what they are. + imports := p.Imports + if mode&load.GetTestDeps != 0 { + // Process test dependencies when -t is specified. + // (But don't get test dependencies for test dependencies: + // we always pass mode 0 to the recursive calls below.) + imports = str.StringList(imports, p.TestImports, p.XTestImports) + } + for i, path := range imports { + if path == "C" { + continue + } + // Fail fast on import naming full vendor path. + // Otherwise expand path as needed for test imports. + // Note that p.Imports can have additional entries beyond p.Internal.Build.Imports. + orig := path + if i < len(p.Internal.Build.Imports) { + orig = p.Internal.Build.Imports[i] + } + if j, ok := load.FindVendor(orig); ok { + stk.Push(path) + err := &load.PackageError{ + ImportStack: stk.Copy(), + Err: load.ImportErrorf(path, "%s must be imported as %s", path, path[j+len("vendor/"):]), + } + stk.Pop() + base.Errorf("%s", err) + continue + } + // If this is a test import, apply module and vendor lookup now. + // We cannot pass ResolveImport to download, because + // download does caching based on the value of path, + // so it must be the fully qualified path already. + if i >= len(p.Imports) { + path = load.ResolveImportPath(p, path) + } + download(path, p, stk, 0) + } + + if isWildcard { + stk.Pop() + } + } +} + +// downloadPackage runs the create or download command +// to make the first copy of or update a copy of the given package. +func downloadPackage(p *load.Package) error { + var ( + vcsCmd *vcs.Cmd + repo, rootPath string + err error + blindRepo bool // set if the repo has unusual configuration + ) + + // p can be either a real package, or a pseudo-package whose “import path” is + // actually a wildcard pattern. + // Trim the path at the element containing the first wildcard, + // and hope that it applies to the wildcarded parts too. + // This makes 'go get rsc.io/pdf/...' work in a fresh GOPATH. + importPrefix := p.ImportPath + if i := strings.Index(importPrefix, "..."); i >= 0 { + slash := strings.LastIndexByte(importPrefix[:i], '/') + if slash < 0 { + return fmt.Errorf("cannot expand ... in %q", p.ImportPath) + } + importPrefix = importPrefix[:slash] + } + if err := checkImportPath(importPrefix); err != nil { + return fmt.Errorf("%s: invalid import path: %v", p.ImportPath, err) + } + security := web.SecureOnly + if cfg.Insecure || module.MatchPrefixPatterns(cfg.GOINSECURE, importPrefix) { + security = web.Insecure + } + + if p.Internal.Build.SrcRoot != "" { + // Directory exists. Look for checkout along path to src. + vcsCmd, rootPath, err = vcs.FromDir(p.Dir, p.Internal.Build.SrcRoot) + if err != nil { + return err + } + repo = "" // should be unused; make distinctive + + // Double-check where it came from. + if *getU && vcsCmd.RemoteRepo != nil { + dir := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath)) + remote, err := vcsCmd.RemoteRepo(vcsCmd, dir) + if err != nil { + // 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 && err == nil { + if rr, err := vcs.RepoRootForImportPath(importPrefix, vcs.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) + } + } + } + } + } else { + // Analyze the import path to determine the version control system, + // repository, and the import path for the root of the repository. + rr, err := vcs.RepoRootForImportPath(importPrefix, vcs.IgnoreMod, security) + if err != nil { + return err + } + vcsCmd, repo, rootPath = rr.VCS, rr.Repo, rr.Root + } + if !blindRepo && !vcsCmd.IsSecure(repo) && security != web.Insecure { + return fmt.Errorf("cannot download, %v uses insecure protocol", repo) + } + + if p.Internal.Build.SrcRoot == "" { + // Package not found. Put in first directory of $GOPATH. + list := filepath.SplitList(cfg.BuildContext.GOPATH) + if len(list) == 0 { + return fmt.Errorf("cannot download, $GOPATH not set. For more details see: 'go help gopath'") + } + // Guard against people setting GOPATH=$GOROOT. + if filepath.Clean(list[0]) == filepath.Clean(cfg.GOROOT) { + return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: 'go help gopath'") + } + if _, err := os.Stat(filepath.Join(list[0], "src/cmd/go/alldocs.go")); err == nil { + return fmt.Errorf("cannot download, %s is a GOROOT, not a GOPATH. For more details see: 'go help gopath'", list[0]) + } + p.Internal.Build.Root = list[0] + p.Internal.Build.SrcRoot = filepath.Join(list[0], "src") + p.Internal.Build.PkgRoot = filepath.Join(list[0], "pkg") + } + root := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath)) + + if err := vcs.CheckNested(vcsCmd, root, p.Internal.Build.SrcRoot); err != nil { + return err + } + + // If we've considered this repository already, don't do it again. + if downloadRootCache[root] { + return nil + } + downloadRootCache[root] = true + + if cfg.BuildV { + fmt.Fprintf(os.Stderr, "%s (download)\n", rootPath) + } + + // Check that this is an appropriate place for the repo to be checked out. + // The target directory must either not exist or have a repo checked out already. + meta := filepath.Join(root, "."+vcsCmd.Cmd) + if _, err := os.Stat(meta); err != nil { + // Metadata file or directory does not exist. Prepare to checkout new copy. + // Some version control tools require the target directory not to exist. + // We require that too, just to avoid stepping on existing work. + if _, err := os.Stat(root); err == nil { + return fmt.Errorf("%s exists but %s does not - stale checkout?", root, meta) + } + + _, err := os.Stat(p.Internal.Build.Root) + gopathExisted := err == nil + + // Some version control tools require the parent of the target to exist. + parent, _ := filepath.Split(root) + if err = os.MkdirAll(parent, 0777); err != nil { + return err + } + if cfg.BuildV && !gopathExisted && p.Internal.Build.Root == cfg.BuildContext.GOPATH { + fmt.Fprintf(os.Stderr, "created GOPATH=%s; see 'go help gopath'\n", p.Internal.Build.Root) + } + + if err = vcsCmd.Create(root, repo); err != nil { + return err + } + } else { + // Metadata directory does exist; download incremental updates. + if err = vcsCmd.Download(root); err != nil { + return err + } + } + + if cfg.BuildN { + // Do not show tag sync in -n; it's noise more than anything, + // and since we're not running commands, no tag will be found. + // But avoid printing nothing. + fmt.Fprintf(os.Stderr, "# cd %s; %s sync/update\n", root, vcsCmd.Cmd) + return nil + } + + // Select and sync to appropriate version of the repository. + tags, err := vcsCmd.Tags(root) + if err != nil { + return err + } + vers := runtime.Version() + if i := strings.Index(vers, " "); i >= 0 { + vers = vers[:i] + } + if err := vcsCmd.TagSync(root, selectTag(vers, tags)); err != nil { + return err + } + + return nil +} + +// selectTag returns the closest matching tag for a given version. +// Closest means the latest one that is not after the current release. +// Version "goX" (or "goX.Y" or "goX.Y.Z") matches tags of the same form. +// Version "release.rN" matches tags of the form "go.rN" (N being a floating-point number). +// Version "weekly.YYYY-MM-DD" matches tags like "go.weekly.YYYY-MM-DD". +// +// NOTE(rsc): Eventually we will need to decide on some logic here. +// For now, there is only "go1". This matches the docs in go help get. +func selectTag(goVersion string, tags []string) (match string) { + for _, t := range tags { + if t == "go1" { + return "go1" + } + } + return "" +} + +// checkImportPath is like module.CheckImportPath, but it forbids leading dots +// in path elements. This can lead to 'go get' creating .git and other VCS +// directories in places we might run VCS tools later. +func checkImportPath(path string) error { + if err := module.CheckImportPath(path); err != nil { + return err + } + checkElem := func(elem string) error { + if elem[0] == '.' { + return fmt.Errorf("malformed import path %q: leading dot in path element", path) + } + return nil + } + elemStart := 0 + for i, r := range path { + if r == '/' { + if err := checkElem(path[elemStart:]); err != nil { + return err + } + elemStart = i + 1 + } + } + if err := checkElem(path[elemStart:]); err != nil { + return err + } + return nil +} diff --git a/src/cmd/go/internal/get/tag_test.go b/src/cmd/go/internal/get/tag_test.go new file mode 100644 index 0000000..9a25dfa --- /dev/null +++ b/src/cmd/go/internal/get/tag_test.go @@ -0,0 +1,100 @@ +// Copyright 2011 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 get + +import "testing" + +var selectTagTestTags = []string{ + "go.r58", + "go.r58.1", + "go.r59", + "go.r59.1", + "go.r61", + "go.r61.1", + "go.weekly.2010-01-02", + "go.weekly.2011-10-12", + "go.weekly.2011-10-12.1", + "go.weekly.2011-10-14", + "go.weekly.2011-11-01", + "go1", + "go1.0.1", + "go1.999", + "go1.9.2", + "go5", + + // these should be ignored: + "release.r59", + "release.r59.1", + "release", + "weekly.2011-10-12", + "weekly.2011-10-12.1", + "weekly", + "foo", + "bar", + "go.f00", + "go!r60", + "go.1999-01-01", + "go.2x", + "go.20000000000000", + "go.2.", + "go.2.0", + "go2x", + "go20000000000000", + "go2.", + "go2.0", +} + +var selectTagTests = []struct { + version string + selected string +}{ + /* + {"release.r57", ""}, + {"release.r58.2", "go.r58.1"}, + {"release.r59", "go.r59"}, + {"release.r59.1", "go.r59.1"}, + {"release.r60", "go.r59.1"}, + {"release.r60.1", "go.r59.1"}, + {"release.r61", "go.r61"}, + {"release.r66", "go.r61.1"}, + {"weekly.2010-01-01", ""}, + {"weekly.2010-01-02", "go.weekly.2010-01-02"}, + {"weekly.2010-01-02.1", "go.weekly.2010-01-02"}, + {"weekly.2010-01-03", "go.weekly.2010-01-02"}, + {"weekly.2011-10-12", "go.weekly.2011-10-12"}, + {"weekly.2011-10-12.1", "go.weekly.2011-10-12.1"}, + {"weekly.2011-10-13", "go.weekly.2011-10-12.1"}, + {"weekly.2011-10-14", "go.weekly.2011-10-14"}, + {"weekly.2011-10-14.1", "go.weekly.2011-10-14"}, + {"weekly.2011-11-01", "go.weekly.2011-11-01"}, + {"weekly.2014-01-01", "go.weekly.2011-11-01"}, + {"weekly.3000-01-01", "go.weekly.2011-11-01"}, + {"go1", "go1"}, + {"go1.1", "go1.0.1"}, + {"go1.998", "go1.9.2"}, + {"go1.1000", "go1.999"}, + {"go6", "go5"}, + + // faulty versions: + {"release.f00", ""}, + {"weekly.1999-01-01", ""}, + {"junk", ""}, + {"", ""}, + {"go2x", ""}, + {"go200000000000", ""}, + {"go2.", ""}, + {"go2.0", ""}, + */ + {"anything", "go1"}, +} + +func TestSelectTag(t *testing.T) { + for _, c := range selectTagTests { + selected := selectTag(c.version, selectTagTestTags) + if selected != c.selected { + t.Errorf("selectTag(%q) = %q, want %q", c.version, selected, c.selected) + } + } +} diff --git a/src/cmd/go/internal/help/help.go b/src/cmd/go/internal/help/help.go new file mode 100644 index 0000000..7a730fc --- /dev/null +++ b/src/cmd/go/internal/help/help.go @@ -0,0 +1,196 @@ +// 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 help implements the ``go help'' command. +package help + +import ( + "bufio" + "bytes" + "fmt" + "io" + "os" + "strings" + "text/template" + "unicode" + "unicode/utf8" + + "cmd/go/internal/base" + "cmd/go/internal/modload" +) + +// Help implements the 'help' command. +func Help(w io.Writer, args []string) { + // 'go help documentation' generates doc.go. + if len(args) == 1 && args[0] == "documentation" { + fmt.Fprintln(w, "// Copyright 2011 The Go Authors. All rights reserved.") + fmt.Fprintln(w, "// Use of this source code is governed by a BSD-style") + fmt.Fprintln(w, "// license that can be found in the LICENSE file.") + fmt.Fprintln(w) + fmt.Fprintln(w, "// Code generated by mkalldocs.sh; DO NOT EDIT.") + fmt.Fprintln(w, "// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.") + fmt.Fprintln(w) + buf := new(bytes.Buffer) + PrintUsage(buf, base.Go) + usage := &base.Command{Long: buf.String()} + cmds := []*base.Command{usage} + for _, cmd := range base.Go.Commands { + // Avoid duplication of the "get" documentation. + if cmd.UsageLine == "module-get" && modload.Enabled() { + continue + } else if cmd.UsageLine == "gopath-get" && !modload.Enabled() { + continue + } + cmds = append(cmds, cmd) + cmds = append(cmds, cmd.Commands...) + } + tmpl(&commentWriter{W: w}, documentationTemplate, cmds) + fmt.Fprintln(w, "package main") + 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) + base.SetExitStatus(2) // failed at 'go help cmd' + base.Exit() + } + + 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 = `{{.Long | trim}} + +Usage: + + {{.UsageLine}} [arguments] + +The commands are: +{{range .Commands}}{{if or (.Runnable) .Commands}} + {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}} + +Use "go help{{with .LongName}} {{.}}{{end}} " for more information about a command. +{{if eq (.UsageLine) "go"}} +Additional help topics: +{{range .Commands}}{{if and (not .Runnable) (not .Commands)}} + {{.Name | printf "%-15s"}} {{.Short}}{{end}}{{end}} + +Use "go help{{with .LongName}} {{.}}{{end}} " for more information about that topic. +{{end}} +` + +var helpTemplate = `{{if .Runnable}}usage: {{.UsageLine}} + +{{end}}{{.Long | trim}} +` + +var documentationTemplate = `{{range .}}{{if .Short}}{{.Short | capitalize}} + +{{end}}{{if .Commands}}` + usageTemplate + `{{else}}{{if .Runnable}}Usage: + + {{.UsageLine}} + +{{end}}{{.Long | trim}} + + +{{end}}{{end}}` + +// commentWriter writes a Go comment to the underlying io.Writer, +// using line comment form (//). +type commentWriter struct { + W io.Writer + wroteSlashes bool // Wrote "//" at the beginning of the current line. +} + +func (c *commentWriter) Write(p []byte) (int, error) { + var n int + for i, b := range p { + if !c.wroteSlashes { + s := "//" + if b != '\n' { + s = "// " + } + if _, err := io.WriteString(c.W, s); err != nil { + return n, err + } + c.wroteSlashes = true + } + n0, err := c.W.Write(p[i : i+1]) + n += n0 + if err != nil { + return n, err + } + if b == '\n' { + c.wroteSlashes = false + } + } + return len(p), nil +} + +// An errWriter wraps a writer, recording whether a write error occurred. +type errWriter struct { + w io.Writer + err error +} + +func (w *errWriter) Write(b []byte) (int, error) { + n, err := w.w.Write(b) + if err != nil { + w.err = err + } + return n, err +} + +// tmpl executes the given template text on data, writing the result to w. +func tmpl(w io.Writer, text string, data interface{}) { + t := template.New("top") + t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize}) + template.Must(t.Parse(text)) + ew := &errWriter{w: w} + err := t.Execute(ew, data) + if ew.err != nil { + // I/O error writing. Ignore write on closed pipe. + if strings.Contains(ew.err.Error(), "pipe") { + base.SetExitStatus(1) + base.Exit() + } + base.Fatalf("writing output: %v", ew.err) + } + if err != nil { + panic(err) + } +} + +func capitalize(s string) string { + if s == "" { + return s + } + r, n := utf8.DecodeRuneInString(s) + return string(unicode.ToTitle(r)) + s[n:] +} + +func PrintUsage(w io.Writer, cmd *base.Command) { + bw := bufio.NewWriter(w) + tmpl(bw, usageTemplate, cmd) + bw.Flush() +} diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go new file mode 100644 index 0000000..57cee4f --- /dev/null +++ b/src/cmd/go/internal/help/helpdoc.go @@ -0,0 +1,875 @@ +// Copyright 2011 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 help + +import "cmd/go/internal/base" + +var HelpC = &base.Command{ + UsageLine: "c", + Short: "calling between Go and C", + Long: ` +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, .S +or .sx 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. + `, +} + +var HelpPackages = &base.Command{ + UsageLine: "packages", + Short: "package lists and patterns", + Long: ` +Many commands apply to a set of packages: + + go action [packages] + +Usually, [packages] is a list of import paths. + +An import path that is a rooted path or that begins with +a . or .. element is interpreted as a file system path and +denotes the package in that directory. + +Otherwise, the import path P denotes the package found in +the directory DIR/src/P for some DIR listed in the GOPATH +environment variable (For more details see: 'go help gopath'). + +If no import paths are given, the action applies to the +package in the current directory. + +There are four reserved names for paths that should not be used +for packages to be built with the go tool: + +- "main" denotes the top-level package in a stand-alone executable. + +- "all" expands to all packages found in all the GOPATH +trees. For example, 'go list all' lists all the packages on the local +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. + +- "cmd" expands to the Go repository's commands and their +internal libraries. + +Import paths beginning with "cmd/" only match source code in +the Go repository. + +An import path is a pattern if it includes one or more "..." wildcards, +each of which can match any string, including the empty string and +strings containing slashes. Such a pattern expands to all package +directories found in the GOPATH trees with names matching the +patterns. + +To make common patterns more convenient, there are two special cases. +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-separated 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. +See golang.org/s/go15vendor for more about vendoring. + +An import path can also name a package to be downloaded from +a remote repository. Run 'go help importpath' for details. + +Every package in a program must have a unique import path. +By convention, this is arranged by starting each path with a +unique prefix that belongs to you. For example, paths used +internally at Google all begin with 'google', and paths +denoting remote repositories begin with the path to the code, +such as 'github.com/user/repo'. + +Packages in a program need not have unique package names, +but there are two reserved package names with special meaning. +The name main indicates a command, not a library. +Commands are built into binaries and cannot be imported. +The name documentation indicates documentation for +a non-Go program in the directory. Files in package documentation +are ignored by the go command. + +As a special case, if the package list is a list of .go files from a +single directory, the command is applied to a single synthesized +package made up of exactly those files, ignoring any build constraints +in those files and ignoring any other files in the directory. + +Directory and file names that begin with "." or "_" are ignored +by the go tool, as are directories named "testdata". + `, +} + +var HelpImportPath = &base.Command{ + UsageLine: "importpath", + Short: "import path syntax", + Long: ` + +An import path (see 'go help packages') denotes a package stored in the local +file system. In general, an import path denotes either a standard package (such +as "unicode/utf8") or a package found in one of the work spaces (For more +details see: 'go help gopath'). + +Relative import paths + +An import path beginning with ./ or ../ is called a relative path. +The toolchain supports relative import paths as a shortcut in two ways. + +First, a relative path can be used as a shorthand on the command line. +If you are working in the directory containing the code imported as +"unicode" and want to run the tests for "unicode/utf8", you can type +"go test ./utf8" instead of needing to specify the full path. +Similarly, in the reverse situation, "go test .." will test "unicode" from +the "unicode/utf8" directory. Relative patterns are also allowed, like +"go test ./..." to test all subdirectories. See 'go help packages' for details +on the pattern syntax. + +Second, if you are compiling a Go program not in a work space, +you can use a relative path in an import statement in that program +to refer to nearby code also not in a work space. +This makes it easy to experiment with small multipackage programs +outside of the usual work spaces, but such programs cannot be +installed with "go install" (there is no work space in which to install them), +so they are rebuilt from scratch each time they are built. +To avoid ambiguity, Go programs cannot use relative import paths +within a work space. + +Remote import paths + +Certain import paths also +describe how to obtain the source code for the package using +a revision control system. + +A few common code hosting sites have special syntax: + + Bitbucket (Git, Mercurial) + + import "bitbucket.org/user/project" + import "bitbucket.org/user/project/sub/directory" + + GitHub (Git) + + import "github.com/user/project" + import "github.com/user/project/sub/directory" + + Launchpad (Bazaar) + + import "launchpad.net/project" + import "launchpad.net/project/series" + import "launchpad.net/project/series/sub/directory" + + import "launchpad.net/~user/project/branch" + import "launchpad.net/~user/project/branch/sub/directory" + + IBM DevOps Services (Git) + + import "hub.jazz.net/git/user/project" + import "hub.jazz.net/git/user/project/sub/directory" + +For code hosted on other servers, import paths may either be qualified +with the version control type, or the go tool can dynamically fetch +the import path over https/http and discover where the code resides +from a tag in the HTML. + +To declare the code location, an import path of the form + + repository.vcs/path + +specifies the given repository, with or without the .vcs suffix, +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 + +For example, + + import "example.org/user/foo.hg" + +denotes the root directory of the Mercurial repository at +example.org/user/foo or foo.hg, and + + import "example.org/repo.git/foo/bar" + +denotes the foo/bar directory of the Git repository at +example.org/repo or repo.git. + +When a version control system supports multiple protocols, +each is tried in turn when downloading. For example, a Git +download tries https://, then git+ssh://. + +By default, downloads are restricted to known secure protocols +(e.g. https, ssh). To override this setting for Git downloads, the +GIT_ALLOW_PROTOCOL environment variable can be set (For more details see: +'go help environment'). + +If the import path is not a known code hosting site and also lacks a +version control qualifier, the go tool attempts to fetch the import +over https/http and looks for a tag in the document's HTML +. + +The meta tag has the form: + + + +The import-prefix is the import path corresponding to the repository +root. It must be a prefix or an exact match of the package being +fetched with "go get". If it's not an exact match, another http +request is made at the prefix to verify the tags match. + +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 "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. + +For example, + + import "example.org/pkg/foo" + +will result in the following requests: + + https://example.org/pkg/foo?go-get=1 (preferred) + http://example.org/pkg/foo?go-get=1 (fallback, only with -insecure) + +If that page contains the meta tag + + + +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. + +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 https://golang.org/ref/mod#module-cache. + +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: + + + +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 https://golang.org/ref/mod#goproxy-protocol for details about the +proxy protocol. + +Import path checking + +When the custom import path feature described above redirects to a +known code hosting site, each of the resulting packages has two possible +import paths, using the custom domain or the known hosting site. + +A package statement is said to have an "import comment" if it is immediately +followed (before the next newline) by a comment of one of these two forms: + + package math // import "path" + package math /* import "path" */ + +The go command will refuse to install a package with an import comment +unless it is being referred to by that import path. In this way, import comments +let package authors make sure the custom import path is used and not a +direct path to the underlying code hosting site. + +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. + `, +} + +var HelpGopath = &base.Command{ + UsageLine: "gopath", + Short: "GOPATH environment variable", + Long: ` +The Go path is used to resolve import statements. +It is implemented by and documented in the go/build package. + +The GOPATH environment variable lists places to look for Go code. +On Unix, the value is a colon-separated string. +On Windows, the value is a semicolon-separated string. +On Plan 9, the value is a list. + +If the environment variable is unset, GOPATH defaults +to a subdirectory named "go" in the user's home directory +($HOME/go on Unix, %USERPROFILE%\go on Windows), +unless that directory holds a Go distribution. +Run "go env GOPATH" to see the current GOPATH. + +See https://golang.org/wiki/SettingGOPATH to set a custom GOPATH. + +Each directory listed in GOPATH must have a prescribed structure: + +The src directory holds source code. The path below src +determines the import path or executable name. + +The pkg directory holds installed package objects. +As in the Go tree, each target operating system and +architecture pair has its own subdirectory of pkg +(pkg/GOOS_GOARCH). + +If DIR is a directory listed in the GOPATH, a package with +source in DIR/src/foo/bar can be imported as "foo/bar" and +has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a". + +The bin directory holds compiled commands. +Each command is named for its source directory, but only +the final element, not the entire path. That is, the +command with source in DIR/src/foo/quux is installed into +DIR/bin/quux, not DIR/bin/foo/quux. The "foo/" prefix is stripped +so that you can add DIR/bin to your PATH to get at the +installed commands. If the GOBIN environment variable is +set, commands are installed to the directory it names instead +of DIR/bin. GOBIN must be an absolute path. + +Here's an example directory layout: + + GOPATH=/home/user/go + + /home/user/go/ + src/ + foo/ + bar/ (go code in package bar) + x.go + quux/ (go code in package main) + y.go + bin/ + quux (installed command) + pkg/ + linux_amd64/ + foo/ + bar.a (installed package object) + +Go searches each directory listed in GOPATH to find source code, +but new packages are always downloaded into the first directory +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 +by code in the directory tree rooted at the parent of "internal". +Here's an extended version of the directory layout above: + + /home/user/go/ + src/ + crash/ + bang/ (go code in package bang) + b.go + foo/ (go code in package foo) + f.go + bar/ (go code in package bar) + x.go + internal/ + baz/ (go code in package baz) + z.go + quux/ (go code in package main) + y.go + + +The code in z.go is imported as "foo/internal/baz", but that +import statement can only appear in source files in the subtree +rooted at foo. The source files foo/f.go, foo/bar/x.go, and +foo/quux/y.go can all import "foo/internal/baz", but the source file +crash/bang/b.go cannot. + +See https://golang.org/s/go14internal for details. + +Vendor Directories + +Go 1.6 includes support for using local copies of external dependencies +to satisfy imports of those dependencies, often referred to as vendoring. + +Code below a directory named "vendor" is importable only +by code in the directory tree rooted at the parent of "vendor", +and only using an import path that omits the prefix up to and +including the vendor element. + +Here's the example from the previous section, +but with the "internal" directory renamed to "vendor" +and a new foo/vendor/crash/bang directory added: + + /home/user/go/ + src/ + crash/ + bang/ (go code in package bang) + b.go + foo/ (go code in package foo) + f.go + bar/ (go code in package bar) + x.go + vendor/ + crash/ + bang/ (go code in package bang) + b.go + baz/ (go code in package baz) + z.go + quux/ (go code in package main) + y.go + +The same visibility rules apply as for internal, but the code +in z.go is imported as "baz", not as "foo/vendor/baz". + +Code in vendor directories deeper in the source tree shadows +code in higher directories. Within the subtree rooted at foo, an import +of "crash/bang" resolves to "foo/vendor/crash/bang", not the +top-level "crash/bang". + +Code in vendor directories is not subject to import path +checking (see 'go help importpath'). + +When 'go get' checks out or updates a git repository, it now also +updates submodules. + +Vendor directories do not affect the placement of new repositories +being checked out for the first time by 'go get': those are always +placed in the main GOPATH, never in a vendor subtree. + +See https://golang.org/s/go15vendor for details. + `, +} + +var HelpEnvironment = &base.Command{ + UsageLine: "environment", + Short: "environment variables", + Long: ` + +The go command and the tools it invokes consult environment variables +for configuration. If an environment variable is unset, the go command +uses a sensible default setting. To see the effective setting of the +variable , run 'go env '. To change the default setting, +run 'go env -w ='. Defaults changed using 'go env -w' +are recorded in a Go environment configuration file stored in the +per-user configuration directory, as reported by os.UserConfigDir. +The location of the configuration file can be changed by setting +the environment variable GOENV, and 'go env GOENV' prints the +effective location, but 'go env -w' cannot change the default location. +See 'go help env' for details. + +General-purpose environment variables: + + GO111MODULE + Controls whether the go command runs in module-aware mode or GOPATH mode. + May be "off", "on", or "auto". + See https://golang.org/ref/mod#mod-commands. + 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. + GOMODCACHE + The directory where the go command will store downloaded modules. + GODEBUG + Enable various debugging facilities. See 'go doc runtime' + for details. + GOENV + The location of the Go environment configuration file. + Cannot be set using 'go env -w'. + 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. Each entry must be a standalone flag. + Because the entries are space-separated, flag values must + not contain spaces. Flags listed on the command line + are applied after this list and therefore override it. + GOINSECURE + Comma-separated list of glob patterns (in the syntax of Go's path.Match) + of module path prefixes that should always be fetched in an insecure + manner. Only applies to dependencies that are being fetched directly. + Unlike the -insecure flag on 'go get', GOINSECURE does not disable + checksum database validation. GOPRIVATE or GONOSUMDB may be used + to achieve that. + 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 https://golang.org/ref/mod#environment-variables + and https://golang.org/ref/mod#module-proxy for details. + GOPRIVATE, GONOPROXY, GONOSUMDB + Comma-separated list of glob patterns (in the syntax of Go's path.Match) + of module path prefixes that should always be fetched directly + or that should not be compared against the checksum database. + See https://golang.org/ref/mod#private-modules. + GOROOT + The root of the go tree. + GOSUMDB + The name of checksum database to use and optionally its public key and + URL. See https://golang.org/ref/mod#authenticating. + GOTMPDIR + The directory where the go command will write + temporary source files, packages, and binaries. + GOVCS + Lists version control commands that may be used with matching servers. + See 'go help vcs'. + +Environment variables for use with cgo: + + AR + The command to use to manipulate library archives when + building with the gccgo compiler. + The default is 'ar'. + 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. + FC + The command to use to compile Fortran 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, how to implement floating point instructions. + Valid values are sse2 (default), softfloat. + 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. + GOWASM + For GOARCH=wasm, comma-separated list of experimental WebAssembly features to use. + Valid values are satconv, signext. + +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'. + Because the variable is defined by Git, the default value cannot + be set using 'go env -w'. + +Additional information available from 'go env' but not read from the environment: + + GOEXE + The executable file name suffix (".exe" on Windows, "" on other systems). + GOGCCFLAGS + A space-separated list of arguments supplied to the CC command. + 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. + If module-aware mode is enabled, but there is no go.mod, GOMOD will be + os.DevNull ("/dev/null" on Unix-like systems, "NUL" on Windows). + If module-aware mode is disabled, GOMOD will be the empty string. + GOTOOLDIR + The directory where the go tools (compile, cover, doc, etc...) are installed. + GOVERSION + The version of the installed Go tree, as reported by runtime.Version. + `, +} + +var HelpFileType = &base.Command{ + UsageLine: "filetype", + Short: "file types", + Long: ` +The go command examines the contents of a restricted set of files +in each directory. It identifies which files to examine based on +the extension of the file name. These extensions are: + + .go + Go source files. + .c, .h + C source files. + If the package uses cgo or SWIG, these will be compiled with the + OS-native compiler (typically gcc); otherwise they will + trigger an error. + .cc, .cpp, .cxx, .hh, .hpp, .hxx + C++ source files. Only useful with cgo or SWIG, and always + compiled with the OS-native compiler. + .m + Objective-C source files. Only useful with cgo, and always + compiled with the OS-native compiler. + .s, .S, .sx + Assembler source files. + If the package uses cgo or SWIG, these will be assembled with the + OS-native assembler (typically gcc (sic)); otherwise they + will be assembled with the Go assembler. + .swig, .swigcxx + SWIG definition files. + .syso + System object files. + +Files of each of these types except .syso may contain build +constraints, but the go command stops scanning for build constraints +at the first item in the file that is not a blank line or //-style +line comment. See the go/build package documentation for +more details. + `, +} + +var HelpBuildmode = &base.Command{ + UsageLine: "buildmode", + Short: "build modes", + Long: ` +The 'go build' and 'go install' commands take a -buildmode argument which +indicates which kind of object file is to be built. Currently supported values +are: + + -buildmode=archive + Build the listed non-main packages into .a files. Packages named + main are ignored. + + -buildmode=c-archive + Build the listed main package, plus all packages it imports, + into a C archive file. The only callable symbols will be those + functions exported using a cgo //export comment. Requires + exactly one main package to be listed. + + -buildmode=c-shared + Build the listed main package, plus all packages it imports, + into a C shared library. The only callable symbols will + be those functions exported using a cgo //export comment. + Requires exactly one main package to be listed. + + -buildmode=default + Listed main packages are built into executables and listed + non-main packages are built into .a files (the default + behavior). + + -buildmode=shared + Combine all the listed non-main packages into a single shared + library that will be used when building with the -linkshared + option. Packages named main are ignored. + + -buildmode=exe + Build the listed main packages and everything they import into + executables. Packages not named main are ignored. + + -buildmode=pie + Build the listed main packages and everything they import into + position independent executables (PIE). Packages not named + main are ignored. + + -buildmode=plugin + Build the listed main packages, plus all packages that they + import, into a Go plugin. Packages not named main are ignored. + +On AIX, when linking a C program that uses a Go archive built with +-buildmode=c-archive, you must pass -Wl,-bnoobjreorder to the C compiler. +`, +} + +var HelpCache = &base.Command{ + UsageLine: "cache", + Short: "build and test caching", + Long: ` +The go command caches build outputs for reuse in future builds. +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. + +The go command periodically deletes cached data that has not been +used recently. Running 'go clean -cache' deletes all cached data. + +The build cache correctly accounts for changes to Go source files, +compilers, compiler options, and so on: cleaning the cache explicitly +should not be necessary in typical use. However, the build cache +does not detect changes to C libraries imported with cgo. +If you have made changes to the C libraries on your system, you +will need to clean the cache explicitly or else use the -a build flag +(see 'go help build') to force rebuilding of packages that +depend on the updated C libraries. + +The go command also caches successful package test results. +See 'go help test' for details. Running 'go clean -testcache' removes +all cached test results (but not cached build results). + +The GODEBUG environment variable can enable printing of debugging +information about the state of the cache: + +GODEBUG=gocacheverify=1 causes the go command to bypass the +use of any cache entries and instead rebuild everything and check +that the results match existing cache entries. + +GODEBUG=gocachehash=1 causes the go command to print the inputs +for all of the content hashes it uses to construct cache lookup keys. +The output is voluminous but can be useful for debugging the cache. + +GODEBUG=gocachetest=1 causes the go command to print details of its +decisions about whether to reuse a cached test result. +`, +} + +var HelpBuildConstraint = &base.Command{ + UsageLine: "buildconstraint", + Short: "build constraints", + Long: ` +A build constraint, also known as a build tag, is a line comment that begins + + // +build + +that lists the conditions under which a file should be included in the package. +Constraints may appear in any kind of source file (not just Go), but +they must appear near the top of the file, preceded +only by blank lines and other line comments. These rules mean that in Go +files a build constraint must appear before the package clause. + +To distinguish build constraints from package documentation, a series of +build constraints must be followed by a blank line. + +A build constraint is evaluated as the OR of space-separated options. +Each option evaluates as the AND of its comma-separated terms. +Each term consists of letters, digits, underscores, and dots. +A term may be negated with a preceding !. +For example, the build constraint: + + // +build linux,386 darwin,!cgo + +corresponds to the boolean formula: + + (linux AND 386) OR (darwin AND (NOT cgo)) + +A file may have multiple build constraints. The overall constraint is the AND +of the individual constraints. That is, the build constraints: + + // +build linux darwin + // +build amd64 + +corresponds to the boolean formula: + + (linux OR darwin) AND amd64 + +During a particular build, the following words are satisfied: + + - the target operating system, as spelled by runtime.GOOS, set with the + GOOS environment variable. + - the target architecture, as spelled by runtime.GOARCH, set with the + GOARCH environment variable. + - the compiler being used, either "gc" or "gccgo" + - "cgo", if the cgo command is supported (see CGO_ENABLED in + 'go help environment'). + - a term for each Go major release, through the current version: + "go1.1" from Go version 1.1 onward, "go1.12" from Go 1.12, and so on. + - any additional tags given by the -tags flag (see 'go help build'). + +There are no separate build tags for beta or minor releases. + +If a file's name, after stripping the extension and a possible _test suffix, +matches any of the following patterns: + *_GOOS + *_GOARCH + *_GOOS_GOARCH +(example: source_windows_amd64.go) where GOOS and GOARCH represent +any known operating system and architecture values respectively, then +the file is considered to have an implicit build constraint requiring +those terms (in addition to any explicit constraints in the file). + +Using GOOS=android matches build tags and files as for GOOS=linux +in addition to android tags and files. + +Using GOOS=illumos matches build tags and files as for GOOS=solaris +in addition to illumos tags and files. + +Using GOOS=ios matches build tags and files as for GOOS=darwin +in addition to ios tags and files. + +To keep a file from being considered for the build: + + // +build ignore + +(any other unsatisfied word will work as well, but "ignore" is conventional.) + +To build a file only when using cgo, and only on Linux and OS X: + + // +build linux,cgo darwin,cgo + +Such a file is usually paired with another file implementing the +default functionality for other systems, which in this case would +carry the constraint: + + // +build !linux,!darwin !cgo + +Naming a file dns_windows.go will cause it to be included only when +building the package for Windows; similarly, math_386.s will be included +only when building the package for 32-bit x86. +`, +} diff --git a/src/cmd/go/internal/imports/build.go b/src/cmd/go/internal/imports/build.go new file mode 100644 index 0000000..50aeabc --- /dev/null +++ b/src/cmd/go/internal/imports/build.go @@ -0,0 +1,251 @@ +// 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"] + } + if name == "solaris" { + have = have || tags["illumos"] + } + if name == "darwin" { + have = have || tags["ios"] + } + 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.* +// +// Exceptions: +// if GOOS=android, then files with GOOS=linux are also matched. +// if GOOS=illumos, then files with GOOS=solaris are also matched. +// if GOOS=ios, then files with GOOS=darwin 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 matchTag(l[n-2], tags, true) && matchTag(l[n-1], tags, true) + } + if n >= 1 && KnownOS[l[n-1]] { + return matchTag(l[n-1], tags, true) + } + if n >= 1 && KnownArch[l[n-1]] { + return matchTag(l[n-1], tags, true) + } + return true +} + +var KnownOS = map[string]bool{ + "aix": true, + "android": true, + "darwin": true, + "dragonfly": true, + "freebsd": true, + "hurd": true, + "illumos": true, + "ios": true, + "js": true, + "linux": true, + "nacl": true, // legacy; don't remove + "netbsd": true, + "openbsd": true, + "plan9": true, + "solaris": true, + "windows": true, + "zos": true, +} + +var KnownArch = map[string]bool{ + "386": true, + "amd64": true, + "amd64p32": true, // legacy; don't remove + "arm": true, + "armbe": true, + "arm64": true, + "arm64be": true, + "ppc64": true, + "ppc64le": true, + "mips": true, + "mipsle": true, + "mips64": true, + "mips64le": true, + "mips64p32": true, + "mips64p32le": true, + "ppc": true, + "riscv": true, + "riscv64": true, + "s390": true, + "s390x": true, + "sparc": true, + "sparc64": true, + "wasm": true, +} diff --git a/src/cmd/go/internal/imports/read.go b/src/cmd/go/internal/imports/read.go new file mode 100644 index 0000000..5e27078 --- /dev/null +++ b/src/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 io.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 io.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/src/cmd/go/internal/imports/read_test.go b/src/cmd/go/internal/imports/read_test.go new file mode 100644 index 0000000..6ea356f --- /dev/null +++ b/src/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/src/cmd/go/internal/imports/scan.go b/src/cmd/go/internal/imports/scan.go new file mode 100644 index 0000000..ee11a87 --- /dev/null +++ b/src/cmd/go/internal/imports/scan.go @@ -0,0 +1,107 @@ +// 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/fs" + "path/filepath" + "sort" + "strconv" + "strings" + + "cmd/go/internal/fsys" +) + +func ScanDir(dir string, tags map[string]bool) ([]string, []string, error) { + infos, err := fsys.ReadDir(dir) + if err != nil { + return nil, nil, err + } + var files []string + for _, info := range infos { + name := info.Name() + + // If the directory entry is a symlink, stat it to obtain the info for the + // link target instead of the link itself. + if info.Mode()&fs.ModeSymlink != 0 { + info, err = fsys.Stat(filepath.Join(dir, name)) + if err != nil { + continue // Ignore broken symlinks. + } + } + + if info.Mode().IsRegular() && !strings.HasPrefix(name, "_") && !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 := fsys.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/src/cmd/go/internal/imports/scan_test.go b/src/cmd/go/internal/imports/scan_test.go new file mode 100644 index 0000000..2d245ee --- /dev/null +++ b/src/cmd/go/internal/imports/scan_test.go @@ -0,0 +1,94 @@ +// 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 ( + "bytes" + "internal/testenv" + "os" + "path" + "path/filepath" + "runtime" + "strings" + "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 TestScanDir(t *testing.T) { + testenv.MustHaveGoBuild(t) + + dirs, err := os.ReadDir("testdata") + if err != nil { + t.Fatal(err) + } + for _, dir := range dirs { + if !dir.IsDir() || strings.HasPrefix(dir.Name(), ".") { + continue + } + t.Run(dir.Name(), func(t *testing.T) { + tagsData, err := os.ReadFile(filepath.Join("testdata", dir.Name(), "tags.txt")) + if err != nil { + t.Fatalf("error reading tags: %v", err) + } + tags := make(map[string]bool) + for _, t := range strings.Fields(string(tagsData)) { + tags[t] = true + } + + wantData, err := os.ReadFile(filepath.Join("testdata", dir.Name(), "want.txt")) + if err != nil { + t.Fatalf("error reading want: %v", err) + } + want := string(bytes.TrimSpace(wantData)) + + imports, _, err := ScanDir(path.Join("testdata", dir.Name()), tags) + if err != nil { + t.Fatal(err) + } + got := strings.Join(imports, "\n") + if got != want { + t.Errorf("ScanDir: got imports:\n%s\n\nwant:\n%s", got, want) + } + }) + } +} diff --git a/src/cmd/go/internal/imports/tags.go b/src/cmd/go/internal/imports/tags.go new file mode 100644 index 0000000..01b448b --- /dev/null +++ b/src/cmd/go/internal/imports/tags.go @@ -0,0 +1,58 @@ +// 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" + "sync" +) + +var ( + tags map[string]bool + tagsOnce sync.Once +) + +// Tags returns a set of build tags that are true for the target platform. +// It includes GOOS, GOARCH, the compiler, possibly "cgo", +// release tags like "go1.13", and user-specified build tags. +func Tags() map[string]bool { + tagsOnce.Do(func() { + 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 +} + +var ( + anyTags map[string]bool + anyTagsOnce sync.Once +) + +// AnyTags returns a special set of build tags that satisfy nearly all +// build tag expressions. Only "ignore" and malformed build tag requirements +// are considered false. +func AnyTags() map[string]bool { + anyTagsOnce.Do(func() { + anyTags = map[string]bool{"*": true} + }) + return anyTags +} diff --git a/src/cmd/go/internal/imports/testdata/android/.h.go b/src/cmd/go/internal/imports/testdata/android/.h.go new file mode 100644 index 0000000..53c529e --- /dev/null +++ b/src/cmd/go/internal/imports/testdata/android/.h.go @@ -0,0 +1,3 @@ +package android + +import _ "h" diff --git a/src/cmd/go/internal/imports/testdata/android/a_android.go b/src/cmd/go/internal/imports/testdata/android/a_android.go new file mode 100644 index 0000000..2ed972e --- /dev/null +++ b/src/cmd/go/internal/imports/testdata/android/a_android.go @@ -0,0 +1,3 @@ +package android + +import _ "a" diff --git a/src/cmd/go/internal/imports/testdata/android/b_android_arm64.go b/src/cmd/go/internal/imports/testdata/android/b_android_arm64.go new file mode 100644 index 0000000..ee9c312 --- /dev/null +++ b/src/cmd/go/internal/imports/testdata/android/b_android_arm64.go @@ -0,0 +1,3 @@ +package android + +import _ "b" diff --git a/src/cmd/go/internal/imports/testdata/android/c_linux.go b/src/cmd/go/internal/imports/testdata/android/c_linux.go new file mode 100644 index 0000000..91624ce --- /dev/null +++ b/src/cmd/go/internal/imports/testdata/android/c_linux.go @@ -0,0 +1,3 @@ +package android + +import _ "c" diff --git a/src/cmd/go/internal/imports/testdata/android/d_linux_arm64.go b/src/cmd/go/internal/imports/testdata/android/d_linux_arm64.go new file mode 100644 index 0000000..34e07df --- /dev/null +++ b/src/cmd/go/internal/imports/testdata/android/d_linux_arm64.go @@ -0,0 +1,3 @@ +package android + +import _ "d" diff --git a/src/cmd/go/internal/imports/testdata/android/e.go b/src/cmd/go/internal/imports/testdata/android/e.go new file mode 100644 index 0000000..d9b2db7 --- /dev/null +++ b/src/cmd/go/internal/imports/testdata/android/e.go @@ -0,0 +1,5 @@ +// +build android + +package android + +import _ "e" diff --git a/src/cmd/go/internal/imports/testdata/android/f.go b/src/cmd/go/internal/imports/testdata/android/f.go new file mode 100644 index 0000000..281e4dd --- /dev/null +++ b/src/cmd/go/internal/imports/testdata/android/f.go @@ -0,0 +1,5 @@ +// +build linux + +package android + +import _ "f" diff --git a/src/cmd/go/internal/imports/testdata/android/g.go b/src/cmd/go/internal/imports/testdata/android/g.go new file mode 100644 index 0000000..66a789c --- /dev/null +++ b/src/cmd/go/internal/imports/testdata/android/g.go @@ -0,0 +1,5 @@ +// +build !android + +package android + +import _ "g" diff --git a/src/cmd/go/internal/imports/testdata/android/tags.txt b/src/cmd/go/internal/imports/testdata/android/tags.txt new file mode 100644 index 0000000..aaf5a6b --- /dev/null +++ b/src/cmd/go/internal/imports/testdata/android/tags.txt @@ -0,0 +1 @@ +android arm64 \ No newline at end of file diff --git a/src/cmd/go/internal/imports/testdata/android/want.txt b/src/cmd/go/internal/imports/testdata/android/want.txt new file mode 100644 index 0000000..0fdf397 --- /dev/null +++ b/src/cmd/go/internal/imports/testdata/android/want.txt @@ -0,0 +1,6 @@ +a +b +c +d +e +f diff --git a/src/cmd/go/internal/imports/testdata/illumos/.h.go b/src/cmd/go/internal/imports/testdata/illumos/.h.go new file mode 100644 index 0000000..53c529e --- /dev/null +++ b/src/cmd/go/internal/imports/testdata/illumos/.h.go @@ -0,0 +1,3 @@ +package android + +import _ "h" diff --git a/src/cmd/go/internal/imports/testdata/illumos/a_illumos.go b/src/cmd/go/internal/imports/testdata/illumos/a_illumos.go new file mode 100644 index 0000000..2e6cb50 --- /dev/null +++ b/src/cmd/go/internal/imports/testdata/illumos/a_illumos.go @@ -0,0 +1,3 @@ +package illumos + +import _ "a" diff --git a/src/cmd/go/internal/imports/testdata/illumos/b_illumos_amd64.go b/src/cmd/go/internal/imports/testdata/illumos/b_illumos_amd64.go new file mode 100644 index 0000000..2834d80 --- /dev/null +++ b/src/cmd/go/internal/imports/testdata/illumos/b_illumos_amd64.go @@ -0,0 +1,3 @@ +package illumos + +import _ "b" diff --git a/src/cmd/go/internal/imports/testdata/illumos/c_solaris.go b/src/cmd/go/internal/imports/testdata/illumos/c_solaris.go new file mode 100644 index 0000000..d7f9462 --- /dev/null +++ b/src/cmd/go/internal/imports/testdata/illumos/c_solaris.go @@ -0,0 +1,3 @@ +package illumos + +import _ "c" diff --git a/src/cmd/go/internal/imports/testdata/illumos/d_solaris_amd64.go b/src/cmd/go/internal/imports/testdata/illumos/d_solaris_amd64.go new file mode 100644 index 0000000..0f52c2b --- /dev/null +++ b/src/cmd/go/internal/imports/testdata/illumos/d_solaris_amd64.go @@ -0,0 +1,3 @@ +package illumos + +import _ "d" diff --git a/src/cmd/go/internal/imports/testdata/illumos/e.go b/src/cmd/go/internal/imports/testdata/illumos/e.go new file mode 100644 index 0000000..5e1ed3c --- /dev/null +++ b/src/cmd/go/internal/imports/testdata/illumos/e.go @@ -0,0 +1,5 @@ +// +build illumos + +package illumos + +import _ "e" diff --git a/src/cmd/go/internal/imports/testdata/illumos/f.go b/src/cmd/go/internal/imports/testdata/illumos/f.go new file mode 100644 index 0000000..f3e3f72 --- /dev/null +++ b/src/cmd/go/internal/imports/testdata/illumos/f.go @@ -0,0 +1,5 @@ +// +build solaris + +package illumos + +import _ "f" diff --git a/src/cmd/go/internal/imports/testdata/illumos/g.go b/src/cmd/go/internal/imports/testdata/illumos/g.go new file mode 100644 index 0000000..b30f1eb --- /dev/null +++ b/src/cmd/go/internal/imports/testdata/illumos/g.go @@ -0,0 +1,5 @@ +// +build !illumos + +package illumos + +import _ "g" diff --git a/src/cmd/go/internal/imports/testdata/illumos/tags.txt b/src/cmd/go/internal/imports/testdata/illumos/tags.txt new file mode 100644 index 0000000..b6386a3 --- /dev/null +++ b/src/cmd/go/internal/imports/testdata/illumos/tags.txt @@ -0,0 +1 @@ +illumos amd64 diff --git a/src/cmd/go/internal/imports/testdata/illumos/want.txt b/src/cmd/go/internal/imports/testdata/illumos/want.txt new file mode 100644 index 0000000..0fdf397 --- /dev/null +++ b/src/cmd/go/internal/imports/testdata/illumos/want.txt @@ -0,0 +1,6 @@ +a +b +c +d +e +f diff --git a/src/cmd/go/internal/imports/testdata/star/tags.txt b/src/cmd/go/internal/imports/testdata/star/tags.txt new file mode 100644 index 0000000..f59ec20 --- /dev/null +++ b/src/cmd/go/internal/imports/testdata/star/tags.txt @@ -0,0 +1 @@ +* \ No newline at end of file diff --git a/src/cmd/go/internal/imports/testdata/star/want.txt b/src/cmd/go/internal/imports/testdata/star/want.txt new file mode 100644 index 0000000..139f5f4 --- /dev/null +++ b/src/cmd/go/internal/imports/testdata/star/want.txt @@ -0,0 +1,4 @@ +import1 +import2 +import3 +import4 diff --git a/src/cmd/go/internal/imports/testdata/star/x.go b/src/cmd/go/internal/imports/testdata/star/x.go new file mode 100644 index 0000000..98f9191 --- /dev/null +++ b/src/cmd/go/internal/imports/testdata/star/x.go @@ -0,0 +1,3 @@ +package x + +import "import1" diff --git a/src/cmd/go/internal/imports/testdata/star/x1.go b/src/cmd/go/internal/imports/testdata/star/x1.go new file mode 100644 index 0000000..6a9594a --- /dev/null +++ b/src/cmd/go/internal/imports/testdata/star/x1.go @@ -0,0 +1,9 @@ +// +build blahblh +// +build linux +// +build !linux +// +build windows +// +build darwin + +package x + +import "import4" diff --git a/src/cmd/go/internal/imports/testdata/star/x_darwin.go b/src/cmd/go/internal/imports/testdata/star/x_darwin.go new file mode 100644 index 0000000..a0c3fdd --- /dev/null +++ b/src/cmd/go/internal/imports/testdata/star/x_darwin.go @@ -0,0 +1,3 @@ +package xxxx + +import "import3" diff --git a/src/cmd/go/internal/imports/testdata/star/x_windows.go b/src/cmd/go/internal/imports/testdata/star/x_windows.go new file mode 100644 index 0000000..63c5082 --- /dev/null +++ b/src/cmd/go/internal/imports/testdata/star/x_windows.go @@ -0,0 +1,3 @@ +package x + +import "import2" diff --git a/src/cmd/go/internal/list/context.go b/src/cmd/go/internal/list/context.go new file mode 100644 index 0000000..68d691e --- /dev/null +++ b/src/cmd/go/internal/list/context.go @@ -0,0 +1,37 @@ +// Copyright 2014 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 list + +import ( + "go/build" +) + +type Context struct { + GOARCH string `json:",omitempty"` // target architecture + GOOS string `json:",omitempty"` // target operating system + GOROOT string `json:",omitempty"` // Go root + GOPATH string `json:",omitempty"` // Go path + CgoEnabled bool `json:",omitempty"` // whether cgo can be used + UseAllFiles bool `json:",omitempty"` // use files regardless of +build lines, file names + Compiler string `json:",omitempty"` // compiler to assume when computing target paths + BuildTags []string `json:",omitempty"` // build constraints to match in +build lines + ReleaseTags []string `json:",omitempty"` // releases the current release is compatible with + InstallSuffix string `json:",omitempty"` // suffix to use in the name of the install dir +} + +func newContext(c *build.Context) *Context { + return &Context{ + GOARCH: c.GOARCH, + GOOS: c.GOOS, + GOROOT: c.GOROOT, + GOPATH: c.GOPATH, + CgoEnabled: c.CgoEnabled, + UseAllFiles: c.UseAllFiles, + Compiler: c.Compiler, + BuildTags: c.BuildTags, + ReleaseTags: c.ReleaseTags, + InstallSuffix: c.InstallSuffix, + } +} diff --git a/src/cmd/go/internal/list/list.go b/src/cmd/go/internal/list/list.go new file mode 100644 index 0000000..b4d82d9 --- /dev/null +++ b/src/cmd/go/internal/list/list.go @@ -0,0 +1,761 @@ +// Copyright 2011 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 list implements the ``go list'' command. +package list + +import ( + "bufio" + "bytes" + "context" + "encoding/json" + "fmt" + "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/modinfo" + "cmd/go/internal/modload" + "cmd/go/internal/str" + "cmd/go/internal/work" +) + +var CmdList = &base.Command{ + // 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 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: + + bytes + encoding/json + github.com/gorilla/mux + 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: + + 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 (no longer supported) + ForTest string // package is only for use in named test + Export string // file containing export data (when using -export) + BuildID string // build ID of the compiled package (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 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 + IgnoredOtherFiles []string // non-.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 + + // Embedded files + EmbedPatterns []string // //go:embed patterns + EmbedFiles []string // files matched by EmbedPatterns + TestEmbedPatterns []string // //go:embed patterns in TestGoFiles + TestEmbedFiles []string // files matched by TestEmbedPatterns + XTestEmbedPatterns []string // //go:embed patterns in XTestGoFiles + XTestEmbedFiles []string // files matched by XTestEmbedPatterns + + // Cgo directives + CgoCFLAGS []string // cgo: flags for C compiler + CgoCPPFLAGS []string // cgo: flags for C preprocessor + CgoCXXFLAGS []string // cgo: flags for C++ compiler + CgoFFLAGS []string // cgo: flags for Fortran compiler + CgoLDFLAGS []string // cgo: flags for linker + CgoPkgConfig []string // cgo: pkg-config names + + // Dependency information + 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 + Error *PackageError // error loading package + DepsErrors []*PackageError // errors loading dependencies + } + +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 import paths. See golang.org/s/go15vendor for more about vendoring. + +The error information, if any, is + + type PackageError struct { + ImportStack []string // shortest path from package named on command line to this one + Pos string // position of error (if present, file:line:col) + 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 + } + +For more information about the meaning of these fields see the documentation +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 +omits the packages from consideration during the usual printing. +With the -e flag, the list command never prints errors to standard +error and instead processes the erroneous packages with the usual +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 used when loading this module, if any + GoVersion string // go version used in module + Retracted string // retraction information, if any (with -retracted or -u) + Error *ModuleError // error loading module + } + + type ModuleError struct { + Err string // the error itself + } + +The file GoMod refers to may be outside the module directory if the +module is in the module cache or if the -modfile flag is used. + +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. list -u will also set +the module's Retracted field if the current version is retracted. +The Module's String method indicates an available upgrade by +formatting the newer version in brackets after the current version. +If a version is retracted, the string "(retracted)" will follow it. +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 (retracted) [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 -retracted flag causes list to report information about retracted +module versions. When -retracted is used with -f or -json, the Retracted +field will be set to a string explaining why the version was retracted. +The string is taken from comments on the retract directive in the +module's go.mod file. When -retracted is used with -versions, retracted +versions are listed together with unretracted versions. The -retracted +flag may be used with or without -m. + +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 https://golang.org/ref/mod. + `, +} + +func init() { + CmdList.Run = runList // break init cycle + work.AddBuildFlags(CmdList, work.DefaultBuildFlags) +} + +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, "") + listRetracted = CmdList.Flag.Bool("retracted", false, "") + listTest = CmdList.Flag.Bool("test", false, "") + listU = CmdList.Flag.Bool("u", false, "") + listVersions = CmdList.Flag.Bool("versions", false, "") +) + +var nl = []byte{'\n'} + +func runList(ctx context.Context, cmd *base.Command, args []string) { + load.ModResolveTests = *listTest + work.BuildInit() + out := newTrackingWriter(os.Stdout) + defer out.w.Flush() + + if *listFmt == "" { + if *listM { + *listFmt = "{{.String}}" + if *listVersions { + *listFmt = `{{.Path}}{{range .Versions}} {{.}}{{end}}` + } + } else { + *listFmt = "{{.ImportPath}}" + } + } + + var do func(interface{}) + if *listJson { + do = func(x interface{}) { + b, err := json.MarshalIndent(x, "", "\t") + if err != nil { + out.Flush() + base.Fatalf("%s", err) + } + out.Write(b) + out.Write(nl) + } + } else { + var cachedCtxt *Context + context := func() *Context { + if cachedCtxt == nil { + cachedCtxt = newContext(&cfg.BuildContext) + } + return cachedCtxt + } + fm := template.FuncMap{ + "join": strings.Join, + "context": context, + "module": func(path string) *modinfo.ModulePublic { return modload.ModuleInfo(ctx, path) }, + } + tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt) + if err != nil { + base.Fatalf("%s", err) + } + do = func(x interface{}) { + if err := tmpl.Execute(out, x); err != nil { + out.Flush() + base.Fatalf("%s", err) + } + if out.NeedNL() { + out.Write(nl) + } + } + } + + modload.Init() + if *listRetracted { + if cfg.BuildMod == "vendor" { + base.Fatalf("go list -retracted cannot be used when vendoring is enabled") + } + if !modload.Enabled() { + base.Fatalf("go list -retracted can only be used in module-aware mode") + } + } + + 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.LoadModFile(ctx) // Parses go.mod and sets cfg.BuildMod. + if cfg.BuildMod == "vendor" { + const actionDisabledFormat = "go list -m: can't %s using the vendor directory\n\t(Use -mod=mod or -mod=readonly to bypass.)" + + if *listVersions { + base.Fatalf(actionDisabledFormat, "determine available versions") + } + if *listU { + base.Fatalf(actionDisabledFormat, "determine available upgrades") + } + + for _, arg := range args { + // In vendor mode, the module graph is incomplete: it contains only the + // explicit module dependencies and the modules that supply packages in + // the import graph. Reject queries that imply more information than that. + if arg == "all" { + base.Fatalf(actionDisabledFormat, "compute 'all'") + } + if strings.Contains(arg, "...") { + base.Fatalf(actionDisabledFormat, "match module patterns") + } + } + } + + mods := modload.ListModules(ctx, args, *listU, *listVersions, *listRetracted) + if !*listE { + for _, m := range mods { + if m.Error != nil { + base.Errorf("go list -m: %v", 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 + pkgs := load.PackagesAndErrors(ctx, args) + if !*listE { + w := 0 + for _, pkg := range pkgs { + if pkg.Error != nil { + base.Errorf("%v", pkg.Error) + continue + } + pkgs[w] = pkg + w++ + } + pkgs = pkgs[:w] + base.ExitIfErrors() + } + + 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 len(p.TestGoFiles)+len(p.XTestGoFiles) > 0 { + var pmain, ptest, pxtest *load.Package + var err error + if *listE { + pmain, ptest, pxtest = load.TestPackagesAndErrors(ctx, p, nil) + } else { + pmain, ptest, pxtest, err = load.TestPackagesFor(ctx, p, nil) + if err != nil { + base.Errorf("can't load test package: %s", err) + } + } + if pmain != nil { + pkgs = append(pkgs, pmain) + 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) + } + if ptest != nil && ptest != p { + pkgs = append(pkgs, ptest) + } + if pxtest != nil { + pkgs = append(pkgs, pxtest) + } + } + } + } + + // 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 = loadPackageList(pkgs) + } + + // Do we need to run a build to gather information? + needStale := *listJson || strings.Contains(*listFmt, ".Stale") + if needStale || *listExport || *listCompiled { + var b work.Builder + b.Init() + b.IsCmdList = true + b.NeedExport = *listExport + b.NeedCompiledGoFiles = *listCompiled + a := &work.Action{} + // TODO: Use pkgsFilter? + for _, p := range pkgs { + if len(p.GoFiles)+len(p.CgoFiles) > 0 { + a.Deps = append(a.Deps, b.AutoAction(work.ModeInstall, work.ModeInstall, p)) + } + } + b.Do(ctx, a) + } + + for _, p := range pkgs { + // Show vendor-expanded paths in listing + 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 = loadPackageList(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) + } + } + + // TODO(golang.org/issue/40676): This mechanism could be extended to support + // -u without -m. + if *listRetracted { + // Load retractions for modules that provide packages that will be printed. + // TODO(golang.org/issue/40775): Packages from the same module refer to + // distinct ModulePublic instance. It would be nice if they could all point + // to the same instance. This would require additional global state in + // modload.loaded, so that should be refactored first. For now, we update + // all instances. + modToArg := make(map[*modinfo.ModulePublic]string) + argToMods := make(map[string][]*modinfo.ModulePublic) + var args []string + addModule := func(mod *modinfo.ModulePublic) { + if mod.Version == "" { + return + } + arg := fmt.Sprintf("%s@%s", mod.Path, mod.Version) + if argToMods[arg] == nil { + args = append(args, arg) + } + argToMods[arg] = append(argToMods[arg], mod) + modToArg[mod] = arg + } + for _, p := range pkgs { + if p.Module == nil { + continue + } + addModule(p.Module) + if p.Module.Replace != nil { + addModule(p.Module.Replace) + } + } + + if len(args) > 0 { + listU := false + listVersions := false + rmods := modload.ListModules(ctx, args, listU, listVersions, *listRetracted) + for i, arg := range args { + rmod := rmods[i] + for _, mod := range argToMods[arg] { + mod.Retracted = rmod.Retracted + if rmod.Error != nil && mod.Error == nil { + mod.Error = rmod.Error + } + } + } + } + } + + // 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 + } + } + } + + for _, p := range pkgs { + do(&p.PackagePublic) + } +} + +// loadPackageList is like load.PackageList, but prints error messages and exits +// with nonzero status if listE is not set and any package in the expanded list +// has errors. +func loadPackageList(roots []*load.Package) []*load.Package { + pkgs := load.PackageList(roots) + + if !*listE { + for _, pkg := range pkgs { + if pkg.Error != nil { + base.Errorf("%v", pkg.Error) + } + } + } + + return pkgs +} + +// TrackingWriter tracks the last byte written on every write so +// we can avoid printing a newline if one was already written or +// if there is no output at all. +type TrackingWriter struct { + w *bufio.Writer + last byte +} + +func newTrackingWriter(w io.Writer) *TrackingWriter { + return &TrackingWriter{ + w: bufio.NewWriter(w), + last: '\n', + } +} + +func (t *TrackingWriter) Write(p []byte) (n int, err error) { + n, err = t.w.Write(p) + if n > 0 { + t.last = p[n-1] + } + return +} + +func (t *TrackingWriter) Flush() { + t.w.Flush() +} + +func (t *TrackingWriter) NeedNL() bool { + return t.last != '\n' +} diff --git a/src/cmd/go/internal/load/flag.go b/src/cmd/go/internal/load/flag.go new file mode 100644 index 0000000..7534e65 --- /dev/null +++ b/src/cmd/go/internal/load/flag.go @@ -0,0 +1,93 @@ +// 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 load + +import ( + "cmd/go/internal/base" + "cmd/go/internal/str" + "fmt" + "strings" +) + +var ( + BuildAsmflags PerPackageFlag // -asmflags + BuildGcflags PerPackageFlag // -gcflags + BuildLdflags PerPackageFlag // -ldflags + BuildGccgoflags PerPackageFlag // -gccgoflags +) + +// A PerPackageFlag is a command-line flag implementation (a flag.Value) +// that allows specifying different effective flags for different packages. +// See 'go help build' for more details about per-package flags. +type PerPackageFlag struct { + present bool + values []ppfValue +} + +// A ppfValue is a single = per-package flag value. +type ppfValue struct { + match func(*Package) bool // compiled pattern + flags []string +} + +// Set is called each time the flag is encountered on the command line. +func (f *PerPackageFlag) Set(v string) error { + return f.set(v, base.Cwd) +} + +// set is the implementation of Set, taking a cwd (current working directory) for easier testing. +func (f *PerPackageFlag) set(v, cwd string) error { + f.present = true + match := func(p *Package) bool { return p.Internal.CmdlinePkg || p.Internal.CmdlineFiles } // default predicate with no pattern + // For backwards compatibility with earlier flag splitting, ignore spaces around flags. + v = strings.TrimSpace(v) + if v == "" { + // Special case: -gcflags="" means no flags for command-line arguments + // (overrides previous -gcflags="-whatever"). + f.values = append(f.values, ppfValue{match, []string{}}) + return nil + } + if !strings.HasPrefix(v, "-") { + i := strings.Index(v, "=") + if i < 0 { + return fmt.Errorf("missing = in =") + } + if i == 0 { + return fmt.Errorf("missing in =") + } + pattern := strings.TrimSpace(v[:i]) + match = MatchPackage(pattern, cwd) + v = v[i+1:] + } + flags, err := str.SplitQuotedFields(v) + if err != nil { + return err + } + if flags == nil { + flags = []string{} + } + f.values = append(f.values, ppfValue{match, flags}) + return nil +} + +// String is required to implement flag.Value. +// It is not used, because cmd/go never calls flag.PrintDefaults. +func (f *PerPackageFlag) String() string { return "" } + +// Present reports whether the flag appeared on the command line. +func (f *PerPackageFlag) Present() bool { + return f.present +} + +// For returns the flags to use for the given package. +func (f *PerPackageFlag) For(p *Package) []string { + flags := []string{} + for _, v := range f.values { + if v.match(p) { + flags = v.flags + } + } + return flags +} diff --git a/src/cmd/go/internal/load/flag_test.go b/src/cmd/go/internal/load/flag_test.go new file mode 100644 index 0000000..d3223e1 --- /dev/null +++ b/src/cmd/go/internal/load/flag_test.go @@ -0,0 +1,135 @@ +// 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 load + +import ( + "fmt" + "path/filepath" + "reflect" + "testing" +) + +type ppfTestPackage struct { + path string + dir string + cmdline bool + flags []string +} + +type ppfTest struct { + args []string + pkgs []ppfTestPackage +} + +var ppfTests = []ppfTest{ + // -gcflags=-S applies only to packages on command line. + { + args: []string{"-S"}, + pkgs: []ppfTestPackage{ + {cmdline: true, flags: []string{"-S"}}, + {cmdline: false, flags: []string{}}, + }, + }, + + // -gcflags=-S -gcflags= overrides the earlier -S. + { + args: []string{"-S", ""}, + pkgs: []ppfTestPackage{ + {cmdline: true, flags: []string{}}, + }, + }, + + // -gcflags=net=-S applies only to package net + { + args: []string{"net=-S"}, + pkgs: []ppfTestPackage{ + {path: "math", cmdline: true, flags: []string{}}, + {path: "net", flags: []string{"-S"}}, + }, + }, + + // -gcflags=net=-S -gcflags=net= also overrides the earlier -S + { + args: []string{"net=-S", "net="}, + pkgs: []ppfTestPackage{ + {path: "net", flags: []string{}}, + }, + }, + + // -gcflags=net/...=-S net math + // applies -S to net and net/http but not math + { + args: []string{"net/...=-S"}, + pkgs: []ppfTestPackage{ + {path: "net", flags: []string{"-S"}}, + {path: "net/http", flags: []string{"-S"}}, + {path: "math", flags: []string{}}, + }, + }, + + // -gcflags=net/...=-S -gcflags=-m net math + // applies -m to net and math and -S to other packages matching net/... + // (net matches too, but it was grabbed by the later -gcflags). + { + args: []string{"net/...=-S", "-m"}, + pkgs: []ppfTestPackage{ + {path: "net", cmdline: true, flags: []string{"-m"}}, + {path: "math", cmdline: true, flags: []string{"-m"}}, + {path: "net", cmdline: false, flags: []string{"-S"}}, + {path: "net/http", flags: []string{"-S"}}, + {path: "math", flags: []string{}}, + }, + }, + + // relative path patterns + // ppfDirTest(pattern, n, dirs...) says the first n dirs should match and the others should not. + ppfDirTest(".", 1, "/my/test/dir", "/my/test", "/my/test/other", "/my/test/dir/sub"), + ppfDirTest("..", 1, "/my/test", "/my/test/dir", "/my/test/other", "/my/test/dir/sub"), + ppfDirTest("./sub", 1, "/my/test/dir/sub", "/my/test", "/my/test/dir", "/my/test/other", "/my/test/dir/sub/sub"), + ppfDirTest("../other", 1, "/my/test/other", "/my/test", "/my/test/dir", "/my/test/other/sub", "/my/test/dir/other", "/my/test/dir/sub"), + ppfDirTest("./...", 3, "/my/test/dir", "/my/test/dir/sub", "/my/test/dir/sub/sub", "/my/test/other", "/my/test/other/sub"), + ppfDirTest("../...", 4, "/my/test/dir", "/my/test/other", "/my/test/dir/sub", "/my/test/other/sub", "/my/other/test"), + ppfDirTest("../...sub...", 3, "/my/test/dir/sub", "/my/test/othersub", "/my/test/yellowsubmarine", "/my/other/test"), +} + +func ppfDirTest(pattern string, nmatch int, dirs ...string) ppfTest { + var pkgs []ppfTestPackage + for i, d := range dirs { + flags := []string{} + if i < nmatch { + flags = []string{"-S"} + } + pkgs = append(pkgs, ppfTestPackage{path: "p", dir: d, flags: flags}) + } + return ppfTest{args: []string{pattern + "=-S"}, pkgs: pkgs} +} + +func TestPerPackageFlag(t *testing.T) { + nativeDir := func(d string) string { + if filepath.Separator == '\\' { + return `C:` + filepath.FromSlash(d) + } + return d + } + + for i, tt := range ppfTests { + t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) { + ppFlags := new(PerPackageFlag) + for _, arg := range tt.args { + t.Logf("set(%s)", arg) + if err := ppFlags.set(arg, nativeDir("/my/test/dir")); err != nil { + t.Fatal(err) + } + } + for _, p := range tt.pkgs { + dir := nativeDir(p.dir) + flags := ppFlags.For(&Package{PackagePublic: PackagePublic{ImportPath: p.path, Dir: dir}, Internal: PackageInternal{CmdlinePkg: p.cmdline}}) + if !reflect.DeepEqual(flags, p.flags) { + t.Errorf("For(%v, %v, %v) = %v, want %v", p.path, dir, p.cmdline, flags, p.flags) + } + } + }) + } +} diff --git a/src/cmd/go/internal/load/path.go b/src/cmd/go/internal/load/path.go new file mode 100644 index 0000000..584cdff --- /dev/null +++ b/src/cmd/go/internal/load/path.go @@ -0,0 +1,18 @@ +// 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 load + +import ( + "path/filepath" +) + +// expandPath returns the symlink-expanded form of path. +func expandPath(p string) string { + x, err := filepath.EvalSymlinks(p) + if err == nil { + return x + } + return p +} diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go new file mode 100644 index 0000000..61fde89 --- /dev/null +++ b/src/cmd/go/internal/load/pkg.go @@ -0,0 +1,2594 @@ +// Copyright 2011 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 loads packages. +package load + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "go/build" + "go/scanner" + "go/token" + "io/fs" + "os" + "path" + pathpkg "path" + "path/filepath" + "runtime" + "sort" + "strconv" + "strings" + "unicode" + "unicode/utf8" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/fsys" + "cmd/go/internal/modinfo" + "cmd/go/internal/modload" + "cmd/go/internal/par" + "cmd/go/internal/search" + "cmd/go/internal/str" + "cmd/go/internal/trace" + "cmd/internal/sys" + + "golang.org/x/mod/module" +) + +var IgnoreImports bool // control whether we ignore imports in packages + +// A Package describes a single package found in a directory. +type Package struct { + PackagePublic // visible in 'go list' + Internal PackageInternal // for use inside go command only +} + +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) + Root string `json:",omitempty"` // Go root, Go path dir, or module root 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) + BuildID string `json:",omitempty"` // build ID of the compiled package (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. + // The regular build determines staleness on the fly during action execution. + Stale bool `json:",omitempty"` // would 'go install' do anything for this package? + StaleReason string `json:",omitempty"` // why is Stale true? + + // 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 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 + IgnoredOtherFiles []string `json:",omitempty"` // non-.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 + + // Embedded files + EmbedPatterns []string `json:",omitempty"` // //go:embed patterns + EmbedFiles []string `json:",omitempty"` // files matched by EmbedPatterns + + // Cgo directives + CgoCFLAGS []string `json:",omitempty"` // cgo: flags for C compiler + CgoCPPFLAGS []string `json:",omitempty"` // cgo: flags for C preprocessor + CgoCXXFLAGS []string `json:",omitempty"` // cgo: flags for C++ compiler + CgoFFLAGS []string `json:",omitempty"` // cgo: flags for Fortran compiler + CgoLDFLAGS []string `json:",omitempty"` // cgo: flags for linker + CgoPkgConfig []string `json:",omitempty"` // cgo: pkg-config names + + // Dependency information + 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 is above, packed into the other bools + Error *PackageError `json:",omitempty"` // error loading this package (not dependencies) + DepsErrors []*PackageError `json:",omitempty"` // errors loading dependencies + + // Test information + // 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. + TestGoFiles []string `json:",omitempty"` // _test.go files in package + TestImports []string `json:",omitempty"` // imports from TestGoFiles + TestEmbedPatterns []string `json:",omitempty"` // //go:embed patterns + TestEmbedFiles []string `json:",omitempty"` // files matched by TestEmbedPatterns + XTestGoFiles []string `json:",omitempty"` // _test.go files outside package + XTestImports []string `json:",omitempty"` // imports from XTestGoFiles + XTestEmbedPatterns []string `json:",omitempty"` // //go:embed patterns + XTestEmbedFiles []string `json:",omitempty"` // files matched by XTestEmbedPatterns +} + +// AllFiles returns the names of all the files considered for the package. +// This is used for sanity and security checks, so we include all files, +// even IgnoredGoFiles, because some subcommands consider them. +// The go/build package filtered others out (like foo_wrongGOARCH.s) +// and that's OK. +func (p *Package) AllFiles() []string { + files := str.StringList( + p.GoFiles, + p.CgoFiles, + // no p.CompiledGoFiles, because they are from GoFiles or generated by us + p.IgnoredGoFiles, + p.IgnoredOtherFiles, + p.CFiles, + p.CXXFiles, + p.MFiles, + p.HFiles, + p.FFiles, + p.SFiles, + p.SwigFiles, + p.SwigCXXFiles, + p.SysoFiles, + p.TestGoFiles, + p.XTestGoFiles, + ) + + // EmbedFiles may overlap with the other files. + // Dedup, but delay building the map as long as possible. + // Only files in the current directory (no slash in name) + // need to be checked against the files variable above. + var have map[string]bool + for _, file := range p.EmbedFiles { + if !strings.Contains(file, "/") { + if have == nil { + have = make(map[string]bool) + for _, file := range files { + have[file] = true + } + } + if have[file] { + continue + } + } + files = append(files, file) + } + return files +} + +// 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 + 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 + Embed map[string][]string // //go:embed comment mapping + + Asmflags []string // -asmflags for this package + Gcflags []string // -gcflags for this package + Ldflags []string // -ldflags for this package + Gccgoflags []string // -gccgoflags for this package +} + +// A NoGoError indicates that no Go files for the package were applicable to the +// build for that package. +// +// That may be because there were no files whatsoever, or because all files were +// excluded, or because all non-excluded files were test sources. +type NoGoError struct { + Package *Package +} + +func (e *NoGoError) Error() string { + if len(e.Package.IgnoredGoFiles) > 0 { + // Go files exist, but they were ignored due to build constraints. + return "build constraints exclude all Go files in " + e.Package.Dir + } + if len(e.Package.TestGoFiles)+len(e.Package.XTestGoFiles) > 0 { + // Test Go files exist, but we're not interested in them. + // The double-negative is unfortunate but we want e.Package.Dir + // to appear at the end of error message. + return "no non-test Go files in " + e.Package.Dir + } + return "no Go files in " + e.Package.Dir +} + +// setLoadPackageDataError presents an error found when loading package data +// as a *PackageError. It has special cases for some common errors to improve +// messages shown to users and reduce redundancy. +// +// setLoadPackageDataError returns true if it's safe to load information about +// imported packages, for example, if there was a parse error loading imports +// in one file, but other files are okay. +func (p *Package) setLoadPackageDataError(err error, path string, stk *ImportStack, importPos []token.Position) { + matchErr, isMatchErr := err.(*search.MatchError) + if isMatchErr && matchErr.Match.Pattern() == path { + if matchErr.Match.IsLiteral() { + // The error has a pattern has a pattern similar to the import path. + // It may be slightly different (./foo matching example.com/foo), + // but close enough to seem redundant. + // Unwrap the error so we don't show the pattern. + err = matchErr.Err + } + } + + // Replace (possibly wrapped) *build.NoGoError with *load.NoGoError. + // The latter is more specific about the cause. + var nogoErr *build.NoGoError + if errors.As(err, &nogoErr) { + if p.Dir == "" && nogoErr.Dir != "" { + p.Dir = nogoErr.Dir + } + err = &NoGoError{Package: p} + } + + // Take only the first error from a scanner.ErrorList. PackageError only + // has room for one position, so we report the first error with a position + // instead of all of the errors without a position. + var pos string + var isScanErr bool + if scanErr, ok := err.(scanner.ErrorList); ok && len(scanErr) > 0 { + isScanErr = true // For stack push/pop below. + + scanPos := scanErr[0].Pos + scanPos.Filename = base.ShortPath(scanPos.Filename) + pos = scanPos.String() + err = errors.New(scanErr[0].Msg) + } + + // Report the error on the importing package if the problem is with the import declaration + // for example, if the package doesn't exist or if the import path is malformed. + // On the other hand, don't include a position if the problem is with the imported package, + // for example there are no Go files (NoGoError), or there's a problem in the imported + // package's source files themselves (scanner errors). + // + // TODO(matloob): Perhaps make each of those the errors in the first group + // (including modload.ImportMissingError, ImportMissingSumError, and the + // corresponding "cannot find package %q in any of" GOPATH-mode error + // produced in build.(*Context).Import; modload.AmbiguousImportError, + // and modload.PackageNotInModuleError; and the malformed module path errors + // produced in golang.org/x/mod/module.CheckMod) implement an interface + // to make it easier to check for them? That would save us from having to + // move the modload errors into this package to avoid a package import cycle, + // and from having to export an error type for the errors produced in build. + if !isMatchErr && (nogoErr != nil || isScanErr) { + stk.Push(path) + defer stk.Pop() + } + + p.Error = &PackageError{ + ImportStack: stk.Copy(), + Pos: pos, + Err: err, + } + + if path != stk.Top() { + p.Error.setPos(importPos) + } +} + +// Resolve returns the resolved version of imports, +// which should be p.TestImports or p.XTestImports, NOT p.Imports. +// The imports in p.TestImports and p.XTestImports are not recursively +// loaded during the initial load of p, so they list the imports found in +// the source file, but most processing should be over the vendor-resolved +// import paths. We do this resolution lazily both to avoid file system work +// and because the eventual real load of the test imports (during 'go test') +// can produce better error messages if it starts with the original paths. +// The initial load of p loads all the non-test imports and rewrites +// the vendored paths, so nothing should ever call p.vendored(p.Imports). +func (p *Package) Resolve(imports []string) []string { + if len(imports) > 0 && len(p.Imports) > 0 && &imports[0] == &p.Imports[0] { + panic("internal error: p.Resolve(p.Imports) called") + } + seen := make(map[string]bool) + var all []string + for _, path := range imports { + path = ResolveImportPath(p, path) + if !seen[path] { + seen[path] = true + all = append(all, path) + } + } + sort.Strings(all) + return all +} + +// CoverVar holds the name of the generated coverage variables targeting the named file. +type CoverVar struct { + File string // local file name + Var string // name of count struct +} + +func (p *Package) copyBuild(pp *build.Package) { + p.Internal.Build = pp + + if pp.PkgTargetRoot != "" && cfg.BuildPkgdir != "" { + old := pp.PkgTargetRoot + pp.PkgRoot = cfg.BuildPkgdir + pp.PkgTargetRoot = cfg.BuildPkgdir + pp.PkgObj = filepath.Join(cfg.BuildPkgdir, strings.TrimPrefix(pp.PkgObj, old)) + } + + p.Dir = pp.Dir + p.ImportPath = pp.ImportPath + p.ImportComment = pp.ImportComment + p.Name = pp.Name + p.Doc = pp.Doc + p.Root = pp.Root + p.ConflictDir = pp.ConflictDir + p.BinaryOnly = pp.BinaryOnly + + // TODO? Target + p.Goroot = pp.Goroot + p.Standard = p.Goroot && p.ImportPath != "" && search.IsStandardImportPath(p.ImportPath) + p.GoFiles = pp.GoFiles + p.CgoFiles = pp.CgoFiles + p.IgnoredGoFiles = pp.IgnoredGoFiles + p.IgnoredOtherFiles = pp.IgnoredOtherFiles + p.CFiles = pp.CFiles + p.CXXFiles = pp.CXXFiles + p.MFiles = pp.MFiles + p.HFiles = pp.HFiles + p.FFiles = pp.FFiles + p.SFiles = pp.SFiles + p.SwigFiles = pp.SwigFiles + p.SwigCXXFiles = pp.SwigCXXFiles + p.SysoFiles = pp.SysoFiles + p.CgoCFLAGS = pp.CgoCFLAGS + p.CgoCPPFLAGS = pp.CgoCPPFLAGS + p.CgoCXXFLAGS = pp.CgoCXXFLAGS + p.CgoFFLAGS = pp.CgoFFLAGS + p.CgoLDFLAGS = pp.CgoLDFLAGS + p.CgoPkgConfig = pp.CgoPkgConfig + // We modify p.Imports in place, so make copy now. + p.Imports = make([]string, len(pp.Imports)) + copy(p.Imports, pp.Imports) + p.Internal.RawImports = pp.Imports + p.TestGoFiles = pp.TestGoFiles + p.TestImports = pp.TestImports + p.XTestGoFiles = pp.XTestGoFiles + p.XTestImports = pp.XTestImports + if IgnoreImports { + p.Imports = nil + p.Internal.RawImports = nil + p.TestImports = nil + p.XTestImports = nil + } + p.EmbedPatterns = pp.EmbedPatterns + p.TestEmbedPatterns = pp.TestEmbedPatterns + p.XTestEmbedPatterns = pp.XTestEmbedPatterns +} + +// 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 + Pos string // position of error + Err error // the error itself + IsImportCycle bool // the error is an import cycle + Hard bool // whether the error is soft or hard; soft errors are ignored in some places + alwaysPrintStack bool // whether to always print the ImportStack +} + +func (p *PackageError) Error() string { + // TODO(#43696): decide when to print the stack or the position based on + // the error type and whether the package is in the main module. + // Document the rationale. + if p.Pos != "" && (len(p.ImportStack) == 0 || !p.alwaysPrintStack) { + // Omit import stack. The full path to the file where the error + // is the most important thing. + return p.Pos + ": " + p.Err.Error() + } + + // If the error is an ImportPathError, and the last path on the stack appears + // in the error message, omit that path from the stack to avoid repetition. + // If an ImportPathError wraps another ImportPathError that matches the + // last path on the stack, we don't omit the path. An error like + // "package A imports B: error loading C caused by B" would not be clearer + // if "imports B" were omitted. + if len(p.ImportStack) == 0 { + return p.Err.Error() + } + var optpos string + if p.Pos != "" { + optpos = "\n\t" + p.Pos + } + return "package " + strings.Join(p.ImportStack, "\n\timports ") + optpos + ": " + p.Err.Error() +} + +func (p *PackageError) Unwrap() error { return p.Err } + +// PackageError implements MarshalJSON so that Err is marshaled as a string +// and non-essential fields are omitted. +func (p *PackageError) MarshalJSON() ([]byte, error) { + perr := struct { + ImportStack []string + Pos string + Err string + }{p.ImportStack, p.Pos, p.Err.Error()} + return json.Marshal(perr) +} + +func (p *PackageError) setPos(posList []token.Position) { + if len(posList) == 0 { + return + } + pos := posList[0] + pos.Filename = base.ShortPath(pos.Filename) + p.Pos = pos.String() +} + +// ImportPathError is a type of error that prevents a package from being loaded +// for a given import path. When such a package is loaded, a *Package is +// returned with Err wrapping an ImportPathError: the error is attached to +// the imported package, not the importing package. +// +// The string returned by ImportPath must appear in the string returned by +// Error. Errors that wrap ImportPathError (such as PackageError) may omit +// the import path. +type ImportPathError interface { + error + ImportPath() string +} + +var ( + _ ImportPathError = (*importError)(nil) + _ ImportPathError = (*modload.ImportMissingError)(nil) + _ ImportPathError = (*modload.ImportMissingSumError)(nil) +) + +type importError struct { + importPath string + err error // created with fmt.Errorf +} + +func ImportErrorf(path, format string, args ...interface{}) ImportPathError { + err := &importError{importPath: path, err: fmt.Errorf(format, args...)} + if errStr := err.Error(); !strings.Contains(errStr, path) { + panic(fmt.Sprintf("path %q not in error %q", path, errStr)) + } + return err +} + +func (e *importError) Error() string { + return e.err.Error() +} + +func (e *importError) Unwrap() error { + // Don't return e.err directly, since we're only wrapping an error if %w + // was passed to ImportErrorf. + return errors.Unwrap(e.err) +} + +func (e *importError) ImportPath() string { + return e.importPath +} + +// 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) { + *s = append(*s, p) +} + +func (s *ImportStack) Pop() { + *s = (*s)[0 : len(*s)-1] +} + +func (s *ImportStack) Copy() []string { + return append([]string{}, *s...) +} + +func (s *ImportStack) Top() string { + if len(*s) == 0 { + return "" + } + return (*s)[len(*s)-1] +} + +// shorterThan reports whether sp is shorter than t. +// We use this to record the shortest import sequence +// that leads to a particular package. +func (sp *ImportStack) shorterThan(t []string) bool { + s := *sp + if len(s) != len(t) { + return len(s) < len(t) + } + // If they are the same length, settle ties using string ordering. + for i := range s { + if s[i] != t[i] { + return s[i] < t[i] + } + } + return false // they are equal +} + +// packageCache is a lookup cache for LoadImport, +// so that if we look up a package multiple times +// we return the same pointer each time. +var packageCache = map[string]*Package{} + +// ClearPackageCache clears the in-memory package cache and the preload caches. +// It is only for use by GOPATH-based "go get". +// TODO(jayconrod): When GOPATH-based "go get" is removed, delete this function. +func ClearPackageCache() { + for name := range packageCache { + delete(packageCache, name) + } + resolvedImportCache.Clear() + packageDataCache.Clear() +} + +// ClearPackageCachePartial clears packages with the given import paths from the +// in-memory package cache and the preload caches. It is only for use by +// GOPATH-based "go get". +// TODO(jayconrod): When GOPATH-based "go get" is removed, delete this function. +func ClearPackageCachePartial(args []string) { + shouldDelete := make(map[string]bool) + for _, arg := range args { + shouldDelete[arg] = true + if p := packageCache[arg]; p != nil { + delete(packageCache, arg) + } + } + resolvedImportCache.DeleteIf(func(key interface{}) bool { + return shouldDelete[key.(importSpec).path] + }) + packageDataCache.DeleteIf(func(key interface{}) bool { + return shouldDelete[key.(string)] + }) +} + +// ReloadPackageNoFlags is like LoadImport but makes sure +// not to use the package cache. +// 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, arg) + resolvedImportCache.DeleteIf(func(key interface{}) bool { + return key.(importSpec).path == p.ImportPath + }) + packageDataCache.Delete(p.ImportPath) + } + return LoadImport(context.TODO(), arg, base.Cwd, nil, stk, nil, 0) +} + +// dirToImportPath returns the pseudo-import path we use for a package +// outside the Go path. It begins with _/ and then contains the full path +// to the directory. If the package lives in c:\home\gopher\my\pkg then +// the pseudo-import path is _/c_/home/gopher/my/pkg. +// Using a pseudo-import path like this makes the ./ imports no longer +// a special case, so that all the code to deal with ordinary imports works +// automatically. +func dirToImportPath(dir string) string { + return pathpkg.Join("_", strings.Map(makeImportValid, filepath.ToSlash(dir))) +} + +func makeImportValid(r rune) rune { + // Should match Go spec, compilers, and ../../go/parser/parser.go:/isValidImport. + const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD" + if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) { + return '_' + } + return r +} + +// Mode flags for loadImport and download (in get.go). +const ( + // ResolveImport means that loadImport should do import path expansion. + // That is, ResolveImport means that the import path came from + // a source file and has not been expanded yet to account for + // vendoring or possible module adjustment. + // Every import path should be loaded initially with ResolveImport, + // and then the expanded version (for example with the /vendor/ in it) + // gets recorded as the canonical import path. At that point, future loads + // of that package must not pass ResolveImport, because + // disallowVendor will reject direct use of paths containing /vendor/. + ResolveImport = 1 << iota + + // ResolveModule is for download (part of "go get") and indicates + // that the module adjustment should be done, but not vendor adjustment. + ResolveModule + + // GetTestDeps is for download (part of "go get") and indicates + // that test dependencies should be fetched too. + GetTestDeps +) + +// LoadImport scans the directory named by path, which must be an import path, +// 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(ctx context.Context, path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) *Package { + return loadImport(ctx, nil, path, srcDir, parent, stk, importPos, mode) +} + +func loadImport(ctx context.Context, pre *preload, path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) *Package { + if path == "" { + panic("LoadImport called with empty package path") + } + + var parentPath, parentRoot string + parentIsStd := false + if parent != nil { + parentPath = parent.ImportPath + parentRoot = parent.Root + parentIsStd = parent.Standard + } + bp, loaded, err := loadPackageData(path, parentPath, srcDir, parentRoot, parentIsStd, mode) + if loaded && pre != nil && !IgnoreImports { + pre.preloadImports(bp.Imports, bp) + } + if bp == nil { + if importErr, ok := err.(ImportPathError); !ok || importErr.ImportPath() != path { + // Only add path to the error's import stack if it's not already present on the error. + stk.Push(path) + defer stk.Pop() + } + return &Package{ + PackagePublic: PackagePublic{ + ImportPath: path, + Error: &PackageError{ + ImportStack: stk.Copy(), + Err: err, + }, + }, + } + } + + importPath := bp.ImportPath + p := packageCache[importPath] + if p != nil { + stk.Push(path) + p = reusePackage(p, stk) + stk.Pop() + } else { + p = new(Package) + p.Internal.Local = build.IsLocalImport(path) + p.ImportPath = importPath + packageCache[importPath] = p + + // Load package. + // loadPackageData may return bp != nil even if an error occurs, + // in order to return partial information. + p.load(ctx, path, stk, importPos, bp, err) + + if !cfg.ModulesEnabled && path != cleanImport(path) { + p.Error = &PackageError{ + ImportStack: stk.Copy(), + Err: ImportErrorf(path, "non-canonical import path %q: should be %q", path, pathpkg.Clean(path)), + } + p.Incomplete = true + p.Error.setPos(importPos) + } + } + + // Checked on every import because the rules depend on the code doing the importing. + if perr := disallowInternal(srcDir, parent, parentPath, p, stk); perr != p { + perr.Error.setPos(importPos) + return perr + } + if mode&ResolveImport != 0 { + if perr := disallowVendor(srcDir, path, parentPath, p, stk); perr != p { + perr.Error.setPos(importPos) + return perr + } + } + + if p.Name == "main" && parent != nil && parent.Dir != p.Dir { + perr := *p + perr.Error = &PackageError{ + ImportStack: stk.Copy(), + Err: ImportErrorf(path, "import %q is a program, not an importable package", path), + } + perr.Error.setPos(importPos) + return &perr + } + + if p.Internal.Local && parent != nil && !parent.Internal.Local { + perr := *p + var err error + if path == "." { + err = ImportErrorf(path, "%s: cannot import current directory", path) + } else { + err = ImportErrorf(path, "local import %q in non-local package", path) + } + perr.Error = &PackageError{ + ImportStack: stk.Copy(), + Err: err, + } + perr.Error.setPos(importPos) + return &perr + } + + return p +} + +// loadPackageData loads information needed to construct a *Package. The result +// is cached, and later calls to loadPackageData for the same package will return +// the same data. +// +// loadPackageData returns a non-nil package even if err is non-nil unless +// the package path is malformed (for example, the path contains "mod/" or "@"). +// +// loadPackageData returns a boolean, loaded, which is true if this is the +// first time the package was loaded. Callers may preload imports in this case. +func loadPackageData(path, parentPath, parentDir, parentRoot string, parentIsStd bool, mode int) (bp *build.Package, loaded bool, err error) { + if path == "" { + panic("loadPackageData called with empty package path") + } + + 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 nil, false, fmt.Errorf("disallowed import path %q", path) + } + + if strings.Contains(path, "@") { + return nil, false, errors.New("can only use path@version syntax with 'go get' and 'go install' in module-aware mode") + } + + // Determine canonical package path and directory. + // For a local import the identifier is the pseudo-import path + // we create from the full directory to the package. + // Otherwise it is the usual import path. + // For vendored imports, it is the expanded form. + // + // Note that when modules are enabled, local import paths are normally + // canonicalized by modload.LoadPackages before now. However, if there's an + // error resolving a local path, it will be returned untransformed + // so that 'go list -e' reports something useful. + importKey := importSpec{ + path: path, + parentPath: parentPath, + parentDir: parentDir, + parentRoot: parentRoot, + parentIsStd: parentIsStd, + mode: mode, + } + r := resolvedImportCache.Do(importKey, func() interface{} { + var r resolvedImport + if build.IsLocalImport(path) { + r.dir = filepath.Join(parentDir, path) + r.path = dirToImportPath(r.dir) + } else if cfg.ModulesEnabled { + r.dir, r.path, r.err = modload.Lookup(parentPath, parentIsStd, path) + } 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 + // overhead of repeated calls to buildContext.Import. + // The code is also needed in a few other places anyway. + r.path = resolveImportPath(path, parentPath, parentDir, parentRoot, parentIsStd) + } else if mode&ResolveModule != 0 { + r.path = moduleImportPath(path, parentPath, parentDir, parentRoot) + } + if r.path == "" { + r.path = path + } + return r + }).(resolvedImport) + // Invariant: r.path is set to the resolved import path. If the path cannot + // be resolved, r.path is set to path, the source import path. + // r.path is never empty. + + // Load the package from its directory. If we already found the package's + // directory when resolving its import path, use that. + data := packageDataCache.Do(r.path, func() interface{} { + loaded = true + var data packageData + if r.dir != "" { + var buildMode build.ImportMode + if !cfg.ModulesEnabled { + buildMode = build.ImportComment + } + data.p, data.err = cfg.BuildContext.ImportDir(r.dir, buildMode) + if data.p.Root == "" && cfg.ModulesEnabled { + if info := modload.PackageModuleInfo(path); info != nil { + data.p.Root = info.Dir + } + } + } else if r.err != nil { + data.p = new(build.Package) + data.err = r.err + } else if cfg.ModulesEnabled && path != "unsafe" { + data.p = new(build.Package) + data.err = fmt.Errorf("unknown import path %q: internal error: module loader did not resolve import", r.path) + } else { + buildMode := build.ImportComment + if mode&ResolveImport == 0 || r.path != path { + // Not vendoring, or we already found the vendored path. + buildMode |= build.IgnoreVendor + } + data.p, data.err = cfg.BuildContext.Import(r.path, parentDir, buildMode) + } + data.p.ImportPath = r.path + + // Set data.p.BinDir in cases where go/build.Context.Import + // may give us a path we don't want. + if !data.p.Goroot { + if cfg.GOBIN != "" { + data.p.BinDir = cfg.GOBIN + } else if cfg.ModulesEnabled { + data.p.BinDir = modload.BinDir() + } + } + + if !cfg.ModulesEnabled && data.err == nil && + data.p.ImportComment != "" && data.p.ImportComment != path && + !strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/") { + data.err = fmt.Errorf("code in directory %s expects import %q", data.p.Dir, data.p.ImportComment) + } + return data + }).(packageData) + + return data.p, loaded, data.err +} + +// importSpec describes an import declaration in source code. It is used as a +// cache key for resolvedImportCache. +type importSpec struct { + path string + parentPath, parentDir, parentRoot string + parentIsStd bool + mode int +} + +// resolvedImport holds a canonical identifier for a package. It may also contain +// a path to the package's directory and an error if one occurred. resolvedImport +// is the value type in resolvedImportCache. +type resolvedImport struct { + path, dir string + err error +} + +// packageData holds information loaded from a package. It is the value type +// in packageDataCache. +type packageData struct { + p *build.Package + err error +} + +// resolvedImportCache maps import strings (importSpec) to canonical package names +// (resolvedImport). +var resolvedImportCache par.Cache + +// packageDataCache maps canonical package names (string) to package metadata +// (packageData). +var packageDataCache par.Cache + +// preloadWorkerCount is the number of concurrent goroutines that can load +// packages. Experimentally, there are diminishing returns with more than +// 4 workers. This was measured on the following machines. +// +// * MacBookPro with a 4-core Intel Core i7 CPU +// * Linux workstation with 6-core Intel Xeon CPU +// * Linux workstation with 24-core Intel Xeon CPU +// +// It is very likely (though not confirmed) that this workload is limited +// by memory bandwidth. We don't have a good way to determine the number of +// workers that would saturate the bus though, so runtime.GOMAXPROCS +// seems like a reasonable default. +var preloadWorkerCount = runtime.GOMAXPROCS(0) + +// preload holds state for managing concurrent preloading of package data. +// +// A preload should be created with newPreload before loading a large +// package graph. flush must be called when package loading is complete +// to ensure preload goroutines are no longer active. This is necessary +// because of global mutable state that cannot safely be read and written +// concurrently. In particular, packageDataCache may be cleared by "go get" +// in GOPATH mode, and modload.loaded (accessed via modload.Lookup) may be +// modified by modload.LoadPackages. +type preload struct { + cancel chan struct{} + sema chan struct{} +} + +// newPreload creates a new preloader. flush must be called later to avoid +// accessing global state while it is being modified. +func newPreload() *preload { + pre := &preload{ + cancel: make(chan struct{}), + sema: make(chan struct{}, preloadWorkerCount), + } + return pre +} + +// preloadMatches loads data for package paths matched by patterns. +// When preloadMatches returns, some packages may not be loaded yet, but +// loadPackageData and loadImport are always safe to call. +func (pre *preload) preloadMatches(matches []*search.Match) { + for _, m := range matches { + for _, pkg := range m.Pkgs { + select { + case <-pre.cancel: + return + case pre.sema <- struct{}{}: + go func(pkg string) { + mode := 0 // don't use vendoring or module import resolution + bp, loaded, err := loadPackageData(pkg, "", base.Cwd, "", false, mode) + <-pre.sema + if bp != nil && loaded && err == nil && !IgnoreImports { + pre.preloadImports(bp.Imports, bp) + } + }(pkg) + } + } + } +} + +// preloadImports queues a list of imports for preloading. +// When preloadImports returns, some packages may not be loaded yet, +// but loadPackageData and loadImport are always safe to call. +func (pre *preload) preloadImports(imports []string, parent *build.Package) { + parentIsStd := parent.Goroot && parent.ImportPath != "" && search.IsStandardImportPath(parent.ImportPath) + for _, path := range imports { + if path == "C" || path == "unsafe" { + continue + } + select { + case <-pre.cancel: + return + case pre.sema <- struct{}{}: + go func(path string) { + bp, loaded, err := loadPackageData(path, parent.ImportPath, parent.Dir, parent.Root, parentIsStd, ResolveImport) + <-pre.sema + if bp != nil && loaded && err == nil && !IgnoreImports { + pre.preloadImports(bp.Imports, bp) + } + }(path) + } + } +} + +// flush stops pending preload operations. flush blocks until preload calls to +// loadPackageData have completed. The preloader will not make any new calls +// to loadPackageData. +func (pre *preload) flush() { + // flush is usually deferred. + // Don't hang program waiting for workers on panic. + if v := recover(); v != nil { + panic(v) + } + + close(pre.cancel) + for i := 0; i < preloadWorkerCount; i++ { + pre.sema <- struct{}{} + } +} + +func cleanImport(path string) string { + orig := path + path = pathpkg.Clean(path) + if strings.HasPrefix(orig, "./") && path != ".." && !strings.HasPrefix(path, "../") { + path = "./" + path + } + return path +} + +var isDirCache par.Cache + +func isDir(path string) bool { + return isDirCache.Do(path, func() interface{} { + fi, err := fsys.Stat(path) + return err == nil && fi.IsDir() + }).(bool) +} + +// ResolveImportPath returns the true meaning of path when it appears in parent. +// 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 module legacy conversion (golang.org/issue/25069). +func ResolveImportPath(parent *Package, path string) (found string) { + var parentPath, parentDir, parentRoot string + parentIsStd := false + if parent != nil { + parentPath = parent.ImportPath + parentDir = parent.Dir + parentRoot = parent.Root + parentIsStd = parent.Standard + } + return resolveImportPath(path, parentPath, parentDir, parentRoot, parentIsStd) +} + +func resolveImportPath(path, parentPath, parentDir, parentRoot string, parentIsStd bool) (found string) { + if cfg.ModulesEnabled { + if _, p, e := modload.Lookup(parentPath, parentIsStd, path); e == nil { + return p + } + return path + } + found = vendoredImportPath(path, parentPath, parentDir, parentRoot) + if found != path { + return found + } + return moduleImportPath(path, parentPath, parentDir, parentRoot) +} + +// dirAndRoot returns the source directory and workspace root +// for the package p, guaranteeing that root is a path prefix of dir. +func dirAndRoot(path string, dir, root string) (string, string) { + origDir, origRoot := dir, root + dir = filepath.Clean(dir) + root = filepath.Join(root, "src") + if !str.HasFilePathPrefix(dir, root) || path != "command-line-arguments" && filepath.Join(root, path) != dir { + // Look for symlinks before reporting error. + dir = expandPath(dir) + root = expandPath(root) + } + + if !str.HasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator || path != "command-line-arguments" && !build.IsLocalImport(path) && filepath.Join(root, path) != dir { + base.Fatalf("unexpected directory layout:\n"+ + " import path: %s\n"+ + " root: %s\n"+ + " dir: %s\n"+ + " expand root: %s\n"+ + " expand dir: %s\n"+ + " separator: %s", + path, + filepath.Join(origRoot, "src"), + filepath.Clean(origDir), + origRoot, + origDir, + string(filepath.Separator)) + } + + return dir, root +} + +// vendoredImportPath returns the vendor-expansion of path when it appears in parent. +// If parent is x/y/z, then path might expand to x/y/z/vendor/path, x/y/vendor/path, +// x/vendor/path, vendor/path, or else stay path if none of those exist. +// vendoredImportPath returns the expanded path or, if no expansion is found, the original. +func vendoredImportPath(path, parentPath, parentDir, parentRoot string) (found string) { + if parentRoot == "" { + return path + } + + dir, root := dirAndRoot(parentPath, parentDir, parentRoot) + + vpath := "vendor/" + path + for i := len(dir); i >= len(root); i-- { + if i < len(dir) && dir[i] != filepath.Separator { + continue + } + // Note: checking for the vendor directory before checking + // for the vendor/path directory helps us hit the + // isDir cache more often. It also helps us prepare a more useful + // list of places we looked, to report when an import is not found. + if !isDir(filepath.Join(dir[:i], "vendor")) { + continue + } + targ := filepath.Join(dir[:i], vpath) + if isDir(targ) && hasGoFiles(targ) { + importPath := parentPath + if importPath == "command-line-arguments" { + // If parent.ImportPath is 'command-line-arguments'. + // set to relative directory to root (also chopped root directory) + importPath = dir[len(root)+1:] + } + // We started with parent's dir c:\gopath\src\foo\bar\baz\quux\xyzzy. + // We know the import path for parent's dir. + // We chopped off some number of path elements and + // added vendor\path to produce c:\gopath\src\foo\bar\baz\vendor\path. + // Now we want to know the import path for that directory. + // Construct it by chopping the same number of path elements + // (actually the same number of bytes) from parent's import path + // and then append /vendor/path. + chopped := len(dir) - i + if chopped == len(importPath)+1 { + // We walked up from c:\gopath\src\foo\bar + // and found c:\gopath\src\vendor\path. + // We chopped \foo\bar (length 8) but the import path is "foo/bar" (length 7). + // Use "vendor/path" without any prefix. + return vpath + } + return importPath[:len(importPath)-chopped] + "/" + vpath + } + } + return path +} + +var ( + modulePrefix = []byte("\nmodule ") + goModPathCache par.Cache +) + +// goModPath returns the module path in the go.mod in dir, if any. +func goModPath(dir string) (path string) { + return goModPathCache.Do(dir, func() interface{} { + data, err := os.ReadFile(filepath.Join(dir, "go.mod")) + if err != nil { + return "" + } + var i int + if bytes.HasPrefix(data, modulePrefix[1:]) { + i = 0 + } else { + i = bytes.Index(data, modulePrefix) + if i < 0 { + return "" + } + i++ + } + line := data[i:] + + // Cut line at \n, drop trailing \r if present. + if j := bytes.IndexByte(line, '\n'); j >= 0 { + line = line[:j] + } + if line[len(line)-1] == '\r' { + line = line[:len(line)-1] + } + line = line[len("module "):] + + // If quoted, unquote. + path = strings.TrimSpace(string(line)) + if path != "" && path[0] == '"' { + s, err := strconv.Unquote(path) + if err != nil { + return "" + } + path = s + } + return path + }).(string) +} + +// findVersionElement returns the slice indices of the final version element /vN in path. +// If there is no such element, it returns -1, -1. +func findVersionElement(path string) (i, j int) { + j = len(path) + for i = len(path) - 1; i >= 0; i-- { + if path[i] == '/' { + if isVersionElement(path[i+1 : j]) { + return i, j + } + j = i + } + } + return -1, -1 +} + +// isVersionElement reports whether s is a well-formed path version element: +// v2, v3, v10, etc, but not v0, v05, v1. +func isVersionElement(s string) bool { + if len(s) < 2 || s[0] != 'v' || s[1] == '0' || s[1] == '1' && len(s) == 2 { + return false + } + for i := 1; i < len(s); i++ { + if s[i] < '0' || '9' < s[i] { + return false + } + } + return true +} + +// moduleImportPath translates import paths found in go modules +// back down to paths that can be resolved in ordinary builds. +// +// Define “new” code as code with a go.mod file in the same directory +// or a parent directory. If an import in new code says x/y/v2/z but +// x/y/v2/z does not exist and x/y/go.mod says “module x/y/v2”, +// then go build will read the import as x/y/z instead. +// See golang.org/issue/25069. +func moduleImportPath(path, parentPath, parentDir, parentRoot string) (found string) { + if parentRoot == "" { + return path + } + + // If there are no vN elements in path, leave it alone. + // (The code below would do the same, but only after + // some other file system accesses that we can avoid + // here by returning early.) + if i, _ := findVersionElement(path); i < 0 { + return path + } + + dir, root := dirAndRoot(parentPath, parentDir, parentRoot) + + // Consider dir and parents, up to and including root. + for i := len(dir); i >= len(root); i-- { + if i < len(dir) && dir[i] != filepath.Separator { + continue + } + if goModPath(dir[:i]) != "" { + goto HaveGoMod + } + } + // This code is not in a tree with a go.mod, + // so apply no changes to the path. + return path + +HaveGoMod: + // This import is in a tree with a go.mod. + // Allow it to refer to code in GOPATH/src/x/y/z as x/y/v2/z + // if GOPATH/src/x/y/go.mod says module "x/y/v2", + + // If x/y/v2/z exists, use it unmodified. + if bp, _ := cfg.BuildContext.Import(path, "", build.IgnoreVendor); bp.Dir != "" { + return path + } + + // Otherwise look for a go.mod supplying a version element. + // Some version-like elements may appear in paths but not + // be module versions; we skip over those to look for module + // versions. For example the module m/v2 might have a + // package m/v2/api/v1/foo. + limit := len(path) + for limit > 0 { + i, j := findVersionElement(path[:limit]) + if i < 0 { + return path + } + if bp, _ := cfg.BuildContext.Import(path[:i], "", build.IgnoreVendor); bp.Dir != "" { + if mpath := goModPath(bp.Dir); mpath != "" { + // Found a valid go.mod file, so we're stopping the search. + // If the path is m/v2/p and we found m/go.mod that says + // "module m/v2", then we return "m/p". + if mpath == path[:j] { + return path[:i] + path[j:] + } + // Otherwise just return the original path. + // We didn't find anything worth rewriting, + // and the go.mod indicates that we should + // not consider parent directories. + return path + } + } + limit = i + } + return path +} + +// hasGoFiles reports whether dir contains any files with names ending in .go. +// For a vendor check we must exclude directories that contain no .go files. +// Otherwise it is not possible to vendor just a/b/c and still import the +// non-vendored a/b. See golang.org/issue/13832. +func hasGoFiles(dir string) bool { + files, _ := os.ReadDir(dir) + for _, f := range files { + if !f.IsDir() && strings.HasSuffix(f.Name(), ".go") { + return true + } + } + return false +} + +// reusePackage reuses package p to satisfy the import at the top +// of the import stack stk. If this use causes an import loop, +// reusePackage updates p's error information to record the loop. +func reusePackage(p *Package, stk *ImportStack) *Package { + // We use p.Internal.Imports==nil to detect a package that + // is in the midst of its own loadPackage call + // (all the recursion below happens before p.Internal.Imports gets set). + if p.Internal.Imports == nil { + if p.Error == nil { + p.Error = &PackageError{ + ImportStack: stk.Copy(), + Err: errors.New("import cycle not allowed"), + IsImportCycle: true, + } + } else if !p.Error.IsImportCycle { + // If the error is already set, but it does not indicate that + // we are in an import cycle, set IsImportCycle so that we don't + // end up stuck in a loop down the road. + p.Error.IsImportCycle = true + } + p.Incomplete = true + } + // Don't rewrite the import stack in the error if we have an import cycle. + // If we do, we'll lose the path that describes the cycle. + if p.Error != nil && !p.Error.IsImportCycle && stk.shorterThan(p.Error.ImportStack) { + p.Error.ImportStack = stk.Copy() + } + return 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, 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 + // rooted at the parent of the “internal” directory. + + // There was an error loading the package; stop here. + if p.Error != nil { + return p + } + + // The generated 'testmain' package is allowed to access testing/internal/..., + // as if it were generated into the testing directory tree + // (it's actually in a temporary directory outside any Go tree). + // This cleans up a former kludge in passing functionality to the testing package. + if str.HasPathPrefix(p.ImportPath, "testing/internal") && importerPath == "testmain" { + return p + } + + // We can't check standard packages with gccgo. + if cfg.BuildContext.Compiler == "gccgo" && p.Standard { + return p + } + + // The sort package depends on internal/reflectlite, but during bootstrap + // the path rewriting causes the normal internal checks to fail. + // Instead, just ignore the internal rules during bootstrap. + if p.Standard && strings.HasPrefix(importerPath, "bootstrap/") { + return p + } + + // importerPath is empty: we started + // with a name given on the command line, not an + // import. Anything listed on the command line is fine. + if importerPath == "" { + return p + } + + // Check for "internal" element: three cases depending on begin of string and/or end of string. + i, ok := findInternal(p.ImportPath) + if !ok { + return p + } + + // Internal is present. + // Map import path back to directory corresponding to parent of internal. + if i > 0 { + i-- // rewind over slash in ".../internal" + } + + 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 importer.Internal.CmdlineFiles { + // The importer is a list of command-line files. + // Pretend that the import path is the import path of the + // directory containing them. + // If the directory is outside the main module, this will resolve to ".", + // which is not a prefix of any valid module. + importerPath = modload.DirImportPath(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{ + alwaysPrintStack: true, + ImportStack: stk.Copy(), + Err: ImportErrorf(p.ImportPath, "use of internal package "+p.ImportPath+" not allowed"), + } + perr.Incomplete = true + return &perr +} + +// findInternal looks for the final "internal" path element in the given import path. +// If there isn't one, findInternal returns ok=false. +// Otherwise, findInternal returns ok=true and the index of the "internal". +func findInternal(path string) (index int, ok bool) { + // Three cases, depending on internal at start/end of string or not. + // The order matters: we must return the index of the final element, + // because the final one produces the most restrictive requirement + // on the importer. + switch { + case strings.HasSuffix(path, "/internal"): + return len(path) - len("internal"), true + case strings.Contains(path, "/internal/"): + return strings.LastIndex(path, "/internal/") + 1, true + case path == "internal", strings.HasPrefix(path, "internal/"): + return 0, true + } + return 0, false +} + +// disallowVendor checks that srcDir 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 string, path string, importerPath string, p *Package, stk *ImportStack) *Package { + // If the importerPath is empty, we started + // with a name given on the command line, not an + // import. Anything listed on the command line is fine. + if importerPath == "" { + return p + } + + if perr := disallowVendorVisibility(srcDir, p, importerPath, stk); perr != p { + return perr + } + + // Paths like x/vendor/y must be imported as y, never as x/vendor/y. + if i, ok := FindVendor(path); ok { + perr := *p + perr.Error = &PackageError{ + ImportStack: stk.Copy(), + Err: ImportErrorf(path, "%s must be imported as %s", path, path[i+len("vendor/"):]), + } + perr.Incomplete = true + return &perr + } + + return p +} + +// disallowVendorVisibility checks that srcDir is allowed to import p. +// The rules are the same as for /internal/ except that a path ending in /vendor +// is not subject to the rules, only subdirectories of vendor. +// This allows people to have packages and commands named vendor, +// for maximal compatibility with existing source trees. +func disallowVendorVisibility(srcDir string, p *Package, importerPath string, stk *ImportStack) *Package { + // The stack does not include p.ImportPath. + // If there's nothing on the stack, we started + // with a name given on the command line, not an + // import. Anything listed on the command line is fine. + if importerPath == "" { + return p + } + + // Check for "vendor" element. + i, ok := FindVendor(p.ImportPath) + if !ok { + return p + } + + // Vendor is present. + // Map import path back to directory corresponding to parent of vendor. + if i > 0 { + i-- // rewind over slash in ".../vendor" + } + truncateTo := i + len(p.Dir) - len(p.ImportPath) + if truncateTo < 0 || len(p.Dir) < truncateTo { + return p + } + parent := p.Dir[:truncateTo] + 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 + } + + // Vendor is present, and srcDir is outside parent's tree. Not allowed. + perr := *p + perr.Error = &PackageError{ + ImportStack: stk.Copy(), + Err: errors.New("use of vendored package not allowed"), + } + perr.Incomplete = true + return &perr +} + +// FindVendor looks for the last non-terminating "vendor" path element in the given import path. +// If there isn't one, FindVendor returns ok=false. +// Otherwise, FindVendor returns ok=true and the index of the "vendor". +// +// Note that terminating "vendor" elements don't count: "x/vendor" is its own package, +// not the vendored copy of an import "" (the empty import path). +// This will allow people to have packages or commands named vendor. +// This may help reduce breakage, or it may just be confusing. We'll see. +func FindVendor(path string) (index int, ok bool) { + // Two cases, depending on internal at start of string or not. + // The order matters: we must return the index of the final element, + // because the final one is where the effective import path starts. + switch { + case strings.Contains(path, "/vendor/"): + return strings.LastIndex(path, "/vendor/") + 1, true + case strings.HasPrefix(path, "vendor/"): + return 0, true + } + return 0, false +} + +type TargetDir int + +const ( + ToTool TargetDir = iota // to GOROOT/pkg/tool (default for cmd/*) + ToBin // to bin dir inside package root (default for non-cmd/*) + StalePath // an old import path; fail to build +) + +// InstallTargetDir reports the target directory for installing the command p. +func InstallTargetDir(p *Package) TargetDir { + if strings.HasPrefix(p.ImportPath, "code.google.com/p/go.tools/cmd/") { + return StalePath + } + if p.Goroot && strings.HasPrefix(p.ImportPath, "cmd/") && p.Name == "main" { + switch p.ImportPath { + case "cmd/go", "cmd/gofmt": + return ToBin + } + return ToTool + } + return ToBin +} + +var cgoExclude = map[string]bool{ + "runtime/cgo": true, +} + +var cgoSyscallExclude = map[string]bool{ + "runtime/cgo": true, + "runtime/race": true, + "runtime/msan": true, +} + +var foldPath = make(map[string]string) + +// exeFromImportPath returns an executable name +// for a package using the import path. +// +// The executable name is the last element of the import path. +// In module-aware mode, an additional rule is used on import paths +// consisting of two or more path elements. If the last element is +// a vN path element specifying the major version, then the +// second last element of the import path is used instead. +func (p *Package) exeFromImportPath() string { + _, elem := pathpkg.Split(p.ImportPath) + if cfg.ModulesEnabled { + // If this is example.com/mycmd/v2, it's more useful to + // install it as mycmd than as v2. See golang.org/issue/24667. + if elem != p.ImportPath && isVersionElement(elem) { + _, elem = pathpkg.Split(pathpkg.Dir(p.ImportPath)) + } + } + return elem +} + +// exeFromFiles returns an executable name for a package +// using the first element in GoFiles or CgoFiles collections without the prefix. +// +// Returns empty string in case of empty collection. +func (p *Package) exeFromFiles() string { + var src string + if len(p.GoFiles) > 0 { + src = p.GoFiles[0] + } else if len(p.CgoFiles) > 0 { + src = p.CgoFiles[0] + } else { + return "" + } + _, elem := filepath.Split(src) + return elem[:len(elem)-len(".go")] +} + +// DefaultExecName returns the default executable name for a package +func (p *Package) DefaultExecName() string { + if p.Internal.CmdlineFiles { + return p.exeFromFiles() + } + return p.exeFromImportPath() +} + +// load populates p using information from bp, err, which should +// be the result of calling build.Context.Import. +// stk contains the import stack, not including path itself. +func (p *Package) load(ctx context.Context, path string, stk *ImportStack, importPos []token.Position, bp *build.Package, err error) { + p.copyBuild(bp) + + // The localPrefix is the path we interpret ./ imports relative to. + // Synthesized main packages sometimes override this. + if p.Internal.Local { + p.Internal.LocalPrefix = dirToImportPath(p.Dir) + } + + // setError sets p.Error if it hasn't already been set. We may proceed + // after encountering some errors so that 'go list -e' has more complete + // output. If there's more than one error, we should report the first. + setError := func(err error) { + if p.Error == nil { + p.Error = &PackageError{ + ImportStack: stk.Copy(), + Err: err, + } + + // Add the importer's position information if the import position exists, and + // the current package being examined is the importer. + // If we have not yet accepted package p onto the import stack, + // then the cause of the error is not within p itself: the error + // must be either in an explicit command-line argument, + // or on the importer side (indicated by a non-empty importPos). + if path != stk.Top() && len(importPos) > 0 { + p.Error.setPos(importPos) + } + } + } + + if err != nil { + p.Incomplete = true + p.setLoadPackageDataError(err, path, stk, importPos) + } + + useBindir := p.Name == "main" + if !p.Standard { + switch cfg.BuildBuildmode { + case "c-archive", "c-shared", "plugin": + useBindir = false + } + } + + if useBindir { + // Report an error when the old code.google.com/p/go.tools paths are used. + if InstallTargetDir(p) == StalePath { + // TODO(matloob): remove this branch, and StalePath itself. code.google.com/p/go is so + // old, even this code checking for it is stale now! + newPath := strings.Replace(p.ImportPath, "code.google.com/p/go.", "golang.org/x/", 1) + e := ImportErrorf(p.ImportPath, "the %v command has moved; use %v instead.", p.ImportPath, newPath) + setError(e) + return + } + elem := p.DefaultExecName() + 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 = modload.BinDir() + } + if p.Internal.Build.BinDir != "" { + // Install to GOBIN or bin of GOPATH entry. + p.Target = filepath.Join(p.Internal.Build.BinDir, elem) + if !p.Goroot && strings.Contains(elem, "/") && cfg.GOBIN != "" { + // Do not create $GOBIN/goos_goarch/elem. + p.Target = "" + p.Internal.GobinSubdir = true + } + } + if InstallTargetDir(p) == ToTool { + // This is for 'go tool'. + // Override all the usual logic and force it into the tool directory. + if cfg.BuildToolchainName == "gccgo" { + p.Target = filepath.Join(base.ToolDir, elem) + } else { + p.Target = filepath.Join(cfg.GOROOTpkg, "tool", full) + } + } + if p.Target != "" && cfg.BuildContext.GOOS == "windows" { + p.Target += ".exe" + } + } else if p.Internal.Local { + // Local import turned into absolute path. + // No permanent install target. + p.Target = "" + } else { + p.Target = p.Internal.Build.PkgObj + if cfg.BuildLinkshared && p.Target != "" { + // TODO(bcmills): The reliance on p.Target implies that -linkshared does + // not work for any package that lacks a Target — such as a non-main + // package in module mode. We should probably fix that. + shlibnamefile := p.Target[:len(p.Target)-2] + ".shlibname" + shlib, err := os.ReadFile(shlibnamefile) + if err != nil && !os.IsNotExist(err) { + base.Fatalf("reading shlibname: %v", err) + } + if err == nil { + libname := strings.TrimSpace(string(shlib)) + if cfg.BuildContext.Compiler == "gccgo" { + p.Shlib = filepath.Join(p.Internal.Build.PkgTargetRoot, "shlibs", libname) + } else { + p.Shlib = filepath.Join(p.Internal.Build.PkgTargetRoot, libname) + } + } + } + } + + // 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, 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 "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", true) + } + if p.UsesCgo() && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) { + addImport("syscall", true) + } + + // SWIG adds imports of some standard packages. + if p.UsesSwig() { + addImport("unsafe", true) + if cfg.BuildContext.Compiler != "gccgo" { + addImport("runtime/cgo", true) + } + addImport("syscall", true) + addImport("sync", true) + + // TODO: The .swig and .swigcxx files can use + // %go_import directives to import other packages. + } + + // The linker loads implicit dependencies. + if p.Name == "main" && !p.Internal.ForceLibrary { + for _, dep := range LinkerDeps(p) { + addImport(dep, false) + } + } + + // Check for case-insensitive collisions of import paths. + fold := str.ToFold(p.ImportPath) + if other := foldPath[fold]; other == "" { + foldPath[fold] = p.ImportPath + } else if other != p.ImportPath { + setError(ImportErrorf(p.ImportPath, "case-insensitive import collision: %q and %q", p.ImportPath, other)) + return + } + + if !SafeArg(p.ImportPath) { + setError(ImportErrorf(p.ImportPath, "invalid import path %q", p.ImportPath)) + return + } + + // Errors after this point are caused by this package, not the importing + // package. Pushing the path here prevents us from reporting the error + // with the position of the import declaration. + stk.Push(path) + defer stk.Pop() + + p.EmbedFiles, p.Internal.Embed, err = resolveEmbed(p.Dir, p.EmbedPatterns) + if err != nil { + p.Incomplete = true + setError(err) + embedErr := err.(*EmbedError) + p.Error.setPos(p.Internal.Build.EmbedPatternPos[embedErr.Pattern]) + } + + // Check for case-insensitive collision of input files. + // To avoid problems on case-insensitive files, we reject any package + // where two different input files have equal names under a case-insensitive + // comparison. + inputs := p.AllFiles() + f1, f2 := str.FoldDup(inputs) + if f1 != "" { + setError(fmt.Errorf("case-insensitive file name collision: %q and %q", f1, f2)) + return + } + + // If first letter of input file is ASCII, it must be alphanumeric. + // This avoids files turning into flags when invoking commands, + // and other problems we haven't thought of yet. + // Also, _cgo_ files must be generated by us, not supplied. + // They are allowed to have //go:cgo_ldflag directives. + // The directory scan ignores files beginning with _, + // so we shouldn't see any _cgo_ files anyway, but just be safe. + for _, file := range inputs { + if !SafeArg(file) || strings.HasPrefix(file, "_cgo_") { + setError(fmt.Errorf("invalid input file name %q", file)) + return + } + } + if name := pathpkg.Base(p.ImportPath); !SafeArg(name) { + setError(fmt.Errorf("invalid input directory name %q", name)) + return + } + + // Build list of imported packages and full dependency list. + imports := make([]*Package, 0, len(p.Imports)) + for i, path := range importPaths { + if path == "C" { + continue + } + p1 := LoadImport(ctx, path, p.Dir, p, stk, p.Internal.Build.ImportPos[path], ResolveImport) + + path = p1.ImportPath + importPaths[i] = path + if i < len(p.Imports) { + p.Imports[i] = path + } + + imports = append(imports, p1) + if p1.Incomplete { + p.Incomplete = true + } + } + p.Internal.Imports = imports + p.collectDeps() + + // unsafe is a fake package. + if p.Standard && (p.ImportPath == "unsafe" || cfg.BuildContext.Compiler == "gccgo") { + p.Target = "" + } + + // If cgo is not enabled, ignore cgo supporting sources + // just as we ignore go files containing import "C". + if !cfg.BuildContext.CgoEnabled { + p.CFiles = nil + p.CXXFiles = nil + p.MFiles = nil + p.SwigFiles = nil + p.SwigCXXFiles = nil + // Note that SFiles are okay (they go to the Go assembler) + // and HFiles are okay (they might be used by the SFiles). + // Also Sysofiles are okay (they might not contain object + // code; see issue #16050). + } + + // The gc toolchain only permits C source files with cgo or SWIG. + if len(p.CFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() && cfg.BuildContext.Compiler == "gc" { + setError(fmt.Errorf("C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CFiles, " "))) + return + } + + // C++, Objective-C, and Fortran source files are permitted only with cgo or SWIG, + // regardless of toolchain. + if len(p.CXXFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() { + setError(fmt.Errorf("C++ source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CXXFiles, " "))) + return + } + if len(p.MFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() { + setError(fmt.Errorf("Objective-C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.MFiles, " "))) + return + } + if len(p.FFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() { + setError(fmt.Errorf("Fortran source files not allowed when not using cgo or SWIG: %s", strings.Join(p.FFiles, " "))) + return + } + + if cfg.ModulesEnabled && p.Error == nil { + mainPath := p.ImportPath + if p.Internal.CmdlineFiles { + mainPath = "command-line-arguments" + } + p.Module = modload.PackageModuleInfo(mainPath) + if p.Name == "main" && len(p.DepsErrors) == 0 { + p.Internal.BuildInfo = modload.PackageBuildInfo(mainPath, p.Deps) + } + } +} + +// An EmbedError indicates a problem with a go:embed directive. +type EmbedError struct { + Pattern string + Err error +} + +func (e *EmbedError) Error() string { + return fmt.Sprintf("pattern %s: %v", e.Pattern, e.Err) +} + +func (e *EmbedError) Unwrap() error { + return e.Err +} + +// ResolveEmbed resolves //go:embed patterns and returns only the file list. +// For use by go mod vendor to find embedded files it should copy into the +// vendor directory. +// TODO(#42504): Once go mod vendor uses load.PackagesAndErrors, just +// call (*Package).ResolveEmbed +func ResolveEmbed(dir string, patterns []string) ([]string, error) { + files, _, err := resolveEmbed(dir, patterns) + return files, err +} + +// resolveEmbed resolves //go:embed patterns to precise file lists. +// It sets files to the list of unique files matched (for go list), +// and it sets pmap to the more precise mapping from +// patterns to files. +func resolveEmbed(pkgdir string, patterns []string) (files []string, pmap map[string][]string, err error) { + var pattern string + defer func() { + if err != nil { + err = &EmbedError{ + Pattern: pattern, + Err: err, + } + } + }() + + // TODO(rsc): All these messages need position information for better error reports. + pmap = make(map[string][]string) + have := make(map[string]int) + dirOK := make(map[string]bool) + pid := 0 // pattern ID, to allow reuse of have map + for _, pattern = range patterns { + pid++ + + // Check pattern is valid for //go:embed. + if _, err := path.Match(pattern, ""); err != nil || !validEmbedPattern(pattern) { + return nil, nil, fmt.Errorf("invalid pattern syntax") + } + + // Glob to find matches. + match, err := fsys.Glob(pkgdir + string(filepath.Separator) + filepath.FromSlash(pattern)) + if err != nil { + return nil, nil, err + } + + // Filter list of matches down to the ones that will still exist when + // the directory is packaged up as a module. (If p.Dir is in the module cache, + // only those files exist already, but if p.Dir is in the current module, + // then there may be other things lying around, like symbolic links or .git directories.) + var list []string + for _, file := range match { + rel := filepath.ToSlash(file[len(pkgdir)+1:]) // file, relative to p.Dir + + what := "file" + info, err := fsys.Lstat(file) + if err != nil { + return nil, nil, err + } + if info.IsDir() { + what = "directory" + } + + // Check that directories along path do not begin a new module + // (do not contain a go.mod). + for dir := file; len(dir) > len(pkgdir)+1 && !dirOK[dir]; dir = filepath.Dir(dir) { + if _, err := fsys.Stat(filepath.Join(dir, "go.mod")); err == nil { + return nil, nil, fmt.Errorf("cannot embed %s %s: in different module", what, rel) + } + if dir != file { + if info, err := fsys.Lstat(dir); err == nil && !info.IsDir() { + return nil, nil, fmt.Errorf("cannot embed %s %s: in non-directory %s", what, rel, dir[len(pkgdir)+1:]) + } + } + dirOK[dir] = true + if elem := filepath.Base(dir); isBadEmbedName(elem) { + if dir == file { + return nil, nil, fmt.Errorf("cannot embed %s %s: invalid name %s", what, rel, elem) + } else { + return nil, nil, fmt.Errorf("cannot embed %s %s: in invalid directory %s", what, rel, elem) + } + } + } + + switch { + default: + return nil, nil, fmt.Errorf("cannot embed irregular file %s", rel) + + case info.Mode().IsRegular(): + if have[rel] != pid { + have[rel] = pid + list = append(list, rel) + } + + case info.IsDir(): + // Gather all files in the named directory, stopping at module boundaries + // and ignoring files that wouldn't be packaged into a module. + count := 0 + err := fsys.Walk(file, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + rel := filepath.ToSlash(path[len(pkgdir)+1:]) + name := info.Name() + if path != file && (isBadEmbedName(name) || name[0] == '.' || name[0] == '_') { + // Ignore bad names, assuming they won't go into modules. + // Also avoid hidden files that user may not know about. + // See golang.org/issue/42328. + if info.IsDir() { + return fs.SkipDir + } + return nil + } + if info.IsDir() { + if _, err := fsys.Stat(filepath.Join(path, "go.mod")); err == nil { + return filepath.SkipDir + } + return nil + } + if !info.Mode().IsRegular() { + return nil + } + count++ + if have[rel] != pid { + have[rel] = pid + list = append(list, rel) + } + return nil + }) + if err != nil { + return nil, nil, err + } + if count == 0 { + return nil, nil, fmt.Errorf("cannot embed directory %s: contains no embeddable files", rel) + } + } + } + + if len(list) == 0 { + return nil, nil, fmt.Errorf("no matching files found") + } + sort.Strings(list) + pmap[pattern] = list + } + + for file := range have { + files = append(files, file) + } + sort.Strings(files) + return files, pmap, nil +} + +func validEmbedPattern(pattern string) bool { + return pattern != "." && fs.ValidPath(pattern) +} + +// isBadEmbedName reports whether name is the base name of a file that +// can't or won't be included in modules and therefore shouldn't be treated +// as existing for embedding. +func isBadEmbedName(name string) bool { + if err := module.CheckFilePath(name); err != nil { + return true + } + switch name { + // Empty string should be impossible but make it bad. + case "": + return true + // Version control directories won't be present in module. + case ".bzr", ".hg", ".git", ".svn": + return true + } + return false +} + +// collectDeps populates p.Deps and p.DepsErrors by iterating over +// p.Internal.Imports. +// +// TODO(jayconrod): collectDeps iterates over transitive imports for every +// package. We should only need to visit direct imports. +func (p *Package) collectDeps() { + deps := make(map[string]*Package) + var q []*Package + q = append(q, p.Internal.Imports...) + for i := 0; i < len(q); i++ { + p1 := q[i] + path := p1.ImportPath + // The same import path could produce an error or not, + // depending on what tries to import it. + // Prefer to record entries with errors, so we can report them. + p0 := deps[path] + if p0 == nil || p1.Error != nil && (p0.Error == nil || len(p0.Error.ImportStack) > len(p1.Error.ImportStack)) { + deps[path] = p1 + for _, p2 := range p1.Internal.Imports { + if deps[p2.ImportPath] != p2 { + q = append(q, p2) + } + } + } + } + + p.Deps = make([]string, 0, len(deps)) + for dep := range deps { + p.Deps = append(p.Deps, dep) + } + sort.Strings(p.Deps) + for _, dep := range p.Deps { + p1 := deps[dep] + if p1 == nil { + panic("impossible: missing entry in package cache for " + dep + " imported by " + p.ImportPath) + } + if p1.Error != nil { + p.DepsErrors = append(p.DepsErrors, p1.Error) + } + } +} + +// SafeArg reports whether arg is a "safe" command-line argument, +// meaning that when it appears in a command-line, it probably +// doesn't have some special meaning other than its own name. +// Obviously args beginning with - are not safe (they look like flags). +// Less obviously, args beginning with @ are not safe (they look like +// GNU binutils flagfile specifiers, sometimes called "response files"). +// To be conservative, we reject almost any arg beginning with non-alphanumeric ASCII. +// We accept leading . _ and / as likely in file system paths. +// There is a copy of this function in cmd/compile/internal/gc/noder.go. +func SafeArg(name string) bool { + if name == "" { + return false + } + c := name[0] + return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || c == '.' || c == '_' || c == '/' || c >= utf8.RuneSelf +} + +// LinkerDeps returns the list of linker-induced dependencies for main package p. +func LinkerDeps(p *Package) []string { + // Everything links runtime. + deps := []string{"runtime"} + + // External linking mode forces an import of runtime/cgo. + if externalLinkingForced(p) && cfg.BuildContext.Compiler != "gccgo" { + deps = append(deps, "runtime/cgo") + } + // On ARM with GOARM=5, it forces an import of math, for soft floating point. + if cfg.Goarch == "arm" { + deps = append(deps, "math") + } + // Using the race detector forces an import of runtime/race. + if cfg.BuildRace { + deps = append(deps, "runtime/race") + } + // Using memory sanitizer forces an import of runtime/msan. + if cfg.BuildMSan { + deps = append(deps, "runtime/msan") + } + + return deps +} + +// externalLinkingForced reports whether external linking is being +// forced even for programs that do not use cgo. +func externalLinkingForced(p *Package) bool { + if !cfg.BuildContext.CgoEnabled { + return false + } + + // Some targets must use external linking even inside GOROOT. + switch cfg.BuildContext.GOOS { + case "android": + if cfg.BuildContext.GOARCH != "arm64" { + return true + } + case "ios": + return true + } + + // Currently build modes c-shared, pie (on systems that do not + // support PIE with internal linking mode (currently all + // systems: issue #18968)), plugin, and -linkshared force + // external linking mode, as of course does + // -ldflags=-linkmode=external. External linking mode forces + // an import of runtime/cgo. + // If there are multiple -linkmode options, the last one wins. + pieCgo := cfg.BuildBuildmode == "pie" && !sys.InternalLinkPIESupported(cfg.BuildContext.GOOS, cfg.BuildContext.GOARCH) + linkmodeExternal := false + if p != nil { + ldflags := BuildLdflags.For(p) + for i := len(ldflags) - 1; i >= 0; i-- { + a := ldflags[i] + if a == "-linkmode=external" || + a == "-linkmode" && i+1 < len(ldflags) && ldflags[i+1] == "external" { + linkmodeExternal = true + break + } else if a == "-linkmode=internal" || + a == "-linkmode" && i+1 < len(ldflags) && ldflags[i+1] == "internal" { + break + } + } + } + + return cfg.BuildBuildmode == "c-shared" || cfg.BuildBuildmode == "plugin" || pieCgo || cfg.BuildLinkshared || linkmodeExternal +} + +// mkAbs rewrites list, which must be paths relative to p.Dir, +// into a sorted list of absolute paths. It edits list in place but for +// convenience also returns list back to its caller. +func (p *Package) mkAbs(list []string) []string { + for i, f := range list { + list[i] = filepath.Join(p.Dir, f) + } + sort.Strings(list) + return list +} + +// 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)) +} + +// 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, +// using absolute paths. "Possibly relevant" means that files are not excluded +// due to build tags, but files with names beginning with . or _ are still excluded. +func (p *Package) InternalAllGoFiles() []string { + return p.mkAbs(str.StringList(p.IgnoredGoFiles, p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles)) +} + +// usesSwig reports whether the package needs to run SWIG. +func (p *Package) UsesSwig() bool { + return len(p.SwigFiles) > 0 || len(p.SwigCXXFiles) > 0 +} + +// usesCgo reports whether the package needs to run cgo +func (p *Package) UsesCgo() bool { + return len(p.CgoFiles) > 0 +} + +// 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{} + 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) + } + for _, root := range roots { + walk(root) + } + 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 TestPackageList(ctx context.Context, 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(ctx, 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 +} + +// LoadImportWithFlags loads the package with the given import path and +// sets tool flags on that package. This function is useful loading implicit +// dependencies (like sync/atomic for coverage). +// TODO(jayconrod): delete this function and set flags automatically +// in LoadImport instead. +func LoadImportWithFlags(path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) *Package { + p := LoadImport(context.TODO(), path, srcDir, parent, stk, importPos, mode) + setToolFlags(p) + return p +} + +// ModResolveTests indicates whether calls to the module loader should also +// resolve test dependencies of the requested packages. +// +// If ModResolveTests is true, then the module loader needs to resolve test +// dependencies at the same time as packages; otherwise, the test dependencies +// of those packages could be missing, and resolving those missing dependencies +// could change the selected versions of modules that provide other packages. +// +// TODO(#40775): Change this from a global variable to an explicit function +// argument where needed. +var ModResolveTests bool + +// PackagesAndErrors returns the packages named by the command line arguments +// 'patterns'. If a named package cannot be loaded, PackagesAndErrors returns +// a *Package with the Error field describing the failure. If errors are found +// loading imported packages, the DepsErrors field is set. The Incomplete field +// may be set as well. +// +// To obtain a flat list of packages, use PackageList. +// To report errors loading packages, use ReportPackageErrors. +func PackagesAndErrors(ctx context.Context, patterns []string) []*Package { + ctx, span := trace.StartSpan(ctx, "load.PackagesAndErrors") + defer span.Done() + + for _, p := range patterns { + // Listing is only supported with all patterns referring to either: + // - Files that are part of the same directory. + // - Explicit package paths or patterns. + if strings.HasSuffix(p, ".go") { + // We need to test whether the path is an actual Go file and not a + // package path or pattern ending in '.go' (see golang.org/issue/34653). + if fi, err := fsys.Stat(p); err == nil && !fi.IsDir() { + return []*Package{GoFilesPackage(ctx, patterns)} + } + } + } + + var matches []*search.Match + if modload.Init(); cfg.ModulesEnabled { + loadOpts := modload.PackageOpts{ + ResolveMissingImports: true, + LoadTests: ModResolveTests, + SilenceErrors: true, + } + matches, _ = modload.LoadPackages(ctx, loadOpts, patterns...) + } else { + matches = search.ImportPaths(patterns) + } + + var ( + pkgs []*Package + stk ImportStack + seenPkg = make(map[*Package]bool) + ) + + pre := newPreload() + defer pre.flush() + pre.preloadMatches(matches) + + for _, m := range matches { + for _, pkg := range m.Pkgs { + if pkg == "" { + panic(fmt.Sprintf("ImportPaths returned empty package for pattern %s", m.Pattern())) + } + p := loadImport(ctx, pre, pkg, base.Cwd, nil, &stk, nil, 0) + p.Match = append(p.Match, m.Pattern()) + p.Internal.CmdlinePkg = true + if m.IsLiteral() { + // Note: do not set = m.IsLiteral 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) + } + + if len(m.Errs) > 0 { + // In addition to any packages that were actually resolved from the + // pattern, there was some error in resolving the pattern itself. + // Report it as a synthetic package. + p := new(Package) + p.ImportPath = m.Pattern() + // Pass an empty ImportStack and nil importPos: the error arose from a pattern, not an import. + var stk ImportStack + var importPos []token.Position + p.setLoadPackageDataError(m.Errs[0], m.Pattern(), &stk, importPos) + p.Incomplete = true + p.Match = append(p.Match, m.Pattern()) + p.Internal.CmdlinePkg = true + if m.IsLiteral() { + p.Internal.CmdlinePkgLiteral = true + } + pkgs = append(pkgs, p) + } + } + + // 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 +} + +// CheckPackageErrors prints errors encountered loading pkgs and their +// dependencies, then exits with a non-zero status if any errors were found. +func CheckPackageErrors(pkgs []*Package) { + printed := map[*PackageError]bool{} + for _, pkg := range pkgs { + if pkg.Error != nil { + base.Errorf("%v", pkg.Error) + printed[pkg.Error] = true + } + for _, err := range pkg.DepsErrors { + // Since these are errors in dependencies, + // the same error might show up multiple times, + // once in each package that depends on it. + // Only print each once. + if !printed[err] { + printed[err] = true + base.Errorf("%v", err) + } + } + } + base.ExitIfErrors() + + // Check for duplicate loads of the same package. + // That should be impossible, but if it does happen then + // we end up trying to build the same package twice, + // usually in parallel overwriting the same files, + // which doesn't work very well. + seen := map[string]bool{} + reported := map[string]bool{} + for _, pkg := range PackageList(pkgs) { + if seen[pkg.ImportPath] && !reported[pkg.ImportPath] { + reported[pkg.ImportPath] = true + base.Errorf("internal error: duplicate loads of %s", pkg.ImportPath) + } + seen[pkg.ImportPath] = true + } + base.ExitIfErrors() +} + +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) + } +} + +// GoFilesPackage creates a package for building a collection of Go files +// (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(ctx context.Context, gofiles []string) *Package { + modload.Init() + + for _, f := range gofiles { + if !strings.HasSuffix(f, ".go") { + pkg := new(Package) + pkg.Internal.Local = true + pkg.Internal.CmdlineFiles = true + pkg.Name = f + pkg.Error = &PackageError{ + Err: fmt.Errorf("named files must be .go files: %s", pkg.Name), + } + return pkg + } + } + + var stk ImportStack + ctxt := cfg.BuildContext + ctxt.UseAllFiles = true + + // Synthesize fake "directory" that only shows the named files, + // to make it look like this is a standard package or + // command directory. So that local imports resolve + // consistently, the files must all be in the same directory. + var dirent []fs.FileInfo + var dir string + for _, file := range gofiles { + fi, err := fsys.Stat(file) + if err != nil { + base.Fatalf("%s", err) + } + if fi.IsDir() { + base.Fatalf("%s is a directory, should be a Go file", file) + } + dir1, _ := filepath.Split(file) + if dir1 == "" { + dir1 = "./" + } + if dir == "" { + dir = dir1 + } else if dir != dir1 { + base.Fatalf("named files must all be in one directory; have %s and %s", dir, dir1) + } + dirent = append(dirent, fi) + } + ctxt.ReadDir = func(string) ([]fs.FileInfo, error) { return dirent, nil } + + if cfg.ModulesEnabled { + modload.ImportFromFiles(ctx, gofiles) + } + + var err error + if dir == "" { + dir = base.Cwd + } + dir, err = filepath.Abs(dir) + if err != nil { + base.Fatalf("%s", err) + } + + bp, err := ctxt.ImportDir(dir, 0) + pkg := new(Package) + pkg.Internal.Local = true + pkg.Internal.CmdlineFiles = true + pkg.load(ctx, "command-line-arguments", &stk, nil, bp, err) + pkg.Internal.LocalPrefix = dirToImportPath(dir) + pkg.ImportPath = "command-line-arguments" + pkg.Target = "" + pkg.Match = gofiles + + if pkg.Name == "main" { + exe := pkg.DefaultExecName() + cfg.ExeSuffix + + if cfg.GOBIN != "" { + pkg.Target = filepath.Join(cfg.GOBIN, exe) + } else if cfg.ModulesEnabled { + pkg.Target = filepath.Join(modload.BinDir(), exe) + } + } + + setToolFlags(pkg) + + return pkg +} diff --git a/src/cmd/go/internal/load/pkg_test.go b/src/cmd/go/internal/load/pkg_test.go new file mode 100644 index 0000000..1e59fb9 --- /dev/null +++ b/src/cmd/go/internal/load/pkg_test.go @@ -0,0 +1,78 @@ +package load + +import ( + "cmd/go/internal/cfg" + "testing" +) + +func TestPkgDefaultExecName(t *testing.T) { + oldModulesEnabled := cfg.ModulesEnabled + defer func() { cfg.ModulesEnabled = oldModulesEnabled }() + for _, tt := range []struct { + in string + files []string + wantMod string + wantGopath string + }{ + {"example.com/mycmd", []string{}, "mycmd", "mycmd"}, + {"example.com/mycmd/v0", []string{}, "v0", "v0"}, + {"example.com/mycmd/v1", []string{}, "v1", "v1"}, + {"example.com/mycmd/v2", []string{}, "mycmd", "v2"}, // Semantic import versioning, use second last element in module mode. + {"example.com/mycmd/v3", []string{}, "mycmd", "v3"}, // Semantic import versioning, use second last element in module mode. + {"mycmd", []string{}, "mycmd", "mycmd"}, + {"mycmd/v0", []string{}, "v0", "v0"}, + {"mycmd/v1", []string{}, "v1", "v1"}, + {"mycmd/v2", []string{}, "mycmd", "v2"}, // Semantic import versioning, use second last element in module mode. + {"v0", []string{}, "v0", "v0"}, + {"v1", []string{}, "v1", "v1"}, + {"v2", []string{}, "v2", "v2"}, + {"command-line-arguments", []string{"output.go", "foo.go"}, "output", "output"}, + } { + { + cfg.ModulesEnabled = true + pkg := new(Package) + pkg.ImportPath = tt.in + pkg.GoFiles = tt.files + pkg.Internal.CmdlineFiles = len(tt.files) > 0 + gotMod := pkg.DefaultExecName() + if gotMod != tt.wantMod { + t.Errorf("pkg.DefaultExecName with ImportPath = %q in module mode = %v; want %v", tt.in, gotMod, tt.wantMod) + } + } + { + cfg.ModulesEnabled = false + pkg := new(Package) + pkg.ImportPath = tt.in + pkg.GoFiles = tt.files + pkg.Internal.CmdlineFiles = len(tt.files) > 0 + gotGopath := pkg.DefaultExecName() + if gotGopath != tt.wantGopath { + t.Errorf("pkg.DefaultExecName with ImportPath = %q in gopath mode = %v; want %v", tt.in, gotGopath, tt.wantGopath) + } + } + } +} + +func TestIsVersionElement(t *testing.T) { + t.Parallel() + for _, tt := range []struct { + in string + want bool + }{ + {"v0", false}, + {"v05", false}, + {"v1", false}, + {"v2", true}, + {"v3", true}, + {"v9", true}, + {"v10", true}, + {"v11", true}, + {"v", false}, + {"vx", false}, + } { + got := isVersionElement(tt.in) + if got != tt.want { + t.Errorf("isVersionElement(%q) = %v; want %v", tt.in, got, tt.want) + } + } +} diff --git a/src/cmd/go/internal/load/search.go b/src/cmd/go/internal/load/search.go new file mode 100644 index 0000000..cf09c7b --- /dev/null +++ b/src/cmd/go/internal/load/search.go @@ -0,0 +1,56 @@ +// 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 load + +import ( + "path/filepath" + "strings" + + "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 search.IsRelativePath(pattern): + // Split pattern into leading pattern-free directory path + // (including all . and .. elements) and the final pattern. + var dir string + i := strings.Index(pattern, "...") + if i < 0 { + dir, pattern = pattern, "" + } else { + j := strings.LastIndex(pattern[:i], "/") + dir, pattern = pattern[:j], pattern[j+1:] + } + dir = filepath.Join(cwd, dir) + if pattern == "" { + return func(p *Package) bool { return p.Dir == dir } + } + 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) + if err != nil { + // Cannot make relative - e.g. different drive letters on Windows. + return false + } + rel = filepath.ToSlash(rel) + if rel == ".." || strings.HasPrefix(rel, "../") { + return false + } + return matchPath(rel) + } + case pattern == "all": + return func(p *Package) bool { return true } + case pattern == "std": + return func(p *Package) bool { return p.Standard } + case pattern == "cmd": + return func(p *Package) bool { return p.Standard && strings.HasPrefix(p.ImportPath, "cmd/") } + default: + matchPath := search.MatchPattern(pattern) + return func(p *Package) bool { return matchPath(p.ImportPath) } + } +} diff --git a/src/cmd/go/internal/load/test.go b/src/cmd/go/internal/load/test.go new file mode 100644 index 0000000..eb8aef3 --- /dev/null +++ b/src/cmd/go/internal/load/test.go @@ -0,0 +1,752 @@ +// 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" + "context" + "errors" + "fmt" + "go/ast" + "go/build" + "go/doc" + "go/parser" + "go/token" + "internal/lazytemplate" + "path/filepath" + "sort" + "strings" + "unicode" + "unicode/utf8" + + "cmd/go/internal/str" + "cmd/go/internal/trace" +) + +var TestMainDeps = []string{ + // Dependencies for testmain. + "os", + "reflect", + "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 is like TestPackagesAndErrors but it returns +// an error if the test packages or their dependencies have errors. +// Only test packages without errors are returned. +func TestPackagesFor(ctx context.Context, p *Package, cover *TestCover) (pmain, ptest, pxtest *Package, err error) { + pmain, ptest, pxtest = TestPackagesAndErrors(ctx, p, cover) + for _, p1 := range []*Package{ptest, pxtest, pmain} { + if p1 == nil { + // pxtest may be nil + continue + } + if p1.Error != nil { + err = p1.Error + break + } + if len(p1.DepsErrors) > 0 { + perr := p1.DepsErrors[0] + err = perr + break + } + } + if pmain.Error != nil || len(pmain.DepsErrors) > 0 { + pmain = nil + } + if ptest.Error != nil || len(ptest.DepsErrors) > 0 { + ptest = nil + } + if pxtest != nil && (pxtest.Error != nil || len(pxtest.DepsErrors) > 0) { + pxtest = nil + } + return pmain, ptest, pxtest, err +} + +// TestPackagesAndErrors returns three packages: +// - pmain, the package main corresponding to the test binary (running tests in ptest and pxtest). +// - ptest, the package p compiled with added "package p" test files. +// - pxtest, the result of compiling any "package p_test" (external) test files. +// +// 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. +// +// An error is returned if the testmain source cannot be completely generated +// (for example, due to a syntax error in a test file). No error will be +// returned for errors loading packages, but the Error or DepsError fields +// of the returned packages may be set. +// +// 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 TestPackagesAndErrors(ctx context.Context, p *Package, cover *TestCover) (pmain, ptest, pxtest *Package) { + ctx, span := trace.StartSpan(ctx, "load.TestPackagesAndErrors") + defer span.Done() + + pre := newPreload() + defer pre.flush() + allImports := append([]string{}, p.TestImports...) + allImports = append(allImports, p.XTestImports...) + pre.preloadImports(allImports, p.Internal.Build) + + var ptestErr, pxtestErr *PackageError + var imports, ximports []*Package + var stk ImportStack + var testEmbed, xtestEmbed map[string][]string + stk.Push(p.ImportPath + " (test)") + rawTestImports := str.StringList(p.TestImports) + for i, path := range p.TestImports { + p1 := loadImport(ctx, pre, path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], ResolveImport) + 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. + ptestErr = &PackageError{ + ImportStack: testImportStack(stk[0], p1, p.ImportPath), + Err: errors.New("import cycle not allowed in test"), + IsImportCycle: true, + } + } + p.TestImports[i] = p1.ImportPath + imports = append(imports, p1) + } + var err error + p.TestEmbedFiles, testEmbed, err = resolveEmbed(p.Dir, p.TestEmbedPatterns) + if err != nil && ptestErr == nil { + ptestErr = &PackageError{ + ImportStack: stk.Copy(), + Err: err, + } + embedErr := err.(*EmbedError) + ptestErr.setPos(p.Internal.Build.TestEmbedPatternPos[embedErr.Pattern]) + } + stk.Pop() + + stk.Push(p.ImportPath + "_test") + pxtestNeedsPtest := false + rawXTestImports := str.StringList(p.XTestImports) + for i, path := range p.XTestImports { + p1 := loadImport(ctx, pre, path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], ResolveImport) + if p1.ImportPath == p.ImportPath { + pxtestNeedsPtest = true + } else { + ximports = append(ximports, p1) + } + p.XTestImports[i] = p1.ImportPath + } + p.XTestEmbedFiles, xtestEmbed, err = resolveEmbed(p.Dir, p.XTestEmbedPatterns) + if err != nil && pxtestErr == nil { + pxtestErr = &PackageError{ + ImportStack: stk.Copy(), + Err: err, + } + embedErr := err.(*EmbedError) + pxtestErr.setPos(p.Internal.Build.XTestEmbedPatternPos[embedErr.Pattern]) + } + stk.Pop() + + // Test package. + if len(p.TestGoFiles) > 0 || p.Name == "main" || cover != nil && cover.Local { + ptest = new(Package) + *ptest = *p + ptest.Error = ptestErr + 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.BuildInfo = "" + 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 + if testEmbed == nil && len(p.Internal.Embed) > 0 { + testEmbed = map[string][]string{} + } + for k, v := range p.Internal.Embed { + testEmbed[k] = v + } + ptest.Internal.Embed = testEmbed + ptest.EmbedFiles = str.StringList(p.EmbedFiles, p.TestEmbedFiles) + ptest.collectDeps() + } 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, + Goroot: p.Goroot, + GoFiles: p.XTestGoFiles, + Imports: p.XTestImports, + ForTest: p.ImportPath, + Module: p.Module, + Error: pxtestErr, + EmbedFiles: p.XTestEmbedFiles, + }, + 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, + Embed: xtestEmbed, + }, + } + if pxtestNeedsPtest { + pxtest.Internal.Imports = append(pxtest.Internal.Imports, ptest) + } + pxtest.collectDeps() + } + + // 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), + Module: p.Module, + }, + Internal: PackageInternal{ + Build: &build.Package{Name: "main"}, + BuildInfo: p.Internal.BuildInfo, + 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(ctx, pre, dep, "", nil, &stk, nil, 0) + 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) + } + } + } + + allTestImports := make([]*Package, 0, len(pmain.Internal.Imports)+len(imports)+len(ximports)) + allTestImports = append(allTestImports, pmain.Internal.Imports...) + allTestImports = append(allTestImports, imports...) + allTestImports = append(allTestImports, ximports...) + setToolFlags(allTestImports...) + + // 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 && pmain.Error == nil { + pmain.setLoadPackageDataError(err, p.ImportPath, &stk, nil) + } + 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 + } + pmain.collectDeps() + + // 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) + + // Replace pmain's transitive dependencies with test copies, as necessary. + 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 && pmain.Error == nil { + pmain.Error = &PackageError{Err: err} + } + if data != nil { + pmain.Internal.TestmainGo = &data + } + + return pmain, ptest, pxtest +} + +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, "") + break + } + return stk +} + +// recompileForTest copies and replaces certain packages in pmain's dependency +// graph. This is necessary for two reasons. First, if ptest is different than +// preal, packages that import the package under test should get ptest instead +// of preal. This is particularly important if pxtest depends on functionality +// exposed in test sources in ptest. Second, if there is a main package +// (other than pmain) anywhere, we need to set p.Internal.ForceLibrary and +// clear p.Internal.BuildInfo in the test copy to prevent link conflicts. +// This may happen if both -coverpkg and the command line patterns include +// multiple main packages. +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 = "" + p.Internal.BuildInfo = "" + p.Internal.ForceLibrary = true + } + + // 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 + } + } + + // Force main packages the test imports to be built as libraries. + // Normal imports of main packages are forbidden by the package loader, + // but this can still happen if -coverpkg patterns include main packages: + // covered packages are imported by pmain. Linking multiple packages + // compiled with '-p main' causes duplicate symbol errors. + // See golang.org/issue/30907, golang.org/issue/34114. + if p.Name == "main" && p != pmain && p != ptest { + split() + } + } +} + +// 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. +// The returned testFuncs is always non-nil, even if an error occurred while +// processing test files. +func loadTestFuncs(ptest *Package) (*testFuncs, error) { + t := &testFuncs{ + Package: ptest, + } + var err error + for _, file := range ptest.TestGoFiles { + if lerr := t.load(filepath.Join(ptest.Dir, file), "_test", &t.ImportTest, &t.NeedTest); lerr != nil && err == nil { + err = lerr + } + } + for _, file := range ptest.XTestGoFiles { + if lerr := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.ImportXtest, &t.NeedXtest); lerr != nil && err == nil { + err = lerr + } + } + return t, err +} + +// 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 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 = lazytemplate.New("main", ` +// Code generated by 'go test'. DO NOT EDIT. + +package main + +import ( + "os" +{{if .TestMain}} + "reflect" +{{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) + os.Exit(int(reflect.ValueOf(m).Elem().FieldByName("exitCode").Int())) +{{else}} + os.Exit(m.Run()) +{{end}} +} + +`) diff --git a/src/cmd/go/internal/lockedfile/internal/filelock/filelock.go b/src/cmd/go/internal/lockedfile/internal/filelock/filelock.go new file mode 100644 index 0000000..05f27c3 --- /dev/null +++ b/src/cmd/go/internal/lockedfile/internal/filelock/filelock.go @@ -0,0 +1,99 @@ +// 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 filelock provides a platform-independent API for advisory file +// locking. Calls to functions in this package on platforms that do not support +// advisory locks will return errors for which IsNotSupported returns true. +package filelock + +import ( + "errors" + "io/fs" + "os" +) + +// A File provides the minimal set of methods required to lock an open file. +// File implementations must be usable as map keys. +// The usual implementation is *os.File. +type File interface { + // Name returns the name of the file. + Name() string + + // Fd returns a valid file descriptor. + // (If the File is an *os.File, it must not be closed.) + Fd() uintptr + + // Stat returns the FileInfo structure describing file. + Stat() (fs.FileInfo, error) +} + +// Lock places an advisory write lock on the file, blocking until it can be +// locked. +// +// If Lock returns nil, no other process will be able to place a read or write +// lock on the file until this process exits, closes f, or calls Unlock on it. +// +// If f's descriptor is already read- or write-locked, the behavior of Lock is +// unspecified. +// +// Closing the file may or may not release the lock promptly. Callers should +// ensure that Unlock is always called when Lock succeeds. +func Lock(f File) error { + return lock(f, writeLock) +} + +// RLock places an advisory read lock on the file, blocking until it can be locked. +// +// If RLock returns nil, no other process will be able to place a write lock on +// the file until this process exits, closes f, or calls Unlock on it. +// +// If f is already read- or write-locked, the behavior of RLock is unspecified. +// +// Closing the file may or may not release the lock promptly. Callers should +// ensure that Unlock is always called if RLock succeeds. +func RLock(f File) error { + return lock(f, readLock) +} + +// Unlock removes an advisory lock placed on f by this process. +// +// The caller must not attempt to unlock a file that is not locked. +func Unlock(f File) error { + return unlock(f) +} + +// String returns the name of the function corresponding to lt +// (Lock, RLock, or Unlock). +func (lt lockType) String() string { + switch lt { + case readLock: + return "RLock" + case writeLock: + return "Lock" + default: + return "Unlock" + } +} + +// IsNotSupported returns a boolean indicating whether the error is known to +// report that a function is not supported (possibly for a specific input). +// It is satisfied by ErrNotSupported as well as some syscall errors. +func IsNotSupported(err error) bool { + return isNotSupported(underlyingError(err)) +} + +var ErrNotSupported = errors.New("operation not supported") + +// underlyingError returns the underlying error for known os error types. +func underlyingError(err error) error { + switch err := err.(type) { + case *fs.PathError: + return err.Err + case *os.LinkError: + return err.Err + case *os.SyscallError: + return err.Err + } + return err +} diff --git a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go new file mode 100644 index 0000000..1fa4327 --- /dev/null +++ b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go @@ -0,0 +1,216 @@ +// 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 aix solaris,!illumos + +// This code implements the filelock API using POSIX 'fcntl' locks, which attach +// to an (inode, process) pair rather than a file descriptor. To avoid unlocking +// files prematurely when the same file is opened through different descriptors, +// we allow only one read-lock at a time. +// +// Most platforms provide some alternative API, such as an 'flock' system call +// or an F_OFD_SETLK command for 'fcntl', that allows for better concurrency and +// does not require per-inode bookkeeping in the application. + +package filelock + +import ( + "errors" + "io" + "io/fs" + "math/rand" + "sync" + "syscall" + "time" +) + +type lockType int16 + +const ( + readLock lockType = syscall.F_RDLCK + writeLock lockType = syscall.F_WRLCK +) + +type inode = uint64 // type of syscall.Stat_t.Ino + +type inodeLock struct { + owner File + queue []<-chan File +} + +type token struct{} + +var ( + mu sync.Mutex + inodes = map[File]inode{} + locks = map[inode]inodeLock{} +) + +func lock(f File, lt lockType) (err error) { + // POSIX locks apply per inode and process, and the lock for an inode is + // released when *any* descriptor for that inode is closed. So we need to + // synchronize access to each inode internally, and must serialize lock and + // unlock calls that refer to the same inode through different descriptors. + fi, err := f.Stat() + if err != nil { + return err + } + ino := fi.Sys().(*syscall.Stat_t).Ino + + mu.Lock() + if i, dup := inodes[f]; dup && i != ino { + mu.Unlock() + return &fs.PathError{ + Op: lt.String(), + Path: f.Name(), + Err: errors.New("inode for file changed since last Lock or RLock"), + } + } + inodes[f] = ino + + var wait chan File + l := locks[ino] + if l.owner == f { + // This file already owns the lock, but the call may change its lock type. + } else if l.owner == nil { + // No owner: it's ours now. + l.owner = f + } else { + // Already owned: add a channel to wait on. + wait = make(chan File) + l.queue = append(l.queue, wait) + } + locks[ino] = l + mu.Unlock() + + if wait != nil { + wait <- f + } + + // Spurious EDEADLK errors arise on platforms that compute deadlock graphs at + // the process, rather than thread, level. Consider processes P and Q, with + // threads P.1, P.2, and Q.3. The following trace is NOT a deadlock, but will be + // reported as a deadlock on systems that consider only process granularity: + // + // P.1 locks file A. + // Q.3 locks file B. + // Q.3 blocks on file A. + // P.2 blocks on file B. (This is erroneously reported as a deadlock.) + // P.1 unlocks file A. + // Q.3 unblocks and locks file A. + // Q.3 unlocks files A and B. + // P.2 unblocks and locks file B. + // P.2 unlocks file B. + // + // These spurious errors were observed in practice on AIX and Solaris in + // cmd/go: see https://golang.org/issue/32817. + // + // We work around this bug by treating EDEADLK as always spurious. If there + // really is a lock-ordering bug between the interacting processes, it will + // become a livelock instead, but that's not appreciably worse than if we had + // a proper flock implementation (which generally does not even attempt to + // diagnose deadlocks). + // + // In the above example, that changes the trace to: + // + // P.1 locks file A. + // Q.3 locks file B. + // Q.3 blocks on file A. + // P.2 spuriously fails to lock file B and goes to sleep. + // P.1 unlocks file A. + // Q.3 unblocks and locks file A. + // Q.3 unlocks files A and B. + // P.2 wakes up and locks file B. + // P.2 unlocks file B. + // + // We know that the retry loop will not introduce a *spurious* livelock + // because, according to the POSIX specification, EDEADLK is only to be + // returned when “the lock is blocked by a lock from another process”. + // If that process is blocked on some lock that we are holding, then the + // resulting livelock is due to a real deadlock (and would manifest as such + // when using, for example, the flock implementation of this package). + // If the other process is *not* blocked on some other lock that we are + // holding, then it will eventually release the requested lock. + + nextSleep := 1 * time.Millisecond + const maxSleep = 500 * time.Millisecond + for { + err = setlkw(f.Fd(), lt) + if err != syscall.EDEADLK { + break + } + time.Sleep(nextSleep) + + nextSleep += nextSleep + if nextSleep > maxSleep { + nextSleep = maxSleep + } + // Apply 10% jitter to avoid synchronizing collisions when we finally unblock. + nextSleep += time.Duration((0.1*rand.Float64() - 0.05) * float64(nextSleep)) + } + + if err != nil { + unlock(f) + return &fs.PathError{ + Op: lt.String(), + Path: f.Name(), + Err: err, + } + } + + return nil +} + +func unlock(f File) error { + var owner File + + mu.Lock() + ino, ok := inodes[f] + if ok { + owner = locks[ino].owner + } + mu.Unlock() + + if owner != f { + panic("unlock called on a file that is not locked") + } + + err := setlkw(f.Fd(), syscall.F_UNLCK) + + mu.Lock() + l := locks[ino] + if len(l.queue) == 0 { + // No waiters: remove the map entry. + delete(locks, ino) + } else { + // The first waiter is sending us their file now. + // Receive it and update the queue. + l.owner = <-l.queue[0] + l.queue = l.queue[1:] + locks[ino] = l + } + delete(inodes, f) + mu.Unlock() + + return err +} + +// setlkw calls FcntlFlock with F_SETLKW for the entire file indicated by fd. +func setlkw(fd uintptr, lt lockType) error { + for { + err := syscall.FcntlFlock(fd, syscall.F_SETLKW, &syscall.Flock_t{ + Type: int16(lt), + Whence: io.SeekStart, + Start: 0, + Len: 0, // All bytes. + }) + if err != syscall.EINTR { + return err + } + } +} + +func isNotSupported(err error) bool { + return err == syscall.ENOSYS || err == syscall.ENOTSUP || err == syscall.EOPNOTSUPP || err == ErrNotSupported +} diff --git a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_other.go b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_other.go new file mode 100644 index 0000000..bc48034 --- /dev/null +++ b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_other.go @@ -0,0 +1,36 @@ +// 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 !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!plan9,!solaris,!windows + +package filelock + +import "io/fs" + +type lockType int8 + +const ( + readLock = iota + 1 + writeLock +) + +func lock(f File, lt lockType) error { + return &fs.PathError{ + Op: lt.String(), + Path: f.Name(), + Err: ErrNotSupported, + } +} + +func unlock(f File) error { + return &fs.PathError{ + Op: "Unlock", + Path: f.Name(), + Err: ErrNotSupported, + } +} + +func isNotSupported(err error) bool { + return err == ErrNotSupported +} diff --git a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_plan9.go b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_plan9.go new file mode 100644 index 0000000..0798ee4 --- /dev/null +++ b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_plan9.go @@ -0,0 +1,36 @@ +// 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 plan9 + +package filelock + +import "io/fs" + +type lockType int8 + +const ( + readLock = iota + 1 + writeLock +) + +func lock(f File, lt lockType) error { + return &fs.PathError{ + Op: lt.String(), + Path: f.Name(), + Err: ErrNotSupported, + } +} + +func unlock(f File) error { + return &fs.PathError{ + Op: "Unlock", + Path: f.Name(), + Err: ErrNotSupported, + } +} + +func isNotSupported(err error) bool { + return err == ErrNotSupported +} diff --git a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_test.go b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_test.go new file mode 100644 index 0000000..2ac2052 --- /dev/null +++ b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_test.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. + +// +build !js,!plan9 + +package filelock_test + +import ( + "fmt" + "internal/testenv" + "os" + "os/exec" + "path/filepath" + "runtime" + "testing" + "time" + + "cmd/go/internal/lockedfile/internal/filelock" +) + +func lock(t *testing.T, f *os.File) { + t.Helper() + err := filelock.Lock(f) + t.Logf("Lock(fd %d) = %v", f.Fd(), err) + if err != nil { + t.Fail() + } +} + +func rLock(t *testing.T, f *os.File) { + t.Helper() + err := filelock.RLock(f) + t.Logf("RLock(fd %d) = %v", f.Fd(), err) + if err != nil { + t.Fail() + } +} + +func unlock(t *testing.T, f *os.File) { + t.Helper() + err := filelock.Unlock(f) + t.Logf("Unlock(fd %d) = %v", f.Fd(), err) + if err != nil { + t.Fail() + } +} + +func mustTempFile(t *testing.T) (f *os.File, remove func()) { + t.Helper() + + base := filepath.Base(t.Name()) + f, err := os.CreateTemp("", base) + if err != nil { + t.Fatalf(`os.CreateTemp("", %q) = %v`, base, err) + } + t.Logf("fd %d = %s", f.Fd(), f.Name()) + + return f, func() { + f.Close() + os.Remove(f.Name()) + } +} + +func mustOpen(t *testing.T, name string) *os.File { + t.Helper() + + f, err := os.OpenFile(name, os.O_RDWR, 0) + if err != nil { + t.Fatalf("os.Open(%q) = %v", name, err) + } + + t.Logf("fd %d = os.Open(%q)", f.Fd(), name) + return f +} + +const ( + quiescent = 10 * time.Millisecond + probablyStillBlocked = 10 * time.Second +) + +func mustBlock(t *testing.T, op string, f *os.File) (wait func(*testing.T)) { + t.Helper() + + desc := fmt.Sprintf("%s(fd %d)", op, f.Fd()) + + done := make(chan struct{}) + go func() { + t.Helper() + switch op { + case "Lock": + lock(t, f) + case "RLock": + rLock(t, f) + default: + panic("invalid op: " + op) + } + close(done) + }() + + select { + case <-done: + t.Fatalf("%s unexpectedly did not block", desc) + return nil + + case <-time.After(quiescent): + t.Logf("%s is blocked (as expected)", desc) + return func(t *testing.T) { + t.Helper() + select { + case <-time.After(probablyStillBlocked): + t.Fatalf("%s is unexpectedly still blocked", desc) + case <-done: + } + } + } +} + +func TestLockExcludesLock(t *testing.T) { + t.Parallel() + + f, remove := mustTempFile(t) + defer remove() + + other := mustOpen(t, f.Name()) + defer other.Close() + + lock(t, f) + lockOther := mustBlock(t, "Lock", other) + unlock(t, f) + lockOther(t) + unlock(t, other) +} + +func TestLockExcludesRLock(t *testing.T) { + t.Parallel() + + f, remove := mustTempFile(t) + defer remove() + + other := mustOpen(t, f.Name()) + defer other.Close() + + lock(t, f) + rLockOther := mustBlock(t, "RLock", other) + unlock(t, f) + rLockOther(t) + unlock(t, other) +} + +func TestRLockExcludesOnlyLock(t *testing.T) { + t.Parallel() + + f, remove := mustTempFile(t) + defer remove() + rLock(t, f) + + f2 := mustOpen(t, f.Name()) + defer f2.Close() + + doUnlockTF := false + switch runtime.GOOS { + case "aix", "solaris": + // When using POSIX locks (as on Solaris), we can't safely read-lock the + // same inode through two different descriptors at the same time: when the + // first descriptor is closed, the second descriptor would still be open but + // silently unlocked. So a second RLock must block instead of proceeding. + lockF2 := mustBlock(t, "RLock", f2) + unlock(t, f) + lockF2(t) + default: + rLock(t, f2) + doUnlockTF = true + } + + other := mustOpen(t, f.Name()) + defer other.Close() + lockOther := mustBlock(t, "Lock", other) + + unlock(t, f2) + if doUnlockTF { + unlock(t, f) + } + lockOther(t) + unlock(t, other) +} + +func TestLockNotDroppedByExecCommand(t *testing.T) { + testenv.MustHaveExec(t) + + f, remove := mustTempFile(t) + defer remove() + + lock(t, f) + + other := mustOpen(t, f.Name()) + defer other.Close() + + // Some kinds of file locks are dropped when a duplicated or forked file + // descriptor is unlocked. Double-check that the approach used by os/exec does + // not accidentally drop locks. + cmd := exec.Command(os.Args[0], "-test.run=^$") + if err := cmd.Run(); err != nil { + t.Fatalf("exec failed: %v", err) + } + + lockOther := mustBlock(t, "Lock", other) + unlock(t, f) + lockOther(t) + unlock(t, other) +} diff --git a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_unix.go b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_unix.go new file mode 100644 index 0000000..ed07bac --- /dev/null +++ b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_unix.go @@ -0,0 +1,44 @@ +// 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 darwin dragonfly freebsd illumos linux netbsd openbsd + +package filelock + +import ( + "io/fs" + "syscall" +) + +type lockType int16 + +const ( + readLock lockType = syscall.LOCK_SH + writeLock lockType = syscall.LOCK_EX +) + +func lock(f File, lt lockType) (err error) { + for { + err = syscall.Flock(int(f.Fd()), int(lt)) + if err != syscall.EINTR { + break + } + } + if err != nil { + return &fs.PathError{ + Op: lt.String(), + Path: f.Name(), + Err: err, + } + } + return nil +} + +func unlock(f File) error { + return lock(f, syscall.LOCK_UN) +} + +func isNotSupported(err error) bool { + return err == syscall.ENOSYS || err == syscall.ENOTSUP || err == syscall.EOPNOTSUPP || err == ErrNotSupported +} diff --git a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_windows.go b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_windows.go new file mode 100644 index 0000000..19de27e --- /dev/null +++ b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_windows.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. + +// +build windows + +package filelock + +import ( + "internal/syscall/windows" + "io/fs" + "syscall" +) + +type lockType uint32 + +const ( + readLock lockType = 0 + writeLock lockType = windows.LOCKFILE_EXCLUSIVE_LOCK +) + +const ( + reserved = 0 + allBytes = ^uint32(0) +) + +func lock(f File, lt lockType) error { + // Per https://golang.org/issue/19098, “Programs currently expect the Fd + // method to return a handle that uses ordinary synchronous I/O.” + // However, LockFileEx still requires an OVERLAPPED structure, + // which contains the file offset of the beginning of the lock range. + // We want to lock the entire file, so we leave the offset as zero. + ol := new(syscall.Overlapped) + + err := windows.LockFileEx(syscall.Handle(f.Fd()), uint32(lt), reserved, allBytes, allBytes, ol) + if err != nil { + return &fs.PathError{ + Op: lt.String(), + Path: f.Name(), + Err: err, + } + } + return nil +} + +func unlock(f File) error { + ol := new(syscall.Overlapped) + err := windows.UnlockFileEx(syscall.Handle(f.Fd()), reserved, allBytes, allBytes, ol) + if err != nil { + return &fs.PathError{ + Op: "Unlock", + Path: f.Name(), + Err: err, + } + } + return nil +} + +func isNotSupported(err error) bool { + switch err { + case windows.ERROR_NOT_SUPPORTED, windows.ERROR_CALL_NOT_IMPLEMENTED, ErrNotSupported: + return true + default: + return false + } +} diff --git a/src/cmd/go/internal/lockedfile/lockedfile.go b/src/cmd/go/internal/lockedfile/lockedfile.go new file mode 100644 index 0000000..82e1a89 --- /dev/null +++ b/src/cmd/go/internal/lockedfile/lockedfile.go @@ -0,0 +1,187 @@ +// 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 lockedfile creates and manipulates files whose contents should only +// change atomically. +package lockedfile + +import ( + "fmt" + "io" + "io/fs" + "os" + "runtime" +) + +// A File is a locked *os.File. +// +// Closing the file releases the lock. +// +// If the program exits while a file is locked, the operating system releases +// the lock but may not do so promptly: callers must ensure that all locked +// files are closed before exiting. +type File struct { + osFile + closed bool +} + +// osFile embeds a *os.File while keeping the pointer itself unexported. +// (When we close a File, it must be the same file descriptor that we opened!) +type osFile struct { + *os.File +} + +// OpenFile is like os.OpenFile, but returns a locked file. +// If flag includes os.O_WRONLY or os.O_RDWR, the file is write-locked; +// otherwise, it is read-locked. +func OpenFile(name string, flag int, perm fs.FileMode) (*File, error) { + var ( + f = new(File) + err error + ) + f.osFile.File, err = openFile(name, flag, perm) + if err != nil { + return nil, err + } + + // Although the operating system will drop locks for open files when the go + // command exits, we want to hold locks for as little time as possible, and we + // especially don't want to leave a file locked after we're done with it. Our + // Close method is what releases the locks, so use a finalizer to report + // missing Close calls on a best-effort basis. + runtime.SetFinalizer(f, func(f *File) { + panic(fmt.Sprintf("lockedfile.File %s became unreachable without a call to Close", f.Name())) + }) + + return f, nil +} + +// Open is like os.Open, but returns a read-locked file. +func Open(name string) (*File, error) { + return OpenFile(name, os.O_RDONLY, 0) +} + +// Create is like os.Create, but returns a write-locked file. +func Create(name string) (*File, error) { + return OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) +} + +// Edit creates the named file with mode 0666 (before umask), +// but does not truncate existing contents. +// +// If Edit succeeds, methods on the returned File can be used for I/O. +// The associated file descriptor has mode O_RDWR and the file is write-locked. +func Edit(name string) (*File, error) { + return OpenFile(name, os.O_RDWR|os.O_CREATE, 0666) +} + +// Close unlocks and closes the underlying file. +// +// Close may be called multiple times; all calls after the first will return a +// non-nil error. +func (f *File) Close() error { + if f.closed { + return &fs.PathError{ + Op: "close", + Path: f.Name(), + Err: fs.ErrClosed, + } + } + f.closed = true + + err := closeFile(f.osFile.File) + runtime.SetFinalizer(f, nil) + return err +} + +// Read opens the named file with a read-lock and returns its contents. +func Read(name string) ([]byte, error) { + f, err := Open(name) + if err != nil { + return nil, err + } + defer f.Close() + + return io.ReadAll(f) +} + +// Write opens the named file (creating it with the given permissions if needed), +// then write-locks it and overwrites it with the given content. +func Write(name string, content io.Reader, perm fs.FileMode) (err error) { + f, err := OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) + if err != nil { + return err + } + + _, err = io.Copy(f, content) + if closeErr := f.Close(); err == nil { + err = closeErr + } + return err +} + +// Transform invokes t with the result of reading the named file, with its lock +// still held. +// +// If t returns a nil error, Transform then writes the returned contents back to +// the file, making a best effort to preserve existing contents on error. +// +// t must not modify the slice passed to it. +func Transform(name string, t func([]byte) ([]byte, error)) (err error) { + f, err := Edit(name) + if err != nil { + return err + } + defer f.Close() + + old, err := io.ReadAll(f) + if err != nil { + return err + } + + new, err := t(old) + if err != nil { + return err + } + + if len(new) > len(old) { + // The overall file size is increasing, so write the tail first: if we're + // about to run out of space on the disk, we would rather detect that + // failure before we have overwritten the original contents. + if _, err := f.WriteAt(new[len(old):], int64(len(old))); err != nil { + // Make a best effort to remove the incomplete tail. + f.Truncate(int64(len(old))) + return err + } + } + + // We're about to overwrite the old contents. In case of failure, make a best + // effort to roll back before we close the file. + defer func() { + if err != nil { + if _, err := f.WriteAt(old, 0); err == nil { + f.Truncate(int64(len(old))) + } + } + }() + + if len(new) >= len(old) { + if _, err := f.WriteAt(new[:len(old)], 0); err != nil { + return err + } + } else { + if _, err := f.WriteAt(new, 0); err != nil { + return err + } + // The overall file size is decreasing, so shrink the file to its final size + // after writing. We do this after writing (instead of before) so that if + // the write fails, enough filesystem space will likely still be reserved + // to contain the previous contents. + if err := f.Truncate(int64(len(new))); err != nil { + return err + } + } + + return nil +} diff --git a/src/cmd/go/internal/lockedfile/lockedfile_filelock.go b/src/cmd/go/internal/lockedfile/lockedfile_filelock.go new file mode 100644 index 0000000..efc6646 --- /dev/null +++ b/src/cmd/go/internal/lockedfile/lockedfile_filelock.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. + +// +build !plan9 + +package lockedfile + +import ( + "io/fs" + "os" + + "cmd/go/internal/fsys" + "cmd/go/internal/lockedfile/internal/filelock" +) + +func openFile(name string, flag int, perm fs.FileMode) (*os.File, error) { + // On BSD systems, we could add the O_SHLOCK or O_EXLOCK flag to the OpenFile + // call instead of locking separately, but we have to support separate locking + // calls for Linux and Windows anyway, so it's simpler to use that approach + // consistently. + + f, err := fsys.OpenFile(name, flag&^os.O_TRUNC, perm) + if err != nil { + return nil, err + } + + switch flag & (os.O_RDONLY | os.O_WRONLY | os.O_RDWR) { + case os.O_WRONLY, os.O_RDWR: + err = filelock.Lock(f) + default: + err = filelock.RLock(f) + } + if err != nil { + f.Close() + return nil, err + } + + if flag&os.O_TRUNC == os.O_TRUNC { + if err := f.Truncate(0); err != nil { + // The documentation for os.O_TRUNC says “if possible, truncate file when + // opened”, but doesn't define “possible” (golang.org/issue/28699). + // We'll treat regular files (and symlinks to regular files) as “possible” + // and ignore errors for the rest. + if fi, statErr := f.Stat(); statErr != nil || fi.Mode().IsRegular() { + filelock.Unlock(f) + f.Close() + return nil, err + } + } + } + + return f, nil +} + +func closeFile(f *os.File) error { + // Since locking syscalls operate on file descriptors, we must unlock the file + // while the descriptor is still valid — that is, before the file is closed — + // and avoid unlocking files that are already closed. + err := filelock.Unlock(f) + + if closeErr := f.Close(); err == nil { + err = closeErr + } + return err +} diff --git a/src/cmd/go/internal/lockedfile/lockedfile_plan9.go b/src/cmd/go/internal/lockedfile/lockedfile_plan9.go new file mode 100644 index 0000000..70d6edd --- /dev/null +++ b/src/cmd/go/internal/lockedfile/lockedfile_plan9.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. + +// +build plan9 + +package lockedfile + +import ( + "io/fs" + "math/rand" + "os" + "strings" + "time" + + "cmd/go/internal/fsys" +) + +// Opening an exclusive-use file returns an error. +// The expected error strings are: +// +// - "open/create -- file is locked" (cwfs, kfs) +// - "exclusive lock" (fossil) +// - "exclusive use file already open" (ramfs) +var lockedErrStrings = [...]string{ + "file is locked", + "exclusive lock", + "exclusive use file already open", +} + +// Even though plan9 doesn't support the Lock/RLock/Unlock functions to +// manipulate already-open files, IsLocked is still meaningful: os.OpenFile +// itself may return errors that indicate that a file with the ModeExclusive bit +// set is already open. +func isLocked(err error) bool { + s := err.Error() + + for _, frag := range lockedErrStrings { + if strings.Contains(s, frag) { + return true + } + } + + return false +} + +func openFile(name string, flag int, perm fs.FileMode) (*os.File, error) { + // Plan 9 uses a mode bit instead of explicit lock/unlock syscalls. + // + // Per http://man.cat-v.org/plan_9/5/stat: “Exclusive use files may be open + // for I/O by only one fid at a time across all clients of the server. If a + // second open is attempted, it draws an error.” + // + // So we can try to open a locked file, but if it fails we're on our own to + // figure out when it becomes available. We'll use exponential backoff with + // some jitter and an arbitrary limit of 500ms. + + // If the file was unpacked or created by some other program, it might not + // have the ModeExclusive bit set. Set it before we call OpenFile, so that we + // can be confident that a successful OpenFile implies exclusive use. + if fi, err := fsys.Stat(name); err == nil { + if fi.Mode()&fs.ModeExclusive == 0 { + if err := os.Chmod(name, fi.Mode()|fs.ModeExclusive); err != nil { + return nil, err + } + } + } else if !os.IsNotExist(err) { + return nil, err + } + + nextSleep := 1 * time.Millisecond + const maxSleep = 500 * time.Millisecond + for { + f, err := fsys.OpenFile(name, flag, perm|fs.ModeExclusive) + if err == nil { + return f, nil + } + + if !isLocked(err) { + return nil, err + } + + time.Sleep(nextSleep) + + nextSleep += nextSleep + if nextSleep > maxSleep { + nextSleep = maxSleep + } + // Apply 10% jitter to avoid synchronizing collisions. + nextSleep += time.Duration((0.1*rand.Float64() - 0.05) * float64(nextSleep)) + } +} + +func closeFile(f *os.File) error { + return f.Close() +} diff --git a/src/cmd/go/internal/lockedfile/lockedfile_test.go b/src/cmd/go/internal/lockedfile/lockedfile_test.go new file mode 100644 index 0000000..34327dd --- /dev/null +++ b/src/cmd/go/internal/lockedfile/lockedfile_test.go @@ -0,0 +1,271 @@ +// 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. + +// js does not support inter-process file locking. +// +build !js + +package lockedfile_test + +import ( + "fmt" + "internal/testenv" + "os" + "os/exec" + "path/filepath" + "testing" + "time" + + "cmd/go/internal/lockedfile" +) + +func mustTempDir(t *testing.T) (dir string, remove func()) { + t.Helper() + + dir, err := os.MkdirTemp("", filepath.Base(t.Name())) + if err != nil { + t.Fatal(err) + } + return dir, func() { os.RemoveAll(dir) } +} + +const ( + quiescent = 10 * time.Millisecond + probablyStillBlocked = 10 * time.Second +) + +func mustBlock(t *testing.T, desc string, f func()) (wait func(*testing.T)) { + t.Helper() + + done := make(chan struct{}) + go func() { + f() + close(done) + }() + + select { + case <-done: + t.Fatalf("%s unexpectedly did not block", desc) + return nil + + case <-time.After(quiescent): + return func(t *testing.T) { + t.Helper() + select { + case <-time.After(probablyStillBlocked): + t.Fatalf("%s is unexpectedly still blocked after %v", desc, probablyStillBlocked) + case <-done: + } + } + } +} + +func TestMutexExcludes(t *testing.T) { + t.Parallel() + + dir, remove := mustTempDir(t) + defer remove() + + path := filepath.Join(dir, "lock") + + mu := lockedfile.MutexAt(path) + t.Logf("mu := MutexAt(_)") + + unlock, err := mu.Lock() + if err != nil { + t.Fatalf("mu.Lock: %v", err) + } + t.Logf("unlock, _ := mu.Lock()") + + mu2 := lockedfile.MutexAt(mu.Path) + t.Logf("mu2 := MutexAt(mu.Path)") + + wait := mustBlock(t, "mu2.Lock()", func() { + unlock2, err := mu2.Lock() + if err != nil { + t.Errorf("mu2.Lock: %v", err) + return + } + t.Logf("unlock2, _ := mu2.Lock()") + t.Logf("unlock2()") + unlock2() + }) + + t.Logf("unlock()") + unlock() + wait(t) +} + +func TestReadWaitsForLock(t *testing.T) { + t.Parallel() + + dir, remove := mustTempDir(t) + defer remove() + + path := filepath.Join(dir, "timestamp.txt") + + f, err := lockedfile.Create(path) + if err != nil { + t.Fatalf("Create: %v", err) + } + defer f.Close() + + const ( + part1 = "part 1\n" + part2 = "part 2\n" + ) + _, err = f.WriteString(part1) + if err != nil { + t.Fatalf("WriteString: %v", err) + } + t.Logf("WriteString(%q) = ", part1) + + wait := mustBlock(t, "Read", func() { + b, err := lockedfile.Read(path) + if err != nil { + t.Errorf("Read: %v", err) + return + } + + const want = part1 + part2 + got := string(b) + if got == want { + t.Logf("Read(_) = %q", got) + } else { + t.Errorf("Read(_) = %q, _; want %q", got, want) + } + }) + + _, err = f.WriteString(part2) + if err != nil { + t.Errorf("WriteString: %v", err) + } else { + t.Logf("WriteString(%q) = ", part2) + } + f.Close() + + wait(t) +} + +func TestCanLockExistingFile(t *testing.T) { + t.Parallel() + + dir, remove := mustTempDir(t) + defer remove() + path := filepath.Join(dir, "existing.txt") + + if err := os.WriteFile(path, []byte("ok"), 0777); err != nil { + t.Fatalf("os.WriteFile: %v", err) + } + + f, err := lockedfile.Edit(path) + if err != nil { + t.Fatalf("first Edit: %v", err) + } + + wait := mustBlock(t, "Edit", func() { + other, err := lockedfile.Edit(path) + if err != nil { + t.Errorf("second Edit: %v", err) + } + other.Close() + }) + + f.Close() + wait(t) +} + +// TestSpuriousEDEADLK verifies that the spurious EDEADLK reported in +// https://golang.org/issue/32817 no longer occurs. +func TestSpuriousEDEADLK(t *testing.T) { + // P.1 locks file A. + // Q.3 locks file B. + // Q.3 blocks on file A. + // P.2 blocks on file B. (Spurious EDEADLK occurs here.) + // P.1 unlocks file A. + // Q.3 unblocks and locks file A. + // Q.3 unlocks files A and B. + // P.2 unblocks and locks file B. + // P.2 unlocks file B. + + testenv.MustHaveExec(t) + + dirVar := t.Name() + "DIR" + + if dir := os.Getenv(dirVar); dir != "" { + // Q.3 locks file B. + b, err := lockedfile.Edit(filepath.Join(dir, "B")) + if err != nil { + t.Fatal(err) + } + defer b.Close() + + if err := os.WriteFile(filepath.Join(dir, "locked"), []byte("ok"), 0666); err != nil { + t.Fatal(err) + } + + // Q.3 blocks on file A. + a, err := lockedfile.Edit(filepath.Join(dir, "A")) + // Q.3 unblocks and locks file A. + if err != nil { + t.Fatal(err) + } + defer a.Close() + + // Q.3 unlocks files A and B. + return + } + + dir, remove := mustTempDir(t) + defer remove() + + // P.1 locks file A. + a, err := lockedfile.Edit(filepath.Join(dir, "A")) + if err != nil { + t.Fatal(err) + } + + cmd := exec.Command(os.Args[0], "-test.run="+t.Name()) + cmd.Env = append(os.Environ(), fmt.Sprintf("%s=%s", dirVar, dir)) + + qDone := make(chan struct{}) + waitQ := mustBlock(t, "Edit A and B in subprocess", func() { + out, err := cmd.CombinedOutput() + if err != nil { + t.Errorf("%v:\n%s", err, out) + } + close(qDone) + }) + + // Wait until process Q has either failed or locked file B. + // Otherwise, P.2 might not block on file B as intended. +locked: + for { + if _, err := os.Stat(filepath.Join(dir, "locked")); !os.IsNotExist(err) { + break locked + } + select { + case <-qDone: + break locked + case <-time.After(1 * time.Millisecond): + } + } + + waitP2 := mustBlock(t, "Edit B", func() { + // P.2 blocks on file B. (Spurious EDEADLK occurs here.) + b, err := lockedfile.Edit(filepath.Join(dir, "B")) + // P.2 unblocks and locks file B. + if err != nil { + t.Error(err) + return + } + // P.2 unlocks file B. + b.Close() + }) + + // P.1 unlocks file A. + a.Close() + + waitQ(t) + waitP2(t) +} diff --git a/src/cmd/go/internal/lockedfile/mutex.go b/src/cmd/go/internal/lockedfile/mutex.go new file mode 100644 index 0000000..180a36c --- /dev/null +++ b/src/cmd/go/internal/lockedfile/mutex.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 lockedfile + +import ( + "fmt" + "os" + "sync" +) + +// A Mutex provides mutual exclusion within and across processes by locking a +// well-known file. Such a file generally guards some other part of the +// filesystem: for example, a Mutex file in a directory might guard access to +// the entire tree rooted in that directory. +// +// Mutex does not implement sync.Locker: unlike a sync.Mutex, a lockedfile.Mutex +// can fail to lock (e.g. if there is a permission error in the filesystem). +// +// Like a sync.Mutex, a Mutex may be included as a field of a larger struct but +// must not be copied after first use. The Path field must be set before first +// use and must not be change thereafter. +type Mutex struct { + Path string // The path to the well-known lock file. Must be non-empty. + mu sync.Mutex // A redundant mutex. The race detector doesn't know about file locking, so in tests we may need to lock something that it understands. +} + +// MutexAt returns a new Mutex with Path set to the given non-empty path. +func MutexAt(path string) *Mutex { + if path == "" { + panic("lockedfile.MutexAt: path must be non-empty") + } + return &Mutex{Path: path} +} + +func (mu *Mutex) String() string { + return fmt.Sprintf("lockedfile.Mutex(%s)", mu.Path) +} + +// Lock attempts to lock the Mutex. +// +// If successful, Lock returns a non-nil unlock function: it is provided as a +// return-value instead of a separate method to remind the caller to check the +// accompanying error. (See https://golang.org/issue/20803.) +func (mu *Mutex) Lock() (unlock func(), err error) { + if mu.Path == "" { + panic("lockedfile.Mutex: missing Path during Lock") + } + + // We could use either O_RDWR or O_WRONLY here. If we choose O_RDWR and the + // file at mu.Path is write-only, the call to OpenFile will fail with a + // permission error. That's actually what we want: if we add an RLock method + // in the future, it should call OpenFile with O_RDONLY and will require the + // files must be readable, so we should not let the caller make any + // assumptions about Mutex working with write-only files. + f, err := OpenFile(mu.Path, os.O_RDWR|os.O_CREATE, 0666) + if err != nil { + return nil, err + } + mu.mu.Lock() + + return func() { + mu.mu.Unlock() + f.Close() + }, nil +} diff --git a/src/cmd/go/internal/lockedfile/transform_test.go b/src/cmd/go/internal/lockedfile/transform_test.go new file mode 100644 index 0000000..407d48e --- /dev/null +++ b/src/cmd/go/internal/lockedfile/transform_test.go @@ -0,0 +1,104 @@ +// Copyright 2019 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. + +// js does not support inter-process file locking. +// +build !js + +package lockedfile_test + +import ( + "bytes" + "encoding/binary" + "math/rand" + "path/filepath" + "testing" + "time" + + "cmd/go/internal/lockedfile" +) + +func isPowerOf2(x int) bool { + return x > 0 && x&(x-1) == 0 +} + +func roundDownToPowerOf2(x int) int { + if x <= 0 { + panic("nonpositive x") + } + bit := 1 + for x != bit { + x = x &^ bit + bit <<= 1 + } + return x +} + +func TestTransform(t *testing.T) { + dir, remove := mustTempDir(t) + defer remove() + path := filepath.Join(dir, "blob.bin") + + const maxChunkWords = 8 << 10 + buf := make([]byte, 2*maxChunkWords*8) + for i := uint64(0); i < 2*maxChunkWords; i++ { + binary.LittleEndian.PutUint64(buf[i*8:], i) + } + if err := lockedfile.Write(path, bytes.NewReader(buf[:8]), 0666); err != nil { + t.Fatal(err) + } + + var attempts int64 = 128 + if !testing.Short() { + attempts *= 16 + } + const parallel = 32 + + var sem = make(chan bool, parallel) + + for n := attempts; n > 0; n-- { + sem <- true + go func() { + defer func() { <-sem }() + + time.Sleep(time.Duration(rand.Intn(100)) * time.Microsecond) + chunkWords := roundDownToPowerOf2(rand.Intn(maxChunkWords) + 1) + offset := rand.Intn(chunkWords) + + err := lockedfile.Transform(path, func(data []byte) (chunk []byte, err error) { + chunk = buf[offset*8 : (offset+chunkWords)*8] + + if len(data)&^7 != len(data) { + t.Errorf("read %d bytes, but each write is an integer multiple of 8 bytes", len(data)) + return chunk, nil + } + + words := len(data) / 8 + if !isPowerOf2(words) { + t.Errorf("read %d 8-byte words, but each write is a power-of-2 number of words", words) + return chunk, nil + } + + u := binary.LittleEndian.Uint64(data) + for i := 1; i < words; i++ { + next := binary.LittleEndian.Uint64(data[i*8:]) + if next != u+1 { + t.Errorf("wrote sequential integers, but read integer out of sequence at offset %d", i) + return chunk, nil + } + u = next + } + + return chunk, nil + }) + + if err != nil { + t.Errorf("unexpected error from Transform: %v", err) + } + }() + } + + for n := parallel; n > 0; n-- { + sem <- true + } +} diff --git a/src/cmd/go/internal/modcmd/download.go b/src/cmd/go/internal/modcmd/download.go new file mode 100644 index 0000000..a602bb9 --- /dev/null +++ b/src/cmd/go/internal/modcmd/download.go @@ -0,0 +1,214 @@ +// 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 ( + "context" + "encoding/json" + "os" + "runtime" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/modfetch" + "cmd/go/internal/modload" + + "golang.org/x/mod/module" +) + +var cmdDownload = &base.Command{ + UsageLine: "go mod download [-x] [-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 +(equivalent to 'go mod download all'). + +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 writes nothing to standard output. It may print progress +messages and errors to standard error. + +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) + } + +The -x flag causes download to print the commands download executes. + +See https://golang.org/ref/mod#go-mod-download for more about 'go mod download'. + +See https://golang.org/ref/mod#version-queries for more about version queries. + `, +} + +var downloadJSON = cmdDownload.Flag.Bool("json", false, "") + +func init() { + cmdDownload.Run = runDownload // break init cycle + + // TODO(jayconrod): https://golang.org/issue/35849 Apply -x to other 'go mod' commands. + cmdDownload.Flag.BoolVar(&cfg.BuildX, "x", false, "") + base.AddModCommonFlags(&cmdDownload.Flag) +} + +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(ctx context.Context, cmd *base.Command, args []string) { + // Check whether modules are enabled and whether we're in a module. + modload.ForceUseModules = true + if !modload.HasModRoot() && len(args) == 0 { + base.Fatalf("go mod download: no modules specified (see 'go help mod download')") + } + haveExplicitArgs := len(args) > 0 + if !haveExplicitArgs { + args = []string{"all"} + } + if modload.HasModRoot() { + modload.LoadModFile(ctx) // to fill Target + targetAtUpgrade := modload.Target.Path + "@upgrade" + targetAtPatch := modload.Target.Path + "@patch" + for _, arg := range args { + switch arg { + case modload.Target.Path, targetAtUpgrade, targetAtPatch: + os.Stderr.WriteString("go mod download: skipping argument " + arg + " that resolves to the main module\n") + } + } + } + + downloadModule := func(m *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(ctx, mod) + if err != nil { + m.Error = err.Error() + return + } + m.Sum = modfetch.Sum(mod) + m.Dir, err = modfetch.Download(ctx, mod) + if err != nil { + m.Error = err.Error() + return + } + } + + var mods []*moduleJSON + listU := false + listVersions := false + listRetractions := false + type token struct{} + sem := make(chan token, runtime.GOMAXPROCS(0)) + infos := modload.ListModules(ctx, args, listU, listVersions, listRetractions) + if !haveExplicitArgs { + // 'go mod download' is sometimes run without arguments to pre-populate + // the module cache. It may fetch modules that aren't needed to build + // packages in the main mdoule. This is usually not intended, so don't save + // sums for downloaded modules (golang.org/issue/45332). + // TODO(golang.org/issue/45551): For now, save sums needed to load the + // build list (same as 1.15 behavior). In the future, report an error if + // go.mod or go.sum need to be updated after loading the build list. + modload.WriteGoMod() + modload.DisallowWriteGoMod() + } + + for _, info := range infos { + if info.Replace != nil { + info = info.Replace + } + if info.Version == "" && info.Error == nil { + // main module or module replaced with file path. + // Nothing to download. + continue + } + m := &moduleJSON{ + Path: info.Path, + Version: info.Version, + } + mods = append(mods, m) + if info.Error != nil { + m.Error = info.Error.Err + continue + } + sem <- token{} + go func() { + downloadModule(m) + <-sem + }() + } + + // Fill semaphore channel to wait for goroutines to finish. + for n := cap(sem); n > 0; n-- { + sem <- token{} + } + + if *downloadJSON { + for _, m := range mods { + b, err := json.MarshalIndent(m, "", "\t") + if err != nil { + base.Fatalf("go mod download: %v", err) + } + os.Stdout.Write(append(b, '\n')) + if m.Error != "" { + base.SetExitStatus(1) + } + } + } else { + for _, m := range mods { + if m.Error != "" { + base.Errorf("go mod download: %v", m.Error) + } + } + base.ExitIfErrors() + } + + // If there were explicit arguments, update go.mod and especially go.sum. + // 'go mod download mod@version' is a useful way to add a sum without using + // 'go get mod@version', which may have other side effects. We print this in + // some error message hints. + // + // Don't save sums for 'go mod download' without arguments; see comment above. + if haveExplicitArgs { + modload.WriteGoMod() + } +} diff --git a/src/cmd/go/internal/modcmd/edit.go b/src/cmd/go/internal/modcmd/edit.go new file mode 100644 index 0000000..1df104e --- /dev/null +++ b/src/cmd/go/internal/modcmd/edit.go @@ -0,0 +1,505 @@ +// 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 ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "os" + "strings" + + "cmd/go/internal/base" + "cmd/go/internal/lockedfile" + "cmd/go/internal/modfetch" + "cmd/go/internal/modload" + + "golang.org/x/mod/modfile" + "golang.org/x/mod/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] flag adds a replacement of the given +module path and version pair. If the @v in old@v is omitted, a +replacement without a version on the left side is added, which applies +to all versions of 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 redundant replacements for old[@v], +so omitting @v will drop existing replacements for specific versions. + +The -dropreplace=old[@v] flag drops a replacement of the given +module path and version pair. If the @v is omitted, a replacement without +a version on the left side is dropped. + +The -retract=version and -dropretract=version flags add and drop a +retraction on the given version. The version may be a single version +like "v1.2.3" or a closed interval like "[v1.1.0,v1.1.9]". Note that +-retract=version is a no-op if that retraction already exists. + +The -require, -droprequire, -exclude, -dropexclude, -replace, +-dropreplace, -retract, and -dropretract editing flags may be repeated, +and the changes are applied in the order given. + +The -go=version flag sets the expected Go language version. + +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 + Go string + Require []Require + Exclude []Module + Replace []Replace + Retract []Retract + } + + type Require struct { + Path string + Version string + Indirect bool + } + + type Replace struct { + Old Module + New Module + } + + type Retract struct { + Low string + High string + Rationale string + } + +Retract entries representing a single version (not an interval) will have +the "Low" and "High" fields set to the same value. + +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'. + +See https://golang.org/ref/mod#go-mod-edit for more about 'go mod edit'. + `, +} + +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", "") + cmdEdit.Flag.Var(flagFunc(flagRetract), "retract", "") + cmdEdit.Flag.Var(flagFunc(flagDropRetract), "dropretract", "") + + base.AddModCommonFlags(&cmdEdit.Flag) + base.AddBuildFlagsNX(&cmdEdit.Flag) +} + +func runEdit(ctx context.Context, cmd *base.Command, args []string) { + anyFlags := + *editModule != "" || + *editGo != "" || + *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 { + gomod = modload.ModFilePath() + } + + if *editModule != "" { + if err := module.CheckImportPath(*editModule); err != nil { + base.Fatalf("go mod: invalid -module: %v", err) + } + } + + if *editGo != "" { + if !modfile.GoVersionRE.MatchString(*editGo) { + base.Fatalf(`go mod: invalid -go option; expecting something like "-go 1.12"`) + } + } + + data, err := lockedfile.Read(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(*editModule) + } + + if *editGo != "" { + if err := modFile.AddGoStmt(*editGo); err != nil { + base.Fatalf("go: internal error: %v", err) + } + } + + if len(edits) > 0 { + for _, edit := range edits { + edit(modFile) + } + } + modFile.SortBlocks() + modFile.Cleanup() // clean file after edits + + if *editJSON { + editPrintJSON(modFile) + return + } + + out, err := modFile.Format() + if err != nil { + base.Fatalf("go: %v", err) + } + + if *editPrint { + os.Stdout.Write(out) + return + } + + // Make a best-effort attempt to acquire the side lock, only to exclude + // previous versions of the 'go' command from making simultaneous edits. + if unlock, err := modfetch.SideLock(); err == nil { + defer unlock() + } + + err = lockedfile.Transform(gomod, func(lockedData []byte) ([]byte, error) { + if !bytes.Equal(lockedData, data) { + return nil, errors.New("go.mod changed during editing; not overwriting") + } + return out, nil + }) + if 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.CheckImportPath(path); err != nil { + base.Fatalf("go mod: -%s=%s: invalid path: %v", flag, arg, err) + } + + if !allowedVersionArg(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.CheckImportPath(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.CheckImportPath(path); err != nil { + if !allowDirPath || !modfile.IsDirectoryPath(path) { + return path, version, fmt.Errorf("invalid %s path: %v", adj, err) + } + } + if path != arg && !allowedVersionArg(version) { + return path, version, fmt.Errorf("invalid %s version: %q", adj, version) + } + return path, version, nil +} + +// parseVersionInterval parses a single version like "v1.2.3" or a closed +// interval like "[v1.2.3,v1.4.5]". Note that a single version has the same +// representation as an interval with equal upper and lower bounds: both +// Low and High are set. +func parseVersionInterval(arg string) (modfile.VersionInterval, error) { + if !strings.HasPrefix(arg, "[") { + if !allowedVersionArg(arg) { + return modfile.VersionInterval{}, fmt.Errorf("invalid version: %q", arg) + } + return modfile.VersionInterval{Low: arg, High: arg}, nil + } + if !strings.HasSuffix(arg, "]") { + return modfile.VersionInterval{}, fmt.Errorf("invalid version interval: %q", arg) + } + s := arg[1 : len(arg)-1] + i := strings.Index(s, ",") + if i < 0 { + return modfile.VersionInterval{}, fmt.Errorf("invalid version interval: %q", arg) + } + low := strings.TrimSpace(s[:i]) + high := strings.TrimSpace(s[i+1:]) + if !allowedVersionArg(low) || !allowedVersionArg(high) { + return modfile.VersionInterval{}, fmt.Errorf("invalid version interval: %q", arg) + } + return modfile.VersionInterval{Low: low, High: high}, nil +} + +// allowedVersionArg returns whether a token may be used as a version in go.mod. +// 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. +func allowedVersionArg(arg string) bool { + return !modfile.MustQuote(arg) +} + +// 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) + } + }) +} + +// flagRetract implements the -retract flag. +func flagRetract(arg string) { + vi, err := parseVersionInterval(arg) + if err != nil { + base.Fatalf("go mod: -retract=%s: %v", arg, err) + } + edits = append(edits, func(f *modfile.File) { + if err := f.AddRetract(vi, ""); err != nil { + base.Fatalf("go mod: -retract=%s: %v", arg, err) + } + }) +} + +// flagDropRetract implements the -dropretract flag. +func flagDropRetract(arg string) { + vi, err := parseVersionInterval(arg) + if err != nil { + base.Fatalf("go mod: -dropretract=%s: %v", arg, err) + } + edits = append(edits, func(f *modfile.File) { + if err := f.DropRetract(vi); err != nil { + base.Fatalf("go mod: -dropretract=%s: %v", arg, err) + } + }) +} + +// fileJSON is the -json output data structure. +type fileJSON struct { + Module module.Version + Go string `json:",omitempty"` + Require []requireJSON + Exclude []module.Version + Replace []replaceJSON + Retract []retractJSON +} + +type requireJSON struct { + Path string + Version string `json:",omitempty"` + Indirect bool `json:",omitempty"` +} + +type replaceJSON struct { + Old module.Version + New module.Version +} + +type retractJSON struct { + Low string `json:",omitempty"` + High string `json:",omitempty"` + Rationale string `json:",omitempty"` +} + +// editPrintJSON prints the -json output. +func editPrintJSON(modFile *modfile.File) { + var f fileJSON + if modFile.Module != nil { + f.Module = modFile.Module.Mod + } + if modFile.Go != nil { + f.Go = modFile.Go.Version + } + 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}) + } + for _, r := range modFile.Retract { + f.Retract = append(f.Retract, retractJSON{r.Low, r.High, r.Rationale}) + } + 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/src/cmd/go/internal/modcmd/graph.go b/src/cmd/go/internal/modcmd/graph.go new file mode 100644 index 0000000..a88e9ef --- /dev/null +++ b/src/cmd/go/internal/modcmd/graph.go @@ -0,0 +1,84 @@ +// 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" + "context" + "os" + "sort" + + "cmd/go/internal/base" + "cmd/go/internal/modload" + + "golang.org/x/mod/module" +) + +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. + +See https://golang.org/ref/mod#go-mod-graph for more about 'go mod graph'. + `, + Run: runGraph, +} + +func init() { + base.AddModCommonFlags(&cmdGraph.Flag) +} + +func runGraph(ctx context.Context, cmd *base.Command, args []string) { + if len(args) > 0 { + base.Fatalf("go mod graph: graph takes no arguments") + } + modload.ForceUseModules = true + modload.RootMode = modload.NeedRoot + modload.LoadAllModules(ctx) + + reqs := modload.MinReqs() + format := func(m module.Version) string { + if m.Version == "" { + return m.Path + } + return m.Path + "@" + m.Version + } + + var out []string + var deps int // index in out where deps start + seen := map[module.Version]bool{modload.Target: true} + queue := []module.Version{modload.Target} + for len(queue) > 0 { + var m module.Version + m, queue = queue[0], queue[1:] + list, _ := reqs.Required(m) + for _, r := range list { + if !seen[r] { + queue = append(queue, r) + seen[r] = true + } + 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/src/cmd/go/internal/modcmd/init.go b/src/cmd/go/internal/modcmd/init.go new file mode 100644 index 0000000..73cc282 --- /dev/null +++ b/src/cmd/go/internal/modcmd/init.go @@ -0,0 +1,51 @@ +// 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" + "context" +) + +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 file in the current directory, in +effect creating a new module rooted at the current directory. The go.mod file +must not already exist. + +Init accepts one optional argument, the module path for the new module. If the +module path argument is omitted, init will attempt to infer the module path +using import comments in .go files, vendoring tool configuration files (like +Gopkg.lock), and the current directory (if in GOPATH). + +If a configuration file for a vendoring tool is present, init will attempt to +import module requirements from it. + +See https://golang.org/ref/mod#go-mod-init for more about 'go mod init'. +`, + Run: runInit, +} + +func init() { + base.AddModCommonFlags(&cmdInit.Flag) +} + +func runInit(ctx context.Context, cmd *base.Command, args []string) { + if len(args) > 1 { + base.Fatalf("go mod init: too many arguments") + } + var modPath string + if len(args) == 1 { + modPath = args[0] + } + + modload.ForceUseModules = true + modload.CreateModFile(ctx, modPath) // does all the hard work +} diff --git a/src/cmd/go/internal/modcmd/mod.go b/src/cmd/go/internal/modcmd/mod.go new file mode 100644 index 0000000..d72d0ca --- /dev/null +++ b/src/cmd/go/internal/modcmd/mod.go @@ -0,0 +1,33 @@ +// 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/src/cmd/go/internal/modcmd/tidy.go b/src/cmd/go/internal/modcmd/tidy.go new file mode 100644 index 0000000..67f90b1 --- /dev/null +++ b/src/cmd/go/internal/modcmd/tidy.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. + +// go mod tidy + +package modcmd + +import ( + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/imports" + "cmd/go/internal/modload" + "context" +) + +var cmdTidy = &base.Command{ + UsageLine: "go mod tidy [-e] [-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. + +The -e flag causes tidy to attempt to proceed despite errors +encountered while loading packages. + +See https://golang.org/ref/mod#go-mod-tidy for more about 'go mod tidy'. + `, + Run: runTidy, +} + +var tidyE bool // if true, report errors but proceed anyway. + +func init() { + cmdTidy.Flag.BoolVar(&cfg.BuildV, "v", false, "") + cmdTidy.Flag.BoolVar(&tidyE, "e", false, "") + base.AddModCommonFlags(&cmdTidy.Flag) +} + +func runTidy(ctx context.Context, cmd *base.Command, args []string) { + if len(args) > 0 { + base.Fatalf("go mod tidy: no arguments allowed") + } + + // Tidy aims to make 'go test' reproducible for any package in 'all', so we + // need to include test dependencies. For modules that specify go 1.15 or + // earlier this is a no-op (because 'all' saturates transitive test + // dependencies). + // + // However, with lazy loading (go 1.16+) 'all' includes only the packages that + // are transitively imported by the main module, not the test dependencies of + // those packages. In order to make 'go test' reproducible for the packages + // that are in 'all' but outside of the main module, we must explicitly + // request that their test dependencies be included. + modload.ForceUseModules = true + modload.RootMode = modload.NeedRoot + + modload.CheckTidyVersion(ctx, tidyE) + + modload.LoadPackages(ctx, modload.PackageOpts{ + Tags: imports.AnyTags(), + ResolveMissingImports: true, + LoadTests: true, + AllowErrors: tidyE, + SilenceMissingStdImports: true, + }, "all") + + modload.TidyBuildList() + modload.TrimGoSum() + modload.WriteGoMod() +} diff --git a/src/cmd/go/internal/modcmd/vendor.go b/src/cmd/go/internal/modcmd/vendor.go new file mode 100644 index 0000000..4ef8481 --- /dev/null +++ b/src/cmd/go/internal/modcmd/vendor.go @@ -0,0 +1,379 @@ +// 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" + "context" + "errors" + "fmt" + "go/build" + "io" + "io/fs" + "os" + "path" + "path/filepath" + "sort" + "strings" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/fsys" + "cmd/go/internal/imports" + "cmd/go/internal/load" + "cmd/go/internal/modload" + "cmd/go/internal/str" + + "golang.org/x/mod/module" + "golang.org/x/mod/semver" +) + +var cmdVendor = &base.Command{ + UsageLine: "go mod vendor [-e] [-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. + +The -e flag causes vendor to attempt to proceed despite errors +encountered while loading packages. + +See https://golang.org/ref/mod#go-mod-vendor for more about 'go mod vendor'. + `, + Run: runVendor, +} + +var vendorE bool // if true, report errors but proceed anyway + +func init() { + cmdVendor.Flag.BoolVar(&cfg.BuildV, "v", false, "") + cmdVendor.Flag.BoolVar(&vendorE, "e", false, "") + base.AddModCommonFlags(&cmdVendor.Flag) +} + +func runVendor(ctx context.Context, cmd *base.Command, args []string) { + if len(args) != 0 { + base.Fatalf("go mod vendor: vendor takes no arguments") + } + modload.ForceUseModules = true + modload.RootMode = modload.NeedRoot + + loadOpts := modload.PackageOpts{ + Tags: imports.AnyTags(), + ResolveMissingImports: true, + UseVendorAll: true, + AllowErrors: vendorE, + SilenceMissingStdImports: true, + } + _, pkgs := modload.LoadPackages(ctx, loadOpts, "all") + + vdir := filepath.Join(modload.ModRoot(), "vendor") + if err := os.RemoveAll(vdir); err != nil { + base.Fatalf("go mod vendor: %v", err) + } + + modpkgs := make(map[module.Version][]string) + for _, pkg := range pkgs { + m := modload.PackageModule(pkg) + if m.Path == "" || m == modload.Target { + continue + } + modpkgs[m] = append(modpkgs[m], pkg) + } + + includeAllReplacements := false + isExplicit := map[module.Version]bool{} + if gv := modload.ModFile().Go; gv != nil && semver.Compare("v"+gv.Version, "v1.14") >= 0 { + // If the Go version is at least 1.14, annotate all explicit 'require' and + // 'replace' targets found in the go.mod file so that we can perform a + // stronger consistency check when -mod=vendor is set. + for _, r := range modload.ModFile().Require { + isExplicit[r.Mod] = true + } + includeAllReplacements = true + } + + var vendorMods []module.Version + for m := range isExplicit { + vendorMods = append(vendorMods, m) + } + for m := range modpkgs { + if !isExplicit[m] { + vendorMods = append(vendorMods, m) + } + } + module.Sort(vendorMods) + + var buf bytes.Buffer + for _, m := range vendorMods { + line := moduleLine(m, modload.Replacement(m)) + buf.WriteString(line) + if cfg.BuildV { + os.Stderr.WriteString(line) + } + if isExplicit[m] { + buf.WriteString("## explicit\n") + if cfg.BuildV { + os.Stderr.WriteString("## explicit\n") + } + } + pkgs := modpkgs[m] + sort.Strings(pkgs) + for _, pkg := range pkgs { + fmt.Fprintf(&buf, "%s\n", pkg) + if cfg.BuildV { + fmt.Fprintf(os.Stderr, "%s\n", pkg) + } + vendorPkg(vdir, pkg) + } + } + + if includeAllReplacements { + // Record unused and wildcard replacements at the end of the modules.txt file: + // without access to the complete build list, the consumer of the vendor + // directory can't otherwise determine that those replacements had no effect. + for _, r := range modload.ModFile().Replace { + if len(modpkgs[r.Old]) > 0 { + // We we already recorded this replacement in the entry for the replaced + // module with the packages it provides. + continue + } + + line := moduleLine(r.Old, r.New) + buf.WriteString(line) + if cfg.BuildV { + os.Stderr.WriteString(line) + } + } + } + + if buf.Len() == 0 { + fmt.Fprintf(os.Stderr, "go: no dependencies to vendor\n") + return + } + + if err := os.MkdirAll(vdir, 0777); err != nil { + base.Fatalf("go mod vendor: %v", err) + } + + if err := os.WriteFile(filepath.Join(vdir, "modules.txt"), buf.Bytes(), 0666); err != nil { + base.Fatalf("go mod vendor: %v", err) + } +} + +func moduleLine(m, r module.Version) string { + b := new(strings.Builder) + b.WriteString("# ") + b.WriteString(m.Path) + if m.Version != "" { + b.WriteString(" ") + b.WriteString(m.Version) + } + if r.Path != "" { + b.WriteString(" => ") + b.WriteString(r.Path) + if r.Version != "" { + b.WriteString(" ") + b.WriteString(r.Version) + } + } + b.WriteString("\n") + return b.String() +} + +func vendorPkg(vdir, pkg string) { + // TODO(#42504): Instead of calling modload.ImportMap then build.ImportDir, + // just call load.PackagesAndErrors. To do that, we need to add a good way + // to ignore build constraints. + 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) + } + + copiedFiles := make(map[string]bool) + 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, matchPotentialSourceFile, copiedFiles) + if m := modload.PackageModule(realPath); m.Path != "" { + copyMetadata(m.Path, realPath, dst, src, copiedFiles) + } + + ctx := build.Default + ctx.UseAllFiles = true + bp, err := ctx.ImportDir(src, build.IgnoreVendor) + // Because UseAllFiles is set on the build.Context, it's possible ta get + // a MultiplePackageError on an otherwise valid package: the package could + // have different names for GOOS=windows and GOOS=mac for example. On the + // other hand if there's a NoGoError, the package might have source files + // specifying "// +build ignore" those packages should be skipped because + // embeds from ignored files can't be used. + // TODO(#42504): Find a better way to avoid errors from ImportDir. We'll + // need to figure this out when we switch to PackagesAndErrors as per the + // TODO above. + var multiplePackageError *build.MultiplePackageError + var noGoError *build.NoGoError + if err != nil { + if errors.As(err, &noGoError) { + return // No source files in this package are built. Skip embeds in ignored files. + } else if !errors.As(err, &multiplePackageError) { // multiplePackgeErrors are okay, but others are not. + base.Fatalf("internal error: failed to find embedded files of %s: %v\n", pkg, err) + } + } + embedPatterns := str.StringList(bp.EmbedPatterns, bp.TestEmbedPatterns, bp.XTestEmbedPatterns) + embeds, err := load.ResolveEmbed(bp.Dir, embedPatterns) + if err != nil { + base.Fatalf("go mod vendor: %v", err) + } + for _, embed := range embeds { + embedDst := filepath.Join(dst, embed) + if copiedFiles[embedDst] { + continue + } + + // Copy the file as is done by copyDir below. + r, err := os.Open(filepath.Join(src, embed)) + if err != nil { + base.Fatalf("go mod vendor: %v", err) + } + if err := os.MkdirAll(filepath.Dir(embedDst), 0777); err != nil { + base.Fatalf("go mod vendor: %v", err) + } + w, err := os.Create(embedDst) + if err != nil { + base.Fatalf("go mod vendor: %v", err) + } + if _, err := io.Copy(w, r); err != nil { + base.Fatalf("go mod vendor: %v", err) + } + r.Close() + if err := w.Close(); err != nil { + base.Fatalf("go mod vendor: %v", err) + } + } +} + +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, copiedFiles map[string]bool) { + for parent := 0; ; parent++ { + if copiedMetadata[metakey{modPath, dst}] { + break + } + copiedMetadata[metakey{modPath, dst}] = true + if parent > 0 { + copyDir(dst, src, matchMetadata, copiedFiles) + } + if modPath == pkg { + break + } + pkg = path.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(dir string, info fs.DirEntry) bool { + name := info.Name() + for _, p := range metaPrefixes { + if strings.HasPrefix(name, p) { + return true + } + } + return false +} + +// matchPotentialSourceFile reports whether info may be relevant to a build operation. +func matchPotentialSourceFile(dir string, info fs.DirEntry) bool { + if strings.HasSuffix(info.Name(), "_test.go") { + return false + } + if strings.HasSuffix(info.Name(), ".go") { + f, err := fsys.Open(filepath.Join(dir, info.Name())) + if err != nil { + base.Fatalf("go mod vendor: %v", err) + } + defer f.Close() + + content, err := imports.ReadImports(f, false, nil) + if err == nil && !imports.ShouldBuild(content, imports.AnyTags()) { + // The file is explicitly tagged "ignore", so it can't affect the build. + // Leave it out. + return false + } + return true + } + + // We don't know anything about this file, so optimistically assume that it is + // needed. + return true +} + +// copyDir copies all regular files satisfying match(info) from src to dst. +func copyDir(dst, src string, match func(dir string, info fs.DirEntry) bool, copiedFiles map[string]bool) { + files, err := os.ReadDir(src) + if err != nil { + base.Fatalf("go mod vendor: %v", err) + } + if err := os.MkdirAll(dst, 0777); err != nil { + base.Fatalf("go mod vendor: %v", err) + } + for _, file := range files { + if file.IsDir() || !file.Type().IsRegular() || !match(src, file) { + continue + } + copiedFiles[file.Name()] = true + r, err := os.Open(filepath.Join(src, file.Name())) + if err != nil { + base.Fatalf("go mod vendor: %v", err) + } + dstPath := filepath.Join(dst, file.Name()) + copiedFiles[dstPath] = true + w, err := os.Create(dstPath) + if err != nil { + base.Fatalf("go mod vendor: %v", err) + } + if _, err := io.Copy(w, r); err != nil { + base.Fatalf("go mod vendor: %v", err) + } + r.Close() + if err := w.Close(); err != nil { + base.Fatalf("go mod vendor: %v", err) + } + } +} diff --git a/src/cmd/go/internal/modcmd/verify.go b/src/cmd/go/internal/modcmd/verify.go new file mode 100644 index 0000000..8321429 --- /dev/null +++ b/src/cmd/go/internal/modcmd/verify.go @@ -0,0 +1,128 @@ +// 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" + "context" + "errors" + "fmt" + "io/fs" + "os" + "runtime" + + "cmd/go/internal/base" + "cmd/go/internal/modfetch" + "cmd/go/internal/modload" + + "golang.org/x/mod/module" + "golang.org/x/mod/sumdb/dirhash" +) + +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. + +See https://golang.org/ref/mod#go-mod-verify for more about 'go mod verify'. + `, + Run: runVerify, +} + +func init() { + base.AddModCommonFlags(&cmdVerify.Flag) +} + +func runVerify(ctx context.Context, 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") + } + modload.ForceUseModules = true + modload.RootMode = modload.NeedRoot + + // Only verify up to GOMAXPROCS zips at once. + type token struct{} + sem := make(chan token, runtime.GOMAXPROCS(0)) + + // Use a slice of result channels, so that the output is deterministic. + mods := modload.LoadAllModules(ctx)[1:] + errsChans := make([]<-chan []error, len(mods)) + + for i, mod := range mods { + sem <- token{} + errsc := make(chan []error, 1) + errsChans[i] = errsc + mod := mod // use a copy to avoid data races + go func() { + errsc <- verifyMod(mod) + <-sem + }() + } + + ok := true + for _, errsc := range errsChans { + errs := <-errsc + for _, err := range errs { + base.Errorf("%s", err) + ok = false + } + } + if ok { + fmt.Printf("all modules verified\n") + } +} + +func verifyMod(mod module.Version) []error { + var errs []error + zip, zipErr := modfetch.CachePath(mod, "zip") + if zipErr == nil { + _, zipErr = os.Stat(zip) + } + dir, dirErr := modfetch.DownloadDir(mod) + data, err := os.ReadFile(zip + "hash") + if err != nil { + if zipErr != nil && errors.Is(zipErr, fs.ErrNotExist) && + dirErr != nil && errors.Is(dirErr, fs.ErrNotExist) { + // Nothing downloaded yet. Nothing to verify. + return nil + } + errs = append(errs, fmt.Errorf("%s %s: missing ziphash: %v", mod.Path, mod.Version, err)) + return errs + } + h := string(bytes.TrimSpace(data)) + + if zipErr != nil && errors.Is(zipErr, fs.ErrNotExist) { + // ok + } else { + hZ, err := dirhash.HashZip(zip, dirhash.DefaultHash) + if err != nil { + errs = append(errs, fmt.Errorf("%s %s: %v", mod.Path, mod.Version, err)) + return errs + } else if hZ != h { + errs = append(errs, fmt.Errorf("%s %s: zip has been modified (%v)", mod.Path, mod.Version, zip)) + } + } + if dirErr != nil && errors.Is(dirErr, fs.ErrNotExist) { + // ok + } else { + hD, err := dirhash.HashDir(dir, mod.Path+"@"+mod.Version, dirhash.DefaultHash) + if err != nil { + + errs = append(errs, fmt.Errorf("%s %s: %v", mod.Path, mod.Version, err)) + return errs + } + if hD != h { + errs = append(errs, fmt.Errorf("%s %s: dir has been modified (%v)", mod.Path, mod.Version, dir)) + } + } + return errs +} diff --git a/src/cmd/go/internal/modcmd/why.go b/src/cmd/go/internal/modcmd/why.go new file mode 100644 index 0000000..a5f3e8a --- /dev/null +++ b/src/cmd/go/internal/modcmd/why.go @@ -0,0 +1,139 @@ +// 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 ( + "context" + "fmt" + "strings" + + "cmd/go/internal/base" + "cmd/go/internal/imports" + "cmd/go/internal/modload" + + "golang.org/x/mod/module" +) + +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) + $ + +See https://golang.org/ref/mod#go-mod-why for more about 'go mod why'. + `, +} + +var ( + whyM = cmdWhy.Flag.Bool("m", false, "") + whyVendor = cmdWhy.Flag.Bool("vendor", false, "") +) + +func init() { + cmdWhy.Run = runWhy // break init cycle + base.AddModCommonFlags(&cmdWhy.Flag) +} + +func runWhy(ctx context.Context, cmd *base.Command, args []string) { + modload.ForceUseModules = true + modload.RootMode = modload.NeedRoot + + loadOpts := modload.PackageOpts{ + Tags: imports.AnyTags(), + LoadTests: !*whyVendor, + SilenceErrors: true, + UseVendorAll: *whyVendor, + } + + if *whyM { + listU := false + listVersions := false + listRetractions := false + for _, arg := range args { + if strings.Contains(arg, "@") { + base.Fatalf("go mod why: module query not allowed") + } + } + mods := modload.ListModules(ctx, args, listU, listVersions, listRetractions) + byModule := make(map[module.Version][]string) + _, pkgs := modload.LoadPackages(ctx, loadOpts, "all") + for _, path := range pkgs { + 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 { + // Resolve to packages. + matches, _ := modload.LoadPackages(ctx, loadOpts, args...) + + modload.LoadPackages(ctx, loadOpts, "all") // 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/src/cmd/go/internal/modconv/convert.go b/src/cmd/go/internal/modconv/convert.go new file mode 100644 index 0000000..5d4165c --- /dev/null +++ b/src/cmd/go/internal/modconv/convert.go @@ -0,0 +1,108 @@ +// 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" + "runtime" + "sort" + "strings" + + "cmd/go/internal/base" + "cmd/go/internal/modfetch" + + "golang.org/x/mod/modfile" + "golang.org/x/mod/module" + "golang.org/x/mod/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. + versions := make([]module.Version, len(mf.Require)) + replace := make(map[string]*modfile.Replace) + + for _, r := range mf.Replace { + replace[r.New.Path] = r + replace[r.Old.Path] = r + } + + type token struct{} + sem := make(chan token, runtime.GOMAXPROCS(0)) + for i, r := range mf.Require { + m := r.Mod + if m.Path == "" { + continue + } + if re, ok := replace[m.Path]; ok { + m = re.New + } + sem <- token{} + go func(i int, m module.Version) { + defer func() { <-sem }() + repo, info, err := modfetch.ImportRepoRev(m.Path, m.Version) + if err != nil { + fmt.Fprintf(os.Stderr, "go: converting %s: stat %s@%s: %v\n", base.ShortPath(file), m.Path, m.Version, err) + return + } + + path := repo.ModulePath() + versions[i].Path = path + versions[i].Version = info.Version + }(i, m) + } + // Fill semaphore channel to wait for all tasks to finish. + for n := cap(sem); n > 0; n-- { + sem <- token{} + } + + need := map[string]string{} + for _, v := range versions { + if v.Path == "" { + continue + } + // Don't use semver.Max here; need to preserve +incompatible suffix. + if needv, ok := need[v.Path]; !ok || semver.Compare(needv, v.Version) < 0 { + need[v.Path] = v.Version + } + } + paths := make([]string, 0, len(need)) + for path := range need { + paths = append(paths, path) + } + sort.Strings(paths) + for _, path := range paths { + if re, ok := replace[path]; ok { + err := f.AddReplace(re.Old.Path, re.Old.Version, path, need[path]) + if err != nil { + return fmt.Errorf("add replace: %v", err) + } + } + f.AddNewRequire(path, need[path], false) + } + + f.Cleanup() + return nil +} diff --git a/src/cmd/go/internal/modconv/convert_test.go b/src/cmd/go/internal/modconv/convert_test.go new file mode 100644 index 0000000..66b9ff4 --- /dev/null +++ b/src/cmd/go/internal/modconv/convert_test.go @@ -0,0 +1,189 @@ +// 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" + "context" + "fmt" + "internal/testenv" + "log" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + + "cmd/go/internal/cfg" + "cmd/go/internal/modfetch" + + "golang.org/x/mod/modfile" + "golang.org/x/mod/module" +) + +func TestMain(m *testing.M) { + os.Exit(testMain(m)) +} + +func testMain(m *testing.M) int { + cfg.GOPROXY = "direct" + + if _, err := exec.LookPath("git"); err != nil { + fmt.Fprintln(os.Stderr, "skipping because git binary not found") + fmt.Println("PASS") + return 0 + } + + dir, err := os.MkdirTemp("", "modconv-test-") + if err != nil { + log.Fatal(err) + } + defer os.RemoveAll(dir) + cfg.GOMODCACHE = filepath.Join(dir, "pkg/mod") + + 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 v1.0.3-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 v1.4.2-0.20150131031259-6086d7927ec3 + github.com/docker/docker v1.4.2-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.7-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-20180217031846-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.3.1-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 + )`, + }, + } + + ctx := context.Background() + + for _, tt := range tests { + t.Run(strings.ReplaceAll(tt.path, "/", "_")+"_"+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(ctx, 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 := os.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/src/cmd/go/internal/modconv/dep.go b/src/cmd/go/internal/modconv/dep.go new file mode 100644 index 0000000..2e673c3 --- /dev/null +++ b/src/cmd/go/internal/modconv/dep.go @@ -0,0 +1,132 @@ +// 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" + "internal/lazyregexp" + "net/url" + "path" + "strconv" + "strings" + + "golang.org/x/mod/modfile" + "golang.org/x/mod/module" + "golang.org/x/mod/semver" +) + +func ParseGopkgLock(file string, data []byte) (*modfile.File, error) { + type pkg struct { + Path string + Version string + Source string + } + mf := new(modfile.File) + var list []pkg + var r *pkg + 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, pkg{}) + 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 "source": + r.Source = 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: module.Version{Path: r.Path, Version: r.Version}}) + + if r.Source != "" { + // Convert "source" to import path, such as + // git@test.com:x/y.git and https://test.com/x/y.git. + // We get "test.com/x/y" at last. + source, err := decodeSource(r.Source) + if err != nil { + return nil, err + } + old := module.Version{Path: r.Path, Version: r.Version} + new := module.Version{Path: source, Version: r.Version} + mf.Replace = append(mf.Replace, &modfile.Replace{Old: old, New: new}) + } + } + return mf, nil +} + +var scpSyntaxReg = lazyregexp.New(`^([a-zA-Z0-9_]+)@([a-zA-Z0-9._-]+):(.*)$`) + +func decodeSource(source string) (string, error) { + var u *url.URL + var p string + if m := scpSyntaxReg.FindStringSubmatch(source); m != nil { + // Match SCP-like syntax and convert it to a URL. + // Eg, "git@github.com:user/repo" becomes + // "ssh://git@github.com/user/repo". + u = &url.URL{ + Scheme: "ssh", + User: url.User(m[1]), + Host: m[2], + Path: "/" + m[3], + } + } else { + var err error + u, err = url.Parse(source) + if err != nil { + return "", fmt.Errorf("%q is not a valid URI", source) + } + } + + // If no scheme was passed, then the entire path will have been put into + // u.Path. Either way, construct the normalized path correctly. + if u.Host == "" { + p = source + } else { + p = path.Join(u.Host, u.Path) + } + p = strings.TrimSuffix(p, ".git") + p = strings.TrimSuffix(p, ".hg") + return p, nil +} diff --git a/src/cmd/go/internal/modconv/glide.go b/src/cmd/go/internal/modconv/glide.go new file mode 100644 index 0000000..d1de3f7 --- /dev/null +++ b/src/cmd/go/internal/modconv/glide.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. + +package modconv + +import ( + "strings" + + "golang.org/x/mod/modfile" + "golang.org/x/mod/module" +) + +func ParseGlideLock(file string, data []byte) (*modfile.File, error) { + mf := new(modfile.File) + imports := false + name := "" + for _, line := range strings.Split(string(data), "\n") { + 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/src/cmd/go/internal/modconv/glock.go b/src/cmd/go/internal/modconv/glock.go new file mode 100644 index 0000000..b8dc204 --- /dev/null +++ b/src/cmd/go/internal/modconv/glock.go @@ -0,0 +1,23 @@ +// 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" + + "golang.org/x/mod/modfile" + "golang.org/x/mod/module" +) + +func ParseGLOCKFILE(file string, data []byte) (*modfile.File, error) { + mf := new(modfile.File) + for _, line := range strings.Split(string(data), "\n") { + 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/src/cmd/go/internal/modconv/godeps.go b/src/cmd/go/internal/modconv/godeps.go new file mode 100644 index 0000000..09c0fa3 --- /dev/null +++ b/src/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" + + "golang.org/x/mod/modfile" + "golang.org/x/mod/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/src/cmd/go/internal/modconv/modconv.go b/src/cmd/go/internal/modconv/modconv.go new file mode 100644 index 0000000..dc06072 --- /dev/null +++ b/src/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 "golang.org/x/mod/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/src/cmd/go/internal/modconv/modconv_test.go b/src/cmd/go/internal/modconv/modconv_test.go new file mode 100644 index 0000000..750525d --- /dev/null +++ b/src/cmd/go/internal/modconv/modconv_test.go @@ -0,0 +1,69 @@ +// 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" + "os" + "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 := os.ReadFile(test) + if err != nil { + t.Fatal(err) + } + out, err := Converters[extMap[ext]](test, data) + if err != nil { + t.Fatal(err) + } + want, err := os.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) + } + for _, r := range out.Replace { + fmt.Fprintf(&buf, "replace: %s %s %s %s\n", r.Old.Path, r.Old.Version, r.New.Path, r.New.Version) + } + if !bytes.Equal(buf.Bytes(), want) { + t.Errorf("have:\n%s\nwant:\n%s", buf.Bytes(), want) + } + }) + } +} diff --git a/src/cmd/go/internal/modconv/testdata/cockroach.glock b/src/cmd/go/internal/modconv/testdata/cockroach.glock new file mode 100644 index 0000000..221c8ac --- /dev/null +++ b/src/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/src/cmd/go/internal/modconv/testdata/cockroach.out b/src/cmd/go/internal/modconv/testdata/cockroach.out new file mode 100644 index 0000000..30cdbb7 --- /dev/null +++ b/src/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/src/cmd/go/internal/modconv/testdata/dockermachine.godeps b/src/cmd/go/internal/modconv/testdata/dockermachine.godeps new file mode 100644 index 0000000..a551002 --- /dev/null +++ b/src/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/src/cmd/go/internal/modconv/testdata/dockermachine.out b/src/cmd/go/internal/modconv/testdata/dockermachine.out new file mode 100644 index 0000000..0b39cea --- /dev/null +++ b/src/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/src/cmd/go/internal/modconv/testdata/dockerman.glide b/src/cmd/go/internal/modconv/testdata/dockerman.glide new file mode 100644 index 0000000..5ec765a --- /dev/null +++ b/src/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/src/cmd/go/internal/modconv/testdata/dockerman.out b/src/cmd/go/internal/modconv/testdata/dockerman.out new file mode 100644 index 0000000..5e6370b --- /dev/null +++ b/src/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/src/cmd/go/internal/modconv/testdata/govmomi.out b/src/cmd/go/internal/modconv/testdata/govmomi.out new file mode 100644 index 0000000..188c458 --- /dev/null +++ b/src/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/src/cmd/go/internal/modconv/testdata/govmomi.vmanifest b/src/cmd/go/internal/modconv/testdata/govmomi.vmanifest new file mode 100644 index 0000000..b89e4ab --- /dev/null +++ b/src/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/src/cmd/go/internal/modconv/testdata/juju.out b/src/cmd/go/internal/modconv/testdata/juju.out new file mode 100644 index 0000000..c2430b1 --- /dev/null +++ b/src/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/src/cmd/go/internal/modconv/testdata/juju.tsv b/src/cmd/go/internal/modconv/testdata/juju.tsv new file mode 100644 index 0000000..0bddcef --- /dev/null +++ b/src/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/src/cmd/go/internal/modconv/testdata/moby.out b/src/cmd/go/internal/modconv/testdata/moby.out new file mode 100644 index 0000000..2cb2e05 --- /dev/null +++ b/src/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/src/cmd/go/internal/modconv/testdata/moby.vconf b/src/cmd/go/internal/modconv/testdata/moby.vconf new file mode 100644 index 0000000..53b90d1 --- /dev/null +++ b/src/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/src/cmd/go/internal/modconv/testdata/panicparse.out b/src/cmd/go/internal/modconv/testdata/panicparse.out new file mode 100644 index 0000000..8830033 --- /dev/null +++ b/src/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/src/cmd/go/internal/modconv/testdata/panicparse.vyml b/src/cmd/go/internal/modconv/testdata/panicparse.vyml new file mode 100644 index 0000000..ff3d43f --- /dev/null +++ b/src/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/src/cmd/go/internal/modconv/testdata/prometheus.out b/src/cmd/go/internal/modconv/testdata/prometheus.out new file mode 100644 index 0000000..d11b8ec --- /dev/null +++ b/src/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/src/cmd/go/internal/modconv/testdata/prometheus.vjson b/src/cmd/go/internal/modconv/testdata/prometheus.vjson new file mode 100644 index 0000000..648bec4 --- /dev/null +++ b/src/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/src/cmd/go/internal/modconv/testdata/traefik.dep b/src/cmd/go/internal/modconv/testdata/traefik.dep new file mode 100644 index 0000000..8510f0f --- /dev/null +++ b/src/cmd/go/internal/modconv/testdata/traefik.dep @@ -0,0 +1,79 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + +[[projects]] + name = "github.com/Nvveen/Gotty" + packages = ["."] + revision = "a8b993ba6abdb0e0c12b0125c603323a71c7790c" + source = "github.com/ijc25/Gotty" + +[[projects]] + branch = "master" + name = "github.com/OpenDNS/vegadns2client" + packages = ["."] + revision = "a3fa4a771d87bda2514a90a157e1fed1b6897d2e" + +[[projects]] + name = "github.com/PuerkitoBio/purell" + packages = ["."] + revision = "8a290539e2e8629dbc4e6bad948158f790ec31f4" + version = "v1.0.0" + +[[projects]] + name = "github.com/PuerkitoBio/urlesc" + packages = ["."] + revision = "5bd2802263f21d8788851d5305584c82a5c75d7e" + +[[projects]] + name = "github.com/Shopify/sarama" + packages = ["."] + revision = "70f6a705d4a17af059acbc6946fb2bd30762acd7" + +[[projects]] + name = "github.com/VividCortex/gohistogram" + packages = ["."] + revision = "51564d9861991fb0ad0f531c99ef602d0f9866e6" + version = "v1.0.0" + +[[projects]] + branch = "containous-fork" + name = "github.com/abbot/go-http-auth" + packages = ["."] + revision = "65b0cdae8d7fe5c05c7430e055938ef6d24a66c9" + source = "github.com/containous/go-http-auth" + +[[projects]] + branch = "master" + name = "github.com/abronan/valkeyrie" + packages = [ + ".", + "store", + "store/boltdb", + "store/consul", + "store/etcd/v2", + "store/etcd/v3", + "store/zookeeper" + ] + revision = "063d875e3c5fd734fa2aa12fac83829f62acfc70" + +[[projects]] + branch = "master" + name = "github.com/mesosphere/mesos-dns" + packages = [ + "detect", + "errorutil", + "logging", + "models", + "records", + "records/labels", + "records/state", + "util" + ] + revision = "b47dc4c19f215e98da687b15b4c64e70f629bea5" + source = "git@github.com:containous/mesos-dns.git" + + [[projects]] + name = "gopkg.in/fsnotify.v1" + packages = ["."] + revision = "629574ca2a5df945712d3079857300b5e4da0236" + source = "github.com/fsnotify/fsnotify" + version = "v1.4.2" \ No newline at end of file diff --git a/src/cmd/go/internal/modconv/testdata/traefik.out b/src/cmd/go/internal/modconv/testdata/traefik.out new file mode 100644 index 0000000..5054295 --- /dev/null +++ b/src/cmd/go/internal/modconv/testdata/traefik.out @@ -0,0 +1,14 @@ +github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c +github.com/OpenDNS/vegadns2client a3fa4a771d87bda2514a90a157e1fed1b6897d2e +github.com/PuerkitoBio/purell v1.0.0 +github.com/PuerkitoBio/urlesc 5bd2802263f21d8788851d5305584c82a5c75d7e +github.com/Shopify/sarama 70f6a705d4a17af059acbc6946fb2bd30762acd7 +github.com/VividCortex/gohistogram v1.0.0 +github.com/abbot/go-http-auth 65b0cdae8d7fe5c05c7430e055938ef6d24a66c9 +github.com/abronan/valkeyrie 063d875e3c5fd734fa2aa12fac83829f62acfc70 +github.com/mesosphere/mesos-dns b47dc4c19f215e98da687b15b4c64e70f629bea5 +gopkg.in/fsnotify.v1 v1.4.2 +replace: github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c github.com/ijc25/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c +replace: github.com/abbot/go-http-auth 65b0cdae8d7fe5c05c7430e055938ef6d24a66c9 github.com/containous/go-http-auth 65b0cdae8d7fe5c05c7430e055938ef6d24a66c9 +replace: github.com/mesosphere/mesos-dns b47dc4c19f215e98da687b15b4c64e70f629bea5 github.com/containous/mesos-dns b47dc4c19f215e98da687b15b4c64e70f629bea5 +replace: gopkg.in/fsnotify.v1 v1.4.2 github.com/fsnotify/fsnotify v1.4.2 diff --git a/src/cmd/go/internal/modconv/testdata/upspin.dep b/src/cmd/go/internal/modconv/testdata/upspin.dep new file mode 100644 index 0000000..be77bcb --- /dev/null +++ b/src/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/src/cmd/go/internal/modconv/testdata/upspin.out b/src/cmd/go/internal/modconv/testdata/upspin.out new file mode 100644 index 0000000..00597db --- /dev/null +++ b/src/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/src/cmd/go/internal/modconv/tsv.go b/src/cmd/go/internal/modconv/tsv.go new file mode 100644 index 0000000..4649579 --- /dev/null +++ b/src/cmd/go/internal/modconv/tsv.go @@ -0,0 +1,23 @@ +// 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" + + "golang.org/x/mod/modfile" + "golang.org/x/mod/module" +) + +func ParseDependenciesTSV(file string, data []byte) (*modfile.File, error) { + mf := new(modfile.File) + for _, line := range strings.Split(string(data), "\n") { + 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/src/cmd/go/internal/modconv/vconf.go b/src/cmd/go/internal/modconv/vconf.go new file mode 100644 index 0000000..9bad2ba --- /dev/null +++ b/src/cmd/go/internal/modconv/vconf.go @@ -0,0 +1,26 @@ +// 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" + + "golang.org/x/mod/modfile" + "golang.org/x/mod/module" +) + +func ParseVendorConf(file string, data []byte) (*modfile.File, error) { + mf := new(modfile.File) + for _, line := range strings.Split(string(data), "\n") { + 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/src/cmd/go/internal/modconv/vjson.go b/src/cmd/go/internal/modconv/vjson.go new file mode 100644 index 0000000..1bd025c --- /dev/null +++ b/src/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" + + "golang.org/x/mod/modfile" + "golang.org/x/mod/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/src/cmd/go/internal/modconv/vmanifest.go b/src/cmd/go/internal/modconv/vmanifest.go new file mode 100644 index 0000000..bcf0008 --- /dev/null +++ b/src/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" + + "golang.org/x/mod/modfile" + "golang.org/x/mod/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/src/cmd/go/internal/modconv/vyml.go b/src/cmd/go/internal/modconv/vyml.go new file mode 100644 index 0000000..cfa4194 --- /dev/null +++ b/src/cmd/go/internal/modconv/vyml.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. + +package modconv + +import ( + "strings" + + "golang.org/x/mod/modfile" + "golang.org/x/mod/module" +) + +func ParseVendorYML(file string, data []byte) (*modfile.File, error) { + mf := new(modfile.File) + vendors := false + path := "" + for _, line := range strings.Split(string(data), "\n") { + 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/src/cmd/go/internal/modfetch/bootstrap.go b/src/cmd/go/internal/modfetch/bootstrap.go new file mode 100644 index 0000000..e4020b0 --- /dev/null +++ b/src/cmd/go/internal/modfetch/bootstrap.go @@ -0,0 +1,17 @@ +// Copyright 2019 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 "golang.org/x/mod/module" + +func useSumDB(mod module.Version) bool { + return false +} + +func lookupSumDB(mod module.Version) (string, []string, error) { + panic("bootstrap") +} diff --git a/src/cmd/go/internal/modfetch/cache.go b/src/cmd/go/internal/modfetch/cache.go new file mode 100644 index 0000000..07e046c --- /dev/null +++ b/src/cmd/go/internal/modfetch/cache.go @@ -0,0 +1,652 @@ +// 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" + "errors" + "fmt" + "io" + "io/fs" + "os" + "path/filepath" + "strings" + "sync" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/lockedfile" + "cmd/go/internal/modfetch/codehost" + "cmd/go/internal/par" + "cmd/go/internal/renameio" + + "golang.org/x/mod/module" + "golang.org/x/mod/semver" +) + +func cacheDir(path string) (string, error) { + if cfg.GOMODCACHE == "" { + // modload.Init exits if GOPATH[0] is empty, and cfg.GOMODCACHE + // is set to GOPATH[0]/pkg/mod if GOMODCACHE is empty, so this should never happen. + return "", fmt.Errorf("internal error: cfg.GOMODCACHE not set") + } + enc, err := module.EscapePath(path) + if err != nil { + return "", err + } + return filepath.Join(cfg.GOMODCACHE, "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.EscapeVersion(m.Version) + if err != nil { + return "", err + } + return filepath.Join(dir, encVer+"."+suffix), nil +} + +// DownloadDir returns the directory to which m should have been downloaded. +// An error will be returned if the module path or version cannot be escaped. +// An error satisfying errors.Is(err, fs.ErrNotExist) will be returned +// along with the directory if the directory does not exist or if the directory +// is not completely populated. +func DownloadDir(m module.Version) (string, error) { + if cfg.GOMODCACHE == "" { + // modload.Init exits if GOPATH[0] is empty, and cfg.GOMODCACHE + // is set to GOPATH[0]/pkg/mod if GOMODCACHE is empty, so this should never happen. + return "", fmt.Errorf("internal error: cfg.GOMODCACHE not set") + } + enc, err := module.EscapePath(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.EscapeVersion(m.Version) + if err != nil { + return "", err + } + + // Check whether the directory itself exists. + dir := filepath.Join(cfg.GOMODCACHE, enc+"@"+encVer) + if fi, err := os.Stat(dir); os.IsNotExist(err) { + return dir, err + } else if err != nil { + return dir, &DownloadDirPartialError{dir, err} + } else if !fi.IsDir() { + return dir, &DownloadDirPartialError{dir, errors.New("not a directory")} + } + + // Check if a .partial file exists. This is created at the beginning of + // a download and removed after the zip is extracted. + partialPath, err := CachePath(m, "partial") + if err != nil { + return dir, err + } + if _, err := os.Stat(partialPath); err == nil { + return dir, &DownloadDirPartialError{dir, errors.New("not completely extracted")} + } else if !os.IsNotExist(err) { + return dir, err + } + + // Check if a .ziphash file exists. It should be created before the + // zip is extracted, but if it was deleted (by another program?), we need + // to re-calculate it. + ziphashPath, err := CachePath(m, "ziphash") + if err != nil { + return dir, err + } + if _, err := os.Stat(ziphashPath); os.IsNotExist(err) { + return dir, &DownloadDirPartialError{dir, errors.New("ziphash file is missing")} + } else if err != nil { + return dir, err + } + return dir, nil +} + +// DownloadDirPartialError is returned by DownloadDir if a module directory +// exists but was not completely populated. +// +// DownloadDirPartialError is equivalent to fs.ErrNotExist. +type DownloadDirPartialError struct { + Dir string + Err error +} + +func (e *DownloadDirPartialError) Error() string { return fmt.Sprintf("%s: %v", e.Dir, e.Err) } +func (e *DownloadDirPartialError) Is(err error) bool { return err == fs.ErrNotExist } + +// lockVersion locks a file within the module cache that guards the downloading +// and extraction of the zipfile for the given module version. +func lockVersion(mod module.Version) (unlock func(), err error) { + path, err := CachePath(mod, "lock") + if err != nil { + return nil, err + } + if err := os.MkdirAll(filepath.Dir(path), 0777); err != nil { + return nil, err + } + return lockedfile.MutexAt(path).Lock() +} + +// SideLock locks a file within the module cache that that previously guarded +// edits to files outside the cache, such as go.sum and go.mod files in the +// user's working directory. +// If err is nil, the caller MUST eventually call the unlock function. +func SideLock() (unlock func(), err error) { + if cfg.GOMODCACHE == "" { + // modload.Init exits if GOPATH[0] is empty, and cfg.GOMODCACHE + // is set to GOPATH[0]/pkg/mod if GOMODCACHE is empty, so this should never happen. + base.Fatalf("go: internal error: cfg.GOMODCACHE not set") + } + + path := filepath.Join(cfg.GOMODCACHE, "cache", "lock") + if err := os.MkdirAll(filepath.Dir(path), 0777); err != nil { + return nil, fmt.Errorf("failed to create cache directory: %w", err) + } + + return lockedfile.MutexAt(path).Lock() +} + +// 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 + + once sync.Once + initRepo func() (Repo, error) + r Repo +} + +func newCachingRepo(path string, initRepo func() (Repo, error)) *cachingRepo { + return &cachingRepo{ + path: path, + initRepo: initRepo, + } +} + +func (r *cachingRepo) repo() Repo { + r.once.Do(func() { + var err error + r.r, err = r.initRepo() + if err != nil { + r.r = errRepo{r.path, err} + } + }) + return r.r +} + +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.repo().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} + } + + info, err = r.repo().Stat(rev) + if err == nil { + // 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 { + file, _ = CachePath(module.Version{Path: r.path, Version: info.Version}, "info") + r.cache.Do("stat:"+info.Version, func() interface{} { + return cachedInfo{info, err} + }) + } + + if err := writeDiskStat(file, info); err != nil { + fmt.Fprintf(os.Stderr, "go: writing stat cache: %v\n", 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{} { + info, err := r.repo().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(version string) ([]byte, error) { + type cached struct { + text []byte + err error + } + c := r.cache.Do("gomod:"+version, func() interface{} { + file, text, err := readDiskGoMod(r.path, version) + if err == nil { + // Note: readDiskGoMod already called checkGoMod. + return cached{text, nil} + } + + text, err = r.repo().GoMod(version) + if err == nil { + if err := checkGoMod(r.path, version, text); err != nil { + return cached{text, err} + } + 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(dst io.Writer, version string) error { + return r.repo().Zip(dst, version) +} + +// InfoFile is like Lookup(path).Stat(version) 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 file, _, err := readDiskStat(path, version); err == nil { + return file, nil + } + + err := TryProxies(func(proxy string) error { + _, err := Lookup(proxy, path).Stat(version) + return err + }) + if 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) { + if _, info, err := readDiskStat(path, rev); err == nil { + rev = info.Version + } else { + err := TryProxies(func(proxy string) error { + info, err := Lookup(proxy, path).Stat(rev) + if err == nil { + rev = info.Version + } + return err + }) + if err != nil { + return nil, err + } + } + } + + _, data, err := readDiskGoMod(path, rev) + if err == nil { + return data, nil + } + + err = TryProxies(func(proxy string) (err error) { + data, err = Lookup(proxy, path).GoMod(rev) + return err + }) + return data, err +} + +// 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 the cache already contains a pseudo-version with the given hash, we + // would previously return that pseudo-version without checking upstream. + // However, that produced an unfortunate side-effect: if the author added a + // tag to the repository, 'go get' would not pick up the effect of that new + // tag on the existing commits, and 'go' commands that referred to those + // commits would use the previous name instead of the new one. + // + // That's especially problematic if the original pseudo-version starts with + // v0.0.0-, as was the case for all pseudo-versions during vgo development, + // since a v0.0.0- pseudo-version has lower precedence than pretty much any + // tagged version. + // + // In practice, we're only looking up by hash during initial conversion of a + // legacy config and during an explicit 'go get', and a little extra latency + // for those operations seems worth the benefit of picking up more accurate + // versions. + // + // Fall back to this resolution scheme only if the GOPROXY setting prohibits + // us from resolving upstream tags. + if cfg.GOPROXY == "off" { + 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 cfg.GOMODCACHE == "" { + // 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 + } + + // A given commit hash may map to more than one pseudo-version, + // depending on which tags are present on the repository. + // Take the highest such version. + var maxVersion string + suffix := "-" + rev + ".info" + err = errNotCached + for _, name := range names { + if strings.HasSuffix(name, suffix) { + v := strings.TrimSuffix(name, ".info") + if IsPseudoVersion(v) && semver.Compare(v, maxVersion) > 0 { + maxVersion = v + file, info, err = readDiskStat(path, strings.TrimSuffix(name, ".info")) + } + } + } + return file, info, err +} + +// 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 go.mod file 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 { + if err := checkGoMod(path, rev, data); err != nil { + return "", nil, err + } + } + + 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 = renameio.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 + } + + if err := renameio.WriteFile(file, data, 0666); 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") + } + + listFile := filepath.Join(dir, "list") + + // We use a separate lockfile here instead of locking listFile itself because + // we want to use Rename to write the file atomically. The list may be read by + // a GOPROXY HTTP server, and if we crash midway through a rewrite (or if the + // HTTP server ignores our locking and serves the file midway through a + // rewrite) it's better to serve a stale list than a truncated one. + unlock, err := lockedfile.MutexAt(listFile + ".lock").Lock() + if err != nil { + base.Fatalf("go: can't lock version list lockfile: %v", err) + } + defer unlock() + + infos, err := os.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") + } + old, _ := renameio.ReadFile(listFile) + if bytes.Equal(buf.Bytes(), old) { + return + } + + if err := renameio.WriteFile(listFile, buf.Bytes(), 0666); err != nil { + base.Fatalf("go: failed to write version list: %v", err) + } +} diff --git a/src/cmd/go/internal/modfetch/cache_test.go b/src/cmd/go/internal/modfetch/cache_test.go new file mode 100644 index 0000000..722c984 --- /dev/null +++ b/src/cmd/go/internal/modfetch/cache_test.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 modfetch + +import ( + "os" + "path/filepath" + "testing" +) + +func TestWriteDiskCache(t *testing.T) { + tmpdir, err := os.MkdirTemp("", "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/src/cmd/go/internal/modfetch/codehost/codehost.go b/src/cmd/go/internal/modfetch/codehost/codehost.go new file mode 100644 index 0000000..378fbae --- /dev/null +++ b/src/cmd/go/internal/modfetch/codehost/codehost.go @@ -0,0 +1,315 @@ +// 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" + exec "internal/execabs" + "io" + "io/fs" + "os" + "path/filepath" + "strings" + "sync" + "time" + + "cmd/go/internal/cfg" + "cmd/go/internal/lockedfile" + "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. + // 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, err error) + + // RecentTag returns the most recent tag on rev or one of its predecessors + // with the given prefix. allowed may be used to filter out unwanted versions. + RecentTag(rev, prefix string, allowed func(string) bool) (tag string, err error) + + // DescendsFrom reports whether rev or any of its ancestors has the given tag. + // + // DescendsFrom must return true for any tag returned by RecentTag for the + // same revision. + DescendsFrom(rev, tag string) (bool, 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 +} + +// UnknownRevisionError is an error equivalent to fs.ErrNotExist, but for a +// revision rather than a file. +type UnknownRevisionError struct { + Rev string +} + +func (e *UnknownRevisionError) Error() string { + return "unknown revision " + e.Rev +} +func (UnknownRevisionError) Is(err error) bool { + return err == fs.ErrNotExist +} + +// ErrNoCommits is an error equivalent to fs.ErrNotExist indicating that a given +// repository or module contains no commits. +var ErrNoCommits error = noCommitsError{} + +type noCommitsError struct{} + +func (noCommitsError) Error() string { + return "no commits" +} +func (noCommitsError) Is(err error) bool { + return err == fs.ErrNotExist +} + +// 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 +} + +// WorkDir returns the name of the cached work directory to use for the +// given repository type and name. +func WorkDir(typ, name string) (dir, lockfile string, err error) { + if cfg.GOMODCACHE == "" { + return "", "", fmt.Errorf("neither GOPATH nor GOMODCACHE are 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(cfg.GOMODCACHE, "cache/vcs", fmt.Sprintf("%x", sha256.Sum256([]byte(key)))) + + if cfg.BuildX { + fmt.Fprintf(os.Stderr, "mkdir -p %s # %s %s\n", filepath.Dir(dir), typ, name) + } + if err := os.MkdirAll(filepath.Dir(dir), 0777); err != nil { + return "", "", err + } + + lockfile = dir + ".lock" + if cfg.BuildX { + fmt.Fprintf(os.Stderr, "# lock %s", lockfile) + } + + unlock, err := lockedfile.MutexAt(lockfile).Lock() + if err != nil { + return "", "", fmt.Errorf("codehost.WorkDir: can't find or create lock file: %v", err) + } + defer unlock() + + data, err := os.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, lockfile, 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 := os.WriteFile(dir+".info", []byte(key), 0666); err != nil { + os.RemoveAll(dir) + return "", "", err + } + return dir, lockfile, nil +} + +type RunError struct { + Cmd string + Err error + Stderr []byte + HelpText string +} + +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.ReplaceAll(string(stderr), "\n", "\n\t") + } + if len(e.HelpText) > 0 { + text += "\n" + e.HelpText + } + 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 os.Getenv("TESTGOVCS") == "panic" { + panic(fmt.Sprintf("use of vcs: %v", cmd)) + } + 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/src/cmd/go/internal/modfetch/codehost/git.go b/src/cmd/go/internal/modfetch/codehost/git.go new file mode 100644 index 0000000..72005e2 --- /dev/null +++ b/src/cmd/go/internal/modfetch/codehost/git.go @@ -0,0 +1,875 @@ +// 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" + "errors" + "fmt" + exec "internal/execabs" + "io" + "io/fs" + "net/url" + "os" + "path/filepath" + "sort" + "strconv" + "strings" + "sync" + "time" + + "cmd/go/internal/lockedfile" + "cmd/go/internal/par" + "cmd/go/internal/web" + + "golang.org/x/mod/semver" +) + +// 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) +} + +// A notExistError wraps another error to retain its original text +// but makes it opaquely equivalent to fs.ErrNotExist. +type notExistError struct { + err error +} + +func (e notExistError) Error() string { return e.err.Error() } +func (notExistError) Is(err error) bool { return err == fs.ErrNotExist } + +const gitWorkDirType = "git3" + +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. + var err error + r.dir, r.mu.Path, err = WorkDir(gitWorkDirType, r.remote) + if err != nil { + return nil, err + } + + unlock, err := r.mu.Lock() + if err != nil { + return nil, err + } + defer unlock() + + if _, err := os.Stat(filepath.Join(r.dir, "objects")); err != nil { + if _, err := Run(r.dir, "git", "init", "--bare"); err != nil { + os.RemoveAll(r.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(r.dir, "git", "remote", "add", "origin", "--", r.remote); err != nil { + os.RemoveAll(r.dir) + return nil, err + } + } + r.remoteURL = r.remote + 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 + r.mu.Path = r.dir + ".lock" + } + return r, nil +} + +type gitRepo struct { + remote, remoteURL string + local bool + dir string + + mu lockedfile.Mutex // protects fetchLevel and git repo state + + fetchLevel int + + statCache par.Cache + + refsOnce sync.Once + // refs maps branch and tag refs (e.g., "HEAD", "refs/heads/master") + // to commits (e.g., "37ffd2e798afde829a34e8955b716ab730b2a6d6") + 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, gitErr := Run(r.dir, "git", "ls-remote", "-q", r.remote) + if gitErr != nil { + if rerr, ok := gitErr.(*RunError); ok { + if bytes.Contains(rerr.Stderr, []byte("fatal: could not read Username")) { + rerr.HelpText = "Confirm the import path was entered correctly.\nIf this is a private repository, see https://golang.org/doc/faq#git_https for additional information." + } + } + + // If the remote URL doesn't exist at all, ideally we should treat the whole + // repository as nonexistent by wrapping the error in a notExistError. + // For HTTP and HTTPS, that's easy to detect: we'll try to fetch the URL + // ourselves and see what code it serves. + if u, err := url.Parse(r.remoteURL); err == nil && (u.Scheme == "http" || u.Scheme == "https") { + if _, err := web.GetBytes(u); errors.Is(err, fs.ErrNotExist) { + gitErr = notExistError{gitErr} + } + } + + r.refsErr = gitErr + 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, ErrNoCommits + } + 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 +} + +// 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, &UnknownRevisionError{Rev: rev} + } + + // Protect r.fetchLevel and the "fetch more and more" sequence. + unlock, err := r.mu.Lock() + if err != nil { + return nil, err + } + defer 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 and its ref, fetch it. + // We do NOT fetch arbitrary hashes (when we don't know the ref) + // because we want to avoid ever importing a commit that isn't + // reachable from refs/tags/* or refs/heads/* or HEAD. + // Both Gerrit and GitHub expose every CL/PR as a named ref, + // and we don't want those commits masquerading as being real + // pseudo-versions in the main repo. + if r.fetchLevel <= fetchSome && ref != "" && 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 err := r.fetchRefsLocked(); err != nil { + return nil, err + } + + return r.statLocal(rev, rev) +} + +// fetchRefsLocked fetches all heads and tags from the origin, along with the +// ancestors of those commits. +// +// We only fetch heads and tags, not arbitrary other commits: we don't want to +// pull in off-branch commits (such as rejected GitHub pull requests) that the +// server may be willing to provide. (See the comments within the stat method +// for more detail.) +// +// fetchRefsLocked requires that r.mu remain locked for the duration of the call. +func (r *gitRepo) fetchRefsLocked() error { + if r.fetchLevel < fetchAll { + // NOTE: To work around a bug affecting Git clients up to at least 2.23.0 + // (2019-08-16), we must first expand the set of local refs, and only then + // unshallow the repository as a separate fetch operation. (See + // golang.org/issue/34266 and + // https://github.com/git/git/blob/4c86140027f4a0d2caaa3ab4bd8bfc5ce3c11c8a/transport.c#L1303-L1309.) + + if _, err := Run(r.dir, "git", "fetch", "-f", r.remote, "refs/heads/*:refs/heads/*", "refs/tags/*:refs/tags/*"); err != nil { + return err + } + + if _, err := os.Stat(filepath.Join(r.dir, "shallow")); err == nil { + if _, err := Run(r.dir, "git", "fetch", "--unshallow", "-f", r.remote); err != nil { + return err + } + } + + r.fetchLevel = fetchAll + } + return nil +} + +// 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, &UnknownRevisionError{Rev: 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, fs.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. + unlock, err := r.mu.Lock() + if err != nil { + return nil, err + } + defer unlock() + + if err := r.fetchRefsLocked(); 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 = &fs.PathError{Path: tag + ":" + file, Op: "read", Err: fmt.Errorf("unexpected non-blob type %q", fileType)} + case "missing": + f.Err = &fs.PathError{Path: tag + ":" + file, Op: "read", Err: fs.ErrNotExist} + case "blob": + f.Data = fileData + } + } + } + if len(bytes.TrimSpace(data)) != 0 { + return badGit() + } + + return missing, nil +} + +func (r *gitRepo) RecentTag(rev, prefix string, allowed func(string) bool) (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 for-each-ref' and reports whether the + // result is definitive. + describe := func() (definitive bool) { + var out []byte + out, err = Run(r.dir, "git", "for-each-ref", "--format", "%(refname)", "refs/tags", "--merged", rev) + if err != nil { + return true + } + + // prefixed tags aren't valid semver tags so compare without prefix, but only tags with correct prefix + var highest string + for _, line := range strings.Split(string(out), "\n") { + line = strings.TrimSpace(line) + // git do support lstrip in for-each-ref format, but it was added in v2.13.0. Stripping here + // instead gives support for git v2.7.0. + if !strings.HasPrefix(line, "refs/tags/") { + continue + } + line = line[len("refs/tags/"):] + + if !strings.HasPrefix(line, prefix) { + continue + } + + semtag := line[len(prefix):] + // Consider only tags that are valid and complete (not just major.minor prefixes). + // NOTE: Do not replace the call to semver.Compare with semver.Max. + // We want to return the actual tag, not a canonicalized version of it, + // and semver.Max currently canonicalizes (see golang.org/issue/32700). + if c := semver.Canonical(semtag); c == "" || !strings.HasPrefix(semtag, c) || !allowed(semtag) { + continue + } + if semver.Compare(semtag, highest) > 0 { + highest = semtag + } + } + + if highest != "" { + tag = prefix + highest + } + + 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. + + unlock, err := r.mu.Lock() + if err != nil { + return "", err + } + defer unlock() + + if err := r.fetchRefsLocked(); err != nil { + return "", err + } + + // 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 the lock. + describe() + return tag, err +} + +func (r *gitRepo) DescendsFrom(rev, tag string) (bool, error) { + // The "--is-ancestor" flag was added to "git merge-base" in version 1.8.0, so + // this won't work with Git 1.7.1. According to golang.org/issue/28550, cmd/go + // already doesn't work with Git 1.7.1, so at least it's not a regression. + // + // git merge-base --is-ancestor exits with status 0 if rev is an ancestor, or + // 1 if not. + _, err := Run(r.dir, "git", "merge-base", "--is-ancestor", "--", tag, rev) + + // Git reports "is an ancestor" with exit code 0 and "not an ancestor" with + // exit code 1. + // Unfortunately, if we've already fetched rev with a shallow history, git + // merge-base has been observed to report a false-negative, so don't stop yet + // even if the exit code is 1! + if err == nil { + return true, nil + } + + // See whether the tag and rev even exist. + tags, err := r.Tags(tag) + if err != nil { + return false, err + } + if len(tags) == 0 { + return false, nil + } + + // NOTE: r.stat is very careful not to fetch commits that we shouldn't know + // about, like rejected GitHub pull requests, so don't try to short-circuit + // that here. + if _, err = r.stat(rev); err != nil { + return false, err + } + + // Now fetch history so that git can search for a path. + unlock, err := r.mu.Lock() + if err != nil { + return false, err + } + defer unlock() + + if r.fetchLevel < fetchAll { + // Fetch the complete history for all refs and heads. It would be more + // efficient to only fetch the history from rev to tag, but that's much more + // complicated, and any kind of shallow fetch is fairly likely to trigger + // bugs in JGit servers and/or the go command anyway. + if err := r.fetchRefsLocked(); err != nil { + return false, err + } + } + + _, err = Run(r.dir, "git", "merge-base", "--is-ancestor", "--", tag, rev) + if err == nil { + return true, nil + } + if ee, ok := err.(*RunError).Err.(*exec.ExitError); ok && ee.ExitCode() == 1 { + return false, nil + } + return false, err +} + +func (r *gitRepo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser, 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 + } + + unlock, err := r.mu.Lock() + if err != nil { + return nil, err + } + defer unlock() + + if err := ensureGitAttributes(r.dir); 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, fs.ErrNotExist + } + return nil, err + } + + return io.NopCloser(bytes.NewReader(archive)), nil +} + +// ensureGitAttributes makes sure export-subst and export-ignore features are +// disabled for this repo. This is intended to be run prior to running git +// archive so that zip files are generated that produce consistent ziphashes +// for a given revision, independent of variables such as git version and the +// size of the repo. +// +// See: https://github.com/golang/go/issues/27153 +func ensureGitAttributes(repoDir string) (err error) { + const attr = "\n* -export-subst -export-ignore\n" + + d := repoDir + "/info" + p := d + "/attributes" + + if err := os.MkdirAll(d, 0755); err != nil { + return err + } + + f, err := os.OpenFile(p, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666) + if err != nil { + return err + } + defer func() { + closeErr := f.Close() + if closeErr != nil { + err = closeErr + } + }() + + b, err := io.ReadAll(f) + if err != nil { + return err + } + if !bytes.HasSuffix(b, []byte(attr)) { + _, err := f.WriteString(attr) + return err + } + + return nil +} diff --git a/src/cmd/go/internal/modfetch/codehost/git_test.go b/src/cmd/go/internal/modfetch/codehost/git_test.go new file mode 100644 index 0000000..89a73ba --- /dev/null +++ b/src/cmd/go/internal/modfetch/codehost/git_test.go @@ -0,0 +1,640 @@ +// 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" + "io/fs" + "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 := os.MkdirTemp("", "gitrepo-test-") + if err != nil { + log.Fatal(err) + } + defer os.RemoveAll(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" { + // Convert absolute path to file URL. LocalGitRepo will not accept + // Windows absolute paths because they look like a host:path remote. + // TODO(golang.org/issue/32456): use url.FromFilePath when implemented. + var url string + if strings.HasPrefix(localGitRepo, "/") { + url = "file://" + localGitRepo + } else { + url = "file:///" + filepath.ToSlash(localGitRepo) + } + return LocalGitRepo(url) + } + 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: fs.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 + 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, 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) + } + zipdata, err := io.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/src/cmd/go/internal/modfetch/codehost/shell.go b/src/cmd/go/internal/modfetch/codehost/shell.go new file mode 100644 index 0000000..ce8b501 --- /dev/null +++ b/src/cmd/go/internal/modfetch/codehost/shell.go @@ -0,0 +1,141 @@ +// 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" + "log" + "os" + "strings" + "time" + + "cmd/go/internal/cfg" + "cmd/go/internal/modfetch/codehost" +) + +func usage() { + fmt.Fprintf(os.Stderr, "usage: go run shell.go vcs remote\n") + os.Exit(2) +} + +func main() { + cfg.GOMODCACHE = "/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 := io.ReadAll(rc) + rc.Close() + if err != nil { + fmt.Fprintf(os.Stderr, "?%s\n", err) + continue + } + + if f[3] != "-" { + if err := os.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/src/cmd/go/internal/modfetch/codehost/svn.go b/src/cmd/go/internal/modfetch/codehost/svn.go new file mode 100644 index 0000000..6ec9e59 --- /dev/null +++ b/src/cmd/go/internal/modfetch/codehost/svn.go @@ -0,0 +1,154 @@ +// Copyright 2019 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" + "encoding/xml" + "fmt" + "io" + "os" + "path" + "path/filepath" + "time" +) + +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, vcsErrorf("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, vcsErrorf("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 svnReadZip(dst io.Writer, workDir, rev, subdir, remote string) (err error) { + // The subversion CLI doesn't provide a command to write the repository + // directly to an archive, so we need to export it to the local filesystem + // instead. Unfortunately, the local filesystem might apply arbitrary + // normalization to the filenames, so we need to obtain those directly. + // + // 'svn export' prints the filenames as they are written, but from reading the + // svn source code (as of revision 1868933), those filenames are encoded using + // the system locale rather than preserved byte-for-byte from the origin. For + // our purposes, that won't do, but we don't want to go mucking around with + // the user's locale settings either — that could impact error messages, and + // we don't know what locales the user has available or what LC_* variables + // their platform supports. + // + // Instead, we'll do a two-pass export: first we'll run 'svn list' to get the + // canonical filenames, then we'll 'svn export' and look for those filenames + // in the local filesystem. (If there is an encoding problem at that point, we + // would probably reject the resulting module anyway.) + + remotePath := remote + if subdir != "" { + remotePath += "/" + subdir + } + + out, err := Run(workDir, []string{ + "svn", "list", + "--non-interactive", + "--xml", + "--incremental", + "--recursive", + "--revision", rev, + "--", remotePath, + }) + if err != nil { + return err + } + + type listEntry struct { + Kind string `xml:"kind,attr"` + Name string `xml:"name"` + Size int64 `xml:"size"` + } + var list struct { + Entries []listEntry `xml:"entry"` + } + if err := xml.Unmarshal(out, &list); err != nil { + return vcsErrorf("unexpected response from svn list --xml: %v\n%s", err, out) + } + + exportDir := filepath.Join(workDir, "export") + // Remove any existing contents from a previous (failed) run. + if err := os.RemoveAll(exportDir); err != nil { + return err + } + defer os.RemoveAll(exportDir) // best-effort + + _, err = Run(workDir, []string{ + "svn", "export", + "--non-interactive", + "--quiet", + + // Suppress any platform- or host-dependent transformations. + "--native-eol", "LF", + "--ignore-externals", + "--ignore-keywords", + + "--revision", rev, + "--", remotePath, + exportDir, + }) + if err != nil { + return err + } + + // Scrape the exported files out of the filesystem and encode them in the zipfile. + + // “All files in the zip file are expected to be + // nested in a single top-level directory, whose name is not specified.” + // We'll (arbitrarily) choose the base of the remote path. + basePath := path.Join(path.Base(remote), subdir) + + zw := zip.NewWriter(dst) + for _, e := range list.Entries { + if e.Kind != "file" { + continue + } + + zf, err := zw.Create(path.Join(basePath, e.Name)) + if err != nil { + return err + } + + f, err := os.Open(filepath.Join(exportDir, e.Name)) + if err != nil { + if os.IsNotExist(err) { + return vcsErrorf("file reported by 'svn list', but not written by 'svn export': %s", e.Name) + } + return fmt.Errorf("error opening file created by 'svn export': %v", err) + } + + n, err := io.Copy(zf, f) + f.Close() + if err != nil { + return err + } + if n != e.Size { + return vcsErrorf("file size differs between 'svn list' and 'svn export': file %s listed as %v bytes, but exported as %v bytes", e.Name, e.Size, n) + } + } + + return zw.Close() +} diff --git a/src/cmd/go/internal/modfetch/codehost/vcs.go b/src/cmd/go/internal/modfetch/codehost/vcs.go new file mode 100644 index 0000000..c2cca08 --- /dev/null +++ b/src/cmd/go/internal/modfetch/codehost/vcs.go @@ -0,0 +1,616 @@ +// 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 ( + "errors" + "fmt" + "internal/lazyregexp" + "io" + "io/fs" + "os" + "path/filepath" + "sort" + "strconv" + "strings" + "sync" + "time" + + "cmd/go/internal/lockedfile" + "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. +// +// TODO(golang.org/issue/31730): See if we can invert this. (Return a +// distinguished error for “repo not found” and treat everything else +// as terminal.) +type VCSError struct { + Err error +} + +func (e *VCSError) Error() string { return e.Err.Error() } + +func vcsErrorf(format string, a ...interface{}) error { + return &VCSError{Err: fmt.Errorf(format, a...)} +} + +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 { + mu lockedfile.Mutex // protects all commands, so we don't have to decide which are safe on a per-VCS basis + + 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} + var err error + r.dir, r.mu.Path, err = WorkDir(vcsWorkDirType+vcs, r.remote) + if err != nil { + return nil, err + } + + if cmd.init == nil { + return r, nil + } + + unlock, err := r.mu.Lock() + if err != nil { + return nil, err + } + defer unlock() + + if _, err := os.Stat(filepath.Join(r.dir, "."+vcs)); err != nil { + if _, err := Run(r.dir, cmd.init(r.remote)); err != nil { + os.RemoveAll(r.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 *lazyregexp.Regexp // regexp to extract tag names from output of tags cmd + branches func(remote string) []string // cmd to list local branches + branchRE *lazyregexp.Regexp // regexp to extract branch names from output of tags cmd + badLocalRevRE *lazyregexp.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 + doReadZip func(dst io.Writer, workDir, rev, subdir, remote string) error // arbitrary function to read rev's subdir as zip file +} + +var re = lazyregexp.New + +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} + }, + doReadZip: svnReadZip, + }, + + "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) { + unlock, err := r.mu.Lock() + if err != nil { + return nil, err + } + defer unlock() + + 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) { + unlock, err := r.mu.Lock() + if err != nil { + return nil, err + } + defer unlock() + + 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() { + if len(r.cmd.fetch) > 0 { + _, 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, &UnknownRevisionError{Rev: 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 + } + + // r.Stat acquires r.mu, so lock after that. + unlock, err := r.mu.Lock() + if err != nil { + return nil, err + } + defer unlock() + + out, err := Run(r.dir, r.cmd.readFile(rev, file, r.remote)) + if err != nil { + return nil, fs.ErrNotExist + } + return out, nil +} + +func (r *vcsRepo) ReadFileRevs(revs []string, file string, maxSize int64) (map[string]*FileRev, error) { + // We don't technically need to lock here since we're returning an error + // uncondititonally, but doing so anyway will help to avoid baking in + // lock-inversion bugs. + unlock, err := r.mu.Lock() + if err != nil { + return nil, err + } + defer unlock() + + return nil, vcsErrorf("ReadFileRevs not implemented") +} + +func (r *vcsRepo) RecentTag(rev, prefix string, allowed func(string) bool) (tag string, err error) { + // We don't technically need to lock here since we're returning an error + // uncondititonally, but doing so anyway will help to avoid baking in + // lock-inversion bugs. + unlock, err := r.mu.Lock() + if err != nil { + return "", err + } + defer unlock() + + return "", vcsErrorf("RecentTag not implemented") +} + +func (r *vcsRepo) DescendsFrom(rev, tag string) (bool, error) { + unlock, err := r.mu.Lock() + if err != nil { + return false, err + } + defer unlock() + + return false, vcsErrorf("DescendsFrom not implemented") +} + +func (r *vcsRepo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser, err error) { + if r.cmd.readZip == nil && r.cmd.doReadZip == nil { + return nil, vcsErrorf("ReadZip not implemented for %s", r.cmd.vcs) + } + + unlock, err := r.mu.Lock() + if err != nil { + return nil, err + } + defer unlock() + + if rev == "latest" { + rev = r.cmd.latest + } + f, err := os.CreateTemp("", "go-readzip-*.zip") + if err != nil { + return nil, err + } + if r.cmd.doReadZip != nil { + lw := &limitedWriter{ + W: f, + N: maxSize, + ErrLimitReached: errors.New("ReadZip: encoded file exceeds allowed size"), + } + err = r.cmd.doReadZip(lw, r.dir, rev, subdir, r.remote) + if err == nil { + _, err = f.Seek(0, io.SeekStart) + } + } else 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, vcsErrorf("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, vcsErrorf("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 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, vcsErrorf("unexpected revno from bzr log: %q", line) + } + revno = i + case "timestamp": + j := strings.Index(val, " ") + if j < 0 { + return nil, vcsErrorf("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, vcsErrorf("unexpected timestamp from bzr log: %q", line) + } + tm = t.UTC() + } + } + if revno == 0 || tm.IsZero() { + return nil, vcsErrorf("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:") || strings.HasPrefix(line, "hash:") { + f := strings.Fields(line) + if len(f) != 5 || len(f[1]) != 40 || f[4] != "UTC" { + return nil, vcsErrorf("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, vcsErrorf("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, vcsErrorf("unexpected response from fossil info: %q", out) +} + +type limitedWriter struct { + W io.Writer + N int64 + ErrLimitReached error +} + +func (l *limitedWriter) Write(p []byte) (n int, err error) { + if l.N > 0 { + max := len(p) + if l.N < int64(max) { + max = int(l.N) + } + n, err = l.W.Write(p[:max]) + l.N -= int64(n) + if err != nil || n >= len(p) { + return n, err + } + } + + return n, l.ErrLimitReached +} diff --git a/src/cmd/go/internal/modfetch/coderepo.go b/src/cmd/go/internal/modfetch/coderepo.go new file mode 100644 index 0000000..2dcbb99 --- /dev/null +++ b/src/cmd/go/internal/modfetch/coderepo.go @@ -0,0 +1,1082 @@ +// 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" + "errors" + "fmt" + "io" + "io/fs" + "os" + "path" + "sort" + "strings" + "time" + + "cmd/go/internal/modfetch/codehost" + + "golang.org/x/mod/modfile" + "golang.org/x/mod/module" + "golang.org/x/mod/semver" + modzip "golang.org/x/mod/zip" +) + +// A codeRepo implements modfetch.Repo using an underlying codehost.Repo. +type codeRepo struct { + modPath string + + // code is the repository containing this module. + code codehost.Repo + // codeRoot is the import path at the root of code. + codeRoot string + // codeDir is the directory (relative to root) at which we expect to find the module. + // If pathMajor is non-empty and codeRoot is not the full modPath, + // then we look in both codeDir and codeDir/pathMajor[1:]. + codeDir string + + // pathMajor is the suffix of modPath that indicates its major version, + // or the empty string if modPath is at major version 0 or 1. + // + // pathMajor is typically of the form "/vN", but possibly ".vN", or + // ".vN-unstable" for modules resolved using gopkg.in. + pathMajor string + // pathPrefix is the prefix of modPath that excludes pathMajor. + // It is used only for logging. + pathPrefix string + + // pseudoMajor is the major version prefix to require when generating + // pseudo-versions for this module, derived from the module path. pseudoMajor + // is empty if the module path does not include a version suffix (that is, + // accepts either v0 or v1). + pseudoMajor string +} + +// newCodeRepo returns a Repo that reads the source code for the module with the +// given path, from the repo stored in code, with the root of the repo +// containing the path given by codeRoot. +func newCodeRepo(code codehost.Repo, codeRoot, path string) (Repo, error) { + if !hasPathPrefix(path, codeRoot) { + return nil, fmt.Errorf("mismatched repo: found %s for %s", codeRoot, path) + } + pathPrefix, pathMajor, ok := module.SplitPathVersion(path) + if !ok { + return nil, fmt.Errorf("invalid module path %q", path) + } + if codeRoot == path { + pathPrefix = path + } + pseudoMajor := module.PathMajorPrefix(pathMajor) + + // Compute codeDir = bar, the subdirectory within the repo + // corresponding to the module root. + // + // At this point we might have: + // path = github.com/rsc/foo/bar/v2 + // codeRoot = github.com/rsc/foo + // pathPrefix = github.com/rsc/foo/bar + // pathMajor = /v2 + // pseudoMajor = v2 + // + // which gives + // codeDir = bar + // + // We know that pathPrefix is a prefix of path, and codeRoot is a prefix of + // path, but codeRoot may or may not be a prefix of pathPrefix, because + // codeRoot may be the entire path (in which case codeDir should be empty). + // That occurs in two situations. + // + // One is when a go-import meta tag resolves the complete module path, + // including the pathMajor suffix: + // path = nanomsg.org/go/mangos/v2 + // codeRoot = nanomsg.org/go/mangos/v2 + // pathPrefix = nanomsg.org/go/mangos + // pathMajor = /v2 + // pseudoMajor = v2 + // + // The other is similar: for gopkg.in only, the major version is encoded + // with a dot rather than a slash, and thus can't be in a subdirectory. + // path = gopkg.in/yaml.v2 + // codeRoot = gopkg.in/yaml.v2 + // pathPrefix = gopkg.in/yaml + // pathMajor = .v2 + // pseudoMajor = v2 + // + codeDir := "" + if codeRoot != path { + if !hasPathPrefix(pathPrefix, codeRoot) { + return nil, fmt.Errorf("repository rooted at %s cannot contain module %s", codeRoot, path) + } + codeDir = strings.Trim(pathPrefix[len(codeRoot):], "/") + } + + r := &codeRepo{ + modPath: path, + code: code, + codeRoot: codeRoot, + 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, &module.ModuleError{ + Path: r.modPath, + Err: err, + } + } + + var list, 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 err := module.CheckPathMajor(v, r.pathMajor); err != nil { + if r.codeDir == "" && r.pathMajor == "" && semver.Major(v) > "v1" { + incompatible = append(incompatible, v) + } + continue + } + + list = append(list, v) + } + SortVersions(list) + SortVersions(incompatible) + + return r.appendIncompatibleVersions(list, incompatible) +} + +// appendIncompatibleVersions appends "+incompatible" versions to list if +// appropriate, returning the final list. +// +// The incompatible list contains candidate versions without the '+incompatible' +// prefix. +// +// Both list and incompatible must be sorted in semantic order. +func (r *codeRepo) appendIncompatibleVersions(list, incompatible []string) ([]string, error) { + if len(incompatible) == 0 || r.pathMajor != "" { + // No +incompatible versions are possible, so no need to check them. + return list, nil + } + + versionHasGoMod := func(v string) (bool, error) { + _, err := r.code.ReadFile(v, "go.mod", codehost.MaxGoMod) + if err == nil { + return true, nil + } + if !os.IsNotExist(err) { + return false, &module.ModuleError{ + Path: r.modPath, + Err: err, + } + } + return false, nil + } + + if len(list) > 0 { + ok, err := versionHasGoMod(list[len(list)-1]) + if err != nil { + return nil, err + } + if ok { + // The latest compatible version has a go.mod file, so assume that all + // subsequent versions do as well, and do not include any +incompatible + // versions. Even if we are wrong, the author clearly intends module + // consumers to be on the v0/v1 line instead of a higher +incompatible + // version. (See https://golang.org/issue/34189.) + // + // We know of at least two examples where this behavior is desired + // (github.com/russross/blackfriday@v2.0.0 and + // github.com/libp2p/go-libp2p@v6.0.23), and (as of 2019-10-29) have no + // concrete examples for which it is undesired. + return list, nil + } + } + + var ( + lastMajor string + lastMajorHasGoMod bool + ) + for i, v := range incompatible { + major := semver.Major(v) + + if major != lastMajor { + rem := incompatible[i:] + j := sort.Search(len(rem), func(j int) bool { + return semver.Major(rem[j]) != major + }) + latestAtMajor := rem[j-1] + + var err error + lastMajor = major + lastMajorHasGoMod, err = versionHasGoMod(latestAtMajor) + if err != nil { + return nil, err + } + } + + if lastMajorHasGoMod { + // The latest release of this major version has a go.mod file, so it is + // not allowed as +incompatible. It would be confusing to include some + // minor versions of this major version as +incompatible but require + // semantic import versioning for others, so drop all +incompatible + // versions for this major version. + // + // If we're wrong about a minor version in the middle, users will still be + // able to 'go get' specific tags for that version explicitly — they just + // won't appear in 'go list' or as the results for queries with inequality + // bounds. + continue + } + list = append(list, v+"+incompatible") + } + + return list, nil +} + +func (r *codeRepo) Stat(rev string) (*RevInfo, error) { + if rev == "latest" { + return r.Latest() + } + codeRev := r.revToRev(rev) + info, err := r.code.Stat(codeRev) + if err != nil { + return nil, &module.ModuleError{ + Path: r.modPath, + Err: &module.InvalidVersionError{ + Version: rev, + Err: 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, "") +} + +// convert converts a version as reported by the code host to a version as +// interpreted by the module system. +// +// If statVers is a valid module version, it is used for the Version field. +// Otherwise, the Version is derived from the passed-in info and recent tags. +func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, error) { + info2 := &RevInfo{ + Name: info.Name, + Short: info.Short, + Time: info.Time, + } + + // 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. + var canUseIncompatible func() bool + canUseIncompatible = func() bool { + var ok bool + if r.codeDir == "" && r.pathMajor == "" { + _, errGoMod := r.code.ReadFile(info.Name, "go.mod", codehost.MaxGoMod) + if errGoMod != nil { + ok = true + } + } + canUseIncompatible = func() bool { return ok } + return ok + } + + invalidf := func(format string, args ...interface{}) error { + return &module.ModuleError{ + Path: r.modPath, + Err: &module.InvalidVersionError{ + Version: info2.Version, + Err: fmt.Errorf(format, args...), + }, + } + } + + // checkGoMod verifies that the go.mod file for the module exists or does not + // exist as required by info2.Version and the module path represented by r. + checkGoMod := func() (*RevInfo, error) { + // If r.codeDir is non-empty, then the go.mod file must exist: the module + // author — not the module consumer, — gets to decide how to carve up the repo + // into modules. + // + // Conversely, if the go.mod file exists, the module author — not the module + // consumer — gets to determine the module's path + // + // r.findDir verifies both of these conditions. Execute it now so that + // r.Stat will correctly return a notExistError if the go.mod location or + // declared module path doesn't match. + _, _, _, 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, &module.ModuleError{ + Path: r.modPath, + Err: &module.InvalidVersionError{ + Version: info2.Version, + Err: notExistError{err: err}, + }, + } + } + + // If the version is +incompatible, then the go.mod file must not exist: + // +incompatible is not an ongoing opt-out from semantic import versioning. + if strings.HasSuffix(info2.Version, "+incompatible") { + if !canUseIncompatible() { + if r.pathMajor != "" { + return nil, invalidf("+incompatible suffix not allowed: module path includes a major version suffix, so major version must match") + } else { + return nil, invalidf("+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required") + } + } + + if err := module.CheckPathMajor(strings.TrimSuffix(info2.Version, "+incompatible"), r.pathMajor); err == nil { + return nil, invalidf("+incompatible suffix not allowed: major version %s is compatible", semver.Major(info2.Version)) + } + } + + return info2, nil + } + + // Determine version. + // + // If statVers is canonical, then the original call was repo.Stat(statVers). + // Since the version is canonical, we must not resolve it to anything but + // itself, possibly with a '+incompatible' annotation: we do not need to do + // the work required to look for an arbitrary pseudo-version. + if statVers != "" && statVers == module.CanonicalVersion(statVers) { + info2.Version = statVers + + if IsPseudoVersion(info2.Version) { + if err := r.validatePseudoVersion(info, info2.Version); err != nil { + return nil, err + } + return checkGoMod() + } + + if err := module.CheckPathMajor(info2.Version, r.pathMajor); err != nil { + if canUseIncompatible() { + info2.Version += "+incompatible" + return checkGoMod() + } else { + if vErr, ok := err.(*module.InvalidVersionError); ok { + // We're going to describe why the version is invalid in more detail, + // so strip out the existing “invalid version” wrapper. + err = vErr.Err + } + return nil, invalidf("module contains a go.mod file, so major version must be compatible: %v", err) + } + } + + return checkGoMod() + } + + // statVers is empty or non-canonical, so we need to resolve it to a canonical + // version or pseudo-version. + + // Derive or verify a version from a code repo tag. + // Tag must have a prefix matching codeDir. + tagPrefix := "" + if r.codeDir != "" { + tagPrefix = r.codeDir + "/" + } + + isRetracted, err := r.retractedVersions() + if err != nil { + isRetracted = func(string) bool { return false } + } + + // tagToVersion returns the version obtained by trimming tagPrefix from tag. + // If the tag is invalid, retracted, or a pseudo-version, tagToVersion returns + // an empty version. + tagToVersion := func(tag string) (v string, tagIsCanonical bool) { + if !strings.HasPrefix(tag, tagPrefix) { + return "", false + } + trimmed := tag[len(tagPrefix):] + // Tags that look like pseudo-versions would be confusing. Ignore them. + if IsPseudoVersion(tag) { + return "", false + } + + v = semver.Canonical(trimmed) // Not module.Canonical: we don't want to pick up an explicit "+incompatible" suffix from the tag. + if v == "" || !strings.HasPrefix(trimmed, v) { + return "", false // Invalid or incomplete version (just vX or vX.Y). + } + if isRetracted(v) { + return "", false + } + if v == trimmed { + tagIsCanonical = true + } + + if err := module.CheckPathMajor(v, r.pathMajor); err != nil { + if canUseIncompatible() { + return v + "+incompatible", tagIsCanonical + } + return "", false + } + + return v, tagIsCanonical + } + + // If the VCS gave us a valid version, use that. + if v, tagIsCanonical := tagToVersion(info.Version); tagIsCanonical { + info2.Version = v + return checkGoMod() + } + + // Look through the tags on the revision for either a usable canonical version + // or an appropriate base for a pseudo-version. + var pseudoBase string + for _, pathTag := range info.Tags { + v, tagIsCanonical := tagToVersion(pathTag) + if tagIsCanonical { + if statVers != "" && semver.Compare(v, statVers) == 0 { + // The user requested a non-canonical version, but the tag for the + // canonical equivalent refers to the same revision. Use it. + info2.Version = v + return checkGoMod() + } else { + // Save the highest canonical tag for the revision. If we don't find a + // better match, we'll use it as the canonical version. + // + // NOTE: Do not replace this with semver.Max. Despite the name, + // semver.Max *also* canonicalizes its arguments, which uses + // semver.Canonical instead of module.CanonicalVersion and thereby + // strips our "+incompatible" suffix. + if semver.Compare(info2.Version, v) < 0 { + info2.Version = v + } + } + } else if v != "" && semver.Compare(v, statVers) == 0 { + // The user explicitly requested something equivalent to this tag. We + // can't use the version from the tag directly: since the tag is not + // canonical, it could be ambiguous. For example, tags v0.0.1+a and + // v0.0.1+b might both exist and refer to different revisions. + // + // The tag is otherwise valid for the module, so we can at least use it as + // the base of an unambiguous pseudo-version. + // + // If multiple tags match, tagToVersion will canonicalize them to the same + // base version. + pseudoBase = v + } + } + + // If we found any canonical tag for the revision, return it. + // Even if we found a good pseudo-version base, a canonical version is better. + if info2.Version != "" { + return checkGoMod() + } + + // Find the highest tagged version in the revision's history, subject to + // major version and +incompatible constraints. Use that version as the + // pseudo-version base so that the pseudo-version sorts higher. Ignore + // retracted versions. + allowedMajor := func(major string) func(v string) bool { + return func(v string) bool { + return (major == "" || semver.Major(v) == major) && !isRetracted(v) + } + } + if pseudoBase == "" { + var tag string + if r.pseudoMajor != "" || canUseIncompatible() { + tag, _ = r.code.RecentTag(info.Name, tagPrefix, allowedMajor(r.pseudoMajor)) + } else { + // Allow either v1 or v0, but not incompatible higher versions. + tag, _ = r.code.RecentTag(info.Name, tagPrefix, allowedMajor("v1")) + if tag == "" { + tag, _ = r.code.RecentTag(info.Name, tagPrefix, allowedMajor("v0")) + } + } + pseudoBase, _ = tagToVersion(tag) // empty if the tag is invalid + } + + info2.Version = PseudoVersion(r.pseudoMajor, pseudoBase, info.Time, info.Short) + return checkGoMod() +} + +// validatePseudoVersion checks that version has a major version compatible with +// r.modPath and encodes a base version and commit metadata that agrees with +// info. +// +// Note that verifying a nontrivial base version in particular may be somewhat +// expensive: in order to do so, r.code.DescendsFrom will need to fetch at least +// enough of the commit history to find a path between version and its base. +// Fortunately, many pseudo-versions — such as those for untagged repositories — +// have trivial bases! +func (r *codeRepo) validatePseudoVersion(info *codehost.RevInfo, version string) (err error) { + defer func() { + if err != nil { + if _, ok := err.(*module.ModuleError); !ok { + if _, ok := err.(*module.InvalidVersionError); !ok { + err = &module.InvalidVersionError{Version: version, Pseudo: true, Err: err} + } + err = &module.ModuleError{Path: r.modPath, Err: err} + } + } + }() + + if err := module.CheckPathMajor(version, r.pathMajor); err != nil { + return err + } + + rev, err := PseudoVersionRev(version) + if err != nil { + return err + } + if rev != info.Short { + switch { + case strings.HasPrefix(rev, info.Short): + return fmt.Errorf("revision is longer than canonical (%s)", info.Short) + case strings.HasPrefix(info.Short, rev): + return fmt.Errorf("revision is shorter than canonical (%s)", info.Short) + default: + return fmt.Errorf("does not match short name of revision (%s)", info.Short) + } + } + + t, err := PseudoVersionTime(version) + if err != nil { + return err + } + if !t.Equal(info.Time.Truncate(time.Second)) { + return fmt.Errorf("does not match version-control timestamp (expected %s)", info.Time.UTC().Format(pseudoVersionTimestampFormat)) + } + + tagPrefix := "" + if r.codeDir != "" { + tagPrefix = r.codeDir + "/" + } + + // A pseudo-version should have a precedence just above its parent revisions, + // and no higher. Otherwise, it would be possible for library authors to "pin" + // dependency versions (and bypass the usual minimum version selection) by + // naming an extremely high pseudo-version rather than an accurate one. + // + // Moreover, if we allow a pseudo-version to use any arbitrary pre-release + // tag, we end up with infinitely many possible names for each commit. Each + // name consumes resources in the module cache and proxies, so we want to + // restrict them to a finite set under control of the module author. + // + // We address both of these issues by requiring the tag upon which the + // pseudo-version is based to refer to some ancestor of the revision. We + // prefer the highest such tag when constructing a new pseudo-version, but do + // not enforce that property when resolving existing pseudo-versions: we don't + // know when the parent tags were added, and the highest-tagged parent may not + // have existed when the pseudo-version was first resolved. + base, err := PseudoVersionBase(strings.TrimSuffix(version, "+incompatible")) + if err != nil { + return err + } + if base == "" { + if r.pseudoMajor == "" && semver.Major(version) == "v1" { + return fmt.Errorf("major version without preceding tag must be v0, not v1") + } + return nil + } else { + for _, tag := range info.Tags { + versionOnly := strings.TrimPrefix(tag, tagPrefix) + if versionOnly == base { + // The base version is canonical, so if the version from the tag is + // literally equal (not just equivalent), then the tag is canonical too. + // + // We allow pseudo-versions to be derived from non-canonical tags on the + // same commit, so that tags like "v1.1.0+some-metadata" resolve as + // close as possible to the canonical version ("v1.1.0") while still + // enforcing a total ordering ("v1.1.1-0.[…]" with a unique suffix). + // + // However, canonical tags already have a total ordering, so there is no + // reason not to use the canonical tag directly, and we know that the + // canonical tag must already exist because the pseudo-version is + // derived from it. In that case, referring to the revision by a + // pseudo-version derived from its own canonical tag is just confusing. + return fmt.Errorf("tag (%s) found on revision %s is already canonical, so should not be replaced with a pseudo-version derived from that tag", tag, rev) + } + } + } + + tags, err := r.code.Tags(tagPrefix + base) + if err != nil { + return err + } + + var lastTag string // Prefer to log some real tag rather than a canonically-equivalent base. + ancestorFound := false + for _, tag := range tags { + versionOnly := strings.TrimPrefix(tag, tagPrefix) + if semver.Compare(versionOnly, base) == 0 { + lastTag = tag + ancestorFound, err = r.code.DescendsFrom(info.Name, tag) + if ancestorFound { + break + } + } + } + + if lastTag == "" { + return fmt.Errorf("preceding tag (%s) not found", base) + } + + if !ancestorFound { + if err != nil { + return err + } + rev, err := PseudoVersionRev(version) + if err != nil { + return fmt.Errorf("not a descendent of preceding tag (%s)", lastTag) + } + return fmt.Errorf("revision %s is not a descendent of preceding tag (%s)", rev, lastTag) + } + return 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 "", &module.ModuleError{ + Path: r.modPath, + Err: &module.InvalidVersionError{ + Version: version, + Err: errors.New("syntax error"), + }, + } + } + return r.revToRev(version), nil +} + +// findDir locates the directory within the repo containing the module. +// +// If r.pathMajor is non-empty, this can be either r.codeDir or — if a go.mod +// file exists — r.codeDir/r.pathMajor[1:]. +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) || r.canReplaceMismatchedVersionDueToBug(mpath1)) + + var file2 string + if r.pathMajor != "" && r.codeRoot != r.modPath && !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 major version ok. + return rev, r.codeDir, gomod1, nil + } + if err1 == nil { + // Explicit go.mod with non-matching major version 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) + } + if _, _, ok := module.SplitPathVersion(mpath1); !ok { + return "", "", nil, fmt.Errorf("%s has malformed module path %q%s at revision %s", file1, 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) +} + +// isMajor reports whether the versions allowed for mpath are compatible with +// the major version(s) implied by pathMajor, or false if mpath has an invalid +// version suffix. +func isMajor(mpath, pathMajor string) bool { + if mpath == "" { + // If we don't have a path, we don't know what version(s) it is compatible with. + return false + } + _, mpathMajor, ok := module.SplitPathVersion(mpath) + if !ok { + // An invalid module path is not compatible with any version. + return false + } + if pathMajor == "" { + // All of the valid versions for a gopkg.in module that requires major + // version v0 or v1 are compatible with the "v0 or v1" implied by an empty + // pathMajor. + switch module.PathMajorPrefix(mpathMajor) { + case "", "v0", "v1": + return true + default: + return false + } + } + if mpathMajor == "" { + // Even if pathMajor is ".v0" or ".v1", we can't be sure that a module + // without a suffix is tagged appropriately. Besides, we don't expect clones + // of non-gopkg.in modules to have gopkg.in paths, so a non-empty, + // non-gopkg.in mpath is probably the wrong module for any such pathMajor + // anyway. + return false + } + // If both pathMajor and mpathMajor are non-empty, then we only care that they + // have the same major-version validation rules. A clone fetched via a /v2 + // path might replace a module with path gopkg.in/foo.v2-unstable, and that's + // ok. + return pathMajor[1:] == mpathMajor[1:] +} + +// canReplaceMismatchedVersionDueToBug reports whether versions of r +// could replace versions of mpath with otherwise-mismatched major versions +// due to a historical bug in the Go command (golang.org/issue/34254). +func (r *codeRepo) canReplaceMismatchedVersionDueToBug(mpath string) bool { + // The bug caused us to erroneously accept unversioned paths as replacements + // for versioned gopkg.in paths. + unversioned := r.pathMajor == "" + replacingGopkgIn := strings.HasPrefix(mpath, "gopkg.in/") + return unversioned && replacingGopkgIn +} + +func (r *codeRepo) GoMod(version string) (data []byte, err error) { + if version != module.CanonicalVersion(version) { + return nil, fmt.Errorf("version %s is not canonical", version) + } + + if IsPseudoVersion(version) { + // findDir ignores the metadata encoded in a pseudo-version, + // only using the revision at the end. + // Invoke Stat to verify the metadata explicitly so we don't return + // a bogus file for an invalid version. + _, err := r.Stat(version) + if err != nil { + return nil, err + } + } + + 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) retractedVersions() (func(string) bool, error) { + versions, err := r.Versions("") + if err != nil { + return nil, err + } + + for i, v := range versions { + if strings.HasSuffix(v, "+incompatible") { + versions = versions[:i] + break + } + } + if len(versions) == 0 { + return func(string) bool { return false }, nil + } + + var highest string + for i := len(versions) - 1; i >= 0; i-- { + v := versions[i] + if semver.Prerelease(v) == "" { + highest = v + break + } + } + if highest == "" { + highest = versions[len(versions)-1] + } + + data, err := r.GoMod(highest) + if err != nil { + return nil, err + } + f, err := modfile.ParseLax("go.mod", data, nil) + if err != nil { + return nil, err + } + retractions := make([]modfile.VersionInterval, len(f.Retract)) + for _, r := range f.Retract { + retractions = append(retractions, r.VersionInterval) + } + + return func(v string) bool { + for _, r := range retractions { + if semver.Compare(r.Low, v) <= 0 && semver.Compare(v, r.High) <= 0 { + return true + } + } + return false + }, nil +} + +func (r *codeRepo) Zip(dst io.Writer, version string) error { + if version != module.CanonicalVersion(version) { + return fmt.Errorf("version %s is not canonical", version) + } + + if IsPseudoVersion(version) { + // findDir ignores the metadata encoded in a pseudo-version, + // only using the revision at the end. + // Invoke Stat to verify the metadata explicitly so we don't return + // a bogus file for an invalid version. + _, err := r.Stat(version) + if err != nil { + return err + } + } + + rev, subdir, _, err := r.findDir(version) + if err != nil { + return err + } + dl, err := r.code.ReadZip(rev, subdir, codehost.MaxZipFile) + if err != nil { + return err + } + defer dl.Close() + subdir = strings.Trim(subdir, "/") + + // Spool to local file. + f, err := os.CreateTemp("", "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 + } + + var files []modzip.File + if subdir != "" { + subdir += "/" + } + haveLICENSE := false + topPrefix := "" + 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") + } + name := strings.TrimPrefix(zf.Name, topPrefix) + if !strings.HasPrefix(name, subdir) { + continue + } + name = strings.TrimPrefix(name, subdir) + if name == "" || strings.HasSuffix(name, "/") { + continue + } + files = append(files, zipFile{name: name, f: zf}) + if name == "LICENSE" { + haveLICENSE = true + } + } + + if !haveLICENSE && subdir != "" { + data, err := r.code.ReadFile(rev, "LICENSE", codehost.MaxLICENSE) + if err == nil { + files = append(files, dataFile{name: "LICENSE", data: data}) + } + } + + return modzip.Create(dst, module.Version{Path: r.modPath, Version: version}, files) +} + +type zipFile struct { + name string + f *zip.File +} + +func (f zipFile) Path() string { return f.name } +func (f zipFile) Lstat() (fs.FileInfo, error) { return f.f.FileInfo(), nil } +func (f zipFile) Open() (io.ReadCloser, error) { return f.f.Open() } + +type dataFile struct { + name string + data []byte +} + +func (f dataFile) Path() string { return f.name } +func (f dataFile) Lstat() (fs.FileInfo, error) { return dataFileInfo{f}, nil } +func (f dataFile) Open() (io.ReadCloser, error) { + return io.NopCloser(bytes.NewReader(f.data)), nil +} + +type dataFileInfo struct { + f dataFile +} + +func (fi dataFileInfo) Name() string { return path.Base(fi.f.name) } +func (fi dataFileInfo) Size() int64 { return int64(len(fi.f.data)) } +func (fi dataFileInfo) Mode() fs.FileMode { return 0644 } +func (fi dataFileInfo) ModTime() time.Time { return time.Time{} } +func (fi dataFileInfo) IsDir() bool { return false } +func (fi dataFileInfo) Sys() interface{} { return 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 + } +} diff --git a/src/cmd/go/internal/modfetch/coderepo_test.go b/src/cmd/go/internal/modfetch/coderepo_test.go new file mode 100644 index 0000000..02e399f --- /dev/null +++ b/src/cmd/go/internal/modfetch/coderepo_test.go @@ -0,0 +1,802 @@ +// 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" + "crypto/sha256" + "encoding/hex" + "hash" + "internal/testenv" + "io" + "log" + "os" + "reflect" + "strings" + "testing" + "time" + + "cmd/go/internal/cfg" + "cmd/go/internal/modfetch/codehost" + + "golang.org/x/mod/sumdb/dirhash" +) + +func TestMain(m *testing.M) { + os.Exit(testMain(m)) +} + +func testMain(m *testing.M) int { + cfg.GOPROXY = "direct" + + // The sum database is populated using a released version of the go command, + // but this test may include fixes for additional modules that previously + // could not be fetched. Since this test isn't executing any of the resolved + // code, bypass the sum database. + cfg.GOSUMDB = "off" + + dir, err := os.MkdirTemp("", "gitrepo-test-") + if err != nil { + log.Fatal(err) + } + defer os.RemoveAll(dir) + + cfg.GOMODCACHE = dir + return m.Run() +} + +const ( + vgotest1git = "github.com/rsc/vgotest1" + vgotest1hg = "vcs-test.golang.org/hg/vgotest1.hg" +) + +var altVgotests = map[string]string{ + "hg": vgotest1hg, +} + +type codeRepoTest struct { + vcs string + path string + mpath string + rev string + err string + version string + name string + short string + time time.Time + gomod string + gomodErr string + zip []string + zipErr string + zipSum string + zipFileHash string +} + +var codeRepoTests = []codeRepoTest{ + { + vcs: "git", + 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", + }, + zipSum: "h1:zVEjciLdlk/TPWCOyZo7k24T+tOKRQC+u8MKq/xS80I=", + zipFileHash: "738a00ddbfe8c329dce6b48e1f23c8e22a92db50f3cfb2653caa0d62676bc09c", + }, + { + vcs: "git", + path: "github.com/rsc/vgotest1", + rev: "v0.0.0-20180219231006-80d85c5d4d17", + version: "v0.0.0-20180219231006-80d85c5d4d17", + name: "80d85c5d4d17598a0e9055e7c175a32b415d6128", + short: "80d85c5d4d17", + time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC), + zip: []string{ + "LICENSE", + "README.md", + "pkg/p.go", + }, + zipSum: "h1:nOznk2xKsLGkTnXe0q9t1Ewt9jxK+oadtafSUqHM3Ec=", + zipFileHash: "bacb08f391e29d2eaaef8281b5c129ee6d890e608ee65877e0003c0181a766c8", + }, + { + vcs: "git", + path: "github.com/rsc/vgotest1", + rev: "v0.0.1-0.20180219231006-80d85c5d4d17", + err: `github.com/rsc/vgotest1@v0.0.1-0.20180219231006-80d85c5d4d17: invalid pseudo-version: tag (v0.0.0) found on revision 80d85c5d4d17 is already canonical, so should not be replaced with a pseudo-version derived from that tag`, + }, + { + vcs: "git", + 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", + }, + zipSum: "h1:e040hOoWGeuJLawDjK9DW6med+cz9FxMFYDMOVG8ctQ=", + zipFileHash: "74caab65cfbea427c341fa815f3bb0378681d8f0e3cf62a7f207014263ec7be3", + }, + { + vcs: "git", + 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), + err: "missing github.com/rsc/vgotest1/go.mod and .../v2/go.mod at revision v2.0.0", + }, + { + vcs: "git", + 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", + }, + zipSum: "h1:e040hOoWGeuJLawDjK9DW6med+cz9FxMFYDMOVG8ctQ=", + zipFileHash: "74caab65cfbea427c341fa815f3bb0378681d8f0e3cf62a7f207014263ec7be3", + }, + { + vcs: "git", + 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", + }, + }, + { + vcs: "git", + 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), + err: "missing github.com/rsc/vgotest1/go.mod and .../v2/go.mod at revision v2.0.0", + }, + { + vcs: "git", + 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), + err: "missing github.com/rsc/vgotest1/go.mod and .../v54321/go.mod at revision 80d85c5d4d17", + }, + { + vcs: "git", + path: "github.com/rsc/vgotest1/submod", + rev: "v1.0.0", + err: "unknown revision submod/v1.0.0", + }, + { + vcs: "git", + path: "github.com/rsc/vgotest1/submod", + rev: "v1.0.3", + err: "unknown revision submod/v1.0.3", + }, + { + vcs: "git", + 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", + }, + zipSum: "h1:iMsJ/9uQsk6MnZNnJK311f11QiSlmN92Q2aSjCywuJY=", + zipFileHash: "95801bfa69c5197ae809af512946d22f22850068527cd78100ae3f176bc8043b", + }, + { + vcs: "git", + 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", + }, + zipSum: "h1:M69k7q+8bQ+QUpHov45Z/NoR8rj3DsQJUnXLWvf01+Q=", + zipFileHash: "58af45fb248d320ea471f568e006379e2b8d71d6d1663f9b19b2e00fd9ac9265", + }, + { + vcs: "git", + 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", + zipSum: "h1:QmgYy/zt+uoWhDpcsgrSVzYFvKtBEjl5zT/FRz9GTzA=", + zipFileHash: "1aedf1546d322a0121879ddfd6d0e8bfbd916d2cafbeb538ddb440e04b04b9ef", + }, + { + vcs: "git", + 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), + err: "github.com/rsc/vgotest1/v2/go.mod has non-.../v2 module path \"github.com/rsc/vgotest\" at revision v2.0.3", + }, + { + vcs: "git", + 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), + err: "github.com/rsc/vgotest1/go.mod and .../v2/go.mod both have .../v2 module paths at revision v2.0.4", + }, + { + vcs: "git", + 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", + zipSum: "h1:RIEb9q1SUSEQOzMn0zfl/LQxGFWlhWEAdeEguf1MLGU=", + zipFileHash: "7d92c2c328c5e9b0694101353705d5843746ec1d93a1e986d0da54c8a14dfe6d", + }, + { + // redirect to github + vcs: "git", + 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", + zipSum: "h1:haUSojyo3j2M9g7CEUFG8Na09dtn7QKxvPGaPVQdGwM=", + zipFileHash: "5c08ba2c09a364f93704aaa780e7504346102c6ef4fe1333a11f09904a732078", + }, + { + // redirect to static hosting proxy + vcs: "mod", + 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 + vcs: "git", + 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), + zipSum: "h1:Yxu6pHX9X2RECiuw/Q5/4uvajuaowck8zOFKXgbfNBk=", + zipFileHash: "ac2c165a5c10aa5a7545dea60a08e019270b982fa6c8bdcb5943931de64922fe", + }, + { + vcs: "git", + 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), + zipSum: "h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=", + zipFileHash: "e4fa69ba057356614edbc1da881a7d3ebb688505be49f65965686bcb859e2fae", + }, + { + // package in subdirectory - custom domain + // In general we can't reject these definitively in Lookup, + // but gopkg.in is special. + vcs: "git", + path: "gopkg.in/yaml.v2/abc", + err: "invalid module path \"gopkg.in/yaml.v2/abc\"", + }, + { + // package in subdirectory - github + // Because it's a package, Stat should fail entirely. + vcs: "git", + path: "github.com/rsc/quote/buggy", + rev: "c4d4236f", + err: "missing github.com/rsc/quote/buggy/go.mod at revision c4d4236f9242", + }, + { + vcs: "git", + 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", + zipSum: "h1:uUkhRGrsEyx/laRdeS6YIQKIys8pg+lRSRdVMTYjivs=", + zipFileHash: "7b0a141b1b0b49772ab4eecfd11dfd6609a94a5e868cab04a3abb1861ffaa877", + }, + { + vcs: "git", + 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", + zipSum: "h1:829vOVxxusYHC+IqBtkX5mbKtsY9fheQiQn0MZRVLfQ=", + zipFileHash: "9e7cb3f4f1e66d722306442b0dbe1f6f43d74d1736d54c510537bdfb1d6f432f", + }, + { + vcs: "git", + 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", + zipSum: "h1:YJYZRsM9BHFTlVr8YADjT0cJH8uFIDtoc5NLiVqZEx8=", + zipFileHash: "c15e49d58b7a4c37966cbe5bc01a0330cd5f2927e990e1839bda1d407766d9c5", + }, + { + vcs: "git", + 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", + zipSum: "h1:AFxeG48hTWHhDTQDk/m2gorfVHUEa9vo3tp3D7TzwjI=", + zipFileHash: "b5de0da7bbbec76709eef1ac71b6c9ff423b9fbf3bb97b56743450d4937b06d5", + }, + { + vcs: "git", + 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", + }, + { + vcs: "git", + path: "vcs-test.golang.org/go/v2module/v2", + rev: "v2.0.0", + version: "v2.0.0", + name: "203b91c896acd173aa719e4cdcb7d463c4b090fa", + short: "203b91c896ac", + time: time.Date(2019, 4, 3, 15, 52, 15, 0, time.UTC), + gomod: "module vcs-test.golang.org/go/v2module/v2\n\ngo 1.12\n", + zipSum: "h1:JItBZ+gwA5WvtZEGEbuDL4lUttGtLrs53lmdurq3bOg=", + zipFileHash: "9ea9ae1673cffcc44b7fdd3cc89953d68c102449b46c982dbf085e4f2e394da5", + }, +} + +func TestCodeRepo(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + tmpdir, err := os.MkdirTemp("", "modfetch-test-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpdir) + + t.Run("parallel", func(t *testing.T) { + for _, tt := range codeRepoTests { + f := func(tt codeRepoTest) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + if tt.vcs != "mod" { + testenv.MustHaveExecPath(t, tt.vcs) + } + + repo := Lookup("direct", tt.path) + + 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) + } + } + + needHash := !testing.Short() && (tt.zipFileHash != "" || tt.zipSum != "") + if tt.zip != nil || tt.zipErr != "" || needHash { + f, err := os.CreateTemp(tmpdir, tt.version+".zip.") + if err != nil { + t.Fatalf("os.CreateTemp: %v", err) + } + zipfile := f.Name() + defer func() { + f.Close() + os.Remove(zipfile) + }() + + var w io.Writer + var h hash.Hash + if needHash { + h = sha256.New() + w = io.MultiWriter(f, h) + } else { + w = f + } + err = repo.Zip(w, tt.version) + f.Close() + 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) + } + + if tt.zip != nil { + 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) + } + } + + if needHash { + sum, err := dirhash.HashZip(zipfile, dirhash.Hash1) + if err != nil { + t.Errorf("repo.Zip(%q): %v", tt.version, err) + } else if sum != tt.zipSum { + t.Errorf("repo.Zip(%q): got file with sum %q, want %q", tt.version, sum, tt.zipSum) + } else if zipFileHash := hex.EncodeToString(h.Sum(nil)); zipFileHash != tt.zipFileHash { + t.Errorf("repo.Zip(%q): got file with hash %q, want %q (but content has correct sum)", tt.version, zipFileHash, tt.zipFileHash) + } + } + } + } + } + t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.rev, f(tt)) + if strings.HasPrefix(tt.path, vgotest1git) { + for vcs, alt := range altVgotests { + altTest := tt + altTest.vcs = vcs + altTest.path = alt + strings.TrimPrefix(altTest.path, vgotest1git) + if strings.HasPrefix(altTest.mpath, vgotest1git) { + altTest.mpath = alt + strings.TrimPrefix(altTest.mpath, vgotest1git) + } + var m map[string]string + if alt == vgotest1hg { + m = hgmap + } + altTest.version = remap(altTest.version, m) + altTest.name = remap(altTest.name, m) + altTest.short = remap(altTest.short, m) + altTest.rev = remap(altTest.rev, m) + altTest.err = remap(altTest.err, m) + altTest.gomodErr = remap(altTest.gomodErr, m) + altTest.zipErr = remap(altTest.zipErr, m) + altTest.zipSum = "" + altTest.zipFileHash = "" + t.Run(strings.ReplaceAll(altTest.path, "/", "_")+"/"+altTest.rev, f(altTest)) + } + } + } + }) +} + +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.ReplaceAll(name, k, v) + if codehost.AllHex(k) { + name = strings.ReplaceAll(name, k[:12], v[:12]) + } + } + return name +} + +var codeRepoVersionsTests = []struct { + vcs string + path string + prefix string + versions []string +}{ + { + vcs: "git", + 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"}, + }, + { + vcs: "git", + path: "github.com/rsc/vgotest1", + prefix: "v1.0", + versions: []string{"v1.0.0", "v1.0.1", "v1.0.2", "v1.0.3"}, + }, + { + vcs: "git", + 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"}, + }, + { + vcs: "mod", + path: "swtch.com/testmod", + versions: []string{"v1.0.0", "v1.1.1"}, + }, + { + vcs: "git", + path: "gopkg.in/natefinch/lumberjack.v2", + versions: []string{"v2.0.0"}, + }, +} + +func TestCodeRepoVersions(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + tmpdir, err := os.MkdirTemp("", "vgo-modfetch-test-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpdir) + + t.Run("parallel", func(t *testing.T) { + for _, tt := range codeRepoVersionsTests { + t.Run(strings.ReplaceAll(tt.path, "/", "_"), func(t *testing.T) { + tt := tt + t.Parallel() + if tt.vcs != "mod" { + testenv.MustHaveExecPath(t, tt.vcs) + } + + repo := Lookup("direct", tt.path) + 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 { + vcs string + path string + version string + err string +}{ + { + vcs: "git", + path: "github.com/rsc/empty", + err: "no commits", + }, + { + vcs: "git", + path: "github.com/rsc/vgotest1", + err: `github.com/rsc/vgotest1@v0.0.0-20180219223237-a08abb797a67: invalid version: go.mod has post-v0 module path "github.com/vgotest1/v2" at revision a08abb797a67`, + }, + { + vcs: "git", + path: "github.com/rsc/vgotest1/v2", + err: `github.com/rsc/vgotest1/v2@v2.0.0-20180219223237-a08abb797a67: invalid version: github.com/rsc/vgotest1/go.mod and .../v2/go.mod both have .../v2 module paths at revision a08abb797a67`, + }, + { + vcs: "git", + path: "github.com/rsc/vgotest1/subdir", + err: "github.com/rsc/vgotest1/subdir@v0.0.0-20180219223237-a08abb797a67: invalid version: missing github.com/rsc/vgotest1/subdir/go.mod at revision a08abb797a67", + }, + { + vcs: "git", + path: "vcs-test.golang.org/git/commit-after-tag.git", + version: "v1.0.1-0.20190715211727-b325d8217783", + }, + { + vcs: "git", + path: "vcs-test.golang.org/git/no-tags.git", + version: "v0.0.0-20190715212047-e706ba1d9f6d", + }, + { + vcs: "mod", + path: "swtch.com/testmod", + version: "v1.1.1", + }, +} + +func TestLatest(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + tmpdir, err := os.MkdirTemp("", "vgo-modfetch-test-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpdir) + + t.Run("parallel", func(t *testing.T) { + for _, tt := range latestTests { + name := strings.ReplaceAll(tt.path, "/", "_") + t.Run(name, func(t *testing.T) { + tt := tt + t.Parallel() + if tt.vcs != "mod" { + testenv.MustHaveExecPath(t, tt.vcs) + } + + repo := Lookup("direct", tt.path) + 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 + codehost.Repo +} + +func (ch *fixedTagsRepo) Tags(string) ([]string, error) { return ch.tags, nil } + +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/src/cmd/go/internal/modfetch/fetch.go b/src/cmd/go/internal/modfetch/fetch.go new file mode 100644 index 0000000..eb7d30e --- /dev/null +++ b/src/cmd/go/internal/modfetch/fetch.go @@ -0,0 +1,844 @@ +// 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" + "context" + "errors" + "fmt" + "io" + "io/fs" + "os" + "path/filepath" + "sort" + "strings" + "sync" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/lockedfile" + "cmd/go/internal/par" + "cmd/go/internal/renameio" + "cmd/go/internal/robustio" + "cmd/go/internal/trace" + + "golang.org/x/mod/module" + "golang.org/x/mod/sumdb/dirhash" + modzip "golang.org/x/mod/zip" +) + +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(ctx context.Context, mod module.Version) (dir string, err error) { + if cfg.GOMODCACHE == "" { + // modload.Init exits if GOPATH[0] is empty, and cfg.GOMODCACHE + // is set to GOPATH[0]/pkg/mod if GOMODCACHE is empty, so this should never happen. + base.Fatalf("go: internal error: cfg.GOMODCACHE not set") + } + + // The par.Cache here avoids duplicate work. + type cached struct { + dir string + err error + } + c := downloadCache.Do(mod, func() interface{} { + dir, err := download(ctx, mod) + if err != nil { + return cached{"", err} + } + checkMod(mod) + return cached{dir, nil} + }).(cached) + return c.dir, c.err +} + +func download(ctx context.Context, mod module.Version) (dir string, err error) { + ctx, span := trace.StartSpan(ctx, "modfetch.download "+mod.String()) + defer span.Done() + + dir, err = DownloadDir(mod) + if err == nil { + // The directory has already been completely extracted (no .partial file exists). + return dir, nil + } else if dir == "" || !errors.Is(err, fs.ErrNotExist) { + return "", err + } + + // To avoid cluttering the cache with extraneous files, + // DownloadZip uses the same lockfile as Download. + // Invoke DownloadZip before locking the file. + zipfile, err := DownloadZip(ctx, mod) + if err != nil { + return "", err + } + + unlock, err := lockVersion(mod) + if err != nil { + return "", err + } + defer unlock() + + ctx, span = trace.StartSpan(ctx, "unzip "+zipfile) + defer span.Done() + + // Check whether the directory was populated while we were waiting on the lock. + _, dirErr := DownloadDir(mod) + if dirErr == nil { + return dir, nil + } + _, dirExists := dirErr.(*DownloadDirPartialError) + + // Clean up any remaining temporary directories created by old versions + // (before 1.16), as well as partially extracted directories (indicated by + // DownloadDirPartialError, usually because of a .partial file). This is only + // safe to do because the lock file ensures that their writers are no longer + // active. + parentDir := filepath.Dir(dir) + tmpPrefix := filepath.Base(dir) + ".tmp-" + if old, err := filepath.Glob(filepath.Join(parentDir, tmpPrefix+"*")); err == nil { + for _, path := range old { + RemoveAll(path) // best effort + } + } + if dirExists { + if err := RemoveAll(dir); err != nil { + return "", err + } + } + + partialPath, err := CachePath(mod, "partial") + if err != nil { + return "", err + } + + // Extract the module zip directory at its final location. + // + // To prevent other processes from reading the directory if we crash, + // create a .partial file before extracting the directory, and delete + // the .partial file afterward (all while holding the lock). + // + // Before Go 1.16, we extracted to a temporary directory with a random name + // then renamed it into place with os.Rename. On Windows, this failed with + // ERROR_ACCESS_DENIED when another process (usually an anti-virus scanner) + // opened files in the temporary directory. + // + // Go 1.14.2 and higher respect .partial files. Older versions may use + // partially extracted directories. 'go mod verify' can detect this, + // and 'go clean -modcache' can fix it. + if err := os.MkdirAll(parentDir, 0777); err != nil { + return "", err + } + if err := os.WriteFile(partialPath, nil, 0666); err != nil { + return "", err + } + if err := modzip.Unzip(dir, mod, zipfile); err != nil { + fmt.Fprintf(os.Stderr, "-> %s\n", err) + if rmErr := RemoveAll(dir); rmErr == nil { + os.Remove(partialPath) + } + return "", err + } + if err := os.Remove(partialPath); err != nil { + return "", err + } + + if !cfg.ModCacheRW { + makeDirsReadOnly(dir) + } + return dir, nil +} + +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(ctx context.Context, mod module.Version) (zipfile string, err error) { + // The par.Cache here avoids duplicate work. + type cached struct { + zipfile string + err error + } + c := downloadZipCache.Do(mod, func() interface{} { + zipfile, err := CachePath(mod, "zip") + if err != nil { + return cached{"", err} + } + ziphashfile := zipfile + "hash" + + // Return without locking if the zip and ziphash files exist. + if _, err := os.Stat(zipfile); err == nil { + if _, err := os.Stat(ziphashfile); err == nil { + return cached{zipfile, nil} + } + } + + // The zip or ziphash file does not exist. Acquire the lock and create them. + if cfg.CmdName != "mod download" { + fmt.Fprintf(os.Stderr, "go: downloading %s %s\n", mod.Path, mod.Version) + } + unlock, err := lockVersion(mod) + if err != nil { + return cached{"", err} + } + defer unlock() + + if err := downloadZip(ctx, mod, zipfile); err != nil { + return cached{"", err} + } + return cached{zipfile, nil} + }).(cached) + return c.zipfile, c.err +} + +func downloadZip(ctx context.Context, mod module.Version, zipfile string) (err error) { + ctx, span := trace.StartSpan(ctx, "modfetch.downloadZip "+zipfile) + defer span.Done() + + // Double-check that the zipfile was not created while we were waiting for + // the lock in DownloadZip. + ziphashfile := zipfile + "hash" + var zipExists, ziphashExists bool + if _, err := os.Stat(zipfile); err == nil { + zipExists = true + } + if _, err := os.Stat(ziphashfile); err == nil { + ziphashExists = true + } + if zipExists && ziphashExists { + return nil + } + + // Create parent directories. + if err := os.MkdirAll(filepath.Dir(zipfile), 0777); err != nil { + return err + } + + // Clean up any remaining tempfiles from previous runs. + // This is only safe to do because the lock file ensures that their + // writers are no longer active. + for _, base := range []string{zipfile, zipfile + "hash"} { + if old, err := filepath.Glob(renameio.Pattern(base)); err == nil { + for _, path := range old { + os.Remove(path) // best effort + } + } + } + + // If the zip file exists, the ziphash file must have been deleted + // or lost after a file system crash. Re-hash the zip without downloading. + if zipExists { + return hashZip(mod, zipfile, ziphashfile) + } + + // From here to the os.Rename call below is functionally almost equivalent to + // renameio.WriteToFile, with one key difference: we want to validate the + // contents of the file (by hashing it) before we commit it. Because the file + // is zip-compressed, we need an actual file — or at least an io.ReaderAt — to + // validate it: we can't just tee the stream as we write it. + f, err := os.CreateTemp(filepath.Dir(zipfile), filepath.Base(renameio.Pattern(zipfile))) + if err != nil { + return err + } + defer func() { + if err != nil { + f.Close() + os.Remove(f.Name()) + } + }() + + var unrecoverableErr error + err = TryProxies(func(proxy string) error { + if unrecoverableErr != nil { + return unrecoverableErr + } + repo := Lookup(proxy, mod.Path) + err := repo.Zip(f, mod.Version) + if err != nil { + // Zip may have partially written to f before failing. + // (Perhaps the server crashed while sending the file?) + // Since we allow fallback on error in some cases, we need to fix up the + // file to be empty again for the next attempt. + if _, err := f.Seek(0, io.SeekStart); err != nil { + unrecoverableErr = err + return err + } + if err := f.Truncate(0); err != nil { + unrecoverableErr = err + return err + } + } + return err + }) + if err != nil { + return err + } + + // Double-check that the paths within the zip file are well-formed. + // + // TODO(bcmills): There is a similar check within the Unzip function. Can we eliminate one? + fi, err := f.Stat() + if err != nil { + return err + } + z, err := zip.NewReader(f, fi.Size()) + if err != nil { + return err + } + prefix := mod.Path + "@" + mod.Version + "/" + for _, f := range z.File { + if !strings.HasPrefix(f.Name, prefix) { + return fmt.Errorf("zip for %s has unexpected file %s", prefix[:len(prefix)-1], f.Name) + } + } + + // Sync the file before renaming it: otherwise, after a crash the reader may + // observe a 0-length file instead of the actual contents. + // See https://golang.org/issue/22397#issuecomment-380831736. + if err := f.Sync(); err != nil { + return err + } + if err := f.Close(); err != nil { + return err + } + + // Hash the zip file and check the sum before renaming to the final location. + if err := hashZip(mod, f.Name(), ziphashfile); err != nil { + return err + } + if err := os.Rename(f.Name(), zipfile); err != nil { + return err + } + + // TODO(bcmills): Should we make the .zip and .ziphash files read-only to discourage tampering? + + return nil +} + +// hashZip reads the zip file opened in f, then writes the hash to ziphashfile, +// overwriting that file if it exists. +// +// If the hash does not match go.sum (or the sumdb if enabled), hashZip returns +// an error and does not write ziphashfile. +func hashZip(mod module.Version, zipfile, ziphashfile string) error { + hash, err := dirhash.HashZip(zipfile, dirhash.DefaultHash) + if err != nil { + return err + } + if err := checkModSum(mod, hash); err != nil { + return err + } + return renameio.WriteFile(ziphashfile, []byte(hash), 0666) +} + +// makeDirsReadOnly makes a best-effort attempt to remove write permissions for dir +// and its transitive contents. +func makeDirsReadOnly(dir string) { + type pathMode struct { + path string + mode fs.FileMode + } + var dirs []pathMode // in lexical order + filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error { + if err == nil && d.IsDir() { + info, err := d.Info() + if err == nil && info.Mode()&0222 != 0 { + dirs = append(dirs, pathMode{path, info.Mode()}) + } + } + return nil + }) + + // Run over list backward to chmod children before parents. + for i := len(dirs) - 1; i >= 0; i-- { + os.Chmod(dirs[i].path, dirs[i].mode&^0222) + } +} + +// RemoveAll removes a directory written by Download or Unzip, first applying +// any permission changes needed to do so. +func RemoveAll(dir string) error { + // Module cache has 0555 directories; make them writable in order to remove content. + filepath.WalkDir(dir, func(path string, info fs.DirEntry, err error) error { + if err != nil { + return nil // ignore errors walking in file system + } + if info.IsDir() { + os.Chmod(path, 0777) + } + return nil + }) + return robustio.RemoveAll(dir) +} + +var GoSumFile string // path to go.sum; set by package modload + +type modSum struct { + mod module.Version + sum string +} + +var goSum struct { + mu sync.Mutex + m map[module.Version][]string // content of go.sum file + status map[modSum]modSumStatus // state of sums in m + overwrite bool // if true, overwrite go.sum without incorporating its contents + enabled bool // whether to use go.sum at all +} + +type modSumStatus struct { + used, dirty bool +} + +// initGoSum initializes the go.sum data. +// The boolean it returns reports whether the +// use of go.sum is now enabled. +// The goSum lock must be held. +func initGoSum() (bool, error) { + if GoSumFile == "" { + return false, nil + } + if goSum.m != nil { + return true, nil + } + + goSum.m = make(map[module.Version][]string) + goSum.status = make(map[modSum]modSumStatus) + data, err := lockedfile.Read(GoSumFile) + if err != nil && !os.IsNotExist(err) { + return false, err + } + goSum.enabled = true + readGoSum(goSum.m, GoSumFile, data) + + return true, nil +} + +// 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(dst map[module.Version][]string, file string, data []byte) error { + 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 { + return fmt.Errorf("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]} + dst[mod] = append(dst[mod], f[2]) + } + return nil +} + +// HaveSum returns true if the go.sum file contains an entry for mod. +// The entry's hash must be generated with a known hash algorithm. +// mod.Version may have a "/go.mod" suffix to distinguish sums for +// .mod and .zip files. +func HaveSum(mod module.Version) bool { + goSum.mu.Lock() + defer goSum.mu.Unlock() + inited, err := initGoSum() + if err != nil || !inited { + return false + } + for _, h := range goSum.m[mod] { + if !strings.HasPrefix(h, "h1:") { + continue + } + if !goSum.status[modSum{mod, h}].dirty { + return true + } + } + return false +} + +// checkMod checks the given module's checksum. +func checkMod(mod module.Version) { + // Do the file I/O before acquiring the go.sum lock. + ziphash, err := CachePath(mod, "ziphash") + if err != nil { + base.Fatalf("verifying %v", module.VersionError(mod, err)) + } + data, err := renameio.ReadFile(ziphash) + if err != nil { + base.Fatalf("verifying %v", module.VersionError(mod, err)) + } + h := strings.TrimSpace(string(data)) + if !strings.HasPrefix(h, "h1:") { + base.Fatalf("verifying %v", module.VersionError(mod, fmt.Errorf("unexpected ziphash: %q", h))) + } + + if err := checkModSum(mod, h); err != nil { + base.Fatalf("%s", err) + } +} + +// 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 io.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) error { + h, err := goModSum(data) + if err != nil { + return &module.ModuleError{Path: path, Version: version, Err: fmt.Errorf("verifying go.mod: %v", err)} + } + + return checkModSum(module.Version{Path: path, Version: version + "/go.mod"}, h) +} + +// checkModSum checks that the recorded checksum for mod is h. +// +// mod.Version may have the additional suffix "/go.mod" to request the checksum +// for the module's go.mod file only. +func checkModSum(mod module.Version, h string) error { + // We lock goSum when manipulating it, + // but we arrange to release the lock when calling checkSumDB, + // so that parallel calls to checkModHash can execute parallel calls + // to checkSumDB. + + // Check whether mod+h is listed in go.sum already. If so, we're done. + goSum.mu.Lock() + inited, err := initGoSum() + if err != nil { + goSum.mu.Unlock() + return err + } + done := inited && haveModSumLocked(mod, h) + if inited { + st := goSum.status[modSum{mod, h}] + st.used = true + goSum.status[modSum{mod, h}] = st + } + goSum.mu.Unlock() + + if done { + return nil + } + + // Not listed, so we want to add them. + // Consult checksum database if appropriate. + if useSumDB(mod) { + // Calls base.Fatalf if mismatch detected. + if err := checkSumDB(mod, h); err != nil { + return err + } + } + + // Add mod+h to go.sum, if it hasn't appeared already. + if inited { + goSum.mu.Lock() + addModSumLocked(mod, h) + st := goSum.status[modSum{mod, h}] + st.dirty = true + goSum.status[modSum{mod, h}] = st + goSum.mu.Unlock() + } + return nil +} + +// haveModSumLocked reports whether the pair mod,h is already listed in go.sum. +// If it finds a conflicting pair instead, it calls base.Fatalf. +// goSum.mu must be locked. +func haveModSumLocked(mod module.Version, h string) bool { + for _, vh := range goSum.m[mod] { + if h == vh { + return true + } + if strings.HasPrefix(vh, "h1:") { + base.Fatalf("verifying %s@%s: checksum mismatch\n\tdownloaded: %v\n\tgo.sum: %v"+goSumMismatch, mod.Path, mod.Version, h, vh) + } + } + return false +} + +// addModSumLocked adds the pair mod,h to go.sum. +// goSum.mu must be locked. +func addModSumLocked(mod module.Version, h string) { + if haveModSumLocked(mod, h) { + return + } + if len(goSum.m[mod]) > 0 { + fmt.Fprintf(os.Stderr, "warning: verifying %s@%s: unknown hashes in go.sum: %v; adding %v"+hashVersionMismatch, mod.Path, mod.Version, strings.Join(goSum.m[mod], ", "), h) + } + goSum.m[mod] = append(goSum.m[mod], h) +} + +// checkSumDB checks the mod, h pair against the Go checksum database. +// It calls base.Fatalf if the hash is to be rejected. +func checkSumDB(mod module.Version, h string) error { + modWithoutSuffix := mod + noun := "module" + if strings.HasSuffix(mod.Version, "/go.mod") { + noun = "go.mod" + modWithoutSuffix.Version = strings.TrimSuffix(mod.Version, "/go.mod") + } + + db, lines, err := lookupSumDB(mod) + if err != nil { + return module.VersionError(modWithoutSuffix, fmt.Errorf("verifying %s: %v", noun, err)) + } + + have := mod.Path + " " + mod.Version + " " + h + prefix := mod.Path + " " + mod.Version + " h1:" + for _, line := range lines { + if line == have { + return nil + } + if strings.HasPrefix(line, prefix) { + return module.VersionError(modWithoutSuffix, fmt.Errorf("verifying %s: checksum mismatch\n\tdownloaded: %v\n\t%s: %v"+sumdbMismatch, noun, h, db, line[len(prefix)-len("h1:"):])) + } + } + return nil +} + +// 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 cfg.GOMODCACHE == "" { + // Do not use current directory. + return "" + } + + ziphash, err := CachePath(mod, "ziphash") + if err != nil { + return "" + } + data, err := renameio.ReadFile(ziphash) + if err != nil { + return "" + } + return strings.TrimSpace(string(data)) +} + +// WriteGoSum writes the go.sum file if it needs to be updated. +// +// keep is used to check whether a newly added sum should be saved in go.sum. +// It should have entries for both module content sums and go.mod sums +// (version ends with "/go.mod"). Existing sums will be preserved unless they +// have been marked for deletion with TrimGoSum. +func WriteGoSum(keep map[module.Version]bool) { + goSum.mu.Lock() + defer goSum.mu.Unlock() + + // If we haven't read the go.sum file yet, don't bother writing it. + if !goSum.enabled { + return + } + + // Check whether we need to add sums for which keep[m] is true or remove + // unused sums marked with TrimGoSum. If there are no changes to make, + // just return without opening go.sum. + dirty := false +Outer: + for m, hs := range goSum.m { + for _, h := range hs { + st := goSum.status[modSum{m, h}] + if st.dirty && (!st.used || keep[m]) { + dirty = true + break Outer + } + } + } + if !dirty { + return + } + if cfg.BuildMod == "readonly" { + base.Fatalf("go: updates to go.sum needed, disabled by -mod=readonly") + } + + // Make a best-effort attempt to acquire the side lock, only to exclude + // previous versions of the 'go' command from making simultaneous edits. + if unlock, err := SideLock(); err == nil { + defer unlock() + } + + err := lockedfile.Transform(GoSumFile, func(data []byte) ([]byte, error) { + if !goSum.overwrite { + // Incorporate any sums added by other processes in the meantime. + // Add only the sums that we actually checked: the user may have edited or + // truncated the file to remove erroneous hashes, and we shouldn't restore + // them without good reason. + goSum.m = make(map[module.Version][]string, len(goSum.m)) + readGoSum(goSum.m, GoSumFile, data) + for ms, st := range goSum.status { + if st.used { + addModSumLocked(ms.mod, ms.sum) + } + } + } + + 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 { + st := goSum.status[modSum{m, h}] + if !st.dirty || (st.used && keep[m]) { + fmt.Fprintf(&buf, "%s %s %s\n", m.Path, m.Version, h) + } + } + } + return buf.Bytes(), nil + }) + + if err != nil { + base.Fatalf("go: updating go.sum: %v", err) + } + + goSum.status = make(map[modSum]modSumStatus) + goSum.overwrite = false +} + +// TrimGoSum trims go.sum to contain only the modules needed for reproducible +// builds. +// +// keep is used to check whether a sum should be retained in go.mod. It should +// have entries for both module content sums and go.mod sums (version ends +// with "/go.mod"). +func TrimGoSum(keep map[module.Version]bool) { + goSum.mu.Lock() + defer goSum.mu.Unlock() + inited, err := initGoSum() + if err != nil { + base.Fatalf("%s", err) + } + if !inited { + return + } + + for m, hs := range goSum.m { + if !keep[m] { + for _, h := range hs { + goSum.status[modSum{m, h}] = modSumStatus{used: false, dirty: true} + } + goSum.overwrite = true + } + } +} + +const goSumMismatch = ` + +SECURITY ERROR +This download does NOT match an earlier download recorded in go.sum. +The bits may have been replaced on the origin server, or an attacker may +have intercepted the download attempt. + +For more information, see 'go help module-auth'. +` + +const sumdbMismatch = ` + +SECURITY ERROR +This download does NOT match the one reported by the checksum server. +The bits may have been replaced on the origin server, or an attacker may +have intercepted the download attempt. + +For more information, see 'go help module-auth'. +` + +const hashVersionMismatch = ` + +SECURITY WARNING +This download is listed in go.sum, but using an unknown hash algorithm. +The download cannot be verified. + +For more information, see 'go help module-auth'. + +` + +var HelpModuleAuth = &base.Command{ + UsageLine: "module-auth", + Short: "module authentication using go.sum", + Long: ` +When the go command downloads a module zip file or go.mod file into the +module cache, it computes a cryptographic hash and compares it with a known +value to verify the file hasn't changed since it was first downloaded. Known +hashes are stored in a file in the module root directory named go.sum. Hashes +may also be downloaded from the checksum database depending on the values of +GOSUMDB, GOPRIVATE, and GONOSUMDB. + +For details, see https://golang.org/ref/mod#authenticating. +`, +} + +var HelpPrivate = &base.Command{ + UsageLine: "private", + Short: "configuration for downloading non-public code", + Long: ` +The go command defaults to downloading modules from the public Go module +mirror at proxy.golang.org. It also defaults to validating downloaded modules, +regardless of source, against the public Go checksum database at sum.golang.org. +These defaults work well for publicly available source code. + +The GOPRIVATE environment variable controls which modules the go command +considers to be private (not available publicly) and should therefore not use +the proxy or checksum database. The variable is a comma-separated list of +glob patterns (in the syntax of Go's path.Match) of module path prefixes. +For example, + + GOPRIVATE=*.corp.example.com,rsc.io/private + +causes the go command to treat as private any module with a path prefix +matching either pattern, including git.corp.example.com/xyzzy, rsc.io/private, +and rsc.io/private/quux. + +For fine-grained control over module download and validation, the GONOPROXY +and GONOSUMDB environment variables accept the same kind of glob list +and override GOPRIVATE for the specific decision of whether to use the proxy +and checksum database, respectively. + +For example, if a company ran a module proxy serving private modules, +users would configure go using: + + GOPRIVATE=*.corp.example.com + GOPROXY=proxy.example.com + GONOPROXY=none + +The GOPRIVATE variable is also used to define the "public" and "private" +patterns for the GOVCS variable; see 'go help vcs'. For that usage, +GOPRIVATE applies even in GOPATH mode. In that case, it matches import paths +instead of module paths. + +The 'go env -w' command (see 'go help env') can be used to set these variables +for future go command invocations. + +For more details, see https://golang.org/ref/mod#private-modules. +`, +} diff --git a/src/cmd/go/internal/modfetch/insecure.go b/src/cmd/go/internal/modfetch/insecure.go new file mode 100644 index 0000000..012d05f --- /dev/null +++ b/src/cmd/go/internal/modfetch/insecure.go @@ -0,0 +1,16 @@ +// 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 ( + "cmd/go/internal/cfg" + + "golang.org/x/mod/module" +) + +// allowInsecure reports whether we are allowed to fetch this path in an insecure manner. +func allowInsecure(path string) bool { + return cfg.Insecure || module.MatchPrefixPatterns(cfg.GOINSECURE, path) +} diff --git a/src/cmd/go/internal/modfetch/key.go b/src/cmd/go/internal/modfetch/key.go new file mode 100644 index 0000000..06f9989 --- /dev/null +++ b/src/cmd/go/internal/modfetch/key.go @@ -0,0 +1,9 @@ +// Copyright 2019 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 + +var knownGOSUMDB = map[string]string{ + "sum.golang.org": "sum.golang.org+033de0ae+Ac4zctda0e5eza+HJyk9SxEdh+s3Ux18htTTAD8OuAn8", +} diff --git a/src/cmd/go/internal/modfetch/proxy.go b/src/cmd/go/internal/modfetch/proxy.go new file mode 100644 index 0000000..6c86d8d --- /dev/null +++ b/src/cmd/go/internal/modfetch/proxy.go @@ -0,0 +1,431 @@ +// 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" + "errors" + "fmt" + "io" + "io/fs" + "net/url" + "path" + pathpkg "path" + "path/filepath" + "strings" + "sync" + "time" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/modfetch/codehost" + "cmd/go/internal/web" + + "golang.org/x/mod/module" + "golang.org/x/mod/semver" +) + +var HelpGoproxy = &base.Command{ + UsageLine: "goproxy", + Short: "module proxy protocol", + Long: ` +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. + +For details on the GOPROXY protocol, see +https://golang.org/ref/mod#goproxy-protocol. +`, +} + +var proxyOnce struct { + sync.Once + list []proxySpec + err error +} + +type proxySpec struct { + // url is the proxy URL or one of "off", "direct", "noproxy". + url string + + // fallBackOnError is true if a request should be attempted on the next proxy + // in the list after any error from this proxy. If fallBackOnError is false, + // the request will only be attempted on the next proxy if the error is + // equivalent to os.ErrNotFound, which is true for 404 and 410 responses. + fallBackOnError bool +} + +func proxyList() ([]proxySpec, error) { + proxyOnce.Do(func() { + if cfg.GONOPROXY != "" && cfg.GOPROXY != "direct" { + proxyOnce.list = append(proxyOnce.list, proxySpec{url: "noproxy"}) + } + + goproxy := cfg.GOPROXY + for goproxy != "" { + var url string + fallBackOnError := false + if i := strings.IndexAny(goproxy, ",|"); i >= 0 { + url = goproxy[:i] + fallBackOnError = goproxy[i] == '|' + goproxy = goproxy[i+1:] + } else { + url = goproxy + goproxy = "" + } + + url = strings.TrimSpace(url) + if url == "" { + continue + } + if url == "off" { + // "off" always fails hard, so can stop walking list. + proxyOnce.list = append(proxyOnce.list, proxySpec{url: "off"}) + break + } + if url == "direct" { + proxyOnce.list = append(proxyOnce.list, proxySpec{url: "direct"}) + // For now, "direct" is the end of the line. We may decide to add some + // sort of fallback behavior for them in the future, so ignore + // subsequent entries for forward-compatibility. + break + } + + // Single-word tokens are reserved for built-in behaviors, and anything + // containing the string ":/" or matching an absolute file path must be a + // complete URL. For all other paths, implicitly add "https://". + if strings.ContainsAny(url, ".:/") && !strings.Contains(url, ":/") && !filepath.IsAbs(url) && !path.IsAbs(url) { + url = "https://" + url + } + + // Check that newProxyRepo accepts the URL. + // It won't do anything with the path. + if _, err := newProxyRepo(url, "golang.org/x/text"); err != nil { + proxyOnce.err = err + return + } + + proxyOnce.list = append(proxyOnce.list, proxySpec{ + url: url, + fallBackOnError: fallBackOnError, + }) + } + + if len(proxyOnce.list) == 0 || + len(proxyOnce.list) == 1 && proxyOnce.list[0].url == "noproxy" { + // There were no proxies, other than the implicit "noproxy" added when + // GONOPROXY is set. This can happen if GOPROXY is a non-empty string + // like "," or " ". + proxyOnce.err = fmt.Errorf("GOPROXY list is not the empty string, but contains no entries") + } + }) + + return proxyOnce.list, proxyOnce.err +} + +// TryProxies iterates f over each configured proxy (including "noproxy" and +// "direct" if applicable) until f returns no error or until f returns an +// error that is not equivalent to fs.ErrNotExist on a proxy configured +// not to fall back on errors. +// +// TryProxies then returns that final error. +// +// If GOPROXY is set to "off", TryProxies invokes f once with the argument +// "off". +func TryProxies(f func(proxy string) error) error { + proxies, err := proxyList() + if err != nil { + return err + } + if len(proxies) == 0 { + panic("GOPROXY list is empty") + } + + // We try to report the most helpful error to the user. "direct" and "noproxy" + // errors are best, followed by proxy errors other than ErrNotExist, followed + // by ErrNotExist. + // + // Note that errProxyOff, errNoproxy, and errUseProxy are equivalent to + // ErrNotExist. errUseProxy should only be returned if "noproxy" is the only + // proxy. errNoproxy should never be returned, since there should always be a + // more useful error from "noproxy" first. + const ( + notExistRank = iota + proxyRank + directRank + ) + var bestErr error + bestErrRank := notExistRank + for _, proxy := range proxies { + err := f(proxy.url) + if err == nil { + return nil + } + isNotExistErr := errors.Is(err, fs.ErrNotExist) + + if proxy.url == "direct" || (proxy.url == "noproxy" && err != errUseProxy) { + bestErr = err + bestErrRank = directRank + } else if bestErrRank <= proxyRank && !isNotExistErr { + bestErr = err + bestErrRank = proxyRank + } else if bestErrRank == notExistRank { + bestErr = err + } + + if !proxy.fallBackOnError && !isNotExistErr { + break + } + } + return bestErr +} + +type proxyRepo struct { + url *url.URL + path string + redactedURL string +} + +func newProxyRepo(baseURL, path string) (Repo, error) { + base, err := url.Parse(baseURL) + if err != nil { + return nil, err + } + switch base.Scheme { + case "http", "https": + // ok + case "file": + if *base != (url.URL{Scheme: base.Scheme, Path: base.Path, RawPath: base.RawPath}) { + return nil, fmt.Errorf("invalid file:// proxy URL with non-path elements: %s", base.Redacted()) + } + case "": + return nil, fmt.Errorf("invalid proxy URL missing scheme: %s", base.Redacted()) + default: + return nil, fmt.Errorf("invalid proxy URL scheme (must be https, http, file): %s", base.Redacted()) + } + + enc, err := module.EscapePath(path) + if err != nil { + return nil, err + } + redactedURL := base.Redacted() + base.Path = strings.TrimSuffix(base.Path, "/") + "/" + enc + base.RawPath = strings.TrimSuffix(base.RawPath, "/") + "/" + pathEscape(enc) + return &proxyRepo{base, path, redactedURL}, nil +} + +func (p *proxyRepo) ModulePath() string { + return p.path +} + +// versionError returns err wrapped in a ModuleError for p.path. +func (p *proxyRepo) versionError(version string, err error) error { + if version != "" && version != module.CanonicalVersion(version) { + return &module.ModuleError{ + Path: p.path, + Err: &module.InvalidVersionError{ + Version: version, + Pseudo: IsPseudoVersion(version), + Err: err, + }, + } + } + + return &module.ModuleError{ + Path: p.path, + Version: version, + Err: err, + } +} + +func (p *proxyRepo) getBytes(path string) ([]byte, error) { + body, err := p.getBody(path) + if err != nil { + return nil, err + } + defer body.Close() + return io.ReadAll(body) +} + +func (p *proxyRepo) getBody(path string) (io.ReadCloser, error) { + fullPath := pathpkg.Join(p.url.Path, path) + + target := *p.url + target.Path = fullPath + target.RawPath = pathpkg.Join(target.RawPath, pathEscape(path)) + + resp, err := web.Get(web.DefaultSecurity, &target) + if err != nil { + return nil, err + } + if err := resp.Err(); err != nil { + resp.Body.Close() + return nil, err + } + return resp.Body, nil +} + +func (p *proxyRepo) Versions(prefix string) ([]string, error) { + data, err := p.getBytes("@v/list") + if err != nil { + return nil, p.versionError("", 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) && !IsPseudoVersion(f[0]) { + list = append(list, f[0]) + } + } + SortVersions(list) + return list, nil +} + +func (p *proxyRepo) latest() (*RevInfo, error) { + data, err := p.getBytes("@v/list") + if err != nil { + return nil, p.versionError("", err) + } + + var ( + bestTime time.Time + bestTimeIsFromPseudo bool + bestVersion string + ) + + for _, line := range strings.Split(string(data), "\n") { + f := strings.Fields(line) + if len(f) >= 1 && semver.IsValid(f[0]) { + // If the proxy includes timestamps, prefer the timestamp it reports. + // Otherwise, derive the timestamp from the pseudo-version. + var ( + ft time.Time + ftIsFromPseudo = false + ) + if len(f) >= 2 { + ft, _ = time.Parse(time.RFC3339, f[1]) + } else if IsPseudoVersion(f[0]) { + ft, _ = PseudoVersionTime(f[0]) + ftIsFromPseudo = true + } else { + // Repo.Latest promises that this method is only called where there are + // no tagged versions. Ignore any tagged versions that were added in the + // meantime. + continue + } + if bestTime.Before(ft) { + bestTime = ft + bestTimeIsFromPseudo = ftIsFromPseudo + bestVersion = f[0] + } + } + } + if bestVersion == "" { + return nil, p.versionError("", codehost.ErrNoCommits) + } + + if bestTimeIsFromPseudo { + // We parsed bestTime from the pseudo-version, but that's in UTC and we're + // supposed to report the timestamp as reported by the VCS. + // Stat the selected version to canonicalize the timestamp. + // + // TODO(bcmills): Should we also stat other versions to ensure that we + // report the correct Name and Short for the revision? + return p.Stat(bestVersion) + } + + return &RevInfo{ + Version: bestVersion, + Name: bestVersion, + Short: bestVersion, + Time: bestTime, + }, nil +} + +func (p *proxyRepo) Stat(rev string) (*RevInfo, error) { + encRev, err := module.EscapeVersion(rev) + if err != nil { + return nil, p.versionError(rev, err) + } + data, err := p.getBytes("@v/" + encRev + ".info") + if err != nil { + return nil, p.versionError(rev, err) + } + info := new(RevInfo) + if err := json.Unmarshal(data, info); err != nil { + return nil, p.versionError(rev, fmt.Errorf("invalid response from proxy %q: %w", p.redactedURL, err)) + } + if info.Version != rev && rev == module.CanonicalVersion(rev) && module.Check(p.path, rev) == nil { + // If we request a correct, appropriate version for the module path, the + // proxy must return either exactly that version or an error — not some + // arbitrary other version. + return nil, p.versionError(rev, fmt.Errorf("proxy returned info for version %s instead of requested version", info.Version)) + } + return info, nil +} + +func (p *proxyRepo) Latest() (*RevInfo, error) { + data, err := p.getBytes("@latest") + if err != nil { + if !errors.Is(err, fs.ErrNotExist) { + return nil, p.versionError("", err) + } + return p.latest() + } + info := new(RevInfo) + if err := json.Unmarshal(data, info); err != nil { + return nil, p.versionError("", fmt.Errorf("invalid response from proxy %q: %w", p.redactedURL, err)) + } + return info, nil +} + +func (p *proxyRepo) GoMod(version string) ([]byte, error) { + if version != module.CanonicalVersion(version) { + return nil, p.versionError(version, fmt.Errorf("internal error: version passed to GoMod is not canonical")) + } + + encVer, err := module.EscapeVersion(version) + if err != nil { + return nil, p.versionError(version, err) + } + data, err := p.getBytes("@v/" + encVer + ".mod") + if err != nil { + return nil, p.versionError(version, err) + } + return data, nil +} + +func (p *proxyRepo) Zip(dst io.Writer, version string) error { + if version != module.CanonicalVersion(version) { + return p.versionError(version, fmt.Errorf("internal error: version passed to Zip is not canonical")) + } + + encVer, err := module.EscapeVersion(version) + if err != nil { + return p.versionError(version, err) + } + body, err := p.getBody("@v/" + encVer + ".zip") + if err != nil { + return p.versionError(version, err) + } + defer body.Close() + + lr := &io.LimitedReader{R: body, N: codehost.MaxZipFile + 1} + if _, err := io.Copy(dst, lr); err != nil { + return p.versionError(version, err) + } + if lr.N <= 0 { + return p.versionError(version, fmt.Errorf("downloaded zip file too large")) + } + return 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.ReplaceAll(url.PathEscape(s), "%2F", "/") +} diff --git a/src/cmd/go/internal/modfetch/pseudo.go b/src/cmd/go/internal/modfetch/pseudo.go new file mode 100644 index 0000000..93eb0fa --- /dev/null +++ b/src/cmd/go/internal/modfetch/pseudo.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. + +// 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 ( + "errors" + "fmt" + "strings" + "time" + + "internal/lazyregexp" + + "golang.org/x/mod/module" + "golang.org/x/mod/semver" +) + +var pseudoVersionRE = lazyregexp.New(`^v[0-9]+\.(0\.0-|\d+\.\d+-([^+]*\.)?0\.)\d{14}-[A-Za-z0-9]+(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$`) + +const pseudoVersionTimestampFormat = "20060102150405" + +// 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" + } + segment := fmt.Sprintf("%s-%s", t.UTC().Format(pseudoVersionTimestampFormat), 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 + i := strings.LastIndex(older, ".") + 1 + v, patch := older[:i], older[i:] + + // Reassemble. + return v + incDecimal(patch) + "-0." + segment + build +} + +// ZeroPseudoVersion returns a pseudo-version with a zero timestamp and +// revision, which may be used as a placeholder. +func ZeroPseudoVersion(major string) string { + return PseudoVersion(major, "", time.Time{}, "000000000000") +} + +// incDecimal returns the decimal string incremented by 1. +func incDecimal(decimal string) string { + // Scan right to left turning 9s to 0s until you find a digit to increment. + digits := []byte(decimal) + i := len(digits) - 1 + for ; 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') + } + return string(digits) +} + +// decDecimal returns the decimal string decremented by 1, or the empty string +// if the decimal is all zeroes. +func decDecimal(decimal string) string { + // Scan right to left turning 0s to 9s until you find a digit to decrement. + digits := []byte(decimal) + i := len(digits) - 1 + for ; i >= 0 && digits[i] == '0'; i-- { + digits[i] = '9' + } + if i < 0 { + // decimal is all zeros + return "" + } + if i == 0 && digits[i] == '1' && len(digits) > 1 { + digits = digits[1:] + } else { + digits[i]-- + } + return string(digits) +} + +// IsPseudoVersion reports whether v is a pseudo-version. +func IsPseudoVersion(v string) bool { + return strings.Count(v, "-") >= 2 && semver.IsValid(v) && pseudoVersionRE.MatchString(v) +} + +// IsZeroPseudoVersion returns whether v is a pseudo-version with a zero base, +// timestamp, and revision, as returned by ZeroPseudoVersion. +func IsZeroPseudoVersion(v string) bool { + return v == ZeroPseudoVersion(semver.Major(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) + if err != nil { + return time.Time{}, err + } + t, err := time.Parse("20060102150405", timestamp) + if err != nil { + return time.Time{}, &module.InvalidVersionError{ + Version: v, + Pseudo: true, + Err: fmt.Errorf("malformed time %q", timestamp), + } + } + 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 +} + +// PseudoVersionBase returns the canonical parent version, if any, upon which +// the pseudo-version v is based. +// +// If v has no parent version (that is, if it is "vX.0.0-[…]"), +// PseudoVersionBase returns the empty string and a nil error. +func PseudoVersionBase(v string) (string, error) { + base, _, _, build, err := parsePseudoVersion(v) + if err != nil { + return "", err + } + + switch pre := semver.Prerelease(base); pre { + case "": + // vX.0.0-yyyymmddhhmmss-abcdef123456 → "" + if build != "" { + // Pseudo-versions of the form vX.0.0-yyyymmddhhmmss-abcdef123456+incompatible + // are nonsensical: the "vX.0.0-" prefix implies that there is no parent tag, + // but the "+incompatible" suffix implies that the major version of + // the parent tag is not compatible with the module's import path. + // + // There are a few such entries in the index generated by proxy.golang.org, + // but we believe those entries were generated by the proxy itself. + return "", &module.InvalidVersionError{ + Version: v, + Pseudo: true, + Err: fmt.Errorf("lacks base version, but has build metadata %q", build), + } + } + return "", nil + + case "-0": + // vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456 → vX.Y.Z + // vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456+incompatible → vX.Y.Z+incompatible + base = strings.TrimSuffix(base, pre) + i := strings.LastIndexByte(base, '.') + if i < 0 { + panic("base from parsePseudoVersion missing patch number: " + base) + } + patch := decDecimal(base[i+1:]) + if patch == "" { + // vX.0.0-0 is invalid, but has been observed in the wild in the index + // generated by requests to proxy.golang.org. + // + // NOTE(bcmills): I cannot find a historical bug that accounts for + // pseudo-versions of this form, nor have I seen such versions in any + // actual go.mod files. If we find actual examples of this form and a + // reasonable theory of how they came into existence, it seems fine to + // treat them as equivalent to vX.0.0 (especially since the invalid + // pseudo-versions have lower precedence than the real ones). For now, we + // reject them. + return "", &module.InvalidVersionError{ + Version: v, + Pseudo: true, + Err: fmt.Errorf("version before %s would have negative patch number", base), + } + } + return base[:i+1] + patch + build, nil + + default: + // vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456 → vX.Y.Z-pre + // vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456+incompatible → vX.Y.Z-pre+incompatible + if !strings.HasSuffix(base, ".0") { + panic(`base from parsePseudoVersion missing ".0" before date: ` + base) + } + return strings.TrimSuffix(base, ".0") + build, nil + } +} + +var errPseudoSyntax = errors.New("syntax error") + +func parsePseudoVersion(v string) (base, timestamp, rev, build string, err error) { + if !IsPseudoVersion(v) { + return "", "", "", "", &module.InvalidVersionError{ + Version: v, + Pseudo: true, + Err: errPseudoSyntax, + } + } + build = semver.Build(v) + v = strings.TrimSuffix(v, build) + j := strings.LastIndex(v, "-") + v, rev = v[:j], v[j+1:] + i := strings.LastIndex(v, "-") + if j := strings.LastIndex(v, "."); j > i { + base = v[:j] // "vX.Y.Z-pre.0" or "vX.Y.(Z+1)-0" + timestamp = v[j+1:] + } else { + base = v[:i] // "vX.0.0" + timestamp = v[i+1:] + } + return base, timestamp, rev, build, nil +} diff --git a/src/cmd/go/internal/modfetch/pseudo_test.go b/src/cmd/go/internal/modfetch/pseudo_test.go new file mode 100644 index 0000000..4483f8e --- /dev/null +++ b/src/cmd/go/internal/modfetch/pseudo_test.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. + +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"}, + {"unused", "v0.0.0--", "v0.0.0--.0.20060102150405-hash"}, + {"unused", "v1.0.0+metadata", "v1.0.1-0.20060102150405-hash+metadata"}, + {"unused", "v2.0.0+incompatible", "v2.0.1-0.20060102150405-hash+incompatible"}, + {"unused", "v2.3.0-pre+incompatible", "v2.3.0-pre.0.20060102150405-hash+incompatible"}, +} + +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 TestInvalidPseudoVersionTime(t *testing.T) { + const v = "---" + if _, err := PseudoVersionTime(v); err == nil { + t.Error("expected error, got nil instead") + } +} + +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, "") + } + } +} + +func TestPseudoVersionBase(t *testing.T) { + for _, tt := range pseudoTests { + base, err := PseudoVersionBase(tt.version) + if err != nil { + t.Errorf("PseudoVersionBase(%q): %v", tt.version, err) + } else if base != tt.older { + t.Errorf("PseudoVersionBase(%q) = %q; want %q", tt.version, base, tt.older) + } + } +} + +func TestInvalidPseudoVersionBase(t *testing.T) { + for _, in := range []string{ + "v0.0.0", + "v0.0.0-", // malformed: empty prerelease + "v0.0.0-0.20060102150405-hash", // Z+1 == 0 + "v0.1.0-0.20060102150405-hash", // Z+1 == 0 + "v1.0.0-0.20060102150405-hash", // Z+1 == 0 + "v0.0.0-20060102150405-hash+incompatible", // "+incompatible without base version + "v0.0.0-20060102150405-hash+metadata", // other metadata without base version + } { + base, err := PseudoVersionBase(in) + if err == nil || base != "" { + t.Errorf(`PseudoVersionBase(%q) = %q, %v; want "", error`, in, base, err) + } + } +} + +func TestIncDecimal(t *testing.T) { + cases := []struct { + in, want string + }{ + {"0", "1"}, + {"1", "2"}, + {"99", "100"}, + {"100", "101"}, + {"101", "102"}, + } + + for _, tc := range cases { + got := incDecimal(tc.in) + if got != tc.want { + t.Fatalf("incDecimal(%q) = %q; want %q", tc.in, tc.want, got) + } + } +} + +func TestDecDecimal(t *testing.T) { + cases := []struct { + in, want string + }{ + {"", ""}, + {"0", ""}, + {"00", ""}, + {"1", "0"}, + {"2", "1"}, + {"99", "98"}, + {"100", "99"}, + {"101", "100"}, + } + + for _, tc := range cases { + got := decDecimal(tc.in) + if got != tc.want { + t.Fatalf("decDecimal(%q) = %q; want %q", tc.in, tc.want, got) + } + } +} diff --git a/src/cmd/go/internal/modfetch/repo.go b/src/cmd/go/internal/modfetch/repo.go new file mode 100644 index 0000000..af9e24c --- /dev/null +++ b/src/cmd/go/internal/modfetch/repo.go @@ -0,0 +1,455 @@ +// 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" + "io" + "io/fs" + "os" + "sort" + "strconv" + "time" + + "cmd/go/internal/cfg" + "cmd/go/internal/modfetch/codehost" + "cmd/go/internal/par" + "cmd/go/internal/vcs" + web "cmd/go/internal/web" + + "golang.org/x/mod/module" + "golang.org/x/mod/semver" +) + +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 returns a non-nil error only if there was a problem + // fetching the list of versions: it may return an empty list + // along with a nil error if the list of matching versions + // is known to be empty. + // + // If the underlying repository does not exist, + // Versions returns an error matching errors.Is(_, os.NotExist). + Versions(prefix string) ([]string, 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 writes a zip file for the given version to dst. + Zip(dst io.Writer, version string) error +} + +// A Rev describes a single revision in a module repository. +type RevInfo struct { + Version string // suggested version string for this revision + 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 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 + +type lookupCacheKey struct { + proxy, path string +} + +// Lookup returns the module with the given module path, +// fetched through the given proxy. +// +// The distinguished proxy "direct" indicates that the path should be fetched +// from its origin, and "noproxy" indicates that the patch should be fetched +// directly only if GONOPROXY matches the given path. +// +// For the distinguished proxy "off", Lookup always returns a non-nil error. +// +// A successful return does not guarantee that the module +// has any defined versions. +func Lookup(proxy, path string) Repo { + if traceRepo { + defer logCall("Lookup(%q, %q)", proxy, path)() + } + + type cached struct { + r Repo + } + c := lookupCache.Do(lookupCacheKey{proxy, path}, func() interface{} { + r := newCachingRepo(path, func() (Repo, error) { + r, err := lookup(proxy, path) + if err == nil && traceRepo { + r = newLoggingRepo(r) + } + return r, err + }) + return cached{r} + }).(cached) + + return c.r +} + +// lookup returns the module with the given module path. +func lookup(proxy, path string) (r Repo, err error) { + if cfg.BuildMod == "vendor" { + return nil, errLookupDisabled + } + + if module.MatchPrefixPatterns(cfg.GONOPROXY, path) { + switch proxy { + case "noproxy", "direct": + return lookupDirect(path) + default: + return nil, errNoproxy + } + } + + switch proxy { + case "off": + return errRepo{path, errProxyOff}, nil + case "direct": + return lookupDirect(path) + case "noproxy": + return nil, errUseProxy + default: + return newProxyRepo(proxy, path) + } +} + +type lookupDisabledError struct{} + +func (lookupDisabledError) Error() string { + if cfg.BuildModReason == "" { + return fmt.Sprintf("module lookup disabled by -mod=%s", cfg.BuildMod) + } + return fmt.Sprintf("module lookup disabled by -mod=%s\n\t(%s)", cfg.BuildMod, cfg.BuildModReason) +} + +var errLookupDisabled error = lookupDisabledError{} + +var ( + errProxyOff = notExistErrorf("module lookup disabled by GOPROXY=off") + errNoproxy error = notExistErrorf("disabled by GOPRIVATE/GONOPROXY") + errUseProxy error = notExistErrorf("path does not match GOPRIVATE/GONOPROXY") +) + +func lookupDirect(path string) (Repo, error) { + security := web.SecureOnly + + if allowInsecure(path) { + security = web.Insecure + } + rr, err := vcs.RepoRootForImportPath(path, vcs.PreferMod, security) + if err != nil { + // We don't know where to find code for a module with this path. + return nil, notExistError{err: err} + } + + if rr.VCS.Name == "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 *vcs.RepoRoot) (codehost.Repo, error) { + code, err := codehost.NewRepo(rr.VCS.Cmd, 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.SecureOnly + if allowInsecure(path) { + security = web.Insecure + } + rr, err := vcs.RepoRootForImportPath(path, vcs.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, rev) + 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(dst io.Writer, version string) error { + dstName := "_" + if dst, ok := dst.(interface{ Name() string }); ok { + dstName = strconv.Quote(dst.Name()) + } + defer logCall("Repo[%s]: Zip(%s, %q)", l.r.ModulePath(), dstName, version)() + return l.r.Zip(dst, version) +} + +// errRepo is a Repo that returns the same error for all operations. +// +// It is useful in conjunction with caching, since cache hits will not attempt +// the prohibited operations. +type errRepo struct { + modulePath string + err error +} + +func (r errRepo) ModulePath() string { return r.modulePath } + +func (r errRepo) Versions(prefix string) (tags []string, err error) { return nil, r.err } +func (r errRepo) Stat(rev string) (*RevInfo, error) { return nil, r.err } +func (r errRepo) Latest() (*RevInfo, error) { return nil, r.err } +func (r errRepo) GoMod(version string) ([]byte, error) { return nil, r.err } +func (r errRepo) Zip(dst io.Writer, version string) error { return r.err } + +// A notExistError is like fs.ErrNotExist, but with a custom message +type notExistError struct { + err error +} + +func notExistErrorf(format string, args ...interface{}) error { + return notExistError{fmt.Errorf(format, args...)} +} + +func (e notExistError) Error() string { + return e.err.Error() +} + +func (notExistError) Is(target error) bool { + return target == fs.ErrNotExist +} + +func (e notExistError) Unwrap() error { + return e.err +} diff --git a/src/cmd/go/internal/modfetch/sumdb.go b/src/cmd/go/internal/modfetch/sumdb.go new file mode 100644 index 0000000..4fbc54d --- /dev/null +++ b/src/cmd/go/internal/modfetch/sumdb.go @@ -0,0 +1,279 @@ +// Copyright 2019 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 checksum database lookup + +// +build !cmd_go_bootstrap + +package modfetch + +import ( + "bytes" + "errors" + "fmt" + "io" + "io/fs" + "net/url" + "os" + "path/filepath" + "strings" + "sync" + "time" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/lockedfile" + "cmd/go/internal/web" + + "golang.org/x/mod/module" + "golang.org/x/mod/sumdb" + "golang.org/x/mod/sumdb/note" +) + +// useSumDB reports whether to use the Go checksum database for the given module. +func useSumDB(mod module.Version) bool { + return cfg.GOSUMDB != "off" && !cfg.Insecure && !module.MatchPrefixPatterns(cfg.GONOSUMDB, mod.Path) +} + +// lookupSumDB returns the Go checksum database's go.sum lines for the given module, +// along with the name of the database. +func lookupSumDB(mod module.Version) (dbname string, lines []string, err error) { + dbOnce.Do(func() { + dbName, db, dbErr = dbDial() + }) + if dbErr != nil { + return "", nil, dbErr + } + lines, err = db.Lookup(mod.Path, mod.Version) + return dbName, lines, err +} + +var ( + dbOnce sync.Once + dbName string + db *sumdb.Client + dbErr error +) + +func dbDial() (dbName string, db *sumdb.Client, err error) { + // $GOSUMDB can be "key" or "key url", + // and the key can be a full verifier key + // or a host on our list of known keys. + + // Special case: sum.golang.google.cn + // is an alias, reachable inside mainland China, + // for sum.golang.org. If there are more + // of these we should add a map like knownGOSUMDB. + gosumdb := cfg.GOSUMDB + if gosumdb == "sum.golang.google.cn" { + gosumdb = "sum.golang.org https://sum.golang.google.cn" + } + + key := strings.Fields(gosumdb) + if len(key) >= 1 { + if k := knownGOSUMDB[key[0]]; k != "" { + key[0] = k + } + } + if len(key) == 0 { + return "", nil, fmt.Errorf("missing GOSUMDB") + } + if len(key) > 2 { + return "", nil, fmt.Errorf("invalid GOSUMDB: too many fields") + } + vkey, err := note.NewVerifier(key[0]) + if err != nil { + return "", nil, fmt.Errorf("invalid GOSUMDB: %v", err) + } + name := vkey.Name() + + // No funny business in the database name. + direct, err := url.Parse("https://" + name) + if err != nil || strings.HasSuffix(name, "/") || *direct != (url.URL{Scheme: "https", Host: direct.Host, Path: direct.Path, RawPath: direct.RawPath}) || direct.RawPath != "" || direct.Host == "" { + return "", nil, fmt.Errorf("invalid sumdb name (must be host[/path]): %s %+v", name, *direct) + } + + // Determine how to get to database. + var base *url.URL + if len(key) >= 2 { + // Use explicit alternate URL listed in $GOSUMDB, + // bypassing both the default URL derivation and any proxies. + u, err := url.Parse(key[1]) + if err != nil { + return "", nil, fmt.Errorf("invalid GOSUMDB URL: %v", err) + } + base = u + } + + return name, sumdb.NewClient(&dbClient{key: key[0], name: name, direct: direct, base: base}), nil +} + +type dbClient struct { + key string + name string + direct *url.URL + + once sync.Once + base *url.URL + baseErr error +} + +func (c *dbClient) ReadRemote(path string) ([]byte, error) { + c.once.Do(c.initBase) + if c.baseErr != nil { + return nil, c.baseErr + } + + var data []byte + start := time.Now() + targ := web.Join(c.base, path) + data, err := web.GetBytes(targ) + if false { + fmt.Fprintf(os.Stderr, "%.3fs %s\n", time.Since(start).Seconds(), targ.Redacted()) + } + return data, err +} + +// initBase determines the base URL for connecting to the database. +// Determining the URL requires sending network traffic to proxies, +// so this work is delayed until we need to download something from +// the database. If everything we need is in the local cache and +// c.ReadRemote is never called, we will never do this work. +func (c *dbClient) initBase() { + if c.base != nil { + return + } + + // Try proxies in turn until we find out how to connect to this database. + // + // Before accessing any checksum database URL using a proxy, the proxy + // client should first fetch /sumdb//supported. + // + // If that request returns a successful (HTTP 200) response, then the proxy + // supports proxying checksum database requests. In that case, the client + // should use the proxied access method only, never falling back to a direct + // connection to the database. + // + // If the /sumdb//supported check fails with a “not found” (HTTP + // 404) or “gone” (HTTP 410) response, or if the proxy is configured to fall + // back on errors, the client will try the next proxy. If there are no + // proxies left or if the proxy is "direct" or "off", the client should + // connect directly to that database. + // + // Any other response is treated as the database being unavailable. + // + // See https://golang.org/design/25530-sumdb#proxying-a-checksum-database. + err := TryProxies(func(proxy string) error { + switch proxy { + case "noproxy": + return errUseProxy + case "direct", "off": + return errProxyOff + default: + proxyURL, err := url.Parse(proxy) + if err != nil { + return err + } + if _, err := web.GetBytes(web.Join(proxyURL, "sumdb/"+c.name+"/supported")); err != nil { + return err + } + // Success! This proxy will help us. + c.base = web.Join(proxyURL, "sumdb/"+c.name) + return nil + } + }) + if errors.Is(err, fs.ErrNotExist) { + // No proxies, or all proxies failed (with 404, 410, or were were allowed + // to fall back), or we reached an explicit "direct" or "off". + c.base = c.direct + } else if err != nil { + c.baseErr = err + } +} + +// ReadConfig reads the key from c.key +// and otherwise reads the config (a latest tree head) from GOPATH/pkg/sumdb/. +func (c *dbClient) ReadConfig(file string) (data []byte, err error) { + if file == "key" { + return []byte(c.key), nil + } + + if cfg.SumdbDir == "" { + return nil, errors.New("could not locate sumdb file: missing $GOPATH") + } + targ := filepath.Join(cfg.SumdbDir, file) + data, err = lockedfile.Read(targ) + if errors.Is(err, fs.ErrNotExist) { + // Treat non-existent as empty, to bootstrap the "latest" file + // the first time we connect to a given database. + return []byte{}, nil + } + return data, err +} + +// WriteConfig rewrites the latest tree head. +func (*dbClient) WriteConfig(file string, old, new []byte) error { + if file == "key" { + // Should not happen. + return fmt.Errorf("cannot write key") + } + if cfg.SumdbDir == "" { + return errors.New("could not locate sumdb file: missing $GOPATH") + } + targ := filepath.Join(cfg.SumdbDir, file) + os.MkdirAll(filepath.Dir(targ), 0777) + f, err := lockedfile.Edit(targ) + if err != nil { + return err + } + defer f.Close() + data, err := io.ReadAll(f) + if err != nil { + return err + } + if len(data) > 0 && !bytes.Equal(data, old) { + return sumdb.ErrWriteConflict + } + if _, err := f.Seek(0, 0); err != nil { + return err + } + if err := f.Truncate(0); err != nil { + return err + } + if _, err := f.Write(new); err != nil { + return err + } + return f.Close() +} + +// ReadCache reads cached lookups or tiles from +// GOPATH/pkg/mod/cache/download/sumdb, +// which will be deleted by "go clean -modcache". +func (*dbClient) ReadCache(file string) ([]byte, error) { + targ := filepath.Join(cfg.GOMODCACHE, "cache/download/sumdb", file) + data, err := lockedfile.Read(targ) + // lockedfile.Write does not atomically create the file with contents. + // There is a moment between file creation and locking the file for writing, + // during which the empty file can be locked for reading. + // Treat observing an empty file as file not found. + if err == nil && len(data) == 0 { + err = &fs.PathError{Op: "read", Path: targ, Err: fs.ErrNotExist} + } + return data, err +} + +// WriteCache updates cached lookups or tiles. +func (*dbClient) WriteCache(file string, data []byte) { + targ := filepath.Join(cfg.GOMODCACHE, "cache/download/sumdb", file) + os.MkdirAll(filepath.Dir(targ), 0777) + lockedfile.Write(targ, bytes.NewReader(data), 0666) +} + +func (*dbClient) Log(msg string) { + // nothing for now +} + +func (*dbClient) SecurityError(msg string) { + base.Fatalf("%s", msg) +} diff --git a/src/cmd/go/internal/modfetch/zip_sum_test/testdata/zip_sums.csv b/src/cmd/go/internal/modfetch/zip_sum_test/testdata/zip_sums.csv new file mode 100644 index 0000000..0906975 --- /dev/null +++ b/src/cmd/go/internal/modfetch/zip_sum_test/testdata/zip_sums.csv @@ -0,0 +1,2119 @@ +9fans.net/go,v0.0.2,h1:RYM6lWITV8oADrwLfdzxmt8ucfW6UtP9v1jg4qAbqts=,2c42aad9ed60e24046fbf5720f438884942897197cb790ce58cccdacedd9532d +aahframe.work,v0.12.3,h1:hc3chv+f49yLYVT/aSEhgpoqd8bS0rDKEew1un8AkSo=,0c7e3fab03920a79ace8e0a9ddf4517225f595ce39f2124ec3d9353508da5dbd +aahframework.org/essentials.v0,v0.8.0,h1:R/lcfOuhvZptG4IWX/CzAtpiVJFUjbCxLao6DfmeWBA=,d640fe6b83a31ffe09d12eea37de000be7ec8d7330c0a1d7413d6e31a675628d +bazil.org/fuse,v0.0.0-20180421153158-65cc252bf669,h1:FNCRpXiquG1aoyqcIWVFmpTSKVcx2bQD38uZZeGtdlw=,fce7ed008451861ba30974e95468d716f5ff4fde14e9605dbc2db5fac935c71d +bitbucket.org/abex/go-optional,v0.0.0-20150902044611-5304370459de,h1:iGmurCCO42qFsQ46DzROSsZJFf8/7AKFH/VpRGd2PBw=,02e1b23db09fb6945ba4ca57c0af8125b608fceae125fe625f6536b9e466e7e0 +bitbucket.org/abex/pathfinder,v0.0.0-20170507112819-bdce8b2efbc9,h1:M1jjfmrcOcmWy2/aABpm3k9h/M6NccmjgLtE5gVl+y8=,8469c0a656a895863d4714a658ee4a9634e78547142fa7239331e15d0143c679 +bitbucket.org/abex/sliceconv,v0.0.0-20151017061159-594a23261816,h1:7XPf5/Oar0LfWbnUY29doBDzSr6ToseiJRqkZtb0YOo=,e2433a32246bd5e2fb5d52bf6dc36188a75c4b59b98f76eb7607035b8525dd37 +bitbucket.org/abex/yumeko,v0.0.0-20190825151534-d98ca20ac08c,h1:ES4kIm83Q1RYr9uhhpQhqh/tqjt8H+Xz4xuSAv5Crcw=,1d352a11b3ed5850a425fde048cafa65b2c079c4e9647c52a339b28276065ba9 +bitbucket.org/liamstask/goose,v0.0.0-20150115234039-8488cc47d90c,h1:bkb2NMGo3/Du52wvYj9Whth5KZfMV6d3O0Vbr3nz/UE=,3d64cac7774bf87a9d050222b87387c112bcb6ef0ea0e2b3324a95330573a0c5 +bitbucket.org/ww/goautoneg,v0.0.0-20120707110453-75cd24fc2f2c,h1:t+Ra932MCC0eeyD/vigXqMbZTzgZjd4JOfBJWC6VSMI=,8ad2afdee1dc46b2c78e986bc2cce89cd0b8815b278a01879ef08d56585c247f +bou.ke/monkey,v1.0.1,h1:zEMLInw9xvNakzUUPjfS4Ds6jYPqCFx3m7bRmG5NH2U=,20cb7da509322267189d32a125d7e0f782264508bc8e17306c80424514e797ce +cloud.google.com/go,v0.47.0,h1:1JUtpcY9E7+eTospEwWS2QXP3DEn7poB3E2j0jN74mM=,7739fd24e36a536488115ef0ec9d739e608ee68448f8a469e84855c008b00ecd +cloud.google.com/go/bigquery,v1.0.1,h1:hL+ycaJpVE9M7nLoiXb/Pn10ENE2u+oddxbD8uu0ZVU=,738d1f726ce24f618ee7563f6c9419e6307f8814548f45ad8a227cffbb1448c0 +cloud.google.com/go/datastore,v1.0.0,h1:Kt+gOPPp2LEPWp8CSfxhsM8ik9CcyE/gYu+0r+RnZvM=,41e93ec9526ae580da90300d7e421a6d39d79cb6118d62ad1d3c06422d8a71bf +cloud.google.com/go/pubsub,v1.0.1,h1:W9tAK3E57P75u0XLLR82LZyw8VpAnhmyTOxW9qzmyj8=,8bca46a7c5f0dcd576d23fa9a5f107955316d6f0d8f306ee1d6faa7de99c3d29 +cloud.google.com/go/spanner,v1.0.0,h1:jLKThep5kbWLeBhLgtEfm/OPT08n1z7itVTR82WUBQg=,90579f16545e352c662ae9f62dd02dddf834fe10b33d1dbcfbf0a8aadfcd21f8 +cloud.google.com/go/storage,v1.0.0,h1:VV2nUM3wwLLGh9lSABFgZMjInyUbJeaRSE64WuAIQ+4=,baec4756c573ede58f19eb7ae4acaebd7ac3f0c56413ecbbd216ad46a589a5da +code.cloudfoundry.org/clock,v0.0.0-20180518195852-02e53af36e6c,h1:5eeuG0BHx1+DHeT3AP+ISKZ2ht1UjGhm581ljqYpVeQ=,61785787db7dadaf695506636dcb98c26bbdd0c847f589aa1fb4bbe9ef0e4455 +code.cloudfoundry.org/gofileutils,v0.0.0-20170111115228-4d0c80011a0f,h1:UrKzEwTgeiff9vxdrfdqxibzpWjxLnuXDI5m6z3GJAk=,ec71ca818158525773e53568f71db38f63423822a426e1a18f7d34318e97eb3e +code.cloudfoundry.org/lager,v2.0.0+incompatible,h1:WZwDKDB2PLd/oL+USK4b4aEjUymIej9My2nUQ9oWEwQ=,ce1da175885c2587ca091532a937108ed646e3bd6bd902640891f75ae70adb8b +code.gitea.io/gitea,v1.9.5,h1:Q3PROlfPth1NlLGaeYcr6YVqyfAy7txnFpDKe1BXo7Q=,c7b63394004fb8f355d859f11a007ff17126eac092f90507a80392335351a6df +code.gitea.io/sdk,v0.0.0-20191030144301-2a5a0e75e5cf,h1:uXUz7lXbs33QAYIu1rF0o8tNsa3DlDDSMYek/3CldIo=,6472a2b30b8108cae9b6a4914ce986d61e9ed37baade5ad35cb337270602b70a +code.gitea.io/sdk/gitea,v0.0.0-20191030144301-2a5a0e75e5cf,h1:aAwV+RyellgKMACMu21Vyv/XgSHipLvbJsXDoXP1Yv0=,62570a621e1bf13724fb1f45d7ea95c48de02abb00468cf1da4b35820203d3b4 +contrib.go.opencensus.io/exporter/aws,v0.0.0-20181029163544-2befc13012d0,h1:YsbWYxDZkC7x2OxlsDEYvvEXZ3cBI3qBgUK5BqkZvRw=,3e351a39c3caf9ce263155f2d6e5a4e0cd84177661e1bf40f0d8fd06854831e9 +contrib.go.opencensus.io/exporter/ocagent,v0.6.0,h1:Z1n6UAyr0QwM284yUuh5Zd8JlvxUGAhFZcgMJkMPrGM=,e526ae16b06c682c3661738938f912a2e301a5e2d0ba875c7a0ec40fde825491 +contrib.go.opencensus.io/exporter/stackdriver,v0.12.8,h1:iXI5hr7pUwMx0IwMphpKz5Q3If/G5JiWFVZ5MPPxP9E=,db745d331f8a0455abbbcfeb4bb33dbc5cbb73a119b4e86f833cd497cfc72559 +contrib.go.opencensus.io/integrations/ocsql,v0.1.4,h1:kfg5Yyy1nYUrqzyfW5XX+dzMASky8IJXhtHe0KTYNS4=,0a4be97a579c5212bd83d21a177b279bc5b0c04350a63c56e8f8e611ffcba09c +contrib.go.opencensus.io/resource,v0.1.1,h1:4r2CANuYhKGmYWP02+5E94rLRcS/YeD+KlxSrOsMxk0=,07ad3d36f96cb86ecba376353d02730855e117db3ffac5c2ab2c7cdf4eca25dc +cuelang.org/go,v0.0.11,h1:t7s006dOWh6tgnwPifvO3l704eg8oPuIH7AR1hfTFYk=,69bdc6b3f1000308d399f166dd0d46576019f68cbf37765bd30821584b1296de +dmitri.shuralyov.com/app/changes,v0.0.0-20180602232624-0a106ad413e3,h1:hJiie5Bf3QucGRa4ymsAUOxyhYwGEz1xrsVk0P8erlw=,a4d9079d5550094191f608c628ff2eb6999e0d0b6aea894ba59d063107777dfa +dmitri.shuralyov.com/gpu/mtl,v0.0.0-20190408044501-666a987793e9,h1:VpgP7xuJadIUuKccphEpTJnWhS2jkQyMt6Y7pJCD7fY=,ca5330901fcda83d09553ac362576d196c531157bc9c502e76b237cca262b400 +dmitri.shuralyov.com/html/belt,v0.0.0-20180602232347-f7d459c86be0,h1:SPOUaucgtVls75mg+X7CXigS71EnsfVUK/2CgVrwqgw=,bd6b059cceaea8ab23e65b8118fab5d22f82149417fcc5fcf930ef9a52d582f1 +dmitri.shuralyov.com/service/change,v0.0.0-20181023043359-a85b471d5412,h1:GvWw74lx5noHocd+f6HBMXK6DuggBB1dhVkuGZbv7qM=,8a1ba9c7ba7eea08389c15315a23485d19fc7166d30b5b47a35fab949c4bf886 +dmitri.shuralyov.com/state,v0.0.0-20190403024436-2cf192113e66,h1:/74W9PTF+vJhgRsWpPWlZT77+phX7vXPcelX7JXFu5s=,eda200c06f669f06c56e1d53a1879b88dd7ee99eea1f56d329028fa773cfc2dd +docker.io/go-docker,v1.0.0,h1:VdXS/aNYQxyA9wdLD5z8Q8Ro688/hG8HzKxYVEVbE6s=,b162036b1af6e1e5434e2e5a35faa7191014529259fbf2f4f1b3e7de6b816516 +fyne.io/fyne,v1.1.2,h1:a9YLFXxqN7lKNqTrk+ocw3/3ROrn6aFiofix8ATVOBc=,dc2d7fd4a4ee9852328fc79c52459a53d94d26f6ac3282ebcacc0c6cd6688d23 +git.apache.org/thrift.git,v0.13.0,h1:/3bz5WZ+sqYArk7MBBBbDufMxKKOA56/6JO6psDpUDY=,10412b7bc503ef2a7cc3bf58fe69e5a2d2594354ae3cc5ab2baa2b3ecc8c4f1d +git.fd.io/govpp.git,v0.1.0,h1:fV5H9ghURFfmNAjk7Scb/aG3OGwevLayHfSdS8GsYjE=,0a023d4b5b36131a4fde2c3d19047bbd4f5c3a7cc07c1ccf40bfb75a501f51b3 +git.torproject.org/pluggable-transports/goptlib.git,v1.1.0,h1:LMQAA8pAho+QtYrrVNimJQiINNEwcwuuD99vezD/PAo=,f6769c4813dedf933071289bfd9381aa5eb3a012b3a32d1da02aa9bebd3a3b5b +gitee.com/nggs/util,v0.0.0-20190830024003-3e49d2efc84b,h1:6KQpPEs326uPrICQy9x/PxmR8U0v/XsFzpt0k1nFKcY=,a062c99c2b560a36168fe51eab8f17f4fadf5d534238881628e83d8d61e51c2a +github.com/1and1/oneandone-cloudserver-sdk-go,v1.0.1,h1:RMTyvS5bjvSWiUcfqfr/E2pxHEMrALvU+E12n6biymg=,7f068808fc0857d7de8c8f829cc380dce1c6611a3fc819daf4421e9bcb75a07c +github.com/99designs/gqlgen,v0.10.1,h1:1BgB6XKGTHq7uH4G1/PYyKe2Kz7/vw3AlvMZlD3TEEY=,04b9e7d8a3df6543cd870325b1140ce9ac3f4bbfd8c90ebecec4f908dd420d08 +github.com/AndreasBriese/bbloom,v0.0.0-20190306092124-e2d15f34fcf9,h1:HD8gA2tkByhMAwYaFAX9w2l7vxvBQ5NMoxDrkhqhtn4=,6d7c1af06f8597fde1e86166f26416057392f1b0bdb84f2af555aa461282dd18 +github.com/AsynkronIT/goconsole,v0.0.0-20160504192649-bfa12eebf716,h1:Pk/Kzi5O0T4QxfqvbaUsh8UklbJ9BklZ/ClZBptX5WU=,5a2507b89bb4436881718d785a0ef383652aa99782508b7444cf20255082dab9 +github.com/Azure/azure-amqp-common-go,v1.1.4,h1:DmPXxmLZwi/71CgRTZIKR6yiKEW3eC42S4gSBhfG7y0=,4b800793ff4fefa86a427c445e3a4671b8d1dcd87a44075f6309cace6b0e01e2 +github.com/Azure/azure-amqp-common-go/v2,v2.1.0,h1:+QbFgmWCnPzdaRMfsI0Yb6GrRdBj5jVL8N3EXuEUcBQ=,9a91c6ac9656faea0ddfb0bb497c109451faaba09b85ce3237309f5982b095a3 +github.com/Azure/azure-pipeline-go,v0.2.2,h1:6oiIS9yaG6XCCzhgAgKFfIWyo4LLCiDhZot6ltoThhY=,3e4f90f6ec86d4875e8758f01947adece11c1b4317b448fe0197188765c83efc +github.com/Azure/azure-sdk-for-go,v36.0.0+incompatible,h1:XIaBmA4pgKqQ7jInQPaNJQ4pOHrdJjw9gYXhbyiChaU=,71db17c798b784b96a45efdbabd18ad86d03e5f490701081a2f7bf19efa67c13 +github.com/Azure/azure-service-bus-go,v0.9.1,h1:G1qBLQvHCFDv9pcpgwgFkspzvnGknJRR0PYJ9ytY/JA=,81e42ed51354d71b53daf93b5b9f0f2c20fb7d2923f45ab88eea22419bfbc63a +github.com/Azure/azure-storage-blob-go,v0.8.0,h1:53qhf0Oxa0nOjgbDeeYPUeyiNmafAFEY95rZLK0Tj6o=,3b02b720c25bbb6cdaf77f45a29a21e374e087081dedfeac2700aed6147b4b35 +github.com/Azure/go-ansiterm,v0.0.0-20170929234023-d6e3b3328b78,h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=,b7a14d18891abef8b8a2e622f62a3cebeac32f9f1223dc9d62a6f8769861aaf2 +github.com/Azure/go-autorest,v13.3.0+incompatible,h1:8Ix0VdeOllBx9jEcZ2Wb1uqWUpE1awmJiaHztwaJCPk=,44fdf420bd96bb97df7910806efb25f2fae701078c39f5592f5c4131ffce41e6 +github.com/Azure/go-autorest/autorest,v0.9.2,h1:6AWuh3uWrsZJcNoCHrCF/+g4aKPCU39kaMO6/qrnK/4=,26df5fc6c03e8c66021dd272b04242f6c2ce2a5975f87799dfcf1b9597800dba +github.com/Azure/go-autorest/autorest/adal,v0.8.0,h1:CxTzQrySOxDnKpLjFJeZAS5Qrv/qFPkgLjx5bOAi//I=,af59c00ec7e19cda9b960babaee7bfe27cf3d5f7415ac3afdb4cddc73d4b5743 +github.com/Azure/go-autorest/autorest/azure/auth,v0.4.0,h1:18ld/uw9Rr7VkNie7a7RMAcFIWrJdlUL59TWGfcu530=,2fe394de946f42c2ea8ad07f1b282eac6bb56e372f5c2a35e49dfef0cf015ccb +github.com/Azure/go-autorest/autorest/azure/cli,v0.3.0,h1:5PAqnv+CSTwW9mlZWZAizmzrazFWEgZykEZXpr2hDtY=,729d09b69a1912faa7c2395389bbf67ec22a420d42c15414823d43a380a2f09a +github.com/Azure/go-autorest/autorest/date,v0.2.0,h1:yW+Zlqf26583pE43KhfnhFcdmSWlm5Ew6bxipnr/tbM=,9ec7b48c865a185b72d3822ac2dff7e0163315a23911c87a479a3db616af9853 +github.com/Azure/go-autorest/autorest/mocks,v0.3.0,h1:qJumjCaCudz+OcqE9/XtEPfvtOjOmKaui4EOpFI6zZc=,d5daf74cf531c37b27b39d3bf65b6930aee4b226b5fb4ea91a87be93aaf37f10 +github.com/Azure/go-autorest/autorest/to,v0.3.0,h1:zebkZaadz7+wIQYgC7GXaz3Wb28yKYfVkkBKwc38VF8=,955ee6bde8af1314d22b51f265799147f42f7c705714b1cc1c51144441d5fa9c +github.com/Azure/go-autorest/autorest/validation,v0.2.0,h1:15vMO4y76dehZSq7pAaOLQxC6dZYsSrj2GQpflyM/L4=,10f40b0d943d4d1a0a1cbcb9fdb058b8a3a59a55ae26583566dfaa82883f86ea +github.com/Azure/go-autorest/logger,v0.1.0,h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY=,5e0804944db0707502c9d29defb54961c281a19311c9eb321a246ba054ac5256 +github.com/Azure/go-autorest/tracing,v0.5.0,h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k=,4951b0f4a88a44b7ed4e4834654e4e01922ade35d97899b8596998184abbc652 +github.com/Azure/go-ntlmssp,v0.0.0-20180810175552-4a21cbd618b4,h1:pSm8mp0T2OH2CPmPDPtwHPr3VAQaOwVF/JbllOPP4xA=,64cd585589154ce18d7557ccfd8d26e2c2f5c4ecf13b17bdbfb913e17863d280 +github.com/BurntSushi/locker,v0.0.0-20171006230638-a6e239ea1c69,h1:+tu3HOoMXB7RXEINRVIpxJCT+KdYiI7LAEAUrOw3dIU=,836038343df9e9126b59d54201951191898bd875ec32d93c2018d759f358fcfb +github.com/BurntSushi/toml,v0.3.1,h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=,815c6e594745f2d8842ff9a4b0569c6695e6cdfd5e07e5b3d98d06b72ca41e3c +github.com/BurntSushi/xgb,v0.0.0-20160522181843-27f122750802,h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc=,f52962c7fbeca81ea8a777d1f8b1f1d25803dc437fbb490f253344232884328e +github.com/BurntSushi/xgbutil,v0.0.0-20190907113008-ad855c713046,h1:O/r2Sj+8QcMF7V5IcmiE2sMFV2q3J47BEirxbXJAdzA=,492ce6b11d7faaec4e15d1279d81e28d2e0e9844ad117f9de9411286a5b0e305 +github.com/ChrisTrenkamp/goxpath,v0.0.0-20170922090931-c385f95c6022,h1:y8Gs8CzNfDF5AZvjr+5UyGQvQEBL7pwo+v+wX6q9JI8=,8d79cd78a309a1b0f22790d354b9c4c929c64d03c7e572627ba430908fbb9d78 +github.com/CodisLabs/codis,v0.0.0-20181104082235-de1ad026e329,h1:KyRmPlfd2xewxb54vIBPNILFyCh2R3zNDwLZURDxT0E=,f61ae85688d10dddf0d62c30aaaa2701373fc11851dae4435de0212513c578c1 +github.com/DATA-DOG/go-sqlmock,v1.3.3,h1:CWUqKXe0s8A2z6qCgkP4Kru7wC11YoAnoupUKFDnH08=,5dc430c2836af3bfc85f590366a6e284a251978e9397d0d54fa97db913263461 +github.com/DataDog/datadog-go,v3.2.0+incompatible,h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4=,ede4a024d3c106b2f57ca04d7bfc7610e0c83f4d8a3bace2cf87b42fd5cf66cd +github.com/DataDog/zstd,v1.4.0,h1:vhoV+DUHnRZdKW1i5UMjAk2G4JY8wN4ayRfYDNdEhwo=,601f6fe1f4138d676946f4b27f7a714bbedea8c1785d10c1b74a03c68ad13070 +github.com/FiloSottile/b2,v0.0.0-20170207175032-b197f7a2c317,h1:1GuMjC4tjfwnWBdoTS7YqtQ3JIsEft6NRcdmXdzvYYc=,6ff3cfed3f510fc69b47f263936642950afc7892f557ed716dd8c5584f187411 +github.com/GeertJohan/go-sourcepath,v0.0.0-20150925135350-83e8b8723a9b,h1:D4H5C4VvURnduTQydyEhA6OWnNcZTLUlNX4YBw5yelY=,8bdcf0b6cc58f5ec1cef031b4052e6d699683bf1daf4a1a20f92f67d5be06b82 +github.com/GeertJohan/go.incremental,v1.0.0,h1:7AH+pY1XUgQE4Y1HcXYaMqAI0m9yrFqo/jt0CW30vsg=,ce46b3b717f8d2927046bcfb99c6f490b1b547a681e6b23240ac2c2292a891e8 +github.com/GeertJohan/go.rice,v1.0.0,h1:KkI6O9uMaQU3VEKaj01ulavtF7o1fWT7+pk/4voiMLQ=,2fc48b9422bf356c18ed3fe32ec52f6a8b87ac168f83d2eed249afaebcc3eeb8 +github.com/GoogleCloudPlatform/cloudsql-proxy,v0.0.0-20191017031552-46c5533ff5ba,h1:ZNYxMf89tMi+NydPAq7yGAxMfMNaMHgG+7WL1CEabjc=,25a1fe9f189e6a4d6e108f22abaec7dd36edc819ab5af1a3e448450b73026271 +github.com/GoogleCloudPlatform/docker-credential-gcr,v1.5.0,h1:wykTgKwhVr2t2qs+xI020s6W5dt614QqCHV+7W9dg64=,4acfcaddfe2aa53e1e643ea13ff3534a2fca1e043d008ab5bba5a0910db1f7c2 +github.com/IBM/go-sdk-core,v1.0.1,h1:vF9Lsoih6fxrAxzJp2fWqnO6Mg8x8O8fzwQAdFoUdok=,e063c8f79f94936a165355f61bdc6f2c404975472ad6be5e47bfdb87fb393c72 +github.com/Jeffail/gabs,v1.4.0,h1://5fYRRTq1edjfIrQGvdkcd22pkYUrHZ5YC/H2GJVAo=,cb193b1477109c19b0d2521fc61735619202e58ac4699605f72313d70884ca9e +github.com/Joker/hpp,v0.0.0-20180418125244-6893e659854a,h1:PiDAizhfJbwZMISZ1Itx1ZTFeOFCml89Ofmz3V8rhoU=,4e99372a7576c587c107fb16d1ae0e8662111e2ca5e5127f7cd93bb01cd02076 +github.com/Joker/jade,v1.0.0,h1:lOCEPvTAtWfLpSZYMOv/g44MGQFAolbKh2khHHGu0Kc=,c4a7f39e7483446ff7b0d7e213a4cd813c783108d6d2e7c6e9a8e968789b18bc +github.com/Knetic/govaluate,v3.0.1-0.20171022003610-9aa49832a739+incompatible,h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw=,d1d4ac5b4f5759726368f68b0d47f3c17c6d8689243ec66272311359d28a865b +github.com/Kodeworks/golang-image-ico,v0.0.0-20141118225523-73f0f4cfade9,h1:1ltqoej5GtaWF8jaiA49HwsZD459jqm9YFz9ZtMFpQA=,1d677069e35c4a3e4f290e68c6e2391f6237aee9ce3f39448ed09a2ddab274b0 +github.com/Kubuxu/go-os-helper,v0.0.1,h1:EJiD2VUQyh5A9hWJLmc6iWg6yIcJ7jpBcwC8GMGXfDk=,90a16f95a8a238910ab0dc9004cb6e56242a10810bf1e296a263d2e385f002e0 +github.com/KyleBanks/depth,v1.2.1,h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=,8f3e9af2e038f561d9c34b631fddc7db39e39992a121fd087f0bf980026464d9 +github.com/MakeNowJust/heredoc,v1.0.0,h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=,062afe6e11aa3c3ac0035d08907b80d5e5b7563905603391ee774bda440abf16 +github.com/Masterminds/goutils,v1.1.0,h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg=,b9520e8d2775ac1ff3fbf18c93dbc4b921133f957ae274f5b047965e9359d27d +github.com/Masterminds/semver,v1.5.0,h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=,15f6b54a695c15ffb205d5719e5ed50fab9ba9a739e1b4bdf3a0a319f51a7202 +github.com/Masterminds/semver/v3,v3.0.1,h1:2kKm5lb7dKVrt5TYUiAavE6oFc1cFT0057UVGT+JqLk=,f1eef1a1b6489d895eb32326f3369bd1615812a4c5fbfe60b2b6cc774c6340f0 +github.com/Masterminds/sprig,v2.22.0+incompatible,h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=,1b4d772334cc94e5703291b5f0fe4ac4965ac265424b1060baf18ef5ff9d845c +github.com/Masterminds/squirrel,v1.1.0,h1:baP1qLdoQCeTw3ifCdOq2dkYc6vGcmRdaociKLbEJXs=,cede1b0a054e000a5e6a8000cb02de7ab64ddca9e0f4153732274627adeed0ae +github.com/Microsoft/go-winio,v0.4.14,h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=,7a86644691d3c86c77ae0b639fa27029706552f00cd51b445389a61694576f6b +github.com/Microsoft/hcsshim,v0.8.6,h1:ZfF0+zZeYdzMIVMZHKtDKJvLHj76XCuVae/jNkjj0IA=,900feaaec1c41d4e111a66bbde330b41fc78902c70c0af37d611505bf42e0632 +github.com/NYTimes/gziphandler,v1.1.1,h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=,2948d9f70e4388f13f4ed9400df41dca60841059f7dcc30cf909c82796cc705a +github.com/NaverCloudPlatform/ncloud-sdk-go,v0.0.0-20180110055012-c2e73f942591,h1:/P9HCl71+Eh6vDbKNyRu+rpIIR70UCZWNOGexVV3e6k=,2e9eacfe3e6785beef75391bcebc14a6a082687c0f0582bc441c3d0106b8bf5c +github.com/NebulousLabs/entropy-mnemonics,v0.0.0-20181203154559-bc7e13c5ccd8,h1:wPFCU8DwC4k5C2LfJc/rVp4cmTqzF3vyydxRR3b3HhQ=,6a65ca779cd216db7bf326ebbb5a26a87d85ff6a6ba832eec281c5c09a8294e3 +github.com/Netflix/go-expect,v0.0.0-20180615182759-c93bf25de8e8,h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw=,fbe7b2f58ecb0e1067a6670bbcf0718d54ec407aab81790cc9e58db9a6774775 +github.com/NickBall/go-aes-key-wrap,v0.0.0-20170929221519-1c3aa3e4dfc5,h1:5BIUS5hwyLM298mOf8e8TEgD3cCYqc86uaJdQCYZo/o=,fd78212ec77052b032b9fc308c028e8fc166de3d6ae4494f5eb3254930728a0b +github.com/Nvveen/Gotty,v0.0.0-20120604004816-cd527374f1e5,h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=,362ac7b59d74231419471b65b60079d167785b97fd4aa0de71575088cd192b1e +github.com/OneOfOne/xxhash,v1.2.5,h1:zl/OfRA6nftbBK9qTohYBJ5xvw6C/oNKizR7cZGl3cI=,7ab3c6a0e7c16c987a589e50a9a353e8877cfffea02bf9e04e370fd26a0c85e1 +github.com/OpenBazaar/jsonpb,v0.0.0-20171123000858-37d32ddf4eef,h1:+aqKrHtCJTRp8ziyrjfHbTF5puPQZfgRt65+iM7FD2w=,5f6ea1466b9d27f016c1bf2650669c788db623142cdc8a1794bc1784fc80fc4e +github.com/OpenBazaar/wallet-interface,v0.0.0-20190807004547-aa8e214acd9b,h1:KjQH45msWRtDhb5JAbBW+eU4M/9xIm11rsOSgAaqDOs=,f7ac40d665241766533b1a49a726068d9dfea5e02c7fd426df81f9e390a7003e +github.com/OpenDNS/vegadns2client,v0.0.0-20180418235048-a3fa4a771d87,h1:xPMsUicZ3iosVPSIP7bW5EcGUzjiiMl1OYTe14y/R24=,b73d6b37d519c7bf181e502b92962f1bf961bb0ca3a9ef7057c3d9a8a3c2f3cd +github.com/OwnLocal/goes,v1.0.0,h1:81QQ3z6dvLhgXlkNpLkaYhk8jiKS7saFG01xy039KaU=,ebb6c7e2c12577c590d2d5546b7a4b4e6fa75c9a408ae5244b5ba2cf09dec1d6 +github.com/PuerkitoBio/goquery,v1.5.0,h1:uGvmFXOA73IKluu/F84Xd1tt/z07GYm8X49XKHP7EJk=,f0064ad35f21c2b9d1377b94f09ead56ec1862da3807e78c26b99c4b3a04f5e6 +github.com/PuerkitoBio/purell,v1.1.1,h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=,59e636760d7f2ab41c2f80c1784b1c73d381d44888d1999228dedd634ddcf5ed +github.com/PuerkitoBio/urlesc,v0.0.0-20170810143723-de5bf2ad4578,h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=,1793124273dd94e7089e95716d40529bcf70b9e87162d60218f68dde4d6aeb9d +github.com/Quasilyte/inltest,v0.7.0,h1:yHvFAaoXn+6iK2uKtb8mXB9KURz6SDPyszoyBAC0Xk4=,8fb4273cea3514742aec06ed58f20cea1214cc542799c70c331a80865aaf3988 +github.com/RangelReale/osin,v1.0.1,h1:JcqBe8ljQq9WQJPtioXGxBWyIcfuVMw0BX6yJ9E4HKw=,edbcc6208879bffa533369bbf417db41c1322193ca05d0deecf13075972c9d57 +github.com/RangelReale/osincli,v0.0.0-20160924135400-fababb0555f2,h1:x8Brv0YNEe6jY3V/hQglIG2nd8g5E2Zj5ubGKkPQctQ=,82fc65bad3da9fc26cc77b485e10ee117459e830547ce89592c41d92871e1129 +github.com/Rican7/retry,v0.1.0,h1:FqK94z34ly8Baa6K+G8Mmza9rYWTKOJk+yckIBB5qVk=,c0e956967f2f632ffc889eeae5b82e437f30e9be409870cdd1e7998def458843 +github.com/RoaringBitmap/roaring,v0.4.7,h1:eGUudvFzvF7Kxh7JjYvXfI1f7l22/2duFby7r5+d4oc=,515892d9b8e4350e5ac5b7a487da94d5d9ab9641071e002b778dd864b7a31c2a +github.com/SAP/go-hdb,v0.14.1,h1:hkw4ozGZ/i4eak7ZuGkY5e0hxiXFdNUBNhr4AvZVNFE=,273de28a254c39e9f24293b864c1d664488e4a5d44d535755a5e5b68ae7eed8d +github.com/Sereal/Sereal,v0.0.0-20190529075751-4d99287c2c28,h1:kmfzzWpCZIrVhxx4V/2oSGhGnhtX+/JijVIlPuKYfHg=,eebfe79e62b5a07f98a367d8a84bcf33ed69818c031e70c3ebc6e9fc34361466 +github.com/SermoDigital/jose,v0.0.0-20180104203859-803625baeddc,h1:LkkwnbY+S8WmwkWq1SVyRWMH9nYWO1P5XN3OD1tts/w=,1711f20ec5b1498c98e46b96e578f39b723557ab50183d644702d40f44a1a345 +github.com/Shopify/go-lua,v0.0.0-20181106184032-48449c60c0a9,h1:+2M9NEk3+xSg0+bWzt1kxsL6EtoEg7sgtT11CZjGwq8=,3e399584ff4a876314243c01be3cba5b98b46bba483d6996dd2d0e7f161b7ad8 +github.com/Shopify/goreferrer,v0.0.0-20181106222321-ec9c9a553398,h1:WDC6ySpJzbxGWFh4aMxFFC28wwGp5pEuoTtvA4q/qQ4=,e47cdf750e6aa39707b90e62f4f87e97abb8d64b2525a16c021c82efb24f9969 +github.com/Shopify/sarama,v1.24.1,h1:svn9vfN3R1Hz21WR2Gj0VW9ehaDGkiOS+VqlIcZOkMI=,c5e06f9c835846eeb5cbbbc540ab949f9775ff37c08cab503dd820b858b1f2e7 +github.com/Shopify/toxiproxy,v2.1.4+incompatible,h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc=,9427e70698ee6a906904dfa0652624f640619acef40652a1e5490e13b31e7f61 +github.com/Sirupsen/logrus,v1.0.6,h1:HCAGQRk48dRVPA5Y+Yh0qdCSTzPOyU1tBJ7Q9YzotII=,dc69c77019152ace477a7f5c0cd97fd25d6ab866e01e1dd06f391722f4f9fba9 +github.com/StackExchange/wmi,v0.0.0-20190523213315-cbe66965904d,h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=,68f499ad4c3f45fc6c286fd2a5966e8e15c0f3abc1f96fbf4a979245df936e16 +github.com/Stebalien/go-bitfield,v0.0.1,h1:X3kbSSPUaJK60wV2hjOPZwmpljr6VGCqdq4cBLhbQBo=,9b17a2749922c810f3598606b87b5f2ba0f3c6abc70966911a8c32f0533ee827 +github.com/Telmate/proxmox-api-go,v0.0.0-20190815172943-ef9222844e60,h1:iEmbIRk4brAP3wevhCr5MGAqxHUbbIDHvE+6D1/7pRA=,55dd16e2cd8e6c1464c6456007cdc5d8676b8b096e90230312daa8c84b57b34d +github.com/TheThingsNetwork/api,v0.0.0-20190522113053-d844e8c040fc,h1:hDk+SAT2tV584ye1hqMN5+NHL6RHJDIbe97cNot6/WQ=,7931f7c4699cd1019c950a68361e3b3fec8bbb8e9204c65c08b50bd588ac506a +github.com/TheThingsNetwork/go-account-lib,v2.0.3+incompatible,h1:pnDIalIqac/VlXenPr+L1XEEf3gIq1eIoZ78S5AP1/s=,e62dcb784cbd28bcec55cf332f7dc06779c75c7df66299f4ce542cd6852358b4 +github.com/TheThingsNetwork/go-cayenne-lib,v1.0.0,h1:be7h6E/69+qaYs1iwQ2xjGjSFPXzvU3q6AWBCWayG2Y=,17091b77ac39b8e73ca6ac3f39f34909bc6a3770098ff2dd534b59a10f6e66ad +github.com/TheThingsNetwork/go-utils,v0.0.0-20190813113035-8715cf82e887,h1:DF/1gkOPk3jtwWa9dFd5tUtwb6z3bLw9tZ/UALbS5Ck=,be4c7c2955630b63300f21773efcdc991d5ff201a53b01d92b2f20fede77065c +github.com/TheThingsNetwork/ttn,v2.10.1+incompatible,h1:LQw+g+kinajii5DHJ6I2o82ObaU/Ws+YYgdLkF5eF54=,4a803fe23636f9c99926e6b5a2b956fb42e84ca38c98458a12bd7fe1c22f7439 +github.com/TheThingsNetwork/ttn/api,v0.0.0-20190516081709-034d40b328bd,h1:vCjDYImJDdW+39EXwij00yzDi1pd3TmP6XtCteDJBd0=,9cda2f899f15f57e8f649bbffb955a8153d6c25a13a4e969df8898bb61559a44 +github.com/TheThingsNetwork/ttn/core/types,v0.0.0-20191015060859-00a6f7874bb9,h1:tlWwCxI3/Zu4vJ4dLWb2wMOYSkeMBvLAxQGwJDCFXi8=,7b3895805d6ac341e5df44c2c8154b374b4bed4c8f54e248ea967abfc37186e7 +github.com/TheThingsNetwork/ttn/utils/errors,v0.0.0-20190516081709-034d40b328bd,h1:ITXOJpmUR4Jhp3Xb/xNUIJH4WR0h2/NsxZkSDzFIFiU=,d64decf456c10fdbbb887212ea63749b495264c40bb5ac047b9f0e5ccd7e540b +github.com/TheThingsNetwork/ttn/utils/random,v0.0.0-20190516081709-034d40b328bd,h1:zKTRK1r3K55XxHuUGxnqYg9aiPDduYeilHUEHua+F+Y=,c504030254919a902b3957267b7ce1870f909cbdd65f0f927819f60710e41d9b +github.com/TheThingsNetwork/ttn/utils/security,v0.0.0-20190516081709-034d40b328bd,h1:og10Wq5S/QC+f4ziON4vrxlYKv9gfEKxG8v/MDs00xw=,e6f013adee3a7a212a6f892db59c8efaf715fe49413e6dbca22229fa04f0d006 +github.com/Unknwon/cae,v0.0.0-20160715032808-c6aac99ea2ca,h1:xU8R31tsvj6TesCBog973+UgI3TXjh/LqN5clki6hcc=,15a1394a603423c5bcd4659275be09d7696774990d5f127500f4156c1a78eb85 +github.com/Unknwon/com,v0.0.0-20190321035513-0fed4efef755,h1:1B7wb36fHLSwZfHg6ngZhhtIEHQjiC5H4p7qQGBEffg=,2cfba36da8f59c6dd8c7a20af59e5ccf9558f42bde7e0918a64a9b68dafcf271 +github.com/Unknwon/i18n,v0.0.0-20171114194641-b64d33658966,h1:Mp8GNJ/tdTZIEdLdZfykEJaL3mTyEYrSzYNcdoQKpJk=,a5ce1436582e797d60e967d853fd22458fc7edeb31bd390d6ace979133bedb78 +github.com/Unknwon/paginater,v0.0.0-20170405233947-45e5d631308e,h1:HnbTtNLKnRmwn85vBmyl7nNJCXUw4rh6X3UeIX5nvko=,60e3af4ba9b482892127f829ec7cc837977ca9e9e634be855d599cc08230e606 +github.com/VividCortex/ewma,v1.1.1,h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM=,eebee7c0f20e96abbda1611ed2a3d26b4c2c10393caa6a2dfd1605763a5c1a12 +github.com/VividCortex/gohistogram,v1.0.0,h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE=,16ebeceeb7e4066f90edbfb90282cd90d4dad0f71339199551de3fbdc7e8c545 +github.com/Workiva/go-datastructures,v1.0.50,h1:slDmfW6KCHcC7U+LP3DDBbm4fqTwZGn1beOFPfGaLvo=,1ac8c9334b63ee2b089b7ecc3b6c8d45793cc4ef4c460f6ebbfd6ecea3ee83bc +github.com/a8m/mark,v0.1.1-0.20170507133748-44f2db618845,h1:hIjQrEARcc9LcH8igte3JBpWBZ7+SpinU70dOjU/afo=,048bfeb7427ff5622874d874a52d7215a2cea99f9741c031e9963348785103c2 +github.com/abbot/go-http-auth,v0.4.0,h1:QjmvZ5gSC7jm3Zg54DqWE/T5m1t2AfDu6QlXJT0EVT0=,8204bca24734f55f179dd1c0b820ae5be83151268693a147086f33cd2d4d473c +github.com/abdullin/seq,v0.0.0-20160510034733-d5467c17e7af,h1:DBNMBMuMiWYu0b+8KMJuWmfCkcxl09JwdlqwDZZ6U14=,bcbe9a2c1e3ac0b981ee436cd1bbb2da8220527511b3cea6517a28a881636814 +github.com/abronan/valkeyrie,v0.0.0-20191010124425-1ae9442de16e,h1:4SrbWyef51DHDc957/8Ms/fDM4D+3bkbXqg6OTnIEAo=,553dce6f5ff57f7ccc5ed6a94e6bf29b38b8773236f3b85bb4025dc0d10d2a92 +github.com/aead/siphash,v1.0.1,h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg=,25da04ff418e0b2871b1193a3478977b4aa66c20737b9ca70a5040b876b6d3d9 +github.com/aerogo/http,v1.0.12,h1:1o5QW6TQLNuutQLuPCX0Tn7g/sSH3JMHv79UGIBpvkw=,a58d344ff2010737d2418050f4188339087cfb369c903bd31e20ccba388304a1 +github.com/afex/hystrix-go,v0.0.0-20180502004556-fa1af6a1f4f5,h1:rFw4nCn9iMW+Vajsk51NtYIcwSTkXr+JGrMd36kTDJw=,c0e0ea63b57e95784eeeb18ab8988ac2c3d3a17dc729d557c963f391f372301c +github.com/agext/levenshtein,v1.2.2,h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE=,07caaae8fcdb7c83195a0afffc03c9df76275b1e9a7b69dabfe0d2f47729bc7c +github.com/agl/ed25519,v0.0.0-20170116200512-5312a6153412,h1:w1UutsfOrms1J05zt7ISrnJIXKzwaspym5BTKGx93EI=,98c1510ac20b7d61bf4e2c76e7184fcbd0a8b78b0fc667c2b772777912963d3f +github.com/agnivade/levenshtein,v1.0.1,h1:3oJU7J3FGFmyhn8KHjmVaZCN5hxTr7GxgRue+sxIXdQ=,cb0e7f070ba2b6a10e1c600d71f06508404801ff45046853001b83be6ebedac3 +github.com/ajg/form,v1.5.1,h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=,b063b07639670ce9b6a0065b4dc35ef9e4cebc0c601be27f5494a3e6a87eb78b +github.com/ajstarks/svgo,v0.0.0-20190826172357-de52242f3d65,h1:kZegOsPGxfV9mM8WzfllNZOx3MvM5zItmhQlvITKVvA=,1459a44f9162f463b59eacf58e4bb8873e612c5b3df45fc6e34074310d2269ae +github.com/akamai/AkamaiOPEN-edgegrid-golang,v0.9.0,h1:rXPPPxDA4GCPN0YWwyVHMzcxVpVg8gai2uGhJ3VqOSs=,91c3a4743d959b3bb2bb7359790df4688021830e482d393ea6d4f3a27aebd63d +github.com/akavel/rsrc,v0.8.0,h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw=,13954a09edc3a680d633c5ea7b4be902df3a70ca1720b349faadca44dc0c7ecc +github.com/akyoto/assert,v0.2.3,h1:ftENRGDEK5AKuKmZb9LtbDIHeE8p8cIYI4M92CbA9nE=,f0a31d5859109c37568b8702fcf92cd3a49ec4892dace74d113df5fd49491975 +github.com/akyoto/color,v1.8.11,h1:uCQi+uRyngo1cJhJSv28PQmduGFiOAGNF6F9MFoRDek=,0fa16c51743ca03e108fde20eabb070d17d25111cb287e15f8567268d439098a +github.com/akyoto/colorable,v0.1.7,h1:ge91E25hiOiT/Zu47ij/rTO3cks7wMlTrcQspua1hFM=,07c2dd4d994d9ff1dad97ad2e2650ff60d90f50ecd52380f357e562efda99613 +github.com/akyoto/stringutils,v0.2.6,h1:IP+7jtH8uofpan8MYlV/WMNaLDGBRbzgiTKYnxcAwkw=,802a3b54f91b930c1e8f2376bebf783b16894da626fc7c8064268b07ab567f7c +github.com/akyoto/tty,v0.1.3,h1:AdnLETzgooimWLvoBQLn5bT1j+i0yiB4E596BfFKnmA=,749381ec9dce8bc96bec66c5dfb0874db917a008f9685d9c65c15da43ede964c +github.com/alcortesm/tgz,v0.0.0-20161220082320-9c5fe88206d7,h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=,ccedffb2c46724216b787fb1a79ae33fb0dfdd672c669db000c4ed5a68b08014 +github.com/alecthomas/assert,v0.0.0-20170929043011-405dbfeb8e38,h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U=,873d257170b1363142cbf5e16b49c6a21cccb3e4aaceb9d370c3b78b051a5663 +github.com/alecthomas/chroma,v0.6.8,h1:TW4JJaIdbAbMyUtGEd6BukFlOKYvVQz3vVhLBEUNwMU=,ebc5202e6a0ededc5a2c7396b01b76c050331bead9d047f31fe648cb63e68aa3 +github.com/alecthomas/colour,v0.0.0-20160524082231-60882d9e2721,h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo=,334101c562d2e74338f6baab1de04f3bbff89021d24f4206c551ef47b96a2bfe +github.com/alecthomas/kingpin,v2.2.6+incompatible,h1:5svnBTFgJjZvGKyYBtMB0+m5wvrbUHiqye8wRJMlnYI=,a88daee47262ffeca1f6e348399c16c9be160f3c5e972c0b6c9dc275d85bcdc6 +github.com/alecthomas/kong,v0.2.1-0.20190708041108-0548c6b1afae,h1:C4Q9m+oXOxcSWwYk9XzzafY2xAVAaeubZbUHJkw3PlY=,4292d9b6903d67f060d3bd57ffca0a4ebca359824ce2d32a512ac1b963fa3dc0 +github.com/alecthomas/kong-hcl,v0.1.8-0.20190615233001-b21fea9723c8,h1:atLL+K8Hg0e8863K2X+k7qu+xz3M2a/mWFIACAPf55M=,21a34d6ee62e3419601d0e083b8829001a9833899dd3c2d27a82c794426fd0ee +github.com/alecthomas/log4go,v0.0.0-20180109082532-d146e6b86faa,h1:0zdYOLyuQ3TWIgWNgEH+LnmZNMmkO1ze3wriQt093Mk=,04bdaa7d57a681072316927175c21ca7c9e7a19bd7fee2102b5f40e5b01a7559 +github.com/alecthomas/repr,v0.0.0-20181024024818-d37bc2a10ba1,h1:GDQdwm/gAcJcLAKQQZGOJ4knlw+7rfEQQcmwTbt4p5E=,c01a833ec56f68113f6cd7ed82b7da9bfaec641a10e929e0e3e5e5dadb1a85ad +github.com/alecthomas/template,v0.0.0-20190718012654-fb15b899a751,h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=,25e3be7192932d130d0af31ce5bcddae887647ba4afcfb32009c3b9b79dbbdb3 +github.com/alecthomas/units,v0.0.0-20190924025748-f65c72e2690d,h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=,e6b0ccb38bfba85d90092d1c57671d5f7996757bd71f6f1970c6ae2f9dae3f6e +github.com/alicebob/gopher-json,v0.0.0-20180125190556-5a6b3ba71ee6,h1:45bxf7AZMwWcqkLzDAQugVEwedisr5nRJ1r+7LYnv0U=,2374b534198621157afb9466a52d361b6eed33dcf9bb0674019515e64b16129e +github.com/alicebob/miniredis,v0.0.0-20180911162847-3657542c8629,h1:gLoh8jzwIxdisBnHiWRIuReqtH9cpslSE2564UWXun0=,14b5e988ec6d8357a25ba19a7adbdb34920f5f91401b2b26eb25f04fed9893b0 +github.com/aliyun/alibaba-cloud-sdk-go,v0.0.0-20191031111935-12810c79403d,h1:CmGtZPPsr0C31ZBrzdP+D2oczTbyEBbO3bYg6z5EIDY=,4f0f25f45d954ab970b24783e31b716b619b128081acc9ed7b00727cd7c2d536 +github.com/aliyun/aliyun-oss-go-sdk,v2.0.3+incompatible,h1:724q2AmQ3m1mrdD9kYqK5+1+Zr77vS21jdQ9iF9t4b8=,47ede6a440ad4bb1a1c33d71bd12f76f44aa2487f676b8770152130be3021657 +github.com/aliyun/aliyun-tablestore-go-sdk,v4.1.2+incompatible,h1:ABQ7FF+IxSFHDMOTtjCfmMDMHiCq6EsAoCV/9sFinaM=,82c8ced9cd377462c6ea5070258f97c77ffddd66621e8960b08184eb58416846 +github.com/allegro/bigcache,v1.2.1,h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc=,9250edab8c7851cfa0c6c173e721cf70831e90742a7485c2eba1d6e2cc8c71eb +github.com/anacrolix/envpprof,v1.1.0,h1:hz8QWMN1fA01YNQsUtVvl9hBXQWWMxSnHHoOK9IdrNY=,97f2340bcb169956bad97c59fdc17bbd2eb7c0acefe4e2ae327c7d6bd5a5f6cf +github.com/anacrolix/log,v0.3.0,h1:Btxh7GkT4JYWvWJ1uKOwgobf+7q/1eFQaDdCUXCtssw=,e8bc14381d8746426c7e272228780047e0594d695d02e188269f1e86ef1644d4 +github.com/anacrolix/missinggo,v1.2.1,h1:0IE3TqX5y5D0IxeMwTyIgqdDew4QrzcXaaEnJQyjHvw=,2fb8cba1f6eaf69989ca5c522c2d4afd6c1071ad9459f940b6058dbfc2f3b285 +github.com/anacrolix/missinggo/perf,v1.0.0,h1:7ZOGYziGEBytW49+KmYGTaNfnwUqP1HBsy6BqESAJVw=,f4271e6359cf3dd5cba81bcf1436e8abc5d0c96c11820b881544708caa131713 +github.com/anacrolix/sync,v0.0.0-20180808010631-44578de4e778,h1:XpCDEixzXOB8yaTW/4YBzKrJdMcFI0DzpPTYNv75wzk=,bef95f54e1b17e4e7666cbf552e541e670f29fc3fd354aba0ebeee73f744ea24 +github.com/anacrolix/tagflag,v1.0.1,h1:Yd3d5DaKbRA70k7CoFuBsbmfSWIsvtZ9t80xW/x4vQY=,8fc0a5b5607cde223bacd9e4fa3b26f6166c09a09bfabe2c2c803e45e17971fa +github.com/anacrolix/utp,v0.0.0-20180219060659-9e0e1d1d0572,h1:kpt6TQTVi6gognY+svubHfxxpq0DLU9AfTQyZVc3UOc=,35c47428844d10f077225195f9a6c7587c671b7fc70bbaf59ef74cd6d8834e32 +github.com/andreyvit/diff,v0.0.0-20170406064948-c7f18ee00883,h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=,d39614ff930006640ec15865bca0bb6bf8e1ed145bccf30bab08b88c1d90f670 +github.com/andybalholm/cascadia,v1.0.0,h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRySc45o=,7fd82e560ca1a453974a64c9bf6514b17322d1b7392bad730a5006d929996906 +github.com/andygrunwald/go-jira,v1.5.0,h1:/1CyYLNdwus7TvB/DHyD3udb52K12aYL9m7WaGAO9m4=,3ee973941f400bf95005cada54e09e319cb4943cd6c8d66480243d3b40895821 +github.com/anmitsu/go-shlex,v0.0.0-20161002113705-648efa622239,h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=,3b8376ff631f30d47e0348a8f847050b97c3db89483f45d1cd8f11d23c7c56a2 +github.com/antchfx/htmlquery,v1.0.0,h1:O5IXz8fZF3B3MW+B33MZWbTHBlYmcfw0BAxgErHuaMA=,81c86507bf2a226d5a3d20db547503d490f1e3b77035f267056e80cd73e240e2 +github.com/antchfx/xmlquery,v1.0.0,h1:YuEPqexGG2opZKNc9JU3Zw6zFXwC47wNcy6/F8oKsrM=,969fc21438fe076aee032574578158ac7e030979153dcf7b5ff5c133cbfa4d86 +github.com/antchfx/xpath,v0.0.0-20190129040759-c8489ed3251e,h1:ptBAamGVd6CfRsUtyHD+goy2JGhv1QC32v3gqM8mYAM=,22cb767dc0cafecba39e1b0322cc8aebbc6fd912e4b0fcda8c2c1dde2d80c4d2 +github.com/antchfx/xquery,v0.0.0-20180515051857-ad5b8c7a47b0,h1:JaCC8jz0zdMLk2m+qCCVLLLM/PL93p84w4pK3aJWj60=,9ddc9d830f2d6c7a22604035f0c621228ffa4ed6ff1f1d34655ee477c203c899 +github.com/antihax/optional,v0.0.0-20180407024304-ca021399b1a6,h1:uZuxRZCz65cG1o6K/xUqImNcYKtmk9ylqaH0itMSvzA=,7b0a2bf3eb029d9abe761db1874a501b60f267e675d72ae8c4b8c6f406ddcfd0 +github.com/apache/arrow/go/arrow,v0.0.0-20191024131854-af6fa24be0db,h1:nxAtV4VajJDhKysp2kdcJZsq8Ss1xSA0vZTkVHHJd0E=,4bd8443c24bc06843c0270df4f08f98b3eee6116604ff16d14dce34b242783cf +github.com/apache/thrift,v0.13.0,h1:5hryIiq9gtn+MiLVn0wP37kb/uTeRZgN08WoCsAhIhI=,d75265e363da943c24e7ed69104bf018429024a50968421e48a6ab3e624733c2 +github.com/apex/log,v1.1.1,h1:BwhRZ0qbjYtTob0I+2M+smavV0kOC8XgcnGZcyL9liA=,5bb0f19e5c68b104ed32a311ea9c6f6e2a5e8fa597b342695e069468e2248d83 +github.com/aphistic/golf,v0.0.0-20180712155816-02c07f170c5a,h1:2KLQMJ8msqoPHIPDufkxVcoTtcmE5+1sL9950m4R9Pk=,a0ca77a50520037607c3a2a798b66aee1d5df63f4800b4236f51be2f1e3c1d70 +github.com/aphistic/gomol,v0.0.0-20190314031446-1546845ba714,h1:ml3df+ybkktxzxTLInLXEDqfoFQUMC8kQtdfv8iwI+M=,c2fd1a9db2fb7a5ca7ba9132fbddb5d8efd64babcff7c0f66d41d3cf97b8caab +github.com/aphistic/gomol-console,v0.0.0-20180111152223-9fa1742697a8,h1:tzgowv45TOFALtZLJ9y3k+krzOh2J8IkCvJ8T//6VAU=,26a1b99db9a92a7f5d088e529c43db6de957a3a1650c27d7a872495f73a52880 +github.com/aphistic/gomol-gelf,v0.0.0-20170516042314-573e82a82082,h1:PgPqI/JnStmzwTof+PtT53Pz53dlrz2BmF7cn5CAwQM=,e44d4de8d62391c1e0e70c3b27f4c341bb0398083f33b99be46e29144fad3c50 +github.com/aphistic/gomol-json,v1.1.0,h1:XJWwW8PxYOHf0f0FquuBWcgvZBvQ89nPxZsqQ9pfpro=,0e1ab66a46afe81c4662f8a49ca38042f0c6bc8645895336399adef1eedaff59 +github.com/aphistic/sweet,v0.2.0,h1:I4z+fAUqvKfvZV/CHi5dV0QuwbmIvYYFDjG0Ss5QpAs=,02bebcef905b02cf7195137d9b20920367bb5f8c635a6e5a112b787596414f51 +github.com/aphistic/sweet-junit,v0.0.0-20190314030539-8d7e248096c2,h1:qDCG/a4+mCcRqj+QHTc1RNncar6rpg0oGz9ynH4IRME=,6a3ab195b97bd1981f2ae87a172bc24ecfb44ffbd8d28428f97bfa46e66f559b +github.com/apparentlymart/go-cidr,v1.0.1,h1:NmIwLZ/KdsjIUlhf+/Np40atNXm/+lZ5txfTJ/SpF+U=,5af128e1ecdf5f2203fda104a653f13fb2e46acc3f68b2d7634a760a8f556ea0 +github.com/apparentlymart/go-dump,v0.0.0-20190214190832-042adf3cf4a0,h1:MzVXffFUye+ZcSR6opIgz9Co7WcDx6ZcY+RjfFHoA0I=,3506757fd2dcbcf8e77aa962c923d9ceaf918538bf9b117f98aa562bc83c77ef +github.com/apparentlymart/go-textseg,v1.0.0,h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0=,2572a77af285125f1980e9b751e5a7c3ae59b73c4fc97e7c2407681609991142 +github.com/appc/spec,v0.8.11,h1:BFwMCTHSDwanDlAA3ONbsLllTw4pCW85kVm290dNrV4=,4a17d699b3e2c3cc8b301de260a45c8fc31054fbb5c689e567f24e3e63bf8f79 +github.com/apple/foundationdb/bindings/go,v0.0.0-20190411004307-cd5c9d91fad2,h1:VoHKYIXEQU5LWoambPBOvYxyLqZYHuj+rj5DVnMUc3k=,a2dc6bd23d9066d3acf174c9b33378c08ae4a95cfd017abc70a16388e74ea2c3 +github.com/approvals/go-approval-tests,v0.0.0-20160714161514-ad96e53bea43,h1:ePCAQPf5tUc5IMcUvu6euhSGna7jzs7eiXtJXHig6Zc=,e3b51ab88c4f3b1c4aea2fadd0b3d3e2ec178d37232066b9fe3b0177e1c6e9aa +github.com/aquasecurity/fanal,v0.0.0-20191031102512-c1c079886da6,h1:B84l/SNXzzcqwgIORAmEv7gs4K4l+DJkdliI6ib/zNw=,7247188e1746360364e7ff77aa0c531df69074c49b23e7f67d65134ca577b0e0 +github.com/aquasecurity/go-dep-parser,v0.0.0-20190819075924-ea223f0ef24b,h1:55Ulc/gvfWm4ylhVaR7MxOwujRjA6et7KhmUbSgUFf4=,73ce01b48b9aa56349d928a27bdd4b77c149541385e645951b2e25f1d6ab5d26 +github.com/araddon/dateparse,v0.0.0-20190622164848-0fb0a474d195,h1:c4mLfegoDw6OhSJXTd2jUEQgZUQuJWtocudb97Qn9EM=,3b88bff198316e2795d11340862ef873387cd7dba97eeb17f106f41deb00d602 +github.com/araddon/gou,v0.0.0-20190110011759-c797efecbb61,h1:Xz25cuW4REGC5W5UtpMU3QItMIImag615HiQcRbxqKQ=,936e20f4c9eaa45f54586ab86bce911f0b1f935d0410dd683dc647797ed7225d +github.com/aristanetworks/fsnotify,v1.4.2,h1:it2ydpY6k0aXB7qjb4vGhOYOL6YDC/sr8vhqwokFQwQ=,9c0dd5427e82f044a9e5808a3436b43472ff032f23ac853829e5c166171044a3 +github.com/aristanetworks/glog,v0.0.0-20180419172825-c15b03b3054f,h1:Gj+4e4j6g8zOhckHfGbZnpa0k8yDrc0XRmiyQj2jzlU=,496dd08756b324a7925b670a907328433f1477763a229b76a4eef8ed254c9683 +github.com/aristanetworks/goarista,v0.0.0-20191023202215-f096da5361bb,h1:gXDS2cX8AS8KbnP32J6XMSjzC1FhHEdHfUUCy018VrA=,2c348fcdf827ac0d1238fb556f66ad1f13f05d8c5a6d2b3efe5f94be40af5021 +github.com/aristanetworks/splunk-hec-go,v0.3.3,h1:O7zlcm4ve7JvqTyEK3vSBh1LngLezraqcxv8Ya6tQFY=,545adec43ebdf1c9cdc65cd3d738d131f1b02706d25876de1fda65c4989195af +github.com/armon/circbuf,v0.0.0-20190214190532-5111143e8da2,h1:7Ip0wMmLHLRJdrloDxZfhMm0xrLXZS8+COSu2bXmEQs=,c8b7ba977844b5378a2413c123c3e55d0885fb67f64ad6cf06575a791a36b827 +github.com/armon/consul-api,v0.0.0-20180202201655-eb2c6b5be1b6,h1:G1bPvciwNyF7IUmKXNt9Ak3m6u9DE1rF+RmtIkBpVdA=,091b79667f16ae245785956c490fe05ee26970a89f8ecdbe858ae3510d725088 +github.com/armon/go-metrics,v0.0.0-20190430140413-ec5e00d3c878,h1:EFSB7Zo9Eg91v7MJPVsifUysc/wPdN+NOnVe6bWbdBM=,3d48bc38dda0cff4dbf0b56b9b6e2e8fc3e6be2282f2a612a96a6702cc8a9fc5 +github.com/armon/go-proxyproto,v0.0.0-20190211145416-68259f75880e,h1:h0gP0hBU6DsA5IQduhLWGOEfIUKzJS5hhXQBSgHuF/g=,1004212be9a343c99e1849425845af1ec5e3e35cc4917483721cb03620982d58 +github.com/armon/go-radix,v1.0.0,h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=,df93c816505baf12c3efe61328dc6f8fa42438f68f80b0b3725cae957d021c90 +github.com/armon/go-socks5,v0.0.0-20160902184237-e75332964ef5,h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=,f473e6dce826a0552639833cf72cfaa8bc7141daa7b537622d7f78eacfd9dfb3 +github.com/asaskevich/govalidator,v0.0.0-20190424111038-f61b66f89f4a,h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=,b5dfb936e0256459bc633c8acf433f4a01a468868db9bd6e390a67f4678185f5 +github.com/asdine/storm,v2.1.2+incompatible,h1:dczuIkyqwY2LrtXPz8ixMrU/OFgZp71kbKTHGrXYt/Q=,ffea8b759006a871732554e1e0a42753fb9a5dd9884eb150e1b42806d51cd5fd +github.com/assetsadapterstore/tivalue-adapter,v1.0.3,h1:zcFcT1x1rWDYQEaA3wI7Hr7F25Cspy+O1cr+vUMjrks=,c42adddd544495ef0ebe1d8730bad20c4251c7646e1782542782bc946c839eca +github.com/astaxie/beego,v1.12.0,h1:MRhVoeeye5N+Flul5PoVfD9CslfdoH+xqC/xvSQ5u2Y=,1f14eb5d216170c027754bea1129bbcdafc06a035650e635375c61a17be6f316 +github.com/asticode/go-astilog,v1.0.0,h1:l9tek0K7KoQCmhZ7cvBTtVu0NsKpS9hB6jBLtQyxWYk=,49fe2b286073848e780a9326f7d37771372e61827ff07b80db89667e6ac4d1d4 +github.com/aws/amazon-ssm-agent,v0.0.0-20191011205301-04bb0617297b,h1:xv695CeRjoBS0baQSS5UfQkeo63GiMjmDwiAeY09bSw=,08ede8d7aa20210a4738e0ea033f1bf8fd1ce13bba6c375431c8c1e7a8565c37 +github.com/aws/aws-lambda-go,v1.13.2,h1:8lYuRVn6rESoUNZXdbCmtGB4bBk4vcVYojiHjE4mMrM=,05b1633366a8df9e313df4409d003a277ff7ae46f1079b3ad7f6b48c0dabfb75 +github.com/aws/aws-sdk-go,v1.25.25,h1:j3HLOqcDWjNox1DyvJRs+kVQF42Ghtv6oL6cVBfXS3U=,c34d718d97487766a9a8ac818d37dd135d75d747a8d191a616b75425c32456f2 +github.com/aybabtme/rgbterm,v0.0.0-20170906152045-cc83f3b3ce59,h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo=,a4456a42277e0c987de99e9c4ba141db064107ce737ad1dd2e050aeb1149b67e +github.com/aymerick/raymond,v2.0.2+incompatible,h1:VEp3GpgdAnv9B2GFyTvqgcKvY+mfKMjPOA3SbKLtnU0=,df6e22632cb314b76ab10dd6a1c2c66a79da44200bfec9f5e4f321100d90dc64 +github.com/baiyubin/aliyun-sts-go-sdk,v0.0.0-20180326062324-cfa1a18b161f,h1:ZNv7On9kyUzm7fvRZumSyy/IUiSC7AzL0I1jKKtwooA=,0965da027355d9b385358331ec359cf729ec4571ec4ca86339da925364c13559 +github.com/bartekn/go-bip39,v0.0.0-20171116152956-a05967ea095d,h1:1aAija9gr0Hyv4KfQcRcwlmFIrhkDmIj2dz5bkg/s/8=,6a278508499838d4c57c1dbdafcfc9f9f909e7358c518a8699728053b695d0c5 +github.com/bazelbuild/buildtools,v0.0.0-20191024175656-9f3978593d3e,h1:QdfIPgk+fJY8AcfjVk2/tdc2dNtl6d+7x8dhVBP72Ik=,f768dd2a38a1dedc924740f9b7a3194ca68d8a24db8fb840c547aee3911162d3 +github.com/bbangert/toml,v0.0.0-20130821181452-a2063ce2e5cf,h1:SGoM2ypzNnI+hMs01svW6wRddndk7eWRs1Bx1zOGRTI=,63690dcb3fcf13b55193cfe263b4a4fdbbe2ee9d7f93440375815dac28d34cb9 +github.com/bcext/cashutil,v0.0.0-20190126062106-1194a0af0582,h1:+sgikGWB0jvS9rzLlPww+SSFoieOLB8yieXyX9DRCF4=,4d5b42e5d472015edeef1b6bf54e253a85bab6df1ac16aabea7fd0dea4aa85e3 +github.com/bcext/gcash,v0.0.0-20190404152342-2e38815af4f2,h1:XVuqYNixmuo81vR/PnBRDDiTH7596mAwQlQ8BucvGnM=,6b24e00369a493c32e730a4d78d8c4fd122ffe0ce319c5d72f3c7d2f12ede4b7 +github.com/beego/goyaml2,v0.0.0-20130207012346-5545475820dd,h1:jZtX5jh5IOMu0fpOTC3ayh6QGSPJ/KWOv1lgPvbRw1M=,aaa4165412caaacbb2df4427207a206e09215c3f7a19f8309e9222ca9ff80691 +github.com/beego/x2j,v0.0.0-20131220205130-a0352aadc542,h1:nYXb+3jF6Oq/j8R/y90XrKpreCxIalBWfeyeKymgOPk=,f9a32026b2107f3cc3610ac6b75c4c64818646a316c35e648c8811d4276a9993 +github.com/beevik/etree,v1.1.0,h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=,614a33736f8b9262a809f101df5bf71f47777879b1191165b6247d6b67c7468c +github.com/beevik/guid,v0.0.0-20170504223318-d0ea8faecee0,h1:oLd/YLOTOgA4D4aAUhIE8vhl/LAP1ZJrj0mDQpl7GB8=,5add94fcade6c7afa236112c8da300d47ec499ad1789a5e805c8198062dd0749 +github.com/beevik/ntp,v0.2.0,h1:sGsd+kAXzT0bfVfzJfce04g+dSRfrs+tbQW8lweuYgw=,42e14f30c23ba2f5ddaff76101016d87f0f0a0f1d96d3d20e42fd02842091c76 +github.com/beorn7/perks,v1.0.1,h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=,25bd9e2d94aca770e6dbc1f53725f84f6af4432f631d35dd2c46f96ef0512f1a +github.com/bep/debounce,v1.2.0,h1:wXds8Kq8qRfwAOpAxHrJDbCXgC5aHSzgQb/0gKsHQqo=,ddc0a77e4819b6b826d69fdf1a5a153f3f867a31e030cfe28296355b670adf21 +github.com/bep/gitmap,v1.1.1,h1:Nf8ySnC3I7/xPjuWeCwzukUFv185iTUQ6nOvLy9gCJA=,364163e67741ae331d164fd881964160f19fdbdfe094e0e762314cc37aac646a +github.com/bep/go-tocss,v0.6.0,h1:lJf+nIjsQDpifUr+NgHi9QMBnrr9cFvMvEBT+uV9Q9E=,40e7175da9564796e184e4383bfce703f63244b850999b5a54fd5792bfc5baf5 +github.com/bep/tmc,v0.5.0,h1:AP43LlBcCeJuXqwuQkVbTUOG6gQCo04Et4dHqOOx4hA=,f8e0be71fb845a4ca22825f5b9c51c1a66c29e9ccff723e063781ee64c664c66 +github.com/bgentry/go-netrc,v0.0.0-20140422174119-9fd32a8b3d3d,h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=,59fbb1e8e307ccd7052f77186990d744284b186e8b1c5ebdfb12405ae8d7f935 +github.com/bgentry/speakeasy,v0.1.0,h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=,d4bfd48b9bf68c87f92c94478ac910bcdab272e15eb909d58f1fb939233f75f0 +github.com/bifurcation/mint,v0.0.0-20180715133206-93c51c6ce115,h1:fUjoj2bT6dG8LoEe+uNsKk8J+sLkDbQkJnB6Z1F02Bc=,40a4bd02b9e3477271638bc17ae8537e2675ace0a9b85d753820e979dbf97f36 +github.com/binance-chain/go-sdk,v1.0.8,h1:mC1Tai9diqIWuKTJmrFLal90OCsgtDvyLEItMvglaHA=,3d0f86f959b38f11174d8ee574e77e5d80d2c672d0720dee519f3708e873b0ca +github.com/binance-chain/ledger-cosmos-go,v0.9.9-binance.1,h1:8mAtw1Tp/BhhTrsXmXM60H1fihcvcKLfo2ZSxShaXKw=,f6dc2bfb4d29db01cad72815615301e089d727110d1d5a0de43e829953e45041 +github.com/biogo/hts,v0.0.0-20160420073057-50da7d4131a3,h1:3b+p838vN4sc37brz9W2HDphtSwZFcXZwFLyzm5Vk28=,93be93b79da8920fb5f02bb2e50a364e2b33dc831229d163e7be70c1010cdb9e +github.com/bitcoinsv/bsvd,v0.0.0-20190609155523-4c29707f7173,h1:2yTIV9u7H0BhRDGXH5xrAwAz7XibWJtX2dNezMeNsUo=,8e1e554ddc232e763fac27ddc0661cfe543163802b0d6bb9a2904bf24756ddc3 +github.com/bitcoinsv/bsvlog,v0.0.0-20181216181007-cb81b076bf2e,h1:6f+gRvaPE/4h0g39dqTNPr9/P4mikw0aB+dhiExaWN8=,89f0c34e6936d82a1629d5d255923ff27c0adeb99709269cf62071e48cb5fbd8 +github.com/bitcoinsv/bsvutil,v0.0.0-20181216182056-1d77cf353ea9,h1:hFI8rT84FCA0FFy3cFrkW5Nz4FyNKlIdCvEvvTNySKg=,4d4923e8743012e1f8ed1a1ef721786fc2d5249cc5dafd96fdd350c485378cfe +github.com/bitly/go-hostpool,v0.0.0-20171023180738-a3a6125de932,h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY=,9a55584d7fa2c1639d0ea11cd5b437786c2eadc2401d825e699ad6445fc8e476 +github.com/bitly/go-simplejson,v0.5.0,h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y=,53930281dc7fba8947c1b1f07c82952a38dcaefae23bd3c8e71d70a6daa6cb40 +github.com/blackducksoftware/horizon,v0.0.0-20190625151958-16cafa9109a3,h1:noI1RY2cUFZfdZMIz1+1LzT8ZeuWK703gwmH/ZC2YnQ=,ece353e9e973ce03d131b29c6c00aea53f1b2e507960b389cdfeb2cc317897ef +github.com/blacktear23/go-proxyprotocol,v0.0.0-20180807104634-af7a81e8dd0d,h1:rQlvB2AYWme2bIB18r/SipGiMEVJYE9U0z+MGoU/LtQ=,123c82a455309b3a3118504c0a70771352292abced294dca39a570b89e48adba +github.com/blakesmith/ar,v0.0.0-20190502131153-809d4375e1fb,h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4=,015878daba57ba5ce7228f772b843fffa847d99c7afeb308089bef77f433c510 +github.com/blang/semver,v3.5.1+incompatible,h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=,8d032399cf835b93f7cf641b5477a31a002059eed7888a775f97bd3e9677ad3c +github.com/blevesearch/bleve,v0.8.1,h1:20zBREtGe8dvBxCC+717SaxKcUVQOWk3/Fm75vabKpU=,58a5b5ade8123d54b7510e463c25e1e59e6cd3d98acdcb4d582c42db67c03519 +github.com/blevesearch/blevex,v0.0.0-20180227211930-4b158bb555a3,h1:U6vnxZrTfItfiUiYx0lf/LgHjRSfaKK5QHSom3lEbnA=,defa5966f802eab571cc8d9315323104b776751dd13caae9d8fc0476576d57ca +github.com/blevesearch/go-porterstemmer,v0.0.0-20141230013033-23a2c8e5cf1f,h1:J9ZVHbB2X6JNxbKw/f3Y4E9Xq+Ro+zPiivzgmi3RTvg=,e13cc37d08c58870cdbad544b726934cd62ca6aa2ae35f02598f72e30d7c0f59 +github.com/blevesearch/segment,v0.0.0-20160105220820-db70c57796cc,h1:7OfDAkuAGx71ruzOIFqCkHqGIsVZU0C7PMw5u1bIrwU=,21278826e6ba0f63024a953c480467bf41d6717ae4a87c3021a9f74d2f2ae618 +github.com/blocktree/arkecosystem-adapter,v1.0.4,h1:TkZWCzAgi20CjAMlOpwTDppt6XO7X8Fn5EjSUsuB6kI=,22346af6957b0b8fae47d982605f565e5e16e86bc52a9fdd234b023067896cf2 +github.com/blocktree/bitshares-adapter,v1.0.5,h1:mzYlpip0crtYaDaXbKqtGLAxad83p19HLTVa9LLW3fc=,03ce80398ab59af79feb92b054e5da02a290ef27aef5facb93cdd86de2e0df91 +github.com/blocktree/ddmchain-adapter,v1.0.5,h1:Lx8zD0lOHb9TJ7EcGJQhyvpDkYko6OoV8uwudKRKlJA=,81e65ed5692152fcaa1dbf997f71dc43192abc72dad6fb78b721d742c05c1a7a +github.com/blocktree/eosio-adapter,v1.0.0,h1:cncKE4QbQxDsr8B+HlhU7tywbCtZRsWMln2ek8I5lbc=,cc658d6f9fa5470c5affb4caad58e17637a6d46f8e5d1b3730ed06e570e61959 +github.com/blocktree/ethereum-adapter,v1.1.10,h1:PkmQeRT5ljyCOQZPT0diJo+4G9OqOcJsnRcXeF5fitU=,cf8465db958e214c8196e6311fd5db24f8d28265a37914c2cf9d2dac54a5fd1a +github.com/blocktree/futurepia-adapter,v1.0.12,h1:mL1rDvcM55hKwLhHOkg1v2GwnCEsDniUrqrMG3PK/+4=,ae29bbdb9a4a1ec345f7d220d6a736ed827a307454d0466bb065dacf3d94200d +github.com/blocktree/go-owcdrivers,v1.1.18,h1:KCNm+HczpDfxyUf+Wrvbj/iWwQDJ+ca/FBjm3H06rIY=,65bcca1918d8b9e1048bac14b1393dec246402320b6a5dde20ee6afe84585736 +github.com/blocktree/go-owcrypt,v1.0.3,h1:qfAwJsWYp7WaI26hAwPuFUrMXhD9bWwuGXYWBOLsVes=,f365daad6adfcc5aee14faa1455f772b5e39b1c9ff3598afb1c3645587cb6b2e +github.com/blocktree/moacchain-adapter,v1.0.3,h1:k9drMeekvBsXORortW/zJXaO6CokXVv2EL0/YK3c1/A=,66c87656369c5246bad1527f7385d1cb98bbeda431383f154a23e9bf821a05a2 +github.com/blocktree/nulsio-adapter,v1.1.7,h1:d0xuovBqodBAv8BE/CPZjfe5CNma6FFSP6W3ynJRD0U=,c814c05686483abc345bf4fb997fc61595e738b99cc8a8d36742414f93e948b0 +github.com/blocktree/ontology-adapter,v1.0.8,h1:Lej35ZPPgjS6nP5CEumIUskRNASMZswgrByYSxrWPe0=,fcdeb4c6d8f37a22f52e2938ebc51b4ff1f4cf4116eebce8ecc7591995236853 +github.com/blocktree/openwallet,v1.5.3,h1:6hNj61wLfzEGqbbY0ZOeqGAjSj9snoRSBikgSlWPqZI=,1f169b69cd3ec4a4f82836c2b2178eb162464d6413c09f8170f73a838d28650b +github.com/blocktree/ripple-adapter,v1.0.13,h1:zgJt7onq5+V6pvQ7Kl3xiiSkk3uxuCF07OpwCtJTM8w=,bb7f515a6573eb185da0bebb28bf57364d175ee7f937e18af5b2eac98741464f +github.com/blocktree/virtualeconomy-adapter,v1.1.5,h1:YJ2JKUifSsCjCneM0NUky3WbG0LEm7IKUBmf9EAmAXc=,7a5085b8b0b114e2491032ec6f95e300c28fa309ec5883044d8b954d7d4db06e +github.com/blocktree/waykichain-adapter,v1.0.3,h1:qY/Txh+n4iIJA49rDMj41qpIUj3McjBir8Ls+sX8c3w=,62ea2ff873c84a32d3482c8ec1687221a1e46055b9be18fcd25be584cf2cac5d +github.com/bluele/gcache,v0.0.0-20190518031135-bc40bd653833,h1:yCfXxYaelOyqnia8F/Yng47qhmfC9nKTRIbYRrRueq4=,334accb65479b1b18fb569b08d14eebceb6478ea16abe9fbad2f1c6b6586deb6 +github.com/bluele/slack,v0.0.0-20180528010058-b4b4d354a079,h1:dm7wU6Dyf+rVGryOAB8/J/I+pYT/9AdG8dstD3kdMWU=,2b0055c292b7baa49f56eb9fc710f35f005747ddbef16427d5c985617c3b697d +github.com/bmatcuk/doublestar,v1.1.5,h1:2bNwBOmhyFEFcoB3tGvTD5xanq+4kyOZlB8wFYbMjkk=,81f592b11277591e943b91522497c323fcf0c6b4f3099f495de10f83e8c3e697 +github.com/bmizerany/assert,v0.0.0-20160611221934-b7ed37b82869,h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=,2532a167df77ade7e8012f07c0e3db4d4c15abdb7ffa7b05e1d961408da9a539 +github.com/bmizerany/pat,v0.0.0-20170815010413-6226ea591a40,h1:y4B3+GPxKlrigF1ha5FFErxK+sr6sWxQovRMzwMhejo=,ed04bed4d193e25371ebc6524984da4af9ece5c107fcc82d5aa4914b726706d2 +github.com/bndr/gotabulate,v1.1.2,h1:yC9izuZEphojb9r+KYL4W9IJKO/ceIO8HDwxMA24U4c=,2c1ecc544368e40010082f800c1ee24eaf1b8e0f96fa76a56e4f61dda4cd0d60 +github.com/boltdb/bolt,v1.3.1,h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=,ecaf17b0dbe7c85a017704c72667b2526b492b1a753ce7302a27dd2fb2e6ee79 +github.com/boombuler/barcode,v1.0.0,h1:s1TvRnXwL2xJRaccrdcBQMZxq6X7DvsMogtmJeHDdrc=,ef3832c4d22a09377323980bacd9f5f2ab43d0d20da115e1cfb139e093d7bb9b +github.com/bradfitz/go-smtpd,v0.0.0-20170404230938-deb6d6237625,h1:ckJgFhFWywOx+YLEMIJsTb+NV6NexWICk5+AMSuz3ss=,0a06dd547fed38e2744800b5f4ebae5ac00ee08717ded281510a8d319b8db8f3 +github.com/bradfitz/gomemcache,v0.0.0-20190913173617-a41fca850d0b,h1:L/QXpzIa3pOvUGt1D1lA5KjYhPBAN/3iWdP7xeFS9F0=,eb71acfac0c4ce5f0b6537d8029de98902d83fd38fdcbfd757f06697c6323f78 +github.com/bradfitz/iter,v0.0.0-20190303215204-33e6a9893b0c,h1:FUUopH4brHNO2kJoNN3pV+OBEYmgraLT/KHZrMM69r0=,6883ce0960849ca9c024a4a4e7508ff521da2a3bb66d1974ea2f970a5265ea39 +github.com/bradfitz/latlong,v0.0.0-20140711231157-b74550508561,h1:mz4equOOUOnI4q5E7dyHlRx1x63YEaYwhlVluCDila4=,d1c124508f1825697a2bdb9fac48d2b8805b41f8e546d262fc487d8450962cec +github.com/bradhe/stopwatch,v0.0.0-20180424000511-fd55e776a960,h1:YJWTgxlTgeHlvhe7tZJm0yBcg2GhjDQs8zig5O5vup8=,c2926a4febee7eea0f523b3d4fcaa414c27effc2abc053137a3dbf0b3a4fa324 +github.com/briankassouf/jose,v0.9.2-0.20180619214549-d2569464773f,h1:ZMEzE7R0WNqgbHplzSBaYJhJi5AZWTCK9baU0ebzG6g=,c0b50157ec3c39fbd6ded9d5e6bc763890e6d909db38b337a72876124c2baeeb +github.com/brocaar/lorawan,v0.0.0-20190925120821-154a30dbdce2,h1:51WcQ+VAc/6jZ/8GBJiQ3B7FrT2aXI+YsUx2iG9tJlw=,0082cebaf26ed36c901f9b44b6d785eccc2a0c123088642eac7c9b5711b7d0ca +github.com/bsm/go-vlq,v0.0.0-20150828105119-ec6e8d4f5f4e,h1:D64GF/Xr5zSUnM3q1Jylzo4sK7szhP/ON+nb2DB5XJA=,61fc03674cd72d5a4c55413e8b58fc8eafc58fbb71fb89c719225650754b3469 +github.com/bsm/sarama-cluster,v2.1.15+incompatible,h1:RkV6WiNRnqEEbp81druK8zYhmnIgdOjqSVi0+9Cnl2A=,a8a4867f09704222362b75fa00c9894106a928dc7cf905f1b80ca7bbd1a3b8e5 +github.com/btcsuite/btclog,v0.0.0-20170628155309-84c8d2346e9f,h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo=,74ad4defbabf48c98bbb547be1c40c11fa2c286f599412c774d1c5604dc1808d +github.com/btcsuite/btcutil,v0.0.0-20190425235716-9e5f4b9a998d,h1:yJzD/yFppdVCf6ApMkVy8cUxV0XrxdP9rVf6D87/Mng=,de1ee450ff2cfec2df220fec0d3e265cc812f214892bfad601e142632e2cf3f9 +github.com/btcsuite/go-socks,v0.0.0-20170105172521-4720035b7bfd,h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw=,cc27776f56f7c58c2808af55781e9b3f7d0eb0dc08e4c19c38c6bdf2465ce0e7 +github.com/btcsuite/goleveldb,v1.0.0,h1:Tvd0BfvqX9o823q1j2UZ/epQo09eJh6dTcRp79ilIN4=,13e37462cb2fe5976221f57d357051c1c3cc63a9b0e67e6ed97f98af795d0815 +github.com/btcsuite/snappy-go,v1.0.0,h1:ZxaA6lo2EpxGddsA8JwWOcxlzRybb444sgmeJQMJGQE=,d136165bdbf91780ded5d3ebaba9026f900595e56c19aa0ef29896015eae9627 +github.com/btcsuite/websocket,v0.0.0-20150119174127-31079b680792,h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc=,d45ac16f59082ac369e61c7bbe23153e289cad03619ab8041963d54cd700d6f0 +github.com/btcsuite/winsvc,v1.0.0,h1:J9B4L7e3oqhXOcm+2IuNApwzQec85lE+QaikUcCs+dk=,6893f7a62faec17d7b0856c7464754cab14c4d913e27af5276f6a98b25f3c779 +github.com/buger/jsonparser,v0.0.0-20191004114745-ee4c978eae7e,h1:oJCXMss/3rg5F6Poy9wG3JQusc58Mzk5B9Z6wSnssNE=,7e2dda4c1b4217408903f3b4a1f2cdd93d71bc7682387ba860cfa0cc9fcf88be +github.com/bugsnag/bugsnag-go,v1.5.3,h1:yeRUT3mUE13jL1tGwvoQsKdVbAsQx9AJ+fqahKveP04=,8aaf02df2c1a4e8a5725eea1d91af69c4f9e157c2559a3452388f64a977534c0 +github.com/bugsnag/panicwrap,v1.2.0,h1:OzrKrRvXis8qEvOkfcxNcYbOd2O7xXS2nnKMEMABFQA=,75357d3a5cd89dc04f1f101e02686fc1ef33b4a4f67edb82b3fa63fded3f47e9 +github.com/bwmarrin/discordgo,v0.20.1,h1:Ihh3/mVoRwy3otmaoPDUioILBJq4fdWkpsi83oj2Lmk=,616d49cc107ccd85872b6008f028c4aca021f66381828bb921f15f9e8149988a +github.com/bwmarrin/snowflake,v0.0.0-20180412010544-68117e6bbede,h1:lTJlWdyhwqq7h29GtuIDHW/xi+sMN+JOLMgYAwQ5O74=,2e13ad82f7ae64821f9851a66b4800f1589e413b27b469f28d21970957a3c6da +github.com/c-bata/go-prompt,v0.2.2,h1:uyKRz6Z6DUyj49QVijyM339UJV9yhbr70gESwbNU3e0=,ffe765d86d90afdf8519def13cb027c94a1fbafea7a18e9625210786663436c4 +github.com/c2h5oh/datasize,v0.0.0-20171227191756-4eba002a5eae,h1:2Zmk+8cNvAGuY8AyvZuWpUdpQUAXwfom4ReVMe/CTIo=,b5543f3e104a84e35ac51780968282b455dd30c88730d0da166d8d6512301da6 +github.com/caarlos0/ctrlc,v1.0.0,h1:2DtF8GSIcajgffDFJzyG15vO+1PuBWOMUdFut7NnXhw=,e4b5e9dd37cee2d47ff1c5eeba9a4b6e2b778c349a3615ca9653531f035a3ca6 +github.com/cactus/go-statsd-client/statsd,v0.0.0-20191030180650-a68a2246f89c,h1:rrLWPlpOKwnBpVUXitbgM3+Nie1eBaFfBZqfiPpxVj8=,cbb94149ec688419a91406b374955946c3679b1dde0752d7c0ffdc87432cd0b3 +github.com/caddyserver/caddy,v1.0.3,h1:i9gRhBgvc5ifchwWtSe7pDpsdS9+Q0Rw9oYQmYUTw1w=,029f14052f1ec9937c4028f3231899bf5391d5eeb7f58795d5d470a6f4c338a7 +github.com/campoy/unique,v0.0.0-20180121183637-88950e537e7e,h1:V9a67dfYqPLAvzk5hMQOXYJlZ4SLIXgyKIE+ZiHzgGQ=,4bc20f70e0b170ecdabd740a5de012d05f4c9149e2882fbdb303dc1b1793a77e +github.com/casbin/casbin,v1.9.1,h1:ucjbS5zTrmSLtH4XogqOG920Poe6QatdXtz1FEbApeM=,e2ef71d15eb595374d27961d255941b50691f9eaa91b5590f081fe3a4ab195c2 +github.com/cavaliercoder/go-cpio,v0.0.0-20180626203310-925f9528c45e,h1:hHg27A0RSSp2Om9lubZpiMgVbvn39bsUmW9U5h0twqc=,08b68e1d424b545418828c05c46bce5d795bbb8b534871667650ec6b3e7b33a6 +github.com/cenk/backoff,v2.2.1+incompatible,h1:djdFT7f4gF2ttuzRKPbMOWgZajgesItGLwG5FTQKmmE=,e3d1c641f85f548370aedc6bae3d4b975b09e3b2d1d9060f0e72bd5e2710d4c9 +github.com/cenkalti/backoff,v2.2.1+incompatible,h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=,f8196815a1b4d25e5b8158029d5264801fc8aa5ff128ccf30752fd169693d43b +github.com/cenkalti/backoff/v3,v3.0.0,h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c=,c69bf77e7b43cb3935d763c24af3810d9869a664bbcd26ffad9d3dc1bf602006 +github.com/census-instrumentation/opencensus-proto,v0.2.1,h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=,b3c09f3e635d47b4138695a547d1f2c7138f382cbe5a8b5865b66a8e08233461 +github.com/centrify/cloud-golang-sdk,v0.0.0-20190214225812-119110094d0f,h1:gJzxrodnNd/CtPXjO3WYiakyNzHg3rtAi7rO74ejHYU=,dc3de1393d7ae63ce35393630417ff8c5421a2a03cbf1a20680c7d57a74cd311 +github.com/certifi/gocertifi,v0.0.0-20180118203423-deb3ae2ef261,h1:6/yVvBsKeAw05IUj4AzvrxaCnDjN4nUqKjW9+w5wixg=,054d6c3a6f8d78fba2f08fbc2f23ec839d5a4aead4a184270d87d095c80eb6dc +github.com/cespare/cp,v1.1.1,h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU=,25f2ed5bac9ac3c1891ff364b213f6b7b0ee2e7aed13510738ced93ea71860e3 +github.com/cespare/xxhash,v1.1.0,h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=,fe98c56670b21631f7fd3305a29a3b17e86a6cce3876a2119460717a18538e2e +github.com/cespare/xxhash/v2,v2.1.0,h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA=,655feb22a395d9f56315280770d386eb99cdca79a97970812dbd3b30a7940638 +github.com/chaseadamsio/goorgeous,v0.0.0-20170901132237-098da33fde5f,h1:REH9VH5ubNR0skLaOxK7TRJeRbE2dDfvaouQo8FsRcA=,f81f4ef8ac52852b232ea971d009ec88007f1258c29e10e49918a31a99c6c4cc +github.com/checkpoint-restore/go-criu,v0.0.0-20190109184317-bdb7599cd87b,h1:T4nWG1TXIxeor8mAu5bFguPJgSIGhZqv/f0z55KCrJM=,1d1f5c6e529c87259305d8ed6bf4d381dabbf85458de187981204339e251a5be +github.com/cheekybits/genny,v1.0.0,h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=,770f3e01425b9b0a87a5e0b29fc6ac2cfa67a3f1265aafb16c96a47bafc304e4 +github.com/cheekybits/is,v0.0.0-20150225183255-68e9c0620927,h1:SKI1/fuSdodxmNNyVBR8d7X/HuLnRpvvFO0AgyQk764=,f7bf9ac5b1fc574ef5a373382909af550ef1a7f01182469eaa12e18c7c5fc7cb +github.com/cheggaaa/pb,v2.0.7+incompatible,h1:gLKifR1UkZ/kLkda5gC0K6c8g+jU2sINPtBeOiNlMhU=,383b717f271a2471e57ac52f64dbb77304ec1c0b53c5efeb7a1392668f59d0b4 +github.com/cheggaaa/pb/v3,v3.0.1,h1:m0BngUk2LuSRYdx4fujDKNRXNDpbNCfptPfVT2m6OJY=,781be3118614dfaeb2df44d31d8af36c703c2aaed18e9ca49fa4ef9ba1539236 +github.com/chewxy/hm,v1.0.0,h1:zy/TSv3LV2nD3dwUEQL2VhXeoXbb9QkpmdRAVUFiA6k=,68ab03d9f8cb3d92d6c8234cfd879004be2fd69457d2c9fa6834d1c6ddb22b43 +github.com/chewxy/math32,v1.0.4,h1:dfqy3+BbCmet2zCkaDaIQv9fpMxnmYYlAEV2Iqe3DZo=,7885f637bb90729d04f125e030542b9a6999f9e5dffd3294baffbcdd548bbc3e +github.com/chrismalek/oktasdk-go,v0.0.0-20181212195951-3430665dfaa0,h1:CWU8piLyqoi9qXEUwzOh5KFKGgmSU5ZhktJyYcq6ryQ=,094a132bc1e950677f75e570b17a52f103edd6acd3ec1c0943cf9cda3cd6355a +github.com/chromedp/cdproto,v0.0.0-20191009033829-c22f49c9ff0a,h1:AuIGvB6IuWpMEdfKQ+t77D6dzLpNftzxAsktehYyWn8=,bf85eeebdc65b1e90d851b42f56a3dbf5bcff4923aa426692a1c0d0a1727a522 +github.com/chromedp/chromedp,v0.5.1,h1:PAqhoCWCHzRphYnmmxLSiYk7EEwDplCm4woTCCaV2cQ=,59cd1ab42eeb90e32cc60e77a8fbb19ca629603200d5bd40d611f780e646062b +github.com/chzyer/logex,v1.1.10,h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=,2c94771c1e335a2c58a96444b3768b8e00297747d6ce7e7c14bab2e8b39d91bd +github.com/chzyer/readline,v0.0.0-20180603132655-2972be24d48e,h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=,3dc842677887278fb33d25078d375ae6a7a94bb77a8d205ee2230b581b6947a6 +github.com/chzyer/test,v0.0.0-20180213035817-a1ea475d72b1,h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=,ad8550bed3c4a94bbef57b9fc5bb15806eaceda00925716404320580d60e2f7d +github.com/cihub/seelog,v0.0.0-20170130134532-f561c5e57575,h1:kHaBemcxl8o/pQ5VM1c8PVE1PubbNx3mjUr09OqWGCs=,fc279208e6094fb22c8ea651c6e9794844069693c9b916c225276c54f7e76bfe +github.com/circonus-labs/circonus-gometrics,v2.3.1+incompatible,h1:C29Ae4G5GtYyYMm1aztcyj/J5ckgJm2zwdDajFbx1NY=,d8081141497e3cd34844df66af016c7900d58b324fb689e17e57bc053d91c9ba +github.com/circonus-labs/circonusllhist,v0.1.3,h1:TJH+oke8D16535+jHExHj4nQvzlZrj7ug5D7I/orNUA=,4dc805d9735dd9ca9b8875c0ad23126abb5bc969c5a40c61b5bc891808dbdcb6 +github.com/clbanning/mxj,v1.8.4,h1:HuhwZtbyvyOw+3Z1AowPkU87JkJUSv751ELWaiTpj8I=,8947cf617bdd9efc62817c8ddb17bafe497f35abdf10a3c60f295e387f633f70 +github.com/client9/misspell,v0.3.4,h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=,a3af206372e131dd10a68ac470c66a1b18eaf51c6afacb55b2e2a06e39b90728 +github.com/cloudflare/backoff,v0.0.0-20161212185259-647f3cdfc87a,h1:8d1CEOF1xldesKds5tRG3tExBsMOgWYownMHNCsev54=,2aea6d1528c42cf5f111e035bba564fd0481cb4ddb3b50f783f2481d855947cb +github.com/cloudflare/cfssl,v1.4.0,h1:TdyQbj/bDUMUHf2IkcHU2EHUmzCmRLuJ3fFd8EYMg1E=,845fc5f4a7f4c2356d676916fdd7b4b2217b76c8f9b7a960290ab8884d6f8e0e +github.com/cloudflare/cloudflare-go,v0.10.4,h1:7C1D9mtcNFZLCqmhkHK2BlwKKm9fi4cBqY6qpYtQv5E=,e8f6ee817c9b807c98559ff87d4ed7a284738d9dc253b6db7520911d93bd81e3 +github.com/cloudflare/go-metrics,v0.0.0-20151117154305-6a9aea36fb41,h1:/8sZyuGTAU2+fYv0Sz9lBcipqX0b7i4eUl8pSStk/4g=,9176a680ad7a72cf717e3e01ee1ca6b292cb576b543e12ff1770cc58957bc222 +github.com/cloudflare/golz4,v0.0.0-20150217214814-ef862a3cdc58,h1:F1EaeKL/ta07PY/k9Os/UFtwERei2/XzGemhpGnBKNg=,75832d1c2989b2a0d7eb8d2cec300f6d457254d42927a23f522b164833e791d4 +github.com/cloudflare/redoctober,v0.0.0-20171127175943-746a508df14c,h1:p0Q1GvgWtVf46XpMMibupKiE7aQxPYUIb+/jLTTK2kM=,e69334393aec994f9ba55bbdfa8a65c0cfa46080230068c44ca16a85c0a74079 +github.com/cloudfoundry-community/go-cfclient,v0.0.0-20190201205600-f136f9222381,h1:rdRS5BT13Iae9ssvcslol66gfOOXjaLYwqerEn/cl9s=,f01d41c3c911b59bf717674690799c978f3a841ef695c7ee09f4afe5f7c96e64 +github.com/cloudfoundry-incubator/candiedyaml,v0.0.0-20170901234223-a41693b7b7af,h1:6Cpkahw28+gcBdnXQL7LcMTX488+6jl6hfoTMRT6Hm4=,325af9d6827b8d120a72992c38ba776187fbd947a39c9f1928a43a1a2b262453 +github.com/cloudfoundry/bosh-agent,v2.271.0+incompatible,h1:277mM9hsUzyrd5Qd/5e1LFwiobIYorE7vTBRZohRV8s=,42e253b855d03655ec2cf59ab01a14aa0037f25029517be595dda26ff9a2a552 +github.com/cloudfoundry/bosh-utils,v0.0.0-20191026100324-0b6803ec5382,h1:Rrpgz+K2Zso//XUmqbGlnYi9rw6EtYJ4uLlTNSnSBIw=,c08bbf97e510b2de271fd64f5b2acedfa011b4fd3f30092804992084c67b68b7 +github.com/cloudfoundry/gosigar,v1.1.0,h1:V/dVCzhKOdIU3WRB5inQU20s4yIgL9Dxx/Mhi0SF8eM=,53acb43e5111c6af6af138e1144907bb5f9bf8abc28e71a703502f92c13ba274 +github.com/cloudfoundry/sonde-go,v0.0.0-20171206171820-b33733203bb4,h1:cWfya7mo/zbnwYVio6eWGsFJHqYw4/k/uhwIJ1eqRPI=,6124fdcac54e1baf09703ed2b938a4e2bb55d9cd20f78451f25c16638a95f62d +github.com/cockroachdb/apd,v1.1.0,h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=,fef7ec2fae220f84bfacb17fbfc1b04a666ab7f6fc04f3ff6d2b1e05c380777d +github.com/cockroachdb/apd/v2,v2.0.1,h1:y1Rh3tEU89D+7Tgbw+lp52T6p/GJLpDmNvr10UWqLTE=,9f1c35b8118f70f08150bf5e9da225fa1201f5d0f8c22f326468ea22ab6b791d +github.com/cockroachdb/cockroach-go,v0.0.0-20190916165215-ad57a61cc915,h1:QX2Zc22B15gdWwDCwS7BXmbeD/SWdcRK12gOfZ5BsIs=,e3faa1cdf2a15357d1e2eb200b3bdb81dae3fb084cb04534e0caf27a68487a88 +github.com/cockroachdb/datadriven,v0.0.0-20190809214429-80d97fb3cbaa,h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y=,170480bf3daa133144f2578e3f051f0fd98313666642cab64cef3359753a5c32 +github.com/codahale/hdrhistogram,v0.0.0-20161010025455-3a0bb77429bd,h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=,e7e117da64da2f921b1f9dc57c524430a7f74a78c4b0bad718d85b08e8374e78 +github.com/codegangsta/inject,v0.0.0-20150114235600-33e0aa1cb7c0,h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q=,0a324d56992bffd288fa70a6d10eb9b8a9467665b0b1eb749ac6ae80e8977ee2 +github.com/codegangsta/negroni,v1.0.0,h1:+aYywywx4bnKXWvoWtRfJ91vC59NbEhEY03sZjQhbVY=,2e6301aa682a7c38305f2ee72b276181cd0990f224f9fe115a433a5beb138488 +github.com/codeskyblue/go-sh,v0.0.0-20190412065543-76bd3d59ff27,h1:HHUr4P/aKh4quafGxDT9LDasjGdlGkzLbfmmrlng3kA=,77348ab27860460a015d0e65d08f18ed2194c13981f5fd722143a6e0c2dbb589 +github.com/confluentinc/confluent-kafka-go,v1.1.0,h1:HIW7Nkm8IeKRotC34mGY06DwQMf9Mp9PZMyqDxid2wI=,bc9aee1c8052340809bc43bf015a183985ec3426d404c34acfa3970e3b245340 +github.com/container-storage-interface/spec,v1.2.0,h1:bD9KIVgaVKKkQ/UbVUY9kCaH/CJbhNxe0eeB4JeJV2s=,86ecb02d57af97c9a4de8f2f3cacbceb5c7f2f96ee007133e0cfb9525ce45177 +github.com/containerd/cgroups,v0.0.0-20191011165608-5fbad35c2a7e,h1:3bt+8T1I/CuYx+a5ww32+UT4fc9x8iRiXrhfduFTlBU=,4646f14f27a365ff08abb1266b7ca4dffc1acd5e8e74b57211acbba22b496d46 +github.com/containerd/console,v0.0.0-20181022165439-0650fd9eeb50,h1:WMpHmC6AxwWb9hMqhudkqG7A/p14KiMnl6d3r1iUMjU=,62a7f1da11b3be4c0ef4f9f03b99dcf59dc988f062749f35e4e6bb585fb4e4fe +github.com/containerd/containerd,v1.3.0,h1:xjvXQWABwS2uiv3TWgQt5Uth60Gu86LTGZXMJkjc7rY=,e3f529147f2c909c85ac461126ad092a3c5d5a2abcc4f3c22600685af6dc2f08 +github.com/containerd/continuity,v0.0.0-20190827140505-75bee3e2ccb6,h1:NmTXa/uVnDyp0TY5MKi197+3HWcnYWfnHGyaFthlnGw=,ef1a3a4c2c1508d293eb2730e47e9601cba19d939393b1018d8e476b30dfd90b +github.com/containerd/fifo,v0.0.0-20190816180239-bda0ff6ed73c,h1:KFbqHhDeaHM7IfFtXHfUHMDaUStpM2YwBR+iJCIOsKk=,0c1b858ee9dd28bd915a3f7bd108b98b1d689be3c14535e7e8aee4a60c4a72c0 +github.com/containerd/go-runc,v0.0.0-20190923131748-a2952bc25f51,h1:vmF3zULCGpZ4QJCCLsGUXX7tNXW+0x3r9owerRAmRaU=,76ce6296dc07f1f5957867e9a5925cf9e16c69ad2b635f74a4ec471e6672ee51 +github.com/containerd/ttrpc,v0.0.0-20191028202541-4f1b8fe65a5c,h1:+RqLdWzn0xFunb+sxXaEzHOg8NuEG/eaI+9C1xXX8Mw=,f43884f8f37259c4b50a4413092064f35abd03b9db3bbe2ca3264b5a4b591b04 +github.com/containerd/typeurl,v0.0.0-20190911142611-5eb25027c9fd,h1:bRLyitWw3PT/2YuVaCKTPg0cA5dOFKFwKtkfcP2dLsA=,aa4e0823acf7b686a9521617134a171c5b5813de302e3fba742cd3b7f43ba944 +github.com/containernetworking/cni,v0.7.1,h1:fE3r16wpSEyaqY4Z4oFrLMmIGfBYIKpPrHK31EJ9FzE=,b83f1b8e9bba747e41512737383da57e517cf425beb1bd58882904dae9348b1d +github.com/containers/image,v3.0.2+incompatible,h1:B1lqAE8MUPCrsBLE86J0gnXleeRq8zJnQryhiiGQNyE=,dadc25bfff923d4f2c8b570471be3b0fd1449f42251fb6c318b68e04f6d47b3a +github.com/containers/storage,v1.12.13,h1:GtaLCY8p1Drlk1Oew581jGvB137UaO+kpz0HII67T0A=,08f5ee958be629b73ff02296eb11f4b0698dbd90e585ce019c5428a8e1d371d4 +github.com/containous/flaeg,v1.4.1,h1:VTouP7EF2JeowNvknpP3fJAJLUDsQ1lDHq/QQTQc1xc=,d097191570bb92f920cd15500a93205e6e93b5ee4723a51c9b8e3bfbcfaae505 +github.com/corbym/gocrest,v1.0.3,h1:gwEdq6RkTmq+09CTuM29DfKOCtZ7G7bcyxs3IZ6EVdU=,f13221d177442318b04f468fa57ea92bd9892d86e7cf7bb7299e0c58cea9df48 +github.com/coredns/coredns,v1.1.2,h1:bAFHrSsBeTeRG5W3Nf2su3lUGw7Npw2UKeCJm/3A638=,cbf720a9af4fdc5be08b0eea67fe219bb08c75292e22dca90095bf45cbd4a926 +github.com/coreos/bbolt,v1.3.3,h1:n6AiVyVRKQFNb6mJlwESEvvLoDyiTzXX7ORAUlkeBdY=,63ea574f28bd03b6d2a82304e0f7c96dcb30fa048311a4c8c3ad512dbacc4630 +github.com/coreos/clair,v0.0.0-20180919182544-44ae4bc9590a,h1:glxUtT0RlaVJU86kg78ygzfhwW6D+uj5H+aOK01QDgI=,3bc8c4b06a61c5673fcc69d5278b3a5313633fca1166e94a7140c363399c3dc6 +github.com/coreos/etcd,v3.3.17+incompatible,h1:f/Z3EoDSx1yjaIjLQGo1diYUlQYSBrrAQ5vP8NjwXwo=,d7ca8db509166ce05482c9b3e80cfb8d1086691901e80202f571d152da912153 +github.com/coreos/go-etcd,v2.0.0+incompatible,h1:bXhRBIXoTm9BYHS3gE0TtQuyNZyeEMux2sDi4oo5YOo=,4b226732835b9298af65db5d075024a5971aa11ef4b456899a3830bccd435b07 +github.com/coreos/go-iptables,v0.4.3,h1:jJg1aFuhCqWbgBl1VTqgTHG5faPM60A5JDMjQ2HYv+A=,4626df8f719f93e5d66bd995d586ae3540c24b2203c0d2aab7c6d5e60f89a3dc +github.com/coreos/go-oidc,v2.1.0+incompatible,h1:sdJrfw8akMnCuUlaZU3tE/uYXFgfqom8DBE9so9EBsM=,e2e123270614dd7d47d95ae1fce80a9102df019f9e820d4f5cf5c92c64e1ad91 +github.com/coreos/go-semver,v0.3.0,h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=,b2fc075395ffc34cff4b964681d0ae3cd22096cfcadd2970eeaa877596ceb210 +github.com/coreos/go-systemd,v0.0.0-20190719114852-fd7a80b32e1f,h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c=,22237f0aed3ab6018a1025c65f4f45b4c05f9aa0c0bb9ec880294273b9a15bf2 +github.com/coreos/pkg,v0.0.0-20180928190104-399ea9e2e55f,h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg=,7fe161d49439a9b4136c932233cb4b803b9e3ac7ee46f39ce247defc4f4ea8d7 +github.com/coreos/rkt,v1.30.0,h1:Kkt6sYeEGKxA3Y7SCrY+nHoXkWed6Jr2BBY42GqMymM=,436e294b735bada49407ad3c066ae251ef105ce59076ef8f0f732c586a72970e +github.com/cosiner/argv,v0.0.0-20170225145430-13bacc38a0a5,h1:rIXlvz2IWiupMFlC45cZCXZFvKX/ExBcSLrDy2G0Lp8=,deb11c1c7a2fa44b3497731d497b3d7be5a51cf696ed43280e01822e2eed9b96 +github.com/cosmos/cosmos-sdk,v0.35.0,h1:EPeie1aKHwnXtTzKggvabG7aAPN+DDmju2xquvjFwao=,ccc975b48e3b40f4eb054e28e9243ecb48c0d8ecdf52b9512da26a8200cc7c43 +github.com/cosmos/go-bip39,v0.0.0-20180819234021-555e2067c45d,h1:49RLWk1j44Xu4fjHb6JFYmeUnDORVwHNkDxaQ0ctCVU=,e41d7ea781b15421a4690bedf78543f2eaad00c36c439dd4973131dec1985177 +github.com/cosmos/ledger-cosmos-go,v0.10.3,h1:Qhi5yTR5Pg1CaTpd00pxlGwNl4sFRdtK1J96OTjeFFc=,f1089701d8868e4ff3fd9e9a4104476963f725a713ee2a476b4ef8094a0bca20 +github.com/cosmos/ledger-go,v0.9.2,h1:Nnao/dLwaVTk1Q5U9THldpUMMXU94BOTWPddSmVB6pI=,a77b2063a64133d8dda638d5d602071429d7e2500576bfff5c1763f8572a8517 +github.com/couchbase/go-couchbase,v0.0.0-20191031153726-96c2e23d589a,h1:eKnoG+AQQQIxHEcBIbudmwLJv3S9UQU6oGHzvqhttqE=,5dd3e610f24adb44b31e7ecc6a80a8974b769bd622d569c69fb98bd02610bbef +github.com/couchbase/gomemcached,v0.0.0-20191004160342-7b5da2ec40b2,h1:vZryARwW4PSFXd9arwegEywvMTvPuXL3/oa+4L5NTe8=,5b9a280cd2d546cd0d70fbd6828e73fa0b07fb9d3c0b6bff88d8e23d8e4256f4 +github.com/couchbase/goutils,v0.0.0-20190315194238-f9d42b11473b,h1:bZ9rKU2/V8sY+NulSfxDOnXTWcs1rySqdF1sVepihvo=,a2820e0f01d8c944b70c70515b9924f41b450f3688d19ad4d506b2b9b367c433 +github.com/couchbase/vellum,v0.0.0-20190111184608-e91b68ff3efe,h1:2o6Y7KMjJNsuMTF8f2H2eTKRhqH7+bQbjr+D+LnhE5M=,06e3ca28a98c95bcdfd909168e1dcf45a6667ef59ad59112a01e6bbdcf591e84 +github.com/couchbaselabs/go-couchbase,v0.0.0-20190708161019-23e7ca2ce2b7,h1:1XjEY/gnjQ+AfXef2U6dxCquhiRzkEpxZuWqs+QxTL8=,3429eb55dd38b07bab5e9a57a3e2451449b49bdbc6f16585f8b7557067572499 +github.com/cpu/goacmedns,v0.0.1,h1:GeIU5chKys9zmHgOAgP+bstRaLqcGQ6HJh/hLw9hrus=,12acca48bb444f3832a87b8d238e573bbfa60e5c25dfcf6787a003dfacaf055d +github.com/cpuguy83/go-md2man,v1.0.10,h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=,b9b153bb97e2a702ec5c41f6815985d4295524cdf4f2a9e5633f98e9739f4d6e +github.com/cpuguy83/go-md2man/v2,v2.0.0,h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=,f2fdd06287a80f1bea5552f572d7f2314ec829285a3040b63469e0635f66fb6d +github.com/creack/goselect,v0.1.0,h1:4QiXIhcpSQF50XGaBsFzesjwX/1qOY5bOveQPmN9CXY=,24d8028970032b1a45091ad8ff9b9c280693def1433cb5948ed92c0c975226ea +github.com/creack/pty,v1.1.7,h1:6pwm8kMQKCmgUg0ZHTm5+/YvRK0s3THD/28+T6/kk4A=,e7ea3403784d186aefbe84caed958f8cba2e72a04f30cdb291ece19bec39c8f3 +github.com/cskr/pubsub,v1.0.2,h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0=,39e40a42c10058c188f331ed0bb660a0504d7c2ddd9e835a9970786fdc35feb0 +github.com/cupcake/rdb,v0.0.0-20161107195141-43ba34106c76,h1:Lgdd/Qp96Qj8jqLpq2cI1I1X7BJnu06efS+XkhRoLUQ=,019a246ac0d7f6fcf3758587a031767730cfb824003c311686a4eb552a1dcc57 +github.com/cweill/gotests,v1.5.3,h1:k3t4wW/x/YNixWZJhUIn+mivmK5iV1tJVOwVYkx0UcU=,7ced96d4223a0afcd41922c4d3ae064493dd5bedbc72f6541716fce1cab24b7d +github.com/cxr29/aliyun-openapi-go-sdk,v0.0.0-20151123082822-0b043e4d1e0c,h1:WEWetvNRZlk7JW3M4fycSA3f/2xZGxRdrwmpgRkGoQc=,6c80128745e3acdd01f59bc6c6e3a1f24193e89eb627ad6dcc615e763878b6e4 +github.com/cyphar/filepath-securejoin,v0.2.2,h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg=,d022873dbb9e8d3b7a43c9dedbea54dfc9a6c15f9632ba522a1257e8b948c100 +github.com/cznic/b,v0.0.0-20181122101859-a26611c4d92d,h1:SwD98825d6bdB+pEuTxWOXiSjBrHdOl/UVp75eI7JT8=,1c34b27ce98f70cb0e97c2bbe0bdae216cc1ea6b2617b0e984e2ce30adc06338 +github.com/cznic/fileutil,v0.0.0-20181122101858-4d67cfea8c87,h1:94XgeeTZ+3Xi9zsdgBjP1Byx/wywCImjF8FzQ7OaKdU=,109b4c91722a0f9a4f941d77eff34270684e53ca36e7d14ab2cd4a4e80841d73 +github.com/cznic/golex,v0.0.0-20181122101858-9c343928389c,h1:G8zTsaqyVfIHpgMFcGgdbhHSFhlNc77rAKkhVbQ9kQg=,d2b11a6e0e1de5125a2d550650b4cbb7bf44280ebf1cda74ef4a63e3cfa11012 +github.com/cznic/internal,v0.0.0-20181122101858-3279554c546e,h1:58AcyflCe84EONph4gkyo3eDOEQcW5HIPfQBrD76W68=,bc177d001529bca3f46aa84855db4e783a041c188d3ba237f68fa4522bdca74b +github.com/cznic/kv,v0.0.0-20181122101858-e9cdcade440e,h1:8ji4rZgRKWMQUJlPNEzfzCkX7yFAZFR829Mrh7PXxLA=,4f992bdaf6d17487c7b16669b6d55afa76b321e63f8e4b6a6d1126b44b18b0d9 +github.com/cznic/lldb,v1.1.0,h1:AIA+ham6TSJ+XkMe8imQ/g8KPzMUVWAwqUQQdtuMsHs=,ddec7228568547a5fbfbc6a91208cbcafeed4338a38c41d483448957e4bec186 +github.com/cznic/mathutil,v0.0.0-20181122101859-297441e03548,h1:iwZdTE0PVqJCos1vaoKsclOGD3ADKpshg3SRtYBbwso=,8f69a36f60d885e011b0a90b91246a7e88223cb2883dc6e71eab3f42d653231b +github.com/cznic/parser,v0.0.0-20181122101858-d773202d5b1f,h1:DUtr2TvhM9rmiHKVJWoLqDY2+MdxljW9hlaS/oYoi1c=,18b746a4090720bd9dfe219d0f7bb7fb28565df70417208d7e99dfd79f1ea264 +github.com/cznic/ql,v1.2.0,h1:lcKp95ZtdF0XkWhGnVIXGF8dVD2X+ClS08tglKtf+ak=,05164e379d43eaada0efdd763a50a9ef8f4b7f73a5de7ab866093bb25a4fb747 +github.com/cznic/sortutil,v0.0.0-20181122101858-f5f958428db8,h1:LpMLYGyy67BoAFGda1NeOBQwqlv7nUXpm+rIVHGxZZ4=,67783879c1ae4472fdabb377b1772e4e4c5ced181528c2fc4569b565cb47a57b +github.com/cznic/strutil,v0.0.0-20181122101858-275e90344537,h1:MZRmHqDBd0vxNwenEbKSQqRVT24d3C05ft8kduSwlqM=,867902276444cbffca84d9d5f63754e8b22092d93a94480d8dfebd234ac8ffbd +github.com/cznic/y,v0.0.0-20181122101901-b05e8c2e8d7b,h1:gvFsf4zJcnW6GRN+HPGTxwuw+7sTwzmoeoBQQCZDEnk=,8c84f5e4f9dc5f0809d8ad22d057e404c3e8644dc28e8fc52abbb1d2350f8d3e +github.com/cznic/zappy,v0.0.0-20181122101859-ca47d358d4b1,h1:ytLS5Cgkxq6jObotJ+a13nsejdqzLFPliDf8CQ8OkAA=,505c19b52924ee21b65611bc45640d3ff4671e50ee04f7c17c38342190645595 +github.com/d2g/dhcp4,v0.0.0-20170904100407-a1d1b6c41b1c,h1:Xo2rK1pzOm0jO6abTPIQwbAmqBIOj132otexc1mmzFc=,15df9468cf548a626e1319e92d550432512c4319cf555bf278ea9215de3504e3 +github.com/daaku/go.zipexe,v1.0.0,h1:VSOgZtH418pH9L16hC/JrgSNJbbAL26pj7lmD1+CGdY=,74d7a0242c03c3c03220e56a59da5f97d3478743250740df538e05e6b609f553 +github.com/danwakefield/fnmatch,v0.0.0-20160403171240-cbb64ac3d964,h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ=,f601e8d25a43ed32e00851e1686a93b0175dadea8f4e32c8af2f1533f20736bc +github.com/dave/jennifer,v1.2.0,h1:S15ZkFMRoJ36mGAQgWL1tnr0NQJh9rZ8qatseX/VbBc=,85b37a1b99b7d67664389b8c11b7174f521a396bb59d4e0e766df16336a7f112 +github.com/dave/services,v0.1.0,h1:7isGzpZHJWmOYTV+Pn3f6gpQUmrveJqsQpAkH0HXFbU=,e52a7ffba3aa07cca4888e08248771211abd139928b5cde9b228a61da88eddcc +github.com/davecgh/go-spew,v1.1.1,h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=,6b44a843951f371b7010c754ecc3cabefe815d5ced1c5b9409fb2d697e8a890d +github.com/davecgh/go-xdr,v0.0.0-20161123171359-e6a2ba005892,h1:qg9VbHo1TlL0KDM0vYvBG9EY0X0Yku5WYIPoFWt8f6o=,11cb87912b5288e13534cb396935694c257eb9164ffc20ce21e3bc9955edd82a +github.com/daviddengcn/go-colortext,v0.0.0-20180409174941-186a3d44e920,h1:d/cVoZOrJPJHKH1NdeUjyVAWKp4OpOT+Q+6T1sH7jeU=,159d727adf4f0763ec3dc6156fd46531a2afbffdc17feeb6b5ffe2eb54b35d41 +github.com/davyxu/cellnet,v4.1.0+incompatible,h1:zDRqhkFRhBTD7ajra2888aoRLN1qlv8LV8+qHg/emO4=,f085f088b68b2e379a6dc37501ef2c9809836cfac147a30ed3025571c2d57df7 +github.com/davyxu/golog,v0.1.0,h1:SsV3m2x37sCzFaQzq5OHc5S+PE2VMiL7XUx34JCa7mo=,a3c240bc4b958fa4b4e73caa59c28fc658afbabdb1f28b237874803ca96dcb1f +github.com/dchest/blake256,v1.0.0,h1:6gUgI5MHdz9g0TdrgKqXsoDX+Zjxmm1Sc6OsoGru50I=,9a9ed00a3024f2f7480b59c7b2ee1013cae3026d7dc2f065ce225dcce8cf357e +github.com/dchest/siphash,v1.2.1,h1:4cLinnzVJDKxTCl9B01807Yiy+W7ZzVHj/KIroQRvT4=,877a468e533e28c777c59b3dfea175b38a1f0bc1f8551e3a9e1739b1821c7e3e +github.com/dchest/uniuri,v0.0.0-20160212164326-8902c56451e9,h1:74lLNRzvsdIlkTgfDSMuaPjBr4cf6k7pwQQANm/yLKU=,41db9fb52a841d11d8592a1d4f56e8a440e3991b699ae0f95ab5f5a7b2aeb24c +github.com/deckarep/golang-set,v1.7.1,h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ=,86606609df42529fda55a15475b495f993f0c1cc4be6e1e50a9165a514d1ed71 +github.com/decker502/dnspod-go,v0.2.0,h1:6dwhUFCYbC5bgpebLKn7PrI43e/5mn9tpUL9YcYCdTU=,381fb0bb29ac973f318db3d464f76e5d3016d4963c78ccd7df7dbc4231a68455 +github.com/decred/base58,v1.0.0,h1:BVi1FQCThIjZ0ehG+I99NJ51o0xcc9A/fDKhmJxY6+w=,75b1a2c78759ee2e8755156806ce770c9199464c2d58541388d5ec7c000c99e1 +github.com/decred/dcrd/chaincfg,v1.5.1,h1:u1Xbq0VTnAXIHW5ECqrWe0VYSgf5vWHqpSiwoLBzxAQ=,7344cd4dc90a82342c90811c8180b1fef6c79e9c49caa38135f271cf0ecb056f +github.com/decred/dcrd/chaincfg/chainhash,v1.0.2,h1:rt5Vlq/jM3ZawwiacWjPa+smINyLRN07EO0cNBV6DGU=,a8b24e2c4e64015430b8a6502f9e8c3eeea246021638884dc510508eccda31a0 +github.com/decred/dcrd/chaincfg/v2,v2.0.2,h1:VeGY52lHuYT01tIGbvYj+OO0GaGxGaJmnh+4vGca1+U=,906dec975cf574c55f2eb588dc91a4ddd6be273eaddfbeb45288ea6aebcc6306 +github.com/decred/dcrd/crypto/blake256,v1.0.0,h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=,cd8bbdae14641f0ba44430fc66990dd37bbfcf1e21a965a9fd1871d16cac127d +github.com/decred/dcrd/dcrec,v1.0.0,h1:W+z6Es+Rai3MXYVoPAxYr5U1DGis0Co33scJ6uH2J6o=,a1e16c5ef3633f2dfa23c052778552cf9300821197f5b2dc547e20dd9d45756b +github.com/decred/dcrd/dcrec/edwards,v1.0.0,h1:UDcPNzclKiJlWqV3x1Fl8xMCJrolo4PB4X9t8LwKDWU=,7ed52f3316f5a47c5925e23bebf5016ecfd75e7ac340714b4b94b0e25bdf0611 +github.com/decred/dcrd/dcrec/secp256k1,v1.0.2,h1:awk7sYJ4pGWmtkiGHFfctztJjHMKGLV8jctGQhAbKe0=,5fa2c17fd611665a39e6435283445ec3b46a5b52d14661e04bd1f7ef295ba9d3 +github.com/decred/dcrd/dcrutil,v1.4.0,h1:xD5aUqysGQnsnP1c9J0kGeW8lDIwFGC3ja/gE3HnpCs=,6de50428375fca174f4861f8aa45549360e7733bca0184a882448f0b9f94be2e +github.com/decred/dcrd/dcrutil/v2,v2.0.0,h1:HTqn2tZ8eqBF4y3hJwjyKBmJt16y7/HjzpE82E/crhY=,fa91eb7c5062e0f3f6e7d1b9d8e1a89698f6ee6e7f8f4941929f6d89a293ec76 +github.com/decred/dcrd/wire,v1.3.0,h1:X76I2/a8esUmxXmFpJpAvXEi014IA4twgwcOBeIS8lE=,e17b78d19d0056503627826a0e599ed14a7a4fc8aa2c31c47b12ffc1864aedb1 +github.com/decred/slog,v1.0.0,h1:Dl+W8O6/JH6n2xIFN2p3DNjCmjYwvrXsjlSJTQQ4MhE=,1c27399a3f38fb7b581f4dbe11a0b3e3d5d8afcc8109880771c0e44135388bb0 +github.com/denisenkom/go-mssqldb,v0.0.0-20191001013358-cfbb681360f0,h1:epsH3lb7KVbXHYk7LYGN5EiE0MxcevHU85CKITJ0wUY=,ff2349c73cee9e54cd61e85af75d7d0537fb5f070da5a737b5abede1f7d579ac +github.com/denkhaus/bitshares,v0.6.1-0.20190502142618-5ae8c00cb394,h1:PpFS6pvAoRwH13WlqnX/mrxesu6LNFtiVwoWgfNLCeY=,af76695d3e546cad6a8b56d9d5e431bfeb12bfce643a395fb45d8827409dd9ff +github.com/denkhaus/gojson,v1.0.0,h1:p1hAlN/yAvRvzbdO1HNDQvmBslfyk64IMt3O3DtftPU=,5c0d8d98a53be88e2801d90124e28ba781d2c6a09aaf9a57272df92c5c0e0fe2 +github.com/denkhaus/logging,v0.0.0-20180714213349-14bfb935047c,h1:imM7UU8JD1sNuk2tVEk3QvrY2RZ5f/DOB+UA7c5ThGs=,5a1bb81f35dc7847b0cb8efe3f1e3bac3a34c9f11950a7c7643115c952fa3166 +github.com/denverdino/aliyungo,v0.0.0-20170926055100-d3308649c661,h1:lrWnAyy/F72MbxIxFUzKmcMCdt9Oi8RzpAxzTNQHD7o=,e6ca432bab5a7b1d233c9c1495d32668d31b18803d65f3af27f1d8240b6547d4 +github.com/detached/gorocket,v0.0.0-20170629192631-d44bbd3f26d2,h1:zwp9mAr+YvsgLCFIVJ3/m61Z+NRX35jbD0HBa62ryHY=,f54c9dc20ba925f0b2a726cc1a22466c6e05d7e0080f6e4b5f26e60c15938712 +github.com/detailyang/go-fallocate,v0.0.0-20180908115635-432fa640bd2e,h1:lj77EKYUpYXTd8CD/+QMIf8b6OIOTsfEBSXiAzuEHTU=,dcc45102d034d78825d1aa9d2f61720b4b0d9f76314a7a53b32cf032713a0bde +github.com/devfeel/dotweb,v1.7.3,h1:tt7YtCIp9JPmAS2yksVIsw6CiUkUSz3kVLSiCzRaWDw=,7cdb6d4872bb4c82fc333722fb2be3e39fe391b121550421d240d3008c8e00a0 +github.com/devigned/tab,v0.1.1,h1:3mD6Kb1mUOYeLpJvTVSDwSg5ZsfSxfvxGRTxRsJsITA=,528e21b578f28a998453551c51abfdeed154c981486d49a8ad7c149743ea450f +github.com/dghubble/oauth1,v0.6.0,h1:m1yC01Ohc/eF38jwZ8JUjL1a+XHHXtGQgK+MxQbmSx0=,6d4be6cfc2771fab15e47d2aa9c40d347dab7166f2cae3c248aeb51b10c88b4a +github.com/dghubble/sling,v1.3.0,h1:pZHjCJq4zJvc6qVQ5wN1jo5oNZlNE0+8T/h0XeXBUKU=,880e7f44ee68eae979a34afb2f95ab1c7555712153c45be01d15cbc5991a5fe6 +github.com/dgraph-io/badger,v1.6.0,h1:DshxFxZWXUcO0xX476VJC07Xsr6ZCBVRHKZ93Oh7Evo=,8329ae390aebec6ae360356e77a2743357ad4e0d0bd4c3ae03b7d17e01ad70aa +github.com/dgraph-io/dgo,v1.0.0,h1:DRuI66G+j0XWDOXly4v5PSk2dGkbIopAZIirRjq7lzI=,dae0ee7690b0c58d72be328263d55394f88a4924a8274017021736d702be9cee +github.com/dgrijalva/jwt-go,v3.2.0+incompatible,h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=,26b028eb2d9ee3aef26a96d6790e101f4088ef901008ebab17096966bf6522ad +github.com/dgryski/go-farm,v0.0.0-20190423205320-6a90982ecee2,h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=,d1fb60f1ce562acb07569d53b43353b73f439911c27eecef716305cd2d730258 +github.com/dgryski/go-jump,v0.0.0-20170409065014-e1f439676b57,h1:qZNIK8jjHgLFHAW2wzCWPEv0ZIgcBhU7X3oDt/p3Sv0=,92666f8caf4843c5a9b6bdb0f48f261922595683351958b0909884adf064cfb2 +github.com/dgryski/go-metro,v0.0.0-20180109044635-280f6062b5bc,h1:8WFBn63wegobsYAX0YjD+8suexZDga5CctH4CCTx2+8=,3f97b3cdeaee7b4fbf4fa06b7c52e3ee6bca461a100077892e861c6c8fc03722 +github.com/dgryski/go-sip13,v0.0.0-20190329191031-25c5027a8c7b,h1:Yqiad0+sloMPdd/0Fg22actpFx0dekpzt1xJmVNVkU0=,81d318bf94b85b240278c35d7ef6015510751e31ffa89eb6287d6d236493551e +github.com/digitalocean/go-libvirt,v0.0.0-20190626172931-4d226dd6c437,h1:phR13shVFOIpa1pnLBmewI9p16NEladLPvVylLPeexo=,7748e819d19524170969d2a470c212bb3936778ff630f833adc286e8c21e37cc +github.com/digitalocean/go-qemu,v0.0.0-20181112162955-dd7bb9c771b8,h1:N7nH2py78LcMqYY3rZjjrsX6N7uCN7sjvaosgpXN9Ow=,7530507881e53214ed3c0fb770fb3faed36a57ca6eb376bd2cec91a0e5d575a6 +github.com/digitalocean/godo,v1.11.1,h1:OsTh37YFKk+g6DnAOrkXJ9oDArTkRx5UTkBJ2EWAO38=,5d1ad5b25ad252fb1a02366087fe6e94845ec2dce64dc6e875ed3253a7e0f8ff +github.com/dimchansky/utfbom,v1.1.0,h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4=,27fed73a62fcf06d4ceb28846e5d40786b7e81213aa0d1f4d840e89d25f285f7 +github.com/dimfeld/httppath,v0.0.0-20170720192232-ee938bf73598,h1:MGKhKyiYrvMDZsmLR/+RGffQSXwEkXgfLSA08qDn9AI=,ff59ff07643eccf8a166cc9693fbd18c42869e0bfcc0a9c979435847a7ae4fb1 +github.com/dimfeld/httptreemux,v5.0.1+incompatible,h1:Qj3gVcDNoOthBAqftuD596rm4wg/adLLz5xh5CmpiCA=,031da29a128234db595fdce84301cfe5ff13b4be03c1e344cfe7daadb68559e9 +github.com/disintegration/gift,v1.2.1,h1:Y005a1X4Z7Uc+0gLpSAsKhWi4qLtsdEcMIbbdvdZ6pc=,d9a688a552dc8f5b2319325541e2bbc5c0af66b6e78273058893b259fcca5a0f +github.com/disintegration/imaging,v1.6.1,h1:JnBbK6ECIZb1NsWIikP9pd8gIlTIRx7fuDNpU9fsxOE=,209474c4c0348672c6747a7a73ff887a6d9458b67df78ff342ee3fd628156412 +github.com/djherbis/atime,v1.0.0,h1:ySLvBAM0EvOGaX7TI4dAM5lWj+RdJUCKtGSEHN8SGBg=,fe677e5c1a8bb168904c0856010bed33a770d49eda9edc6dc1b567940bf20afc +github.com/dlclark/regexp2,v1.2.0,h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=,61054c243455e034d7a81e2f6a888cab5a81056a0cc43463cb3536b42cfe7cc1 +github.com/dmotylev/goproperties,v0.0.0-20140630191356-7cbffbaada47,h1:sP2APvSdZpfBiousrppBZNOvu+TE79Myq4kkmmrtSuI=,8afdf7b2989dff361cc80e560c1bd17e5c4ad37826b5caf4b65af8e152cdc6cb +github.com/dnaeon/go-vcr,v1.0.1,h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY=,8f586f95ce5567ef2ae702cf98e56a09ea0cc6171f5cd959e6fcf7502e00dabc +github.com/dnsimple/dnsimple-go,v0.30.0,h1:IBIrn9jMKRMwporIRwdFyKdnHXVmwy6obnguB+ZMDIY=,5821d521b402f93dc19f6eb332d5f4159800336f53626c6dedd99ce4c351a55a +github.com/dnstap/golang-dnstap,v0.1.0,h1:hKtRrSTEHuTmG0vCLgKU8WJkXCARoAJMDrlXHTTPBK8=,fe23fd626917c7f45ead63cef4a4bd1bb366bb30ba5873d9ee5432e79b971349 +github.com/docker/cli,v0.0.0-20191031185610-968ce1ae4d45,h1:KJ4FsevlLR30Q2H1aCACmL3CEoUTAZf16PMAJj+ofXI=,145fef54aa162edc123d514ed7a20bc14564581ad95bb6aae7294c3c08df55fd +github.com/docker/distribution,v2.7.1+incompatible,h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=,be78bc43d74873b67afe05a6b244490088680dab75bdfaf26d0fd4d054595bc7 +github.com/docker/docker,v1.13.1,h1:IkZjBSIc8hBjLpqeAbeE5mca5mNgeatLHBy3GO78BWo=,1decea9f21d4165bc134de72c51055612ff6992409cd56f3c35b7f78f3b542bd +github.com/docker/docker-ce,v0.0.0-20180924210327-f53bd8bb8e43,h1:gZ4lWixV821UVbYtr+oz1ZPCHkbtE+ivfmHyZRgyl2Y=,d670d1c5faec51ee82dbc5d479a7fca60916c1b30547994c206622ab338a735a +github.com/docker/docker-credential-helpers,v0.6.3,h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ=,4dd2971b28524442b7a01e118a8040c3ab90eca50d55a7a232af514d18187324 +github.com/docker/engine-api,v0.4.0,h1:D0Osr6+45yAlQqLyoczv5qJtAu+P0HB0rLCddck03wY=,0db5d01c8401192b4eee6d2f9c34aa297d1a892f25230b470efd73f8f7ab59a4 +github.com/docker/go,v1.5.1-1,h1:hr4w35acWBPhGBXlzPoHpmZ/ygPjnmFVxGxxGnMyP7k=,fd626ee84b1eaea11c2a374fda5ed5ca8ad820bb4746ee31519efeb5038077b5 +github.com/docker/go-connections,v0.4.0,h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=,570ebcee7e6fd844e00c89eeab2b1922081d6969df76078dfe4ffacd3db56ada +github.com/docker/go-events,v0.0.0-20190806004212-e31b211e4f1c,h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8=,0f654eb0e7e07c237a229935ea3488728ddb5b082af2918b64452a1129dccae3 +github.com/docker/go-metrics,v0.0.1,h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=,4efab3706215f5b2d29ba823d3991fd6e2f81c02ce45ef0c73c019ebc90e020b +github.com/docker/go-units,v0.4.0,h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=,0f2be7dce7b1a0ba6a4a786eb144a3398e9a61afc0eec5799a1520d9906fc58c +github.com/docker/libkv,v0.2.1,h1:PNXYaftMVCFS5CmnDtDWTg3wbBO61Q/cEo3KX1oKxto=,7a0c81782d38b550acc2c0ef0ce397adfc13716f483be6a47d0b97fbc6eea0d5 +github.com/docker/libnetwork,v0.5.6,h1:hnGiypBsZR6PW1I8lqaBHh06U6LCJbI3IhOvfsZiymY=,7aea42c405304c495bf159e5004674eb503eb0120eb4c5d1275fdba65d88cc53 +github.com/docker/libtrust,v0.0.0-20160708172513-aabc10ec26b7,h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=,bf1c1230a3b5c0dadb2c9366aabc99181e708369d735dc83c3eb89f597f42adb +github.com/docker/machine,v0.16.2,h1:jyF9k3Zg+oIGxxSdYKPScyj3HqFZ6FjgA/3sblcASiU=,1c13210831cafddba1abbf9ef034135233252c62927df396fee6fa0a45efcb43 +github.com/docker/notary,v0.6.1,h1:6BO5SNujR+CIuj2jwT2/yD6LdD+N9f5VbzR+nfzB5ZA=,439fd6664fb75323d78c5a362483f3375a6ac61a3dd08438a503df470a34f300 +github.com/docker/spdystream,v0.0.0-20160310174837-449fdfce4d96,h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg=,70964f9eef29843634539b8d6e09c8b51ed6aa96b5deda28b7a44613327a22f2 +github.com/docker/swarmkit,v1.12.0,h1:vcbNXevt9xOod0miQxkp9WZ70IsOCe8geXkmFnXP2e0=,b9d09ff080beb0db2d4d4ebca93438dd080769266eb7aab6d5182e1ad7ba2c3a +github.com/docopt/docopt-go,v0.0.0-20180111231733-ee0de3bc6815,h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=,00aad861d150c62598ca4fb01cfbe15c2eefb5186df7e5d4a59286dcf09556c8 +github.com/documize/community,v3.2.0+incompatible,h1:ilePrhqxjc+BWpDRsXPyLyMEE1BrGlqCPMg3T577mzQ=,e9e06bdbef4500c0d2cc609164fe23bc05f8234c2c8483c8c9bc3ffffe22bbf7 +github.com/dogmatiq/dogma,v0.6.0,h1:HdJ0cTcORIxZRTB5Z7RdsBXEr18gB3so7FMIHYiAhEQ=,db91004377004aa3c5f0c462205beea995e93a0be13d7d99d3232dc03209f65c +github.com/donovanhide/eventsource,v0.0.0-20171031113327-3ed64d21fb0b,h1:eR1P/A4QMYF2/LpHRhYAts9wyYEtF7qNk/tVNiYCWc8=,2b911efc5101522ce50399cd7831ef931896541893955441168783666811a1d1 +github.com/dop251/goja,v0.0.0-20190912223329-aa89e6a4c733,h1:cyNc40Dx5YNEO94idePU8rhVd3dn+sd04Arh0kDBAaw=,485156ad52ca9651f728a6039af63f9f11c5bf49846e513635d5fa35d8d39097 +github.com/dotcloud/docker,v1.13.1,h1:jjwxeyQYDwROaGy/YEodF+srQW5hJAnNnaTcfcKoU+0=,83884e41d26b32eae2387080b245792ac8fc0200f645aef02656cb5e4b3d0595 +github.com/drone/go-scm,v1.6.0,h1:PZZWLeSHHwdc6zbSQpg9n0CNoRB+8DAINzX9X/wJifY=,e26d2bc63c53a66252ab24a1b45ced06825bb4101cbd746c581683cf39e520b6 +github.com/dsnet/compress,v0.0.0-20171208185109-cc9eb1d7ad76,h1:eX+pdPPlD279OWgdx7f6KqIRSONuK7egk+jDx7OM3Ac=,25f6bcccb4c1cf6d97ad69253a394bd0a52a633caa623d75b30729aed495a73d +github.com/dsnet/golib/unitconv,v0.0.0-20190531212259-571cdbcff553,h1:mE6azeVhLnKfk6DH3Zcg56L87yJ/uv9HZ5YJOQcPC4s=,603b60f7278fe7299f59d716da2bd287441f1321b5a663828d894e67bc274bed +github.com/duosecurity/duo_api_golang,v0.0.0-20190308151101-6c680f768e74,h1:2MIhn2R6oXQbgW5yHfS+d6YqyMfXiu2L55rFZC4UD/M=,75c90bdd92362e2cc36297193a543fe0cd75c07f82182940ad6158a1d470cc8b +github.com/dustin/go-humanize,v1.0.0,h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=,e01916e082a6646ea12d7800d77af43045c27284ff2a0a77e3484509989cc107 +github.com/dylanmei/iso8601,v0.1.0,h1:812NGQDBcqquTfH5Yeo7lwR0nzx/cKdsmf3qMjPURUI=,1e682968bfcac2115e1fd706ec6bd09a0b676d7d224514d8f8dff9cadbf87e79 +github.com/dylanmei/winrmtest,v0.0.0-20190225150635-99b7fe2fddf1,h1:r1oACdS2XYiAWcfF8BJXkoU8l1J71KehGR+d99yWEDA=,5607cb987ec0a699003eeec5952f0280792fd5db7099ca277bdfae26e93b0ef3 +github.com/eapache/go-resiliency,v1.1.0,h1:1NtRmCAqadE2FN4ZcN6g90TP3uk8cg9rn9eNK2197aU=,a64ebe539335e126b30f79f0f00f39ffe083e794995500a67e0a2156b334788e +github.com/eapache/go-xerial-snappy,v0.0.0-20180814174437-776d5712da21,h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw=,785264afffdcfe50573a1cb0df85ff4186e9e7e4e3a04513752f52d3da1054af +github.com/eapache/queue,v1.1.0,h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=,1dc1b4972e8505c4763c65424b19604c65c944911d16c18c5cbd35aae45626fb +github.com/eclipse/paho.mqtt.golang,v1.2.0,h1:1F8mhG9+aO5/xpdtFkW4SxOJB67ukuDC3t2y2qayIX0=,d36337c4b5a2752b91bcd437bd74e0907bf6c9e6c611dab88407bcca8462e918 +github.com/edgexfoundry/go-mod-core-contracts,v0.1.33,h1:lQbLbRhymV0/QDDDGU26idZ9Kv+Q0IETn81hLpHxi68=,a7a8792a8692d64daea343577a49934be6ba64acbe114b3c24262537b5a9157f +github.com/edsrzf/mmap-go,v1.0.0,h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw=,851a1d4d6e30f97ab23b7e4a6a7da9d1842f126d738f7386010c6ee7bf82518e +github.com/edwingeng/doublejump,v0.0.0-20190102103700-461a0155c7be,h1:FnUE/uuuegwvhGE9z61q9krL5km5Mnwlusq3BT06yy8=,a9cb92422f0bbdd56c80d9873a8f7af6fd2d8d8154a7a11d7cb9232d9146f07c +github.com/efarrer/iothrottler,v0.0.0-20141121142253-60e7e547c7fe,h1:WAx1vRufH0I2pTWldQkXPzpc+jndCOi2FH334LFQ1PI=,04291e6136b933fd2cdcc29f3af78090a9d678534a94823590eb63f1f318db1d +github.com/efritz/backoff,v1.0.0,h1:r1DfNhA1J7p8kZ185J/hLPz2Bl5ezTicUr9KamEAOYw=,064d92e7f3e46079d158cac717e1c9bf96a230a5f31bf28940bd4a99bb91657e +github.com/efritz/glock,v0.0.0-20181228234553-f184d69dff2c,h1:Q3HKbZogL9GGZVdO3PiVCOxZmRCsQAgV1xfelXJF/dY=,716200eb117905f4df509b7260869bb97bf8833c160d2ff1d328d01aa3874bc9 +github.com/eknkc/amber,v0.0.0-20171010120322-cdade1c07385,h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o=,b1dde9f3713742ad0961825a2d962bd99d9390daf8596e7680dfb5f395e54e22 +github.com/elastic/go-sysinfo,v1.0.1,h1:lzGPX2sIXaETeMXitXL2XZU8K4B7k7JBhIKWxdOdUt8=,fe0cd64aa3ac73edbb4240dcbcb660c4ec004f07c36371be6d78543c3b215d92 +github.com/elastic/go-windows,v1.0.0,h1:qLURgZFkkrYyTTkvYpsZIgf83AUsdIHfvlJaqaZ7aSY=,e487e6f1e269766b5815c36e93614b87a185ddc33f7a6f4bf23e5ee6d0d0e3c1 +github.com/elastic/gosigar,v0.10.5,h1:GzPQ+78RaAb4J63unidA/JavQRKrB6s8IOzN6Ib59jo=,a139252942b5ca82ddc3d9ced1daa262de0149a413149d3f0234b43dc3635acf +github.com/elazarl/go-bindata-assetfs,v1.0.0,h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=,3aa225ae5ae4a8059a671fa656d8567f09861f88b88dbef9e06a291efd90013a +github.com/elazarl/goproxy,v0.0.0-20191011121108-aa519ddbe484,h1:pEtiCjIXx3RvGjlUJuCNxNOw0MNblyR9Wi+vJGBFh+8=,6c224ac5720959a46f6d88e0b15dda732c7eb180b3103a826cf6d5459a5e112f +github.com/elazarl/goproxy/ext,v0.0.0-20190711103511-473e67f1d7d2,h1:dWB6v3RcOy03t/bUadywsbyrQwCqZeNIEX6M1OtSZOM=,7244c1fe7490460503559e24e0e478540bc10481d1d8f3afd0a1f6b1a470b52f +github.com/emicklei/go-restful,v2.11.1+incompatible,h1:CjKsv3uWcCMvySPQYKxO8XX3f9zD4FeZRsW4G0B4ffE=,9befcac63629841301235124e728206a96170afd83c78b632d271acafc9acccf +github.com/emicklei/go-restful-swagger12,v0.0.0-20170926063155-7524189396c6,h1:V94anc0ZG3Pa/cAMwP2m1aQW3+/FF8Qmw/GsFyTJAp4=,07fd41dbe765b7d340df21d6353db8bef782f9b6742a93696b6f4133ef1d8955 +github.com/emicklei/proto,v1.6.15,h1:XbpwxmuOPrdES97FrSfpyy67SSCV/wBIKXqgJzh6hNw=,162ad34010e5f81ebed962a33c91ee6356e19631c7a7030bc9b173e85ca34678 +github.com/emirpasic/gods,v1.12.0,h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=,729ea0bda86bf801b61ff66eb019e5b9adc559cd217944abf10bb103fca573ee +github.com/endophage/gotuf,v0.0.0-20151124190824-3b700e20e376,h1:rPyHFhsuPZMEJAe1Oj2vpRC8277wpDJJ+aabkmlHF1A=,2cd5e6d0e748e0625e8c4a08a3b9f74e311e6654a1c5411fa3a9720f5f67cf40 +github.com/envoyproxy/go-control-plane,v0.9.0,h1:67WMNTvGrl7V1dWdKCeTwxDr7nio9clKoTlLhwIPnT4=,07b3a43081c9e1cdccb95c657cba7f483d5099f9ce07b5e3f3e28ce557687521 +github.com/envoyproxy/protoc-gen-validate,v0.1.0,h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=,ec5261f3bbc426d71e2be4c76063ba12460c5d27845d630763e9e911ec4768af +github.com/eoscanada/eos-go,v0.8.10,h1:QUwHRBHEFag/qyW4PR2S9++0se0V4LjPLk1/KsNtXlo=,f1c48e793d1c7864288871a944af4b4ee3363ad6ae5298e9c2f9f42202e6d77c +github.com/erikstmartin/go-testdb,v0.0.0-20160219214506-8d10e4a1bae5,h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=,471feb426b2a7ec1df29cc21c66aef34c9e7aabea751328644d1362593983d21 +github.com/ernesto-jimenez/gogen,v0.0.0-20180125220232-d7d4131e6607,h1:cTavhURetDkezJCvxFggiyLeP40Mrk/TtVg2+ycw1Es=,1f3030cfc89653ba791ae312b19e420dc8eaf1bef51f59dca6aa390f3cd1f3d0 +github.com/etcd-io/bbolt,v1.3.3,h1:gSJmxrs37LgTqR/oyJBWok6k6SvXEUerFTbltIhXkBM=,6630d7aad4b10f76aea88ee6d9086a1edffe371651cc2432edfd0de6beb99120 +github.com/ethantkoenig/rupture,v0.0.0-20180203182544-0a76f03a811a,h1:M1bRpaZAn4GSsqu3hdK2R8H0AH9O6vqCTCbm2oAFGfE=,8559344c496621c06b612453de587e8e4c45c0fbc348a955f8eda7ea2b3d09c8 +github.com/ethereum/go-ethereum,v1.9.6,h1:EacwxMGKZezZi+m3in0Tlyk0veDQgnfZ9BjQqHAaQLM=,778c9bf77dd96bfaf5c3ea84498611490999782fb37edf8257680e27dd8976e8 +github.com/euank/go-kmsg-parser,v2.0.0+incompatible,h1:cHD53+PLQuuQyLZeriD1V/esuG4MuU0Pjs5y6iknohY=,43cadfa5ab226f89ca7a715add32ba23c554a5dfafd3a55449856a6b7012f946 +github.com/evanphx/json-patch,v4.5.0+incompatible,h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M=,5508e810685a5081a3e880aeb24e501bd87920241baa317bfb5f3946b4fa417c +github.com/exoscale/egoscale,v0.18.1,h1:1FNZVk8jHUx0AvWhOZxLEDNlacTU0chMXUUNkm9EZaI=,8cb4f10504b54d31c71bc4a670171a074f7abbab67d939fd404b62ad36cb6aed +github.com/facebookgo/atomicfile,v0.0.0-20151019160806-2de1f203e7d5,h1:BBso6MBKW8ncyZLv37o+KNyy0HrrHgfnOaGQC2qvN+A=,3c9bdee73452cc12c2936b4050d638d36302a958091ceb49c45ffbaff8954218 +github.com/facebookgo/clock,v0.0.0-20150410010913-600d898af40a,h1:yDWHCSQ40h88yih2JAcL6Ls/kVkSE8GFACTGVnMPruw=,5d6b671bd5afef8459fb7561d19bcf7c7f378da9943722d36676735b3c6272fa +github.com/facebookgo/ensure,v0.0.0-20160127193407-b4ab57deab51,h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ=,a96c69c2b5902e0383139ee7089877a5ae2ddcd4eba42a595d13b570907d3fdc +github.com/facebookgo/freeport,v0.0.0-20150612182905-d4adf43b75b9,h1:wWke/RUCl7VRjQhwPlR/v0glZXNYzBHdNUzf/Am2Nmg=,0f717d7eb52e276aec2138a971b091cd04da95826c8f451a20e8e78c4bb8f915 +github.com/facebookgo/grace,v0.0.0-20160926231715-5729e484473f,h1:0mlfEUWnUDVZnqWEVHGerL5bKYDKMEmT/Qk/W/3nGuo=,79f9f73ef925d457d2b70d37b12c3cec97a2e84e73a932397d2f569ec8702ee7 +github.com/facebookgo/httpdown,v0.0.0-20160323221027-a3b1354551a2,h1:3Zvf9wRhl1cOhckN1oRGWPOkIhOketmEcrQ4TeFAoR4=,dbbccf963238c5f80c54edb19aeb016f486f42dcd922fc0be5b832af9449ca4b +github.com/facebookgo/inject,v0.0.0-20161006174721-cc1aa653e50f,h1:jK9r9Ofgc/Yzdlod77G23LfYtwqAmkQCZ9MaP6779OI=,6292702ff520e1fb14231f29bb2639d8f39edc08de479d76757ad97dafbb9174 +github.com/facebookgo/stack,v0.0.0-20160209184415-751773369052,h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A=,0afd18a8394caa29e94bd58a42e0d2be07939f9daf190a9ba2a947f9cbd4ba1a +github.com/facebookgo/stats,v0.0.0-20151006221625-1b76add642e4,h1:0YtRCqIZs2+Tz49QuH6cJVw/IFqzo39gEqZ0iYLxD2M=,d87443825721dc1dd5c358cd9e55b917ee1c3b6b10ab9557375f59d563b628cb +github.com/facebookgo/structtag,v0.0.0-20150214074306-217e25fb9691,h1:KnnwHN59Jxec0htA2pe/i0/WI9vxXLQifdhBrP3lqcQ=,3a9c84e9dc2b9960f1de3cc7a61d91fe2978e64e4e4859a9383259092ec91c5e +github.com/facebookgo/subset,v0.0.0-20150612182917-8dac2c3c4870,h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y=,bb18c678177e1aaaae209a2de9c28b5b7acc34e58fe00517b847a9460bd42df2 +github.com/farsightsec/golang-framestream,v0.0.0-20190425193708-fa4b164d59b8,h1:/iPdQppoAsTfML+yqFSq2EBChiEMnRkh5WvhFgtWwcU=,084f0ac3684b180e3d87db3e7b36a412c750397fbf009579e126c304528c1738 +github.com/fatih/camelcase,v1.0.0,h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=,54664f64f1f24097b80c64b9f606cbe8d8bc410a755ce6cda4f45e46f1141984 +github.com/fatih/color,v1.7.0,h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=,6036f0b31167280b696b5efb43603e71bce31420fb3428afdf74a68bb3a3ebef +github.com/fatih/structs,v1.1.0,h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=,a361ecc95ad12000c66ee143d26b2aa0a4e5de3b045fd5d18a52564622a59148 +github.com/fatih/structtag,v1.0.0,h1:pTHj65+u3RKWYPSGaU290FpI/dXxTaHdVwVwbcPKmEc=,347fce3911900f5947735c12ccb4c6fbe0199c6df040bcaa4d74a8587af896d0 +github.com/fd/go-nat,v1.0.0,h1:DPyQ97sxA9ThrWYRPcWUz/z9TnpTIGRYODIQc/dy64M=,bdf011af97da57ef3c58a091ae760eb885a6322faa3539d3c37bf76d4fff536a +github.com/fernet/fernet-go,v0.0.0-20180830025343-9eac43b88a5e,h1:P10tZmVD2XclAaT9l7OduMH1OLFzTa1wUuUqHZnEdI0=,a484a3172222095507a7f1901a91ab741c28278ea6b878c21c1151c0fd40f46d +github.com/flosch/pongo2,v0.0.0-20190707114632-bbf5a6c351f4,h1:GY1+t5Dr9OKADM64SYnQjw/w99HMYvQ0A8/JoUkxVmc=,814b52f668d2e2528fe9af917506cda4894d22c927283cfb8aaf6857503dfc5a +github.com/flynn/go-shlex,v0.0.0-20150515145356-3f9db97f8568,h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=,ea68a1d391e59ebc04ce986b88e000327bb141e5e8e80ef93af950bca42bb4cc +github.com/fogleman/gg,v1.3.0,h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=,792f7a3ea9eea31b7947dabaf9d5a307389245069078e4bf435d76cb0505439c +github.com/forestgiant/sliceutil,v0.0.0-20160425183142-94783f95db6c,h1:pBgVXWDXju1m8W4lnEeIqTHPOzhTUO81a7yknM/xQR4=,bedd47c23670847642576777cc8b53b9dd8a5a8e7b0a6f2299ebc6fa3b7b6f00 +github.com/fortytw2/leaktest,v1.3.0,h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=,867e6d131510751ba6055c51e7746b0056a6b3dcb1a1b2dfdc694251cd7eb8b3 +github.com/francoispqt/gojay,v1.2.13,h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=,f41e3e4f3086400448dbce1c06c59f5848a6c5983e5466689965e3a2cabcba7c +github.com/frankban/quicktest,v1.5.0,h1:Tb4jWdSpdjKzTUicPnY61PZxKbDoGa7ABbrReT3gQVY=,515b5b2b9320b2982193ad6bd118907aaab9ff62189870e00be459cc4097073c +github.com/fsnotify/fsnotify,v1.4.7,h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=,1d09ad8f3dc41cb6e0288023b47272c1c9393ca411e48f4b5009bca6662dc3ad +github.com/fsouza/fake-gcs-server,v1.2.0,h1:FZUL/EJlyAlHxpUWZs23ae4zNwBwmHM1p5TykkoP85A=,83b547a0780693f154c30137b1eeaf0c0e9628798ae4b7e1d74ebfb8efaf61fc +github.com/fsouza/go-dockerclient,v1.5.0,h1:7OtayOe5HnoG+KWMHgyyPymwaodnB2IDYuVfseKyxbA=,c7025b816e0ba28041a88b1063003f4e31097346d06cf69811f9d55505d3d46c +github.com/fullsailor/pkcs7,v0.0.0-20190404230743-d7302db945fa,h1:RDBNVkRviHZtvDvId8XSGPu3rmpmSe+wKRcEWNgsfWU=,ba36a8fc855d6eecef329d26f8e82132e38d45d06f79f88d3b0bde6d718c8fb2 +github.com/fuyufjh/splunk-hec-go,v0.3.3,h1:7PLVIODblK9FXfuAy8iPZg0lcw1YNzSQHfC+0NYgUxU=,9517f63386f64e0dceca9352f45eb7f160452682a07fa04d3c1ff90eb19ac83d +github.com/gabriel-samfira/sys,v0.0.0-20150608132119-9ddc60d56b51,h1:rUp9t/FbeJM3R3BSYkJfViN3CNQcmk44H20SqkJ/y+k=,1be262d101bd9079bb859639ad6d5eaee80646b6db0fcbeb7146d9381949d2a8 +github.com/gammazero/deque,v0.0.0-20190130191400-2afb3858e9c7,h1:D2LrfOPgGHQprIxmsTpxtzhpmF66HoM6rXSmcqaX7h8=,a1fe4ec3258f68685ee45b68e1d9188d79726af46a1b93281cf11ddc6045a864 +github.com/gammazero/workerpool,v0.0.0-20190406235159-88d534f22b56,h1:VzbudKn/nvxYKOdzgkEBS6SSreRjAgoJ+ZeS4wPFkgc=,cbb92fdf8d457e27923dc6515af4458a55af932ccf468415c8b36bf49845fc00 +github.com/garyburd/go-oauth,v0.0.0-20180319155456-bca2e7f09a17,h1:GOfMz6cRgTJ9jWV0qAezv642OhPnKEG7gtUjJSdStHE=,be051ba0d52eaced1c1985ebdf2dece3f7127ad392645b42fd06c2af9c9caea2 +github.com/garyburd/redigo,v1.6.0,h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc=,68f0d2b454f7a9a000c3335fc0f409123637e4711c6461a4c75e2f128f68f283 +github.com/gavv/monotime,v0.0.0-20161010190848-47d58efa6955,h1:gmtGRvSexPU4B1T/yYo0sLOKzER1YT+b4kPxPpm0Ty4=,c97324768edc8170e05b8925b0551778909c8e15817d4327ac405a4e0b6071f4 +github.com/gcash/bchd,v0.14.7,h1:n3gMXCT4VhU/emiCq61kmKBPADLxBzpX5IlXPnGuR2c=,871644f504d6c3f19dcfc8a7a6e6aa623e6642275a48dfffe770ec61368c2032 +github.com/gcash/bchlog,v0.0.0-20180913005452-b4f036f92fa6,h1:3pZvWJ8MSfWstGrb8Hfh4ZpLyZNcXypcGx2Ju4ZibVM=,d400c8e944edf2a67f46e75335f55c14170c523691804ea71e1a348ad45bc7e7 +github.com/gcash/bchutil,v0.0.0-20191012211144-98e73ec336ba,h1:KVa96lSrJGMYZ414NtYuAlbtCgrmW9kDnjvYXcLrr5A=,7b829a35d22ead0ee82d8a98b1e06da5e63fd07b2798fce8ba87c8da670ef04a +github.com/gcla/gowid,v1.0.0,h1:78Xf5G9+lb4/g3KCB3hX8UJ8VorymMH5PXu9Npvwf8s=,eaa7e0b7bb0912c6b24c98dee0073a2de754c24e1347ce7c5bfc63397ccf0fa6 +github.com/gdamore/encoding,v1.0.0,h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=,638a9832e2f62d118d7c511d86bdae1622a51f331de48a01d929fd24ebe6a2a6 +github.com/gdamore/tcell,v1.3.0,h1:r35w0JBADPZCVQijYebl6YMWWtHRqVEGt7kL2eBADRM=,97c1e828ff9de0cef3a5bbdb3f3def8a351ad6ca65a780d4dd4141b0ee23c88e +github.com/genuinetools/pkg,v0.0.0-20180910213200-1c141f661797,h1:SGpZXDd/CFeDIY4Rq5cFO8K/uqDblHUxjlzOmjFpvRg=,c15cbe95e0a7e38cc0a790b0098170c103ba84d56e7cbaf744a6df10c00efa45 +github.com/genuinetools/reg,v0.16.0,h1:ZhLZPT+aUGHLfy45Ub5FLWik+3Dij1iwaj8A/GyAZBw=,a505ff5357d6095540c89ee27d207a3a4dc7c73840fb6bc9a2f0f3a81e498341 +github.com/gernest/wow,v0.1.0,h1:g9xdwCwP0+xgVYlA2sopI0gZHqXe7HjI/7/LykG4fks=,b49d5efc34e19469e7319df09b35438de307ba7cd8c9333ecba190f457ca8e22 +github.com/getgauge/common,v0.0.0-20190514095629-619e107433ce,h1:/ofMj8gIhPYdb/JEXKj8iYe5Yxl3mrK8YA7yl/06t6Y=,04ab4fb7e8dcf693c3b79028693130cd51fe54f5a16f12622975a7c3eb7705f7 +github.com/getlantern/context,v0.0.0-20190109183933-c447772a6520,h1:NRUJuo3v3WGC/g5YiyF790gut6oQr5f3FBI88Wv0dx4=,27515ae761018c4cfc83043194904170bef0cac037c48ff96fc497502b9bab14 +github.com/getlantern/errors,v0.0.0-20190325191628-abdb3e3e36f7,h1:6uJ+sZ/e03gkbqZ0kUG6mfKoqDb4XMAzMIwlajq19So=,a48d7684463e8c496fea4a2595ca71012c3b222bc77de7c2ddfbe78bc4595ac5 +github.com/getlantern/fdcount,v0.0.0-20170105153814-6a6cb5839bc5,h1:8Q9iN/V24EG01IgXEKVScth/rTXpplBxCYio/yIKtUw=,b24c26d5ede197fd6b7f981cf5db300124e22f48667942c948a9750f7a908c94 +github.com/getlantern/golog,v0.0.0-20190830074920-4ef2e798c2d7,h1:guBYzEaLz0Vfc/jv0czrr2z7qyzTOGC9hiQ0VC+hKjk=,1eeabfbc56105f3d751e1947405f5296db5ded7e25900209fe7327f1b5d785e6 +github.com/getlantern/hex,v0.0.0-20190417191902-c6586a6fe0b7,h1:micT5vkcr9tOVk1FiH8SWKID8ultN44Z+yzd2y/Vyb0=,ea5a13f98a82c1919c59b655de531cbb35ac7dfff3c99072b43b8bfd1c29b774 +github.com/getlantern/hidden,v0.0.0-20190325191715-f02dbb02be55,h1:XYzSdCbkzOC0FDNrgJqGRo8PCMFOBFL9py72DRs7bmc=,c901f2e702114d6268446a381a27737c6123e50191197fd84f17b339238191b4 +github.com/getlantern/idletiming,v0.0.0-20190529182719-d2fbc83372a5,h1:laM1s/bxUH8xbbC9TBGWsOc7A0KCAPZMa4pdwO5e6Vw=,35de51b383e926042d3f8f4859e2d961582cf9964d3b7bb513ac4733cc43162f +github.com/getlantern/mockconn,v0.0.0-20190403061815-a8ffa60494a6,h1:+aO65ByJw74kV8vXqvkj49P5RtIqyUObyeRTIxMz218=,a4a1ccdc9ec68dea571d9603d4a36150b6ccaea447ca88965e088ff0b9eeaa0d +github.com/getlantern/mtime,v0.0.0-20170117193331-ba114e4a82b0,h1:1VNkP55LM/W2IwWN+qi+5X3gZcEQHfj8X9E+FNxVgM4=,5af0b20838a808b86a2a9c87c254d47185d38d5935780dade3bc7a54dc2880f4 +github.com/getlantern/netx,v0.0.0-20190110220209-9912de6f94fd,h1:mn98vs69Kqw56iKhR82mjk16Q1q5aDFFW0E89/QbXkQ=,cb386d0527fb6f549fa0266c770a68d7d83a88bab2194d25b55355f59198fdf0 +github.com/getlantern/ops,v0.0.0-20190325191751-d70cb0d6f85f,h1:wrYrQttPS8FHIRSlsrcuKazukx/xqO/PpLZzZXsF+EA=,321694d3d2f31415653a7b9d97a4a701f36f10ccfbbdb94449f1211137d6f215 +github.com/getsentry/raven-go,v0.2.0,h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs=,eaffe69939612cd05f95e1846b8ddb4043655571be34cdb6412a66b41b6826eb +github.com/gf-third/mysql,v1.4.2,h1:f1M5CNFUG3WkE07UOomtu4o0n/KJKeuUUf5Nc9ZFXs4=,14a08134ce02bd0d07667da91a89c9098d18bad8c790414e37aba906895a5a3e +github.com/gf-third/yaml,v1.0.1,h1:pqD4ix+65DqGphU1MDnToPZfGYk0tuuwRzuTSl3g0d0=,6354a95d7faa222d2e653485bc9dd555aad61a75eb5a5f970de531391ed77a2f +github.com/ghetzel/go-defaults,v1.2.0,h1:U1T64bxhBc6nVZ68QXch1hoHq43h6isqgbvG7kxY9Uc=,f339e441d08af3af184a21f518227db7c705851be82f3fcea611e762ebb633a1 +github.com/ghetzel/go-stockutil,v1.8.6,h1:VgqpePUGGXMHjgArUH5mSAYFC35aiFgkU/TdTU/ts80=,aa0cce06af82b7d1f98a20deaafd6997fa7c3d36fba9a204a34e5d91a2096fa0 +github.com/ghetzel/testify,v1.4.1,h1:wpJirdM+znAnxWruGDBdIys5aU+wGJHNUTkgEo4PYwk=,90206efc10ad71a33bf314ef768d16c6186d23ccb5aa8172663437d497dbfdd7 +github.com/ghetzel/uuid,v0.0.0-20171129191014-dec09d789f3d,h1:YVJe7KwVYazt90hCc/q2dYJVS3062AY6QdT6iHd+Kh8=,924f39fe83589fa269e652c8ca4f7b0dbc59023baada8a55c24692fe5223b67a +github.com/ghodss/yaml,v1.0.1-0.20190212211648-25d852aebe32,h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew=,9771720da98bbdd80dacdefb47b9a0e36faa75caa4745149d150325ba5390e4b +github.com/gin-contrib/gzip,v0.0.1,h1:ezvKOL6jH+jlzdHNE4h9h8q8uMpDQjyl0NN0Jd7jozc=,e994ecc5881938978d6d031e3d0c1bc5968bfe5de2a307aed7c63aecba459ecd +github.com/gin-contrib/sse,v0.1.0,h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=,512c8672f26405172077e764c4817ed8f66edc632d1bed205b5e1b8d282816ab +github.com/gin-gonic/gin,v1.4.0,h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ=,b9bc661bf658179d53fee9e7c587eba4df8326d0c26ad29f785739a78313fc4b +github.com/glacjay/goini,v0.0.0-20161120062552-fd3024d87ee2,h1:+SEORW3KptcFnlhTbn7N0drG3AFnrcmBDWDyQ3Bt06o=,061319068788a9eeef67d4e5cf84a87c4649005aaa4f37c983a868c357e3df3c +github.com/gliderlabs/ssh,v0.2.2,h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=,f9f12d766ceeab9e2134504520de75819d1eeb6733b8b619b7bcd4aac4cca983 +github.com/globalsign/mgo,v0.0.0-20181015135952-eeefdecb41b8,h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is=,c07f09e0c93e6410076edfd621d2decbd361361c536c3e33ba097fa51708f360 +github.com/glycerine/go-unsnap-stream,v0.0.0-20180323001048-9f0cb55181dd,h1:r04MMPyLHj/QwZuMJ5+7tJcBr1AQjpiAK/rZWRrQT7o=,9a66d6f9bb1a268f4b824d6fe7adcd55dc17ed504683bdf2dbf67b32028d9b88 +github.com/glycerine/goconvey,v0.0.0-20190315024820-982ee783a72e,h1:SiEs4J3BKVIeaWrH3tKaz3QLZhJ68iJ/A4xrzIoE5+Y=,344fb699344a5ab09464c0283a65402ae0fe6bd6fac7d40e9c4d403cf4a7714f +github.com/gmallard/stompngo,v1.0.12,h1:uj1Bl9o+dqn0qSR33xHmaKw21W5LzhWo4Q4hS1MCpQU=,88498e4da4e0f7f3923d758a464d53f550921617b1047643def2a973c86dfd03 +github.com/go-aah/forge,v0.8.0,h1:sk4Z523B9ay3JQF4At97U7kecB5yTIm0J2UM/qRVXbQ=,e883adcfb380d6187de84c59a0f8bb3b34931487151873d7a326a1b4df556e48 +github.com/go-acme/lego,v2.7.2+incompatible,h1:ThhpPBgf6oa9X/vRd0kEmWOsX7+vmYdckmGZSb+FEp0=,1a597873ff61c0fbdab6b4f1027141d2e8dbe739bd2018473559bec954f3e651 +github.com/go-acme/lego/v3,v3.1.0,h1:yanYFoYW8azFkCvJfIk7edWWfjkYkhDxe45ZsxoW4Xk=,fbb3cfe2619281c3ccd456b213b5f8c7bf695f82ecac6c97f747dc4159dfe4b2 +github.com/go-ble/ble,v0.0.0-20190521171521-147700f13610,h1:eWay3GzFqTJUEYN1BrbqdDTFeFUGmYLps8SQkn1D7Yo=,a5fb6440935dd7ef8bb3569bc7260bd1ad44e01d41bbb684dbb96cc677fb2234 +github.com/go-chassis/foundation,v0.0.0-20190621030543-c3b63f787f4c,h1:p+Y6yq7RwHmYjEr/vwdVYGacBqFCc2lPQfNRIC3vRIs=,db38c108455e57b3f8f062c22872554d5af9dfa03a723c9fea263a009f3002e6 +github.com/go-chassis/go-archaius,v0.24.0,h1:ubNgs3Rv067PI7t37ZJoIMaPPHIBWV+ni/e7XAdW1hU=,37b0c60692eaed91abd3d2c6a0fc9366a54882f3a6b5ef81f3cc20d14882a13d +github.com/go-chassis/go-chassis,v1.7.3,h1:7fcfaE9Ij+oBbf2lHoHHIvxT9objtt1EHpwRPBUkDhw=,38f8393558528b0212674268f6dc507d5db716fc5745eff09bccf1cd98b86eb7 +github.com/go-chassis/go-chassis-config,v0.14.0,h1:OnM9sx2GalDC7vEIhPecRpQlVa8hz10NOB41+9tii5A=,afc7506eec8591a5ccbb08f073ba19312bc03d87ec15c1532f5daba02f090e00 +github.com/go-chassis/go-restful-swagger20,v1.0.1,h1:HdGto0xroWGK504XN0Um7JBc0OPMHDlWwedkd2mTGII=,2c41388f71dc766088fc3e47e91a2f8c2d7936e40f6a64afff53a12ef73e0d05 +github.com/go-chassis/paas-lager,v1.0.2-0.20190328010332-cf506050ddb2,h1:iORWPbIQ81tJPKWs9TNvcjCQnqvyTlL41F9ILgiTcyM=,a74c06554cf6835e98c4fa548a4aa3dcc317ca93567af893b89a4dba88b783af +github.com/go-chat-bot/bot,v0.0.0-20191022130543-3da6cae45477,h1:JfUELmxvEz/MXI3/iSn2UcB/5CCAvMsxKi88j783ssk=,a059cd1d050747bd0adcd3d4ba91e12b0ace2c038187484726c3d551169d9fa4 +github.com/go-chat-bot/plugins,v0.0.0-20181006134258-491b3f9878d6,h1:qNYjVQnDwznjLk+OnNdczA5SXwEa/RwjPTZSQCKofF4=,b19527108aef487fa1f4856e354f4777644a574248cc7e891bacf1bfb38bd12d +github.com/go-chat-bot/plugins-br,v0.0.0-20170316122923-eb41b30907dc,h1:v/poG4Y4O/z1cUm2cWxiIkFFgRsT3Fe1u1A33evx89g=,6b613e62d3f389f3d6f8f262903bc31c4f1eb4b3ca8d192606f78199b1af0d43 +github.com/go-check/check,v0.0.0-20190902080502-41f04d3bba15,h1:xJdCV5uP69sUzCIIzmhAw6EKKdVk3Tu48oLzM86+XPI=,93bbc1f982dd553e279fb4c7fbc060032096e2b5d0537385ae80247492a6433e +github.com/go-chi/chi,v4.0.2+incompatible,h1:maB6vn6FqCxrpz4FqWdh4+lwpyZIQS7YEAUcHlgXVRs=,25c94ccd43f18002c2dd07e87da1dc393ff87d615441e559bda425ea0979715b +github.com/go-cmd/cmd,v1.0.5,h1:IK23uTRWxq6UJnNWp8nKO7mVCwnPfbaxA2lhzEKfNj0=,2623aa43dbf68c24362bcfb7a216b83c2e7473d4a3e49e7955c3fa5f28b4974c +github.com/go-delve/delve,v1.3.2,h1:K8VjV+Q2YnBYlPq0ctjrvc9h7h03wXszlszzfGW5Tog=,b8a250f2b3ef87da34fbfc655bb23a051b43672bea7a8abc4e083a2b214faf09 +github.com/go-errors/errors,v1.0.1,h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=,bdbee3143e1798eadff4df919479c28ec2d3299a97d445917bc64d6eb6a3b95a +github.com/go-gl/gl,v0.0.0-20181026044259-55b76b7df9d2,h1:78Hza2KHn2PX1jdydQnffaU2A/xM0g3Nx1xmMdep9Gk=,499822d1b3bcc34b82df0fcc13ac9a0ea273c5d68b3e183e18fa76dab9793954 +github.com/go-gl/glfw,v0.0.0-20190409004039-e6da0acd62b1,h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0=,96c694c42e7b866ea8e26dc48b612c4daa8582ce61fdeefbe92c1a4c46163169 +github.com/go-gl/mathgl,v0.0.0-20190713194549-592312d8590a,h1:yoAEv7yeWqfL/l9A/J5QOndXIJCldv+uuQB1DSNQbS0=,39948d90a5672c7866b5b1c01e9e8ce6c80c099306ed80e9e138350840f82110 +github.com/go-ini/ini,v1.49.0,h1:ymWFBUkwN3JFPjvjcJJ5TSTwh84M66QrH+8vOytLgRY=,4820559fd3640c6b5361a7077e8b5c1a4318a06a59df7a095cbf96514d46d432 +github.com/go-kit/kit,v0.9.0,h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk=,f3da9b35b100dd32e7b10c37a0630af60d54afa37c61291e7df94bc0ac31ed03 +github.com/go-ldap/ldap,v3.0.3+incompatible,h1:HTeSZO8hWMS1Rgb2Ziku6b8a7qRIZZMHjsvuZyatzwk=,4197e5fbebc7a1805be236cf75dea301f0b8e15a857e2373653b76157c649f93 +github.com/go-log/log,v0.1.0,h1:wudGTNsiGzrD5ZjgIkVZ517ugi2XRe9Q/xRCzwEO4/U=,ec5845d33a6d7ede81970833cfc3179d53b99019da1ebffef5e71005ff94be43 +github.com/go-logfmt/logfmt,v0.4.0,h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA=,d678198dc0eeaed28736e0d71b919a0bd98501b7275c69a7917122f6de9e0d1c +github.com/go-logr/logr,v0.1.0,h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg=,4c14b7c05eaa48b7f8dbf2ca38c3603dce446f4184a4c0af2f569b046d66201e +github.com/go-logr/zapr,v0.1.0,h1:h+WVe9j6HAA01niTJPA/kKH0i7e0rLZBCwauQFcRE54=,7b60c74f722b8f215711503dd63576845987eff81ef5f9dc052fc9158d1c57e2 +github.com/go-macaron/binding,v1.0.0,h1:ILEIP1e9GaXz//fZIl1zXgHVbM9j1SN89aTGOq8340Y=,3887f50d442cd8f9eeeb0e7710c7cba41c185d8e5a82404ff33e7cbd4e16d0c7 +github.com/go-macaron/cache,v0.0.0-20151013081102-561735312776,h1:UYIHS1r0WotqB5cIa0PAiV0m6GzD9rDBcn4alp5JgCw=,a854b7844fff9ec69025db12a2b03834a2eac570a366962c4eb83984813a9fdb +github.com/go-macaron/captcha,v0.0.0-20190710000913-8dc5911259df,h1:MdgvtI3Y1u/DHNj7xUGOqAv+KGoTikjy8xQtCm12L78=,fb1c643c72ba9ef2c5d613e324e47dbb17ce45a28cbee8cb540ea48a0b3d6a23 +github.com/go-macaron/cors,v0.0.0-20190418220122-6fd6a9bfe14e,h1:auESkcVctNZnNl4EH0TuoCSJMJ7Q7ShU8FS6lDEsAC4=,0f3043631d54efca5615fe7ed819523bbe0c18726ce9e4b0cdc0ef2879aa6044 +github.com/go-macaron/csrf,v0.0.0-20180426211211-503617c6b372,h1:acrx8CnDmlKl+BPoOOLEK9Ko+SrWFB5pxRuGkKj4iqo=,90b5cbd86ff3708d41be70ad3cde77fdedd5ef485b960cc3a9ffea6f0a14902c +github.com/go-macaron/gzip,v0.0.0-20191101043656-b5609500c6fc,h1:z3gfrCJUPhdRHtd8kftnNBzI5ayZ1zQhWARPeL83JNQ=,dfcc1200b66bcb581c6984da9fa4aefc92facc3a07d182c7c37f0978b41b868f +github.com/go-macaron/i18n,v0.0.0-20160612092837-ef57533c3b0f,h1:wDKrZFc9pYJlqFOf7EzGbFMrSFFtyHt3plr2uTdo8Rg=,6c1d5fe7ed23e05ca1af7462e6deac2d993ddacd099ad794faad5c685337742d +github.com/go-macaron/inject,v0.0.0-20160627170012-d8a0b8677191,h1:NjHlg70DuOkcAMqgt0+XA+NHwtu66MkTVVgR4fFWbcI=,666bb04a5df1271326b4fcdbbdc3276400ae7e54f4ed6233792cd6e519676491 +github.com/go-macaron/session,v0.0.0-20191101041208-c5d57a35f512,h1:7ndsXTX42iYHryQz98zUsBJfStJ0kXFKgDrPmRvR400=,3581a7eb19a2a60d41aba7e85afa576c35a97659e162b83292ff67396f899845 +github.com/go-macaron/toolbox,v0.0.0-20180818072302-a77f45a7ce90,h1:3wYKrRg9IjUMfaf3H0Hh7M5Li9ge79Y7aw2yujHa2jQ=,43f2a06502408404c3b1231c3642693632cf20bc4f2cb45881bd2292b1eed714 +github.com/go-martini/martini,v0.0.0-20170121215854-22fa46961aab,h1:xveKWz2iaueeTaUgdetzel+U7exyigDYBryyVfV/rZk=,0561a4dadd68dbc1b38c09ed95bbfc5073b0a7708b9a787d38533ebd48040ec2 +github.com/go-mesh/openlogging,v1.0.1,h1:6raaXo8SK+wuQX1VoNi6QJCSf1fTOFWh7f5f6b2ZEmY=,3606bad571f959cc24382381f7d50fb321819958df37911f6ad6aa5ac3e02181 +github.com/go-ole/go-ole,v1.2.4,h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=,c8b3ef1187d2d7dbfddc4badefcc992c029cd377ae07bff2fa05ec8972836612 +github.com/go-openapi/analysis,v0.19.5,h1:8b2ZgKfKIUTVQpTb77MoRDIMEIwvDVw40o3aOXdfYzI=,22e5ff3f88802059aa86835d8f7c25386afed1159d4e951ef0f87ef62ab4a253 +github.com/go-openapi/errors,v0.19.2,h1:a2kIyV3w+OS3S97zxUndRVD46+FhGOUBDFY7nmu4CsY=,e02e448e5a2c1ff2a011f74d41d505a2f32b369551064940630d6660c600bf3d +github.com/go-openapi/inflect,v0.19.0,h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4=,fbcca36e347a2f560f50ac1c9c63f7d6cd97c8dff9800f08f370b5ce09b77c57 +github.com/go-openapi/jsonpointer,v0.19.3,h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=,1fe6122c9c9d10837439398976a2ff55e8ed905fa7e4a66f3fb0e857c6e06582 +github.com/go-openapi/jsonreference,v0.19.2,h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w=,00b2457c2d091a9817f91f55655a334bed8f75b2d6499ba9192f12564dd51dd9 +github.com/go-openapi/loads,v0.19.4,h1:5I4CCSqoWzT+82bBkNIvmLc0UOsoKKQ4Fz+3VxOB7SY=,adffcd0e2900bf0cca893e6bf014db55ebf161476367ac4dd365f8481c12616f +github.com/go-openapi/runtime,v0.19.7,h1:b2zcE9GCjDVtguugU7+S95vkHjwQEjz/lB+8LOuA9Nw=,4017d9c69d9d2789d0a3b50c6af509831c0f24bfc545f1b43224df2fc5194dbd +github.com/go-openapi/spec,v0.19.4,h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo=,7c12cf07de1b65175474fdde12110716ab237fa862694e4e5051eb15541a964e +github.com/go-openapi/strfmt,v0.19.3,h1:eRfyY5SkaNJCAwmmMcADjY31ow9+N7MCLW7oRkbsINA=,07b9c9b2da9dffc0a830e6536b705282fd17023fe8d04aa909fe1e4e3b6306f5 +github.com/go-openapi/swag,v0.19.5,h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=,54aec6bdc63d1d6609c32b140fe74d099f8b9628d362689556537506724eaeda +github.com/go-openapi/validate,v0.19.4,h1:LGjO87VyXY3bIKjlYpXSFuLRG2mTeuYlZyeNwFFWpyM=,2b1b2612db93ed3fb411cc798150821af5c031b120097bbe6578dc4ce2d6d1df +github.com/go-playground/locales,v0.13.0,h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=,9c4b65273e135b1bdb9bafc7c0b5180a6c5936f54edecbc8807c57a9d107c6b9 +github.com/go-playground/overalls,v0.0.0-20180201144345-22ec1a223b7c,h1:3bjbKXoj7jBYdHpQFbKL2546c4dtltTHzjo+5i4CHBU=,7972d7c49470ee2e187868b30d3157ca58201f50a934caa75ce4d5b134a2a644 +github.com/go-playground/universal-translator,v0.16.0,h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM=,316fba5fa26a586e39fc11698c16e67edabd122efe26f7fff71091a00a59883a +github.com/go-redis/redis,v6.15.6+incompatible,h1:H9evprGPLI8+ci7fxQx6WNZHJSb7be8FqJQRhdQZ5Sg=,e277bbc2acb8462aca5e20ef7569a733501bc765f65303a6e5153a86e6e3090c +github.com/go-sourcemap/sourcemap,v2.1.2+incompatible,h1:0b/xya7BKGhXuqFESKM4oIiRo9WOt2ebz7KxfreD6ug=,1bdaec84a31896eee149acb563f8af0b3ce7899d916383e0b597d6b480b6a622 +github.com/go-sql-driver/mysql,v1.4.1,h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=,f128045df19d340743a155ef282116130d27e27cbc62de160b6072c751b435ba +github.com/go-stack/stack,v1.8.0,h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=,78c2667c710f811307038634ffa43af442619acfeaf1efb593aa4e0ded9df48f +github.com/go-swagger/go-swagger,v0.20.1,h1:37XFujv7lYHLOKawfzLDg4STwwgB5zhPjodN33asJto=,79cc2c57c4e9d03a9399577b942eface46073ee6fa289b86651f1c5d0c513484 +github.com/go-swagger/scan-repo-boundary,v0.0.0-20180623220736-973b3573c013,h1:l9rI6sNaZgNC0LnF3MiE+qTmyBA/tZAg1rtyrGbUMK0=,51aed4b67bce9d988d64ca6be9de2169f709a29d5ea83e78ffb1c2432b346ec6 +github.com/go-telegram-bot-api/telegram-bot-api,v4.6.4+incompatible,h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU=,a0d2549e07c67e066337cc6eadd8be2a961d13b493d4325603010d4e35e519df +github.com/go-test/deep,v1.0.3,h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=,d199ce762552766bd3baf37ae4b0255bb6a6fecf144e8ae5fa3a94f1ce30a180 +github.com/go-xorm/builder,v0.3.4,h1:FxkeGB4Cggdw3tPwutLCpfjng2jugfkg6LDMrd/KsoY=,81028f69e261c29566c24f4717458d04dbe92aebc4eb93a41c1cfeef13b7c5dd +github.com/go-xorm/core,v0.6.0,h1:tp6hX+ku4OD9khFZS8VGBDRY3kfVCtelPfmkgCyHxL0=,8a8c43c039422f38e1775a835bda46e62f4a055b4b38d57967c0e7a6c9b21d23 +github.com/go-xorm/sqlfiddle,v0.0.0-20180821085327-62ce714f951a,h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y=,e539a37b8fb0d23c21e9eb1fe34db0ffcf19e5e4ae3d3b7049bb23c722c4b382 +github.com/go-xorm/xorm,v0.7.9,h1:LZze6n1UvRmM5gpL9/U9Gucwqo6aWlFVlfcHKH10qA0=,8836904c60cf227804fc843c707cd3e99122b95a97801d09dd2bddce4ed5a29f +github.com/go-yaml/yaml,v2.1.0+incompatible,h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o=,842989ea2e54ba8e4ef49cca914a5cd37176c44ccd3bb3e8c44fcbc10cb7832e +github.com/gobuffalo/attrs,v0.1.0,h1:LY6/rbhPD/hfa+AfviaMXBmZBGb0fGHF12yg7f3dPQA=,06c6c210a26c85ae291efe9d54cab9cab26fd1453f4f48962e04c89760e775d0 +github.com/gobuffalo/buffalo,v0.15.0,h1:VsxIcfJaDm4u2UirLHGgMfQpfHVwJP3JoDmGyeeNnc0=,f4553c8809a6764cefac8eefce9a868a42ee7538bdef4eadfcc06075b865a087 +github.com/gobuffalo/buffalo-docker,v1.0.7,h1:kj+AfChcev54v4N8N6PzNFWyiVSenzu6djrgxTBvbTk=,d84d8bea93f017e3ff07eddab57e0fd7007cf2516250d6fea86c8811c36cf786 +github.com/gobuffalo/buffalo-plugins,v1.14.1,h1:ZL22sNZif+k/0I9X7LB8cpVMWh7zcVjfpiqxFlH4xSY=,556641c2c1b3a9d679a3fc46727d41da225f33c63cfbf1ff721203b24e0a9b82 +github.com/gobuffalo/buffalo-pop,v1.23.1,h1:AnxJQZu/ZN7HCm3L8YBJoNWc2UiwSe6UHv5S4DfXUDA=,00dea8b0e63d3f4110b8bd9d32c086163229f56845a9f8b221e0093876065a05 +github.com/gobuffalo/clara,v0.9.1,h1:LYjwmKG0VwwW/nOG2f5jNamvAcfdm2Ysokc/eoVhtZ8=,319f607092c02686dfed2eb047d500c332ddd962341012bdcd91202bb46d37a9 +github.com/gobuffalo/depgen,v0.2.0,h1:CYuqsR8sq+L9G9+A6uUcTEuaK8AGenAjtYOm238fN3M=,efb3db0d05f712580bc8d3dce2967bd09d6c90140ac7bca1fbd5c5c4a28e1836 +github.com/gobuffalo/envy,v1.7.1,h1:OQl5ys5MBea7OGCdvPbBJWRgnhC/fGona6QKfvFeau8=,14ac6a5cd617dc05abfcb136586800f05f861d4a03d8fa66819a18c0d9eddeec +github.com/gobuffalo/events,v1.4.0,h1:Vje/vgTWs+dyhIS0U03oLpvx1SUdAqutv/hDWIz2ErM=,f6d99c722115631805f04fcf22e8edb7a4116bc65d698ac05c58b6a7f768efdc +github.com/gobuffalo/fizz,v1.9.5,h1:Qh0GkP7MYtJs9RZwBkPJ0CzEXynVowdNfrjg8b+TOxA=,2f645d789550f8f97039e1c4ce3e3f09dfeec28d85c8977c2b20caa06cd75b0c +github.com/gobuffalo/flect,v0.1.6,h1:D7KWNRFiCknJKA495/e1BO7oxqf8tbieaLv/ehoZ/+g=,a7011c8d3f59bac18512c76de610bf1a1f022a01ac6695e0c5af7498d33be613 +github.com/gobuffalo/genny,v0.4.1,h1:ylgRyFoVGtfq92Ziq0kyi0Sdwh//pqWEwg+vD3eK1ZA=,4ecf29587a8cbe069fc6b298d9a3cb674a8008ca4e08233904a8cba91d1ba21b +github.com/gobuffalo/gitgen,v0.0.0-20190315122116-cc086187d211,h1:mSVZ4vj4khv+oThUfS+SQU3UuFIZ5Zo6UNcvK8E8Mz8=,c79975f91dd2fd691d70e29678034eb2dc94b5da2f01b0790a919de9d2a632ac +github.com/gobuffalo/github_flavored_markdown,v1.1.0,h1:8Zzj4fTRl/OP2R7sGerzSf6g2nEJnaBEJe7UAOiEvbQ=,2d73a2baad09dc0d0f0c01549c35e83ab0c18c97f859191e54a632c2fb0eaad2 +github.com/gobuffalo/gogen,v0.2.0,h1:Xx7NCe+/y++eII2aWAFZ09/81MhDCsZwvMzIFJoQRnU=,f60900e595a3779b95b299ca9e74c517523860994a0477b360ac447d3318ccbd +github.com/gobuffalo/helpers,v0.4.0,h1:DR/iYihrVCXv1cYeIGSK3EZz2CljO+DqDLQPWZAod9c=,17ae2b069c0ca73b11b4ace6793617e0620f8d8ef171b0010b91e243c4a3bbe3 +github.com/gobuffalo/here,v0.2.3,h1:1xamq7i4CKjGgICCXY0qpxPeXGdB8oVNSevkpqwd5X4=,3808d0fbc11c58cfb0e7b430b9fc30024ba3781febe8e2601a8e2b8f76e48c00 +github.com/gobuffalo/httptest,v1.4.0,h1:DaoTl/2iFRTk9Uau6b0Lh644tcbRtBNMHcWg6WhieS8=,9d1b48f3e525ab4661d02b3fac86f89fe27f648b1ff8e607f39a353c60c0f315 +github.com/gobuffalo/licenser,v1.4.0,h1:S8WY0nLT9zkBTjFYcbJ0E9MEK7SgE86aMfjsnuThQjY=,3e126adeb06dcaee29376804b463ed33af2b821579162039e8a16e45d0334cdc +github.com/gobuffalo/logger,v1.0.1,h1:ZEgyRGgAm4ZAhAO45YXMs5Fp+bzGLESFewzAVBMKuTg=,43510255e52f7472ec17a76847ca42cebab6efe0b573a5dcfd8261e00d86d3b7 +github.com/gobuffalo/makr,v1.2.0,h1:TA6ThoZEcq0F9FCrc/7xS1ycdCIL0K6Ux+5wmwYV7BY=,113259ce8e945acf3dd184534ab6135240fde6b57d5c6ee3787e7c124e313502 +github.com/gobuffalo/mapi,v1.1.0,h1:VEhxtd2aoPXFqVmliLXGSmqPh541OprxYYZFwgNcjn4=,162640cc01d04543030d55ed51841d673cb8257fd78b069a79010e52ec996b73 +github.com/gobuffalo/meta,v0.2.0,h1:QSDlR2nbGewl0OVL9kqtU8SeKq6zSonrKWB6G3EgADs=,6a44e2a02126c65d2e2f09de5f732327001ac05d542abcabb8dc286422469e9a +github.com/gobuffalo/mw-basicauth,v1.0.7,h1:9zTxCpu0ozzwpwvw5MO31w8nEoySNRNfZwM1YAWfGZs=,da5e2767a9d91e14efb25209c9b9dcf5ad07b551d6d54670c43c6225c8e94084 +github.com/gobuffalo/mw-contenttype,v0.0.0-20190129203934-2554e742333b,h1:6LKJWRvshByPo/dvV4B1E2wvsqXp1uoynVndvuuOZZc=,f9e2f7cce4e88ff8d6f86bc61076179b4f23a85eb5fd0a5f28793ef1e7889fab +github.com/gobuffalo/mw-csrf,v0.0.0-20190129204204-25460a055517,h1:pOOXwl1xPLLP8oZw3e3t2wwrc/KSzmlRBcaQwGpG9oo=,b47a0879eadba5c6774ad37c66afea4998767d9df1295b7b17f3469282cc92f2 +github.com/gobuffalo/mw-forcessl,v0.0.0-20180802152810-73921ae7a130,h1:v94+IGhlBro0Lz1gOR3lrdAVSZ0mJF2NxsdppKd7FnI=,533187beeb18b977c8436d0a5596c1bd420b30cce55589cb11af592df063470c +github.com/gobuffalo/mw-i18n,v0.0.0-20190129204410-552713a3ebb4,h1:c1fFPCxA7SozZPqMhpfZoOVa3wUpCl11gyCEZ4nYqUE=,96a1754eff9c9a75c6b48fc3bc9ab102bbf5d23c103b37a82cc88c666c0dbf9b +github.com/gobuffalo/mw-paramlogger,v0.0.0-20190129202837-395da1998525,h1:2QoD5giw2UrYJu65UKDEo9HFcz9yun387twL2zzn+/Q=,d2e3b1baa234032585cc0e7dc1950681dbc05d960ee958578e470df9fa3b8f18 +github.com/gobuffalo/mw-tokenauth,v0.0.0-20190129201951-95847f29c5c8,h1:dqwRMSzfhe3rL0vMDaRvc2ozLqxapWFBEDH6/f0nQT0=,eb6f82200a81da34baa366475479069f08ed797d5edd4976c9f2af1027d37f1c +github.com/gobuffalo/nulls,v0.1.0,h1:pR3SDzXyFcQrzyPreZj+OzNHSxI4DphSOFaQuidxrfw=,a77a09fd75234e7e5589640fae5d261c03ede9ab5ec626406f24c89dfeba2b38 +github.com/gobuffalo/packd,v0.3.0,h1:eMwymTkA1uXsqxS0Tpoop3Lc0u3kTfiMBE6nKtQU4g4=,c7a9263fd464b9f5629bf161521f420b2c40f7780ed6a9ce88184dc4136787a5 +github.com/gobuffalo/packr,v1.30.1,h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg=,20aeea726f6db2ffc8b6dd90b1dce8991f0fd66152a270efdd21c0905b12d5f5 +github.com/gobuffalo/packr/v2,v2.7.1,h1:n3CIW5T17T8v4GGK5sWXLVWJhCz7b5aNLSxW6gYim4o=,60cd83772938a617b37c26a4924ee1f95008d53481724f801eee647e68ce22b1 +github.com/gobuffalo/plush,v3.8.3+incompatible,h1:kzvUTnFPhwyfPEsx7U7LI05/IIslZVGnAlMA1heWub8=,312e219c9827bb7d2dfc954f03fcaa275a3d9eb70687a62ecebad84ede4c51a7 +github.com/gobuffalo/plushgen,v0.1.2,h1:s4yAgNdfNMyMQ7o+Is4f1VlH2L1tKosT+m7BF28C8H4=,0efa90fac0c464409201fa74cace63c4307ac3700a23b3df7c9a9c1c976f0875 +github.com/gobuffalo/pop,v4.12.2+incompatible,h1:WFHMzzHbVLulZnEium1VlYRnWkzHz39FzVLov6rZdDI=,de2837b63e54b15d99234202839e0394183c4ff7c45b9d99162a407c95574003 +github.com/gobuffalo/release,v1.14.0,h1:+Jy7eLN5md6Fg+AMuFRUiK4sTNq4+zXxRho7/wJe1HU=,a0f34f0d3f02ea43434436936766f185b97204a073a605e720190c433c30aaa5 +github.com/gobuffalo/shoulders,v1.2.0,h1:XcPmWbzN7944VXS/I//R7o2eupUHEp3mLFWbUlk1Sco=,4c129ae195bd14520a38c608ba3a27aca674745c1f79fbcce03dacf829802ac6 +github.com/gobuffalo/syncx,v0.0.0-20190224160051-33c29581e754,h1:tpom+2CJmpzAWj5/VEHync2rJGi+epHNIeRSWjzGA+4=,ad9a571b43d72ecce24b8bed85636091710f22d8b06051e1e19ef2051f3e00da +github.com/gobuffalo/tags,v2.1.6+incompatible,h1:xaWOM48Xz8lBh+C8l5R7vSmLAZJK4KeWcLo+0pJ516g=,99bd74d4144bcdfba45fa501cd8d6dec78dc5b0404bbbfebf5bced5b976bb911 +github.com/gobuffalo/uuid,v2.0.5+incompatible,h1:c5uWRuEnYggYCrT9AJm0U2v1QTG7OVDAvxhj8tIV5Gc=,6ab82616cbb02ddd78b9b7db14f580e2e212ceeadcfccff387a973b04be8db37 +github.com/gobuffalo/validate,v2.0.3+incompatible,h1:6f4JCEz11Zi6iIlexMv7Jz10RBPvgI795AOaubtCwTE=,53d876ba454e5e0604ab8078bfb1fca54dcd3ddd859c850cafce757c5f40153d +github.com/gobuffalo/x,v0.0.0-20190224155809-6bb134105960,h1:DoUD23uwnzKJ3t5HH2SeTIszWmc13AV9TAdMhtXQts8=,2435ac54f3ea5c024aea1d4db42a87011bb877f18f0f273f7b3e19b7093c3cfd +github.com/gobwas/glob,v0.2.3,h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=,0cfe486cd63d45ed4cb5863ff1cbd14b15e4b9380dcbf80ff26991b4049f4fdf +github.com/gobwas/httphead,v0.0.0-20180130184737-2c6c146eadee,h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=,5a43ed4a7cd2b063b634f0df5311c0dfa6576683bfc1339f2c5b1b1127fc392b +github.com/gobwas/pool,v0.2.0,h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=,52604b1456b92bb310461167a3e6515562f0f4214f01ed6440e3105f78be188f +github.com/gobwas/ws,v1.0.2,h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=,f9e5c26e83278f19958c68be7b76ad6711c806b6dae766fad7692d2af867bedd +github.com/gocolly/colly,v1.2.0,h1:qRz9YAn8FIH0qzgNUw+HT9UN7wm1oF9OBAilwEWpyrI=,82f210242c4efda461bb6d2cd0543bbadf322c23b840043f236dc1fd74af9325 +github.com/gocql/gocql,v0.0.0-20191018090344-07ace3bab0f8,h1:ZyxBBeTImqFLu9mLtQUnXrO8K/SryXE/xjG/ygl0DxQ=,d38e5bd51d411bc942f295950d87d80e607a8eb186d51b445cc6c2b985681b18 +github.com/godbus/dbus,v4.1.0+incompatible,h1:WqqLRTsQic3apZUK9qC5sGNfXthmPXzUZ7nQPrNITa4=,107ef979cca9f2720633f118263afeb9acb0bf0703cc1e860098d5ec48efccb8 +github.com/gofrs/flock,v0.7.1,h1:DP+LD/t0njgoPBvT5MJLeliUIVQR03hiKR6vezdwHlc=,ee433032ec18df1e38d2385d7f9448820c5a017d895cb930cd8801401940137c +github.com/gofrs/uuid,v3.2.0+incompatible,h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=,4139fd148a7a9389629659253722b302791146583e0db94e351a325ecd06abbf +github.com/gogf/gf,v1.9.10,h1:lPBf0EOxv6AXVWN46EKLID0GMHDGOrs4ZAi/RUJbt+c=,83a8cf0cc2557c1e1b3cdb2112953ca303a09cb6d457d2102b3921db1bfd6fe5 +github.com/gogits/chardet,v0.0.0-20150115103509-2404f7772561,h1:deE7ritpK04PgtpyVOS2TYcQEld9qLCD5b5EbVNOuLA=,4b5c6d4b26d381d37b9a5538b9f2dc29d11f422653b19a2047e439a268c3f5ba +github.com/gogits/cron,v0.0.0-20160810035002-7f3990acf183,h1:EBTlva3AOSb80G3JSwY6ZMdILEZJ1JKuewrbqrNjWuE=,746b3b98243fc5ae7127c5102f9ba4f0b88238d081e9cb113d61be2ec16a6241 +github.com/gogo/googleapis,v1.3.0,h1:M695OaDJ5ipWvDPcoAg/YL9c3uORAegkEfBqTQF/fTQ=,ee9e1dda02a5a415c41b5bdff7f6835e929ea89ff3dc1c766510ee909e03c6c3 +github.com/gogo/protobuf,v1.3.1,h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=,4b63e18981e30565f60b7305e3de71ff9aa42cfccf15b88b3813dd2ba6c27be1 +github.com/gogs/chardet,v0.0.0-20150115103509-2404f7772561,h1:aBzukfDxQlCTVS0NBUjI5YA3iVeaZ9Tb5PxNrrIP1xs=,53b6234983c0828d620ba418be5b4e467ef8c9d634bb3d0a2bd4056e3dfa38b3 +github.com/gogs/cron,v0.0.0-20171120032916-9f6c956d3e14,h1:yXtpJr/LV6PFu4nTLgfjQdcMdzjbqqXMEnHfq0Or6p8=,913889f3018853808015c9198e6d3a25f586d88d88493c3de36530eef967664c +github.com/gogs/git-module,v0.8.2,h1:fCi0Lt8VZuFgjCXeLpkhC3irKLArK4oZ69gFvrDXx/s=,e4010dd8fdfe88a65fa8af6ecf97d7e16d4235d0eeb6a0b4b1f4e4d201c70d23 +github.com/gogs/go-gogs-client,v0.0.0-20190710002546-4c3c18947c15,h1:tgEyCCe4+o8A2K/PEi9lF0QMA6XK+Y/j/WN01LnNbbo=,cc5dcea1cca3d3d3e90a0ad548a660250b1299a61519f6dda5dcd7f2f1412daf +github.com/gogs/go-libravatar,v0.0.0-20161120025154-cd1abbd55d09,h1:UdOSIHZpkYcajRbfebBYzFDsL3SuqObH3bvKYBqgKmI=,f81991af4a649aa273bc0c3e7251f107ba0967f5d83553f5a18ed688d937eff0 +github.com/gogs/gogs,v0.11.91,h1:p8kTD9Sn6a/14u6ain6j0dPENMZ0gVEiM7phSIAL29E=,b41695c115f4e2dfc96bfbc7443fa6f91a6d2c8b32d32db4262e6977f5d55fa7 +github.com/gogs/minwinsvc,v0.0.0-20170301035411-95be6356811a,h1:8DZwxETOVWIinYxDK+i6L+rMb7eGATGaakD6ZucfHVk=,fb48a56a9f610b061af186008072fbd6e51055a12c168e1e347ecf9a05f25767 +github.com/gohugoio/hugo,v0.59.1,h1:nxaeKEY52cdpx3wZN/EcY6dEqbgeFsZaeNkDL8azeZ8=,508257b11bfc1ec77d3993a13929de63fa08e70ae26cd7c53f03857b3db9bbdf +github.com/gohugoio/testmodBuilder/mods,v0.0.0-20190520184928-c56af20f2e95,h1:sgew0XCnZwnzpWxTt3V8LLiCO7OQi3C6dycaE67wfkU=,0d6eabbeb381b08c84e7191fcecc49027ad3382997441180b2d6eea3fafc81b6 +github.com/goji/httpauth,v0.0.0-20160601135302-2da839ab0f4d,h1:lBXNCxVENCipq4D1Is42JVOP4eQjlB8TQ6H69Yx5J9Q=,8467ed1df8ffba8da7ead144b656b6281469ab4d122adf3edf496175ad870192 +github.com/goki/freetype,v0.0.0-20181231101311-fa8a33aabaff,h1:W71vTCKoxtdXgnm1ECDFkfQnpdqAO00zzGXLA5yaEX8=,80884151cd73d38904e4370afba3b870345a883a77c395194582202d805d7d74 +github.com/goki/ki,v0.9.8,h1:SzVTxJrd0ZcnkRTinZdbc41nIFmocJ7pyllEyBzNmys=,ce62e162090d566e2f9cb5b1659327a84c646dced32729e24b420cde4d5cb714 +github.com/goki/prof,v0.0.0-20180502205428-54bc71b5d09b,h1:3zU6niF8uvEaNtRBhOkmgbE/Fx7D6xuALotArTpycNc=,f46b93b6c42a97f06a2f658e49243972f4bd469b296f1010609c8d649163b73f +github.com/golang-collections/collections,v0.0.0-20130729185459-604e922904d3,h1:zN2lZNZRflqFyxVaTIU61KNKQ9C0055u9CAfpmqUvo4=,7847b09c355215616db6309597757ff6be2cf44781d800cdad1628f141dc82ee +github.com/golang-migrate/migrate/v3,v3.5.2,h1:SUWSv6PD8Lr2TGx1lmVW7W2lRoQiVny3stM4He6jczQ=,5086537ee116e958cf9647e28f843a0ac17f5de75ab642e5aef1fe2b360b0e30 +github.com/golang-sql/civil,v0.0.0-20190719163853-cb61b32ac6fe,h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=,22fcd1e01cabf6ec75c6b6c8e443de029611c9dd5cc4673818d52dac465ac688 +github.com/golang/freetype,v0.0.0-20170609003504-e2365dfdc4a0,h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=,cdcb9e6a14933dcbf167b44dcd5083fc6a2e52c4fae8fb79747c691efeb7d84e +github.com/golang/gddo,v0.0.0-20180828051604-96d2a289f41e,h1:8sV50nrSGwclVxkCGHxgWfJhY6cyXS2plGjGvUzrMIw=,9a0683005c7700bb1b7ac155597592d15d02f510a0d2c334f8564c43b9072107 +github.com/golang/glog,v0.0.0-20160126235308-23def4e6c14b,h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=,36b3c522c8102dfe74ca96e474c4c361750bf2bb85bc3cefe4f074c07d6825a9 +github.com/golang/groupcache,v0.0.0-20191027212112-611e8accdfc9,h1:uHTyIjqVhYRhLbJ8nIiOJHkEZZ+5YoOsAbD3sk82NiE=,a4815d7048e9a1dd79a72a09d4c9a946ccff837695d046c7f0f5c24037ce18b3 +github.com/golang/lint,v0.0.0-20180702182130-06c8688daad7,h1:2hRPrmiwPrp3fQX967rNJIhQPtiGXdlQWAxKbKw3VHA=,66e95adf2c1feb4de316d2c0ba9e04a22322df010a67b1054ad3d4fb2f9a1791 +github.com/golang/mock,v1.3.1,h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=,3209f2030646855a3644736b5d7ce2cd9076856cac2f50360805a19c38b7bc45 +github.com/golang/protobuf,v1.3.2,h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=,a004ba3acb85e012cb9e468e1d445a81cfeeb4b4db7e9802f30aa500a8341851 +github.com/golang/snappy,v0.0.1,h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=,0a9a73d55340a8e6d17e72684cf90618b275b6034ce83299abb55ed8fb3860bd +github.com/golangplus/bytes,v0.0.0-20160111154220-45c989fe5450,h1:7xqw01UYS+KCI25bMrPxwNYkSns2Db1ziQPpVq99FpE=,2904c49772d1bade7c81ddae2fa70e42bdce7b006c871c8106d1feb14fe2982b +github.com/golangplus/fmt,v0.0.0-20150411045040-2a5d6d7d2995,h1:f5gsjBiF9tRRVomCvrkGMMWI8W1f2OBFar2c5oakAP0=,2afd341a4d32c84532d6d44574718e1b8000aa57cfc21ced284612fc92b61217 +github.com/golangplus/testing,v0.0.0-20180327235837-af21d9c3145e,h1:KhcknUwkWHKZPbFy2P7jH5LKJ3La+0ZeknkkmrSgqb0=,fc111aa59d03741dad00f05ce869fcb44f5d75b841413e21e7301bc538a0255e +github.com/gomodule/redigo,v2.0.0+incompatible,h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=,77342da7b962489363b3661803ee2fba72b23b8e97af0241877ce6ab8a95d194 +github.com/gonum/blas,v0.0.0-20181208220705-f22b278b28ac,h1:Q0Jsdxl5jbxouNs1TQYt0gxesYMU4VXRbsTlgDloZ50=,bfcad082317ace0d0bdc0832f0835d95aaa90f91cf3fce5d2d81ccdd70c38620 +github.com/gonum/floats,v0.0.0-20181209220543-c233463c7e82,h1:EvokxLQsaaQjcWVWSV38221VAK7qc2zhaO17bKys/18=,52afb5e33a03b027f8f451e23618c2decbe4443f996a203e332858c1a348a627 +github.com/gonum/graph,v0.0.0-20190426092945-678096d81a4b,h1:LilU5ERRFWL+2D6yR1PL2oeS4n+xyTq1vfv39LFVaeE=,411fd86d898ad7ea8c1145610a27f0f13153c86b3ef5e78cb80431125082b5a6 +github.com/gonum/internal,v0.0.0-20181124074243-f884aa714029,h1:8jtTdc+Nfj9AR+0soOeia9UZSvYBvETVHZrugUowJ7M=,e7f40a97eee3574c826a1e75f80ecd94c27853feaab5c43fde7dd95ba516c9dc +github.com/gonum/lapack,v0.0.0-20181123203213-e4cdc5a0bff9,h1:7qnwS9+oeSiOIsiUMajT+0R7HR6hw5NegnKPmn/94oI=,f38b72e072728121b9acf5ae26d947aacc0024dddc09d19e382bacd8669f5997 +github.com/gonum/matrix,v0.0.0-20181209220409-c518dec07be9,h1:V2IgdyerlBa/MxaEFRbV5juy/C3MGdj4ePi+g6ePIp4=,9cea355e35e3f5718b2c69f65712b2c08a1bec13b3cfadf168d98b41b043dd63 +github.com/google/btree,v1.0.0,h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=,8dbcb36f92c7a6dc5f6aef5c26358d98b72caee69829b5b33dddabada2047785 +github.com/google/cadvisor,v0.34.0,h1:No7G6U/TasplR9uNqyc5Jj0Bet5VSYsK5xLygOf4pUw=,5a3807f43a14e6a03b7ceb9ea11f8ac241a42286be90c3b2cba49ee811111848 +github.com/google/certificate-transparency-go,v1.0.21,h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE=,7ddb21b272632236d5fb35b35c837f39d38390ea8dcb97c9f0f5d5aa561c3366 +github.com/google/flatbuffers,v1.11.0,h1:O7CEyB8Cb3/DmtxODGtLHcEvpr81Jm5qLg/hsHnxA2A=,ff61e5077ecc7d46a2020c1b42e0a6405b50271f396d4dcc50c683345059af76 +github.com/google/go-cmp,v0.3.2-0.20191028172631-481baca67f93,h1:VvBteXw2zOXEgm0o3PgONTWf+bhUGsCaiNn3pbkU9LA=,6682f890f076aaa03f2c2afb6bc7304c9d602b9e23ff212f8a9a64f44f432dbc +github.com/google/go-containerregistry,v0.0.0-20191029173801-50b26ee28691,h1:9fkqC5Bq8l2FQgcW6FQbPDUeZvExyg7okl+s4Gg9Jrs=,7bef2c87f7ca8a39e04c770b38160dd5cfdd508546f96fab427225d12d40d85a +github.com/google/go-github,v17.0.0+incompatible,h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=,9831222a466bec73a21627e0c3525da9cadd969468e31d10ecae8580b0568d0e +github.com/google/go-github/v21,v21.0.0,h1:tn4/tmCgPAsezJFwZcMnE7U0R9/AtKRBGX4s4LFdDzI=,0b25aebca5386cdb52515402b81a8e0a676ac30f9843feb0a47a1944b7c8b527 +github.com/google/go-github/v24,v24.0.1,h1:KCt1LjMJEey1qvPXxa9SjaWxwTsCWSq6p2Ju57UR4Q4=,4dd0a57a527a1cc52e6619e9d2e1936534439426f0eb065bfbe1e7c03b60d465 +github.com/google/go-github/v28,v28.1.1,h1:kORf5ekX5qwXO2mGzXXOjMe/g6ap8ahVe0sBEulhSxo=,621cca7f4889897317c18ed021fe0f55c279769f11357d90eb21a29c5ea78d04 +github.com/google/go-querystring,v1.0.0,h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=,1c0a0b81b921ee270e47e05cf0bf8df4475de850671e553c07740849068d4f9f +github.com/google/go-replayers/grpcreplay,v0.1.0,h1:eNb1y9rZFmY4ax45uEEECSa8fsxGRU+8Bil52ASAwic=,794ad7fb2669ea1d1305cf7717a1329146635637739bf2e26d858a318e87f99b +github.com/google/go-replayers/httpreplay,v0.1.0,h1:AX7FUb4BjrrzNvblr/OlgwrmFiep6soj5K2QSDW7BGk=,cf6d3e2262e94db5bad86d944f2f97507b1ffc2943e4385f140eb6f9a01f8e7b +github.com/google/go-tpm,v0.2.0,h1:3Z5ZjNRQ0CsUj3yWXtbbx4Vfb/sQapdSeZJvuaKuQzc=,7e90cb155fa3e7759caa1fe5df1ca43520a7f8e1a31e540573cc8290ff523a23 +github.com/google/go-tpm-tools,v0.0.0-20190906225433-1614c142f845,h1:2WNNKKRI+a5OZi5xiJVfDoOiUyfK/BU1D4w+N6967F4=,2e41ca1e24a1ba5eedf980331527d6a5ad09b8ef653bbd040321572899eff8a2 +github.com/google/gofuzz,v1.0.0,h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=,752570262575bbcb5f0107dbd80a463abacaf51e94e15f96f5bc4166ff2d33e1 +github.com/google/gopacket,v1.1.17,h1:rMrlX2ZY2UbvT+sdz3+6J+pp2z+msCq9MxTU6ymxbBY=,008645038244e12a1bfbda2317372ec34a514250741139b8e4842de7f98639d4 +github.com/google/gxui,v0.0.0-20151028112939-f85e0a97b3a4,h1:OL2d27ueTKnlQJoqLW2fc9pWYulFnJYLWzomGV7HqZo=,be209ad45b16077b010faef4a7bcbf0723dfbe47869a6f4c0aacd534e7fcbfb1 +github.com/google/martian,v2.1.1-0.20190517191504-25dcb96d9e51+incompatible,h1:xmapqc1AyLoB+ddYT6r04bD9lIjlOqGaREovi0SzFaE=,dfc5eac3877863c1f231457f96c54c915ea1c86f86c590710b7477f96e1ba0f3 +github.com/google/netstack,v0.0.0-20191031000057-4787376a6744,h1:wKeh74w+ydKcE1Eo44WDzIOcPHWmxxmtAzkAL0Mlspc=,dd74d0c9fadfb29db3bd09da657cb95300255d562ce596e88c865a71ee5d2519 +github.com/google/pprof,v0.0.0-20191028172815-5e965273ee43,h1:59gkLC5pLENSgzw9Gx73BQQho5i//80XwgIIYWxZjp4=,667012da0f67eb7822d16f532e850091a58c1efebeef5047df9a02e972112484 +github.com/google/readahead,v0.0.0-20161222183148-eaceba169032,h1:6Be3nkuJFyRfCgr6qTIzmRp8y9QwDIbqy/nYr9WDPos=,3a2435123538463dc3412a2eb1be033b7cf8105775c1ff3524351ec405fa1469 +github.com/google/renameio,v0.1.0,h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=,b8510bb34078691a20b8e4902d371afe0eb171b2daf953f67cb3960d1926ccf3 +github.com/google/rpmpack,v0.0.0-20191101142923-13d81472ccfe,h1:P1WflKHEgTAYe39btxYzeds84DhxQSLj4hfoNn0tCyQ=,5144bdeda051f10f407f1f798502ec0d7599f9c4a7e0a79c3711fe2b79f5cae4 +github.com/google/shlex,v0.0.0-20181106134648-c34317bd91bf,h1:7+FW5aGwISbqUtkfmIpZJGRgNFg2ioYPvFaUxdqpDsg=,250fc48c105475c54cc8c9fe5c110e31986590433de2608740d6592d0dc0a4c6 +github.com/google/subcommands,v1.0.1,h1:/eqq+otEXm5vhfBrbREPCSVQbvofip6kIz+mX5TUH7k=,de4249d9823a0509df32ebad2787d5e54c9b53c1059592bd9a3bb0c4cf58034d +github.com/google/uuid,v1.1.1,h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=,2b0cbc45fb0e21c8bfebbae9b04babc196d9f06d9f3b9dec5e2adc8cfd0c1b81 +github.com/google/wire,v0.3.0,h1:imGQZGEVEHpje5056+K+cgdO72p0LQv2xIIFXNGUf60=,38eb402dbe84aee2f891df0e62623f9ff5615dfeb1e4f631eaac5cf1859c9ea6 +github.com/googleapis/gax-go,v2.0.2+incompatible,h1:silFMLAnr330+NRuag/VjIGF7TLp/LBrV2CJKFLWEww=,36fe8c993c8f90067bffbba78f1325ff45ae60c8a85b778d798c56067e55c19e +github.com/googleapis/gax-go/v2,v2.0.5,h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=,846b017e21fc01f408774051d4a10bfccd7c294e10a1ad5d725278889d5f1d42 +github.com/googleapis/gnostic,v0.3.1,h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk=,33277bd9aab84cf04d058a5e2e1dbb5f3c023ba30c6127b4cc8a6662a776de53 +github.com/gopackage/ddp,v0.0.0-20170117053602-652027933df4,h1:4EZlYQIiyecYJlUbVkFXCXHz1QPhVXcHnQKAzBTPfQo=,76b2493aae8a5513b707e4f6c529f57175cca6c834dd19072a51ed3974cd77bc +github.com/gophercloud/gophercloud,v0.6.0,h1:Xb2lcqZtml1XjgYZxbeayEemq7ASbeTp09m36gQFpEU=,f5be75a3b128c9de7385dd7e2a8ec9fba18fb46dcf57624d88249ae99e188ed2 +github.com/gophercloud/utils,v0.0.0-20190128072930-fbb6ab446f01,h1:OgCNGSnEalfkRpn//WGJHhpo7fkP+LhTpvEITZ7CkK4=,c98b6d529b47679302d175f04d7b635824c292edc8a5ede807f9ba8145517ce7 +github.com/gopherjs/gopherjs,v0.0.0-20190915194858-d3ddacdb130f,h1:TyqzGm2z1h3AGhjOoRYyeLcW4WlW81MDQkWa+rx/000=,ff395ad20350783713974a6b4d03254b811d83c0c0caa13bcb329462a7263f70 +github.com/gopherjs/jquery,v0.0.0-20180404123100-3ba2b901425e,h1:Tf0PnEo36tq56/JezxbbiFpEce0pmK6tY7hS6PNS7tI=,26fb481ef7f7010ec901990527d7ef7b06bc18c38cb617db77f8b61263b5b453 +github.com/gopherjs/jsbuiltin,v0.0.0-20180426082241-50091555e127,h1:atBEgNR1C5+LFkl8ipQtLee9RStheS8YeCSkiYqBhOg=,603151a77e4be25c8389014b06449520c2ad5856f0161590a5de5f01bee28912 +github.com/goreleaser/goreleaser,v0.120.5,h1:N3VirNAK9u30Wj7xulfE9/cCvptO0vl+CLhaMEVGbGs=,9c516d6e8db8c6800102ca68e3f674a62dd42877d7785607f56c22f6dc9b5a9e +github.com/goreleaser/nfpm,v1.1.2,h1:9+hnNm/h/ANQWLxZixNO562w4tIO/8VlgCwOKwwZTX4=,9781a05527458d352a744a524c94473d2a72694fd54bc559a5888158bb4fa1fb +github.com/gorhill/cronexpr,v0.0.0-20180427100037-88b0669f7d75,h1:f0n1xnMSmBLzVfsMMvriDyA75NB/oBgILX2GcHXIQzY=,742d8957d3f9fe773150fb3164868a755b2af5b705b38c72c45ca5386715c617 +github.com/gorilla/context,v1.1.1,h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=,4ec8e01fe741a931edeebdee9348ffb49b5cc565ca245551d0d20b67062e6f0b +github.com/gorilla/csrf,v1.6.0,h1:60oN1cFdncCE8tjwQ3QEkFND5k37lQPcRjnlvm7CIJ0=,6fa6b9d34ba1c2409e6575db396f57607c5283e397d38a271b6930c666f166b0 +github.com/gorilla/handlers,v1.4.2,h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg=,9e47491112a46d32e372be827899e8678a881f6407f290564c63e8725b5e9a19 +github.com/gorilla/mux,v1.7.3,h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=,9ffc6c6c1194cb2b9f39237ff90b20eb4a55273404c97364ed9a6500e9571fe3 +github.com/gorilla/pat,v1.0.1,h1:OeSoj6sffw4/majibAY2BAUsXjNP7fEE+w30KickaL4=,e0dedacf6f405854b94932a59b410bbda64d4fff8111b674db987ce242bc9d57 +github.com/gorilla/rpc,v1.1.0,h1:marKfvVP0Gpd/jHlVBKCQ8RAoUPdX7K1Nuh6l1BNh7A=,0e83ae0cbc4164cdaf0b808413f97fed7a90e2096095c14f5495b6dbfaa34266 +github.com/gorilla/schema,v1.1.0,h1:CamqUDOFUBqzrvxuz2vEwo8+SUdwsluFh7IlzJh30LY=,42a6d7dc873e8ba1822551b4e15304d5654a11f6da3cccdc270be847148bbfaf +github.com/gorilla/securecookie,v1.1.1,h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=,dd83a4230e11568159756bbea4d343c88df0cd1415bbbc7cd5badad6cd2ed903 +github.com/gorilla/sessions,v1.2.0,h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ=,8753d00ae6cf8ea0e28c195d4b87875384e2ed79df7eba4cf210fdf9ab0294df +github.com/gorilla/websocket,v1.4.1,h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=,86eb427567de9e2dc84da52ee4f4315496c5ffc2152928df0e3ac4ce8a359ff7 +github.com/gosimple/slug,v1.9.0,h1:r5vDcYrFz9BmfIAMC829un9hq7hKM4cHUrsv36LbEqs=,0f72d897e3decea434cdc68c7d0226afbda7d6b1908e955bf406333e7d6bb4a7 +github.com/gosuri/uitable,v0.0.3,h1:9ZY4qCODg6JL1Ui4dL9LqCF4ghWnAOSV2h7xG98SkHE=,1316f88b6b2689d941a4727889818705a289c72d7f1f4d2d9cf5cd06fecd0b7b +github.com/gotestyourself/gotestyourself,v2.2.0+incompatible,h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI=,653f8ec3ed62f8d235ab67cfc56e7c814d4ac6f56f24000802b32728523c074c +github.com/gotnospirit/makeplural,v0.0.0-20180622080156-a5f48d94d976,h1:b70jEaX2iaJSPZULSUxKtm73LBfsCrMsIlYCUgNGSIs=,5750c916115b851f4881b76d90128802d090558958aa821c691d4fa378018093 +github.com/gotnospirit/messageformat,v0.0.0-20180622080451-0eab1176a3fb,h1:akgcoKcMcMOlzb6fdycEck1Vc3+y7ubUjO6hgAOyqC8=,7189231c806aa1988b50a82019c5f972a5f1b82e61c94776999728ec1894cd29 +github.com/graarh/golang-socketio,v0.0.0-20170510162725-2c44953b9b5f,h1:utzdm9zUvVWGRtIpkdE4+36n+Gv60kNb7mFvgGxLElY=,f41faefdf625d1c04113636d467a9fa47fe083148d7393fa65c0f08e3a4078c3 +github.com/grafana/globalconf,v0.0.0-20181214112547-7a1aae0695d9,h1:2/Bz5A5zR4TMGd9yvgGMal7nhQwHBt5/dfp0sbJFfes=,0393f4fa690096ea26c76373e99f9d9f3bfc9b34e5acd08d639b68f68af7b5e2 +github.com/grandcat/zeroconf,v0.0.0-20190424104450-85eadb44205c,h1:svzQzfVE9t7Y1CGULS5PsMWs4/H4Au/ZTJzU/0CKgqc=,2d364bea1939e3ec55b732cae452feb3182fc1d8ffa30f35aa42c0181709d138 +github.com/graph-gophers/graphql-go,v0.0.0-20190225005345-3e8838d4614c,h1:YyFUsspLqAt3noyPCLz7EFK/o1LpC1j/6MjU0bSVOQ4=,fad60e1061e15848aff79c6620f1cf55a9dd87d58ca2f57fea50c35322c817ac +github.com/graphql-go/graphql,v0.7.9-0.20190403165646-199d20bbfed7,h1:E45QFM7IqRdFnuyFk8GSamb42EckUSyJ55rtVB/w8VQ=,6e9d51c4dc431d2d7c1348fa2b3358ed8e57338a07750177698bde29c913e786 +github.com/gravitational/trace,v0.0.0-20190726142706-a535a178675f,h1:68WxnfBzJRYktZ30fmIjGQ74RsXYLoeH2/NITPktTMY=,6fb8317692ac3aa8280cd4b4749970ec6652ecbe2c629cd43b52005f9a992197 +github.com/graymeta/stow,v0.2.4,h1:qDGstknYXqcnmBQ5TRJtxD9Qv1MuRbYRhLoSMeUDs7U=,67b4e728448b89c2233da14c22f18fe6c720e88a858dff2cd3c7405c7ea10493 +github.com/gregjones/httpcache,v0.0.0-20190611155906-901d90724c79,h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=,73d773791d582cad0d90942e7d92f52d82f13119dd78e849bbd77fae2acc0276 +github.com/grokify/html-strip-tags-go,v0.0.0-20190921062105-daaa06bf1aaf,h1:wIOAyJMMen0ELGiFzlmqxdcV1yGbkyHBAB6PolcNbLA=,0bb5eaff16e4119a9251bb0a26b4190a8e36cbacce8daee8c77df76022e1087c +github.com/grpc-ecosystem/go-grpc-middleware,v1.1.0,h1:THDBEeQ9xZ8JEaCLyLQqXMMdRqNr0QAUJTIkQAUtFjg=,def2c3ec1d07264489b79fa0e8e7a5c23545f16ba3c6e613f5cdba2ae8fe2768 +github.com/grpc-ecosystem/go-grpc-prometheus,v1.2.1-0.20191002090509-6af20e3a5340,h1:uGoIog/wiQHI9GAxXO5TJbT0wWKH3O9HhOJW1F9c3fY=,bca256c9eee3d43fe310c205866c69de454e71346f18ea2b05a32bd2f6018c84 +github.com/grpc-ecosystem/grpc-gateway,v1.11.3,h1:h8+NsYENhxNTuq+dobk3+ODoJtwY4Fu0WQXsxJfL8aM=,d96a88c820576b8b6989944cbe15f4f2d94d2884f29f2f683b975a03a5bdc5fc +github.com/grpc-ecosystem/grpc-opentracing,v0.0.0-20180507213350-8e809c8a8645,h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU=,0606bde24e978e9cd91ae45ca9e5222ce695c21a07ae02e77546496bf23b1c62 +github.com/gucumber/gucumber,v0.0.0-20180127021336-7d5c79e832a2,h1:iR8wSrr/JCzL1Ul+dRVxtIOnP8DGg/m02nHZJ9PH6P0=,4feb5116e650552868f056ee74d179e91239bf166d365267f32e903ccc495dbb +github.com/guptarohit/asciigraph,v0.4.1,h1:YHmCMN8VH81BIUIgTg2Fs3B52QDxNZw2RQ6j5pGoSxo=,976279cdbc5425609c272b2116a92fb5871a40164ae64c51dedffea7b550d2d4 +github.com/guregu/null,v2.1.3-0.20151024101046-79c5bd36b615+incompatible,h1:SZmF1M6CdAm4MmTPYYTG+x9EC8D3FOxUq9S4D37irQg=,1adcbf87f6c55963b0d020ccbac0ebd07e8aca5e0ff22469ac708c6574d7333f +github.com/gxed/go-shellwords,v1.0.3,h1:2TP32H4TAklZUdz84oj95BJhVnIrRasyx2j1cqH5K38=,c63674c66949c0442402bceca8b7768684875a667140ea0b32afdd46fc094a7f +github.com/gxed/hashland/keccakpg,v0.0.1,h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyFSs7UnsU=,c77522ff0820feb7b5be4e1c74d7c64b3aa5afe3452e1dd2f54d1ffa067c6b2d +github.com/gxed/hashland/murmur3,v0.0.1,h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc=,4576d7ae9b5d2f4ebd238de84f3b52b9d4ae4d41822ac0eabd404d346eace067 +github.com/gxed/pubsub,v0.0.0-20180201040156-26ebdf44f824,h1:TF4mX7zXpeyz/xintezebSa7ZDxAGBnqDwcoobvaz2o=,718b183cca4e30a97d3fa06457060b4d3be66742838d98a39b02ea710693d9eb +github.com/h2non/filetype,v1.0.8,h1:le8gpf+FQA0/DlDABbtisA1KiTS0Xi+YSC/E8yY3Y14=,534a477c811032fceb0c8e1ad7a15f35ff95f1d038d41164bb4d265860cc42c3 +github.com/h2non/gock,v1.0.9,h1:17gCehSo8ZOgEsFKpQgqHiR7VLyjxdAG3lkhVvO9QZU=,ab5679329b0c26b523254dd728cad1b4e6e2e7bf11569df73a1dcaa468a46cd6 +github.com/h2non/parth,v0.0.0-20190131123155-b4df798d6542,h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=,3b7b7e4bb3c2d0e22075e13443af78d03fb2ed54b3eb5bb1fa6f528c7ebe3ac0 +github.com/hailocab/go-hostpool,v0.0.0-20160125115350-e80d13ce29ed,h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=,faf2b985681cda77ab928976b620b790585e364b6aff351483227d474db85e9a +github.com/hanwen/go-fuse,v1.0.0,h1:GxS9Zrn6c35/BnfiVsZVWmsG803xwE7eVRDvcf/BEVc=,4b94d038e80959f816a18b34cdcbb5244e87b73956b220aac213483999b54c84 +github.com/hashicorp/aws-sdk-go-base,v0.4.0,h1:zH9hNUdsS+2G0zJaU85ul8D59BGnZBaKM+KMNPAHGwk=,967c057aecede32de140c88b6527149d2441216569620b9d9350522d0f309bdc +github.com/hashicorp/consul,v1.6.1,h1:ISPgwOO8/vPYrCXQNyx63eJAYjPGRnmFsXK7aj2XICs=,0ca8c5046df99a7a6607ab68b6604340af58d1696c7901088adfd9618850629f +github.com/hashicorp/consul/api,v1.2.0,h1:oPsuzLp2uk7I7rojPKuncWbZ+m5TMoD4Ivs+2Rkeh4Y=,2833a78c39a4fa869a928e1218f3aa83130e4f5c03b4d4e355fb76b91fa75946 +github.com/hashicorp/consul/sdk,v0.2.0,h1:GWFYFmry/k4b1hEoy7kSkmU8e30GAyI4VZHk0fRxeL4=,3f0b677061f7e79191cc0d2f8184895c20051166959566a2e48e511b1fab222c +github.com/hashicorp/errwrap,v1.0.0,h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=,ccdf4c90f894d8a5fde4e79d5828c5d27a13e9f7ce3006dd72ce76e6e17cdeb2 +github.com/hashicorp/go-azure-helpers,v0.0.0-20190129193224-166dfd221bb2,h1:VBRx+yPYUZaobnn5ANBcOUf4hhWpTHSQgftG4TcDkhI=,dd17ed56e4b541cffa69679557074071372ab70682f695d8b61126c9393f92dc +github.com/hashicorp/go-bexpr,v0.1.2,h1:ijMXI4qERbzxbCnkxmfUtwMyjrrk3y+Vt0MxojNCbBs=,ac79086a2900ebf2f5414fe54b5799f24b3ddf953a28299f46831a11b10b1df0 +github.com/hashicorp/go-checkpoint,v0.5.0,h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU=,1baf63010271d6c8abc0f4edc9e9d41483cb55218e4e399ca4c70ef225415f36 +github.com/hashicorp/go-cleanhttp,v0.5.1,h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=,e3cc9964b0bc80c6156d6fb064abcb62ff8c00df8be8009b6f6d3aefc2776a23 +github.com/hashicorp/go-discover,v0.0.0-20190403160810-22221edb15cd,h1:SynRxs8h2h7lLSA5py5a3WWkYpImhREtju0CuRd97wc=,c58ed5375890c98a836234f5166cf88b73ad7595899edaa43c775d650043b4b3 +github.com/hashicorp/go-gcp-common,v0.5.0,h1:kkIQTjNTopn4eXQ1+lCiHYZXUtgIZvbc6YtAQkMnTos=,a1fee55619b3579e5fe89b6f944dce87e190b8ea1526f24622ba5941d664b639 +github.com/hashicorp/go-getter,v1.4.0,h1:ENHNi8494porjD0ZhIrjlAHnveSFhY7hvOJrV/fsKkw=,cbae7b8a5f018c78bb304c47840c390b3c3be98b712b90b33d16304f1b427eb1 +github.com/hashicorp/go-hclog,v0.9.2,h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=,e1a873d9fa828038b5b2c93e0f49f9e8187b4f5255d0a3d7989d3ac178807af4 +github.com/hashicorp/go-immutable-radix,v1.1.0,h1:vN9wG1D6KG6YHRTWr8512cxGOVgTMEfgEdSj/hr8MPc=,c23ca92f0fb7dce35b86d35ccf9cfa871db97379d2ca8a0fcc15fde32ff369bb +github.com/hashicorp/go-memdb,v1.0.4,h1:sIdJHAEtV3//iXcUb4LumSQeorYos5V0ptvqvQvFgDA=,c3eedd68e60f3db16499dff27fe4d4e874978c250bab152044965a475cb47c72 +github.com/hashicorp/go-msgpack,v0.5.5,h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI=,fb47605669b0ddd75292aac788208475fecd54e0ea3e9a282d8a98ae8c60d1f5 +github.com/hashicorp/go-multierror,v1.0.0,h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=,a66a1b9dff26a9a7fcaa5aa5e658c13f94c0daeb572536b1ecc7ebe51f4d0be7 +github.com/hashicorp/go-oracle-terraform,v0.0.0-20181016190316-007121241b79,h1:RKu7yAXZTaQsxj1K9GDsh+QVw0+Wu1SWHxtbFN0n+hE=,5b3ab30e1aef56e38d750a5dc344f1ab996859408a6b76a9f48f5f75747fd712 +github.com/hashicorp/go-plugin,v1.0.1,h1:4OtAfUGbnKC6yS48p0CtMX2oFYtzFZVv6rok3cRWgnE=,0853effcccdb7bfac1c122f72cd3a1241b4e0934609541c409e9f59b441ae01e +github.com/hashicorp/go-raftchunking,v0.6.2,h1:imj6CVkwXj6VzgXZQvzS+fSrkbFCzlJ2t00F3PacnuU=,f5c55a3679c8a8f63d798d2b67552bfcd198dc5b9473d81c3ce1b353a055bc5c +github.com/hashicorp/go-retryablehttp,v0.6.3,h1:tuulM+WnToeqa05z83YLmKabZxrySOmJAd4mJ+s2Nfg=,69cb67f4821e97ca8f04b0cb710c61a5acfaa948dda59b949b40fd6fae8e7dec +github.com/hashicorp/go-rootcerts,v1.0.1,h1:DMo4fmknnz0E0evoNYnV48RjWndOsmd6OW+09R3cEP8=,3f558b1a436ed6fb15872383545109227f9552bf5daa95583e9402bbd3a24fff +github.com/hashicorp/go-safetemp,v1.0.0,h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo=,6843a6b60d650ae9be836add0ab5ac1b1719a101bf12fe4ca6678fcd87baa19a +github.com/hashicorp/go-slug,v0.4.0,h1:YSz3afoEZZJVVB46NITf0+opd2cHpaYJ1XSojOyP0x8=,b6a027a2d69ae8786a6830239a79ceac487463237b49e03250a9b1e116f0a5ac +github.com/hashicorp/go-sockaddr,v1.0.2,h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=,50c1b60863b0cd31d03b26d3975f76cab55466666c067cd1823481a61f19af33 +github.com/hashicorp/go-syslog,v1.0.0,h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE=,a0ca8b61ea365e9ecdca513b94f200aef3ff68b4c95d9dabc88ca25fcb33bce6 +github.com/hashicorp/go-tfe,v0.3.25,h1:4rPk/9rSYuRoujKk5FsxSvtC/AjJCQphLS/57yr6wUM=,5ade1d16517697c7bd04b556f852264eef33906c52d32bd6702c47838c1c1c04 +github.com/hashicorp/go-uuid,v1.0.1,h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=,a05417b988b047d55fca8ad4fec6bde56c3907f679fece48f97d608e61e82a5c +github.com/hashicorp/go-version,v1.2.0,h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E=,a3231adb6bf029750970de2955e82e41e4c062b94eb73683e9111aa0c0841008 +github.com/hashicorp/go.net,v0.0.1,h1:sNCoNyDEvN1xa+X0baata4RdcpKwcMS6DH+xwfqPgjw=,71564aa3cb6e2820ee31e4d9e264e4ed889c7916f958b2f54c6f3004d4fcd8d2 +github.com/hashicorp/golang-lru,v0.5.3,h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk=,ac6e8bdc76a1275e3496f1ab2484e28ab4be2c81e2da78b8cdd1c2d269b931e4 +github.com/hashicorp/hcl,v1.0.0,h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=,54149a2e5121b3e81f961c79210e63d6798eb63de28d2599ee59ade1fa76c82b +github.com/hashicorp/hcl/v2,v2.0.0,h1:efQznTz+ydmQXq3BOnRa3AXzvCeTq1P4dKj/z5GLlY8=,6275e2af8b3247c6de72baab13b3be531431f695e001e4d36c920e412a715032 +github.com/hashicorp/hcl2,v0.0.0-20191002203319-fb75b3253c80,h1:PFfGModn55JA0oBsvFghhj0v93me+Ctr3uHC/UmFAls=,42811f77c4da1d31371c51076cbcecc99042fc7a74c6e2622b11bea96043a777 +github.com/hashicorp/hil,v0.0.0-20190212112733-ab17b08d6590,h1:2yzhWGdgQUWZUCNK+AoO35V+HTsgEmcM4J9IkArh7PI=,cb2b110c86a312b7c60094c9b11853ae288945c34fa5861b67ff2d97edaab292 +github.com/hashicorp/logutils,v1.0.0,h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y=,0e88424578d1d6b7793b63d30c180a353ce8041701d25dc7c3bcd9841c36db5b +github.com/hashicorp/mdns,v1.0.1,h1:XFSOubp8KWB+Jd2PDyaX5xUd5bhSP/+pTDZVDMzZJM8=,0f4b33961638b1273ace80b64c6fc7e54a1064484b2a1e182ab3d38a35dbc94f +github.com/hashicorp/memberlist,v0.1.5,h1:AYBsgJOW9gab/toO5tEB8lWetVgDKZycqkebJ8xxpqM=,51054573cad1655b1b349553a8d455eedc15b49f0277edd2e693bc5d0503af62 +github.com/hashicorp/net-rpc-msgpackrpc,v0.0.0-20151116020338-a14192a58a69,h1:lc3c72qGlIMDqQpQH82Y4vaglRMMFdJbziYWriR4UcE=,b0c3a5ec955b0dfb85b39a6aa1d10fe0e810dd78493c0a14ea5760bac1cadd32 +github.com/hashicorp/nomad/api,v0.0.0-20190412184103-1c38ced33adf,h1:U/40PQvWkaXCDdK9QHKf1pVDVcA+NIDVbzzonFGkgIA=,b9e994cd47eed80531b93d9f64be426cbdc6fc6e58323f6b26ae53b1fd692bbd +github.com/hashicorp/packer,v1.4.4,h1:ee+jewbEfTKV77+YtRR0m2Q8suTiXnr010bBFt5vJSA=,d2fc7c22b3528a4acb321fda24575cf2f88df8f5085b3b5da559e44d8b12295a +github.com/hashicorp/raft,v1.1.1,h1:HJr7UE1x/JrJSc9Oy6aDBHtNHUUBHjcQjTgvUVihoZs=,b6a10aa04b5f45486a6111d4a50cb65ee179b091f04a047e316b85f38ebbf873 +github.com/hashicorp/raft-boltdb,v0.0.0-20191021154308-4207f1bf0617,h1:CJDRE/2tBNFOrcoexD2nvTRbQEox3FDxl4NxIezp1b8=,e2008570aed06ba72cd783d6bc729b67b7e0cecd2219a8420dd24dcef82e64f8 +github.com/hashicorp/raft-snapshot,v1.0.1,h1:cx002JsTEAfAP0pIuANlDtTXg/pi2Db6YbRRmLQTQKw=,3d40d03f6793fe87464359f28b136b920daf7aa8544a98270470d04cef132a77 +github.com/hashicorp/serf,v0.8.5,h1:ZynDUIQiA8usmRgPdGPHFdPnb1wgGI9tK3mO9hcAJjc=,88623d0f1a155bb2fe254210f68f1603b42162f031fbf51256f1465b36bc7769 +github.com/hashicorp/terraform,v0.12.13,h1:LACXUTZvAGf8W/6wehHjOgi6YEMN7ejDUpnpll2qbJ0=,4dbe6d0c15f4d934fd583fc20bec55326ffc79cf0d5b7fd28978ba14d178fe8d +github.com/hashicorp/terraform-config-inspect,v0.0.0-20190821133035-82a99dc22ef4,h1:fTkL0YwjohGyN7AqsDhz6bwcGBpT+xBqi3Qhpw58Juw=,1261dc9b65805f9be029f6a42d9e0ddccc89c4d0c50e5fa2895b1b53198195c3 +github.com/hashicorp/terraform-svchost,v0.0.0-20191011084731-65d371908596,h1:hjyO2JsNZUKT1ym+FAdlBEkGPevazYsmVgIMw7dVELg=,8055e9f82b0484eb70594ca682bcf4401d2286c2021ffc72c6c3b6ad9ac9a024 +github.com/hashicorp/vault,v1.2.0-rc1,h1:GFYP6ck5f0EaJsGMD4PARIX5HaHREUxMbTaVPy+dFEg=,89c84474c97b1400ca858fe1b6e0eb3bd91dac17a4aff4336bd95104381e8b2b +github.com/hashicorp/vault-plugin-auth-alicloud,v0.5.2-0.20190725165955-db428c1b0976,h1:f+r1gXVvQJ0+2pfxgBDP1zZUC6lUmPNM0xp7AKupyBg=,3bc95606713215c3ae25f9be06ed2186f8f2e5e9ad8e025fafd332d97045ed09 +github.com/hashicorp/vault-plugin-auth-azure,v0.5.2-0.20190725170003-0fc4bd518aa2,h1:Ua6AFhJYkdNGC5s4uDL7EGVBD/jPUOcnubDkPsaG7K8=,bfa988cf4a3e33e7db3caf2ecad55c2f7c2e3f39088243767927ac8ed8d2556e +github.com/hashicorp/vault-plugin-auth-centrify,v0.5.2-0.20190725170023-9d8d5e0b03e6,h1:UXM3yxzNaruvgaccRjFXKcKnsTTHzp213MJ045wto6A=,165cf5f7daa0e4c286bad12f09eeac648062554399f18890bf35789b6b16e9c7 +github.com/hashicorp/vault-plugin-auth-gcp,v0.5.2-0.20190725170032-0aa7d1c92039,h1:uqYbah1dntV8OccHCbY3bBzYX/zLtjmG0ZIZPV+x6EM=,e9f9ccc7ca02c40291bb27012f2dd1fead86d2de2ab85a6d07b0aa7d98533f49 +github.com/hashicorp/vault-plugin-auth-jwt,v0.5.2-0.20190725170041-1cfee03e8d3a,h1:zdhacnLMH4P47PdSPJo0omNh+IkSvPj0LbiHLQu0aVk=,2b04c80c6d2000558b63ced2c9ba60a4a2ffe4c76d2d58d5fe121f714a3cf291 +github.com/hashicorp/vault-plugin-auth-kubernetes,v0.5.2-0.20190725170047-354505be0ecf,h1:il4UUQC9zfsSRNR2EAQVqC+DzrvzZpFmJReQ7p6/bKw=,d95794ab78e644a95799a3505a83af58a83c6bf775e69832b3660ca47c042d5a +github.com/hashicorp/vault-plugin-auth-oci,v0.0.0-20190904175623-97c0c0187c5c,h1:z6LQZvs1OtoVy2XgbgNhiDgp0U62Xbstn7/cgNZvh6g=,b23f2afa7fab5368d83a01be865e2dddf7ba6c7e8804ac205ccc1701a9239d51 +github.com/hashicorp/vault-plugin-auth-pcf,v0.0.0-20190725170053-826a135618c1,h1:mPyQ1+jB/ztcqebEdmNhSuYq4XVOpB5TUyyi0118T40=,c444159df670a1aba7e59029bf928989091886fa45970f751fe644d243d43744 +github.com/hashicorp/vault-plugin-database-elasticsearch,v0.0.0-20190725170059-5c0d558eb59d,h1:VUD1T3aI5GL8uoSSDhHncHP8ksgepZsvSLhsRG8MJ3s=,b151c27f632b8e05686473b4936b480cec694498c1e446dc5208b4db05c559f1 +github.com/hashicorp/vault-plugin-secrets-ad,v0.5.3-0.20190725170108-e1b17ad0c772,h1:N219G3MUxPRhtOBMFVdsSQWU47MrvivSHLmTAPpHcs4=,c8801ee5f030fa6cb36045f1e321d964224f9a2b4a17100140cafca7a6d8daf5 +github.com/hashicorp/vault-plugin-secrets-alicloud,v0.5.2-0.20190725170114-7d66a3fa0600,h1:kyHR0JOKFDAaC4sjQ3iD1lTH6uaIfmTk4rQ+JOGW5Zo=,f816c029601c9e7235f798e9591246ac935d3b1e330abfb23af59afa6bc08e0d +github.com/hashicorp/vault-plugin-secrets-azure,v0.5.2-0.20190725170121-541440395211,h1:hZ21h0DWWKkoeMW7zkYaPVLxGZtKfYyIcE9G8xug4YQ=,5d71ad3ef26fd40b3afaf852913f38e5be0a1db8844bf21cb787e204cdbc48e4 +github.com/hashicorp/vault-plugin-secrets-gcp,v0.5.3-0.20190725170127-aa49df112140,h1:gSvWU9aYAsHxqKU0ohJD9njlNQ1/qLFPRs85u+xJFv4=,9b209e3ef7b8d7c41e823705cc190699540bbd2076f82344a83c106fa7e4ac98 +github.com/hashicorp/vault-plugin-secrets-gcpkms,v0.5.2-0.20190725170135-aaf270943731,h1:zP2vqetYhON59Mf5FTV9KmyKSnY1cLFzdNW0YYnNKbo=,5d3bc6de4bdad4725c4348a0d6861bce3e80a9eb13d4b05179cd663b47f46545 +github.com/hashicorp/vault-plugin-secrets-kv,v0.5.2-0.20190725170141-1c4dac87f383,h1:4IqT7JQt/GyYKr0HGemkUlYpF45ZALHSN9rHy7Sipos=,10f03c6d8a51714692b43ab69c2cb5f041ac611210aa9804237a9345e930f018 +github.com/hashicorp/vault/api,v1.0.4,h1:j08Or/wryXT4AcHj1oCbMd7IijXcKzYUGw59LGu9onU=,a885d16e067a5586e55914cd8e40f250a28fe94b3b864de47d495ad1f71c4251 +github.com/hashicorp/vault/sdk,v0.1.14-0.20190909201848-e0fbf9b652e2,h1:b65cSyZqljnCPzzsUXvR4P0eXypo1xahQyG809+IySk=,0aca8708570b724605514cab6dbbc9cc7bce5d27786a4b2da87553c437c42463 +github.com/hashicorp/vic,v1.5.1-0.20190403131502-bbfe86ec9443,h1:O/pT5C1Q3mVXMyuqg7yuAWUg/jMZR1/0QTzTRdNR6Uw=,9c09a35b14d797812e6714073471b3472c16f9cb4deb430f9e2dd15fa8d25e32 +github.com/hashicorp/yamux,v0.0.0-20190923154419-df201c70410d,h1:W+SIwDdl3+jXWeidYySAgzytE3piq6GumXeBjFBG67c=,d8a888d6a4ecbc09f2f3663cb47aa2d064298eeb1491f4761a43ae95e93ba035 +github.com/herenow/go-crate,v0.0.0-20190617151714-6f2215a33eca,h1:kk1qCxy+FS5McLJ69dSpB6Y6kHCMa23UwHyglIzJ/bk=,aa618858b9c03e47962afb2a4098ad6cca8ecd09904cdbc5eb62c5a1d74befca +github.com/hetznercloud/hcloud-go,v1.15.1,h1:G8Q+xyAqQ5IUY7yq4HKZgkabFa0S/VXJXq3TGCeT8JM=,028402928c1bc1db686cab5738e6fb91a61252c1236258e2d911dd8da21f8af5 +github.com/hinshun/vt10x,v0.0.0-20180616224451-1954e6464174,h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ=,4afc77bd4950db746c68d23e6ed681d31cd952559d712c1400da476084567cf6 +github.com/hjfreyer/taglib-go,v0.0.0-20151027170453-0ef8bba9c41b,h1:Q4OOFmH18aIjnDJlvYm4BXmpHKXk1zTJP0QZ0otNwPs=,e7735f2cdbb7441dbe6bbc303cff9b9a20d9845dc901e31f6e29e3ef83613390 +github.com/howeyc/fsnotify,v0.9.0,h1:0gtV5JmOKH4A8SsFxG2BczSeXWWPvcMT0euZt5gDAxY=,a72f2f092433c8b53e095d6db3d3e18517db1a5a9814a78ed97194239145740f +github.com/howeyc/gopass,v0.0.0-20190910152052-7cb4b85ec19c,h1:aY2hhxLhjEAbfXOx2nRJxCXezC6CO2V/yN+OCr1srtk=,83560b6c9a6220bcbb4ad2f043e5a190ab11a013b77c1bbff9a3a67ed74d4b37 +github.com/hpcloud/tail,v1.0.0,h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=,3cba484748e2e2919d72663599b8cc6454058976fbca96f9ac78d84f195b922a +github.com/huandu/xstrings,v1.2.0,h1:yPeWdRnmynF7p+lLYz0H2tthW9lqhMJrQV/U7yy4wX0=,fe7011ad569e464d6ff81bdb1d80c4ebdb5baac5c89d17c1644a23cac0c48828 +github.com/huin/goupnp,v1.0.0,h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo=,9685536729d9860766846ad4e56fb961b246d5afa209e4058ee0d021aec37827 +github.com/huin/goutil,v0.0.0-20170803182201-1ca381bf3150,h1:vlNjIqmUZ9CMAWsbURYl3a6wZbw7q5RHVvlXTNS/Bs8=,d887199bd2f388075ff7aaf1d3061b13b92c20e01ccd6337c864fd409fe78831 +github.com/hybridgroup/go-ardrone,v0.0.0-20140402002621-b9750d8d7b78,h1:7of6LJZ4LF9AvF4bTiMr2I72KxodBf1BXrSD9Tz0lWU=,997e0efef1b73cc1930ad67cd649268ff864393fa85dedf32672ecca78647021 +github.com/hybridgroup/mjpeg,v0.0.0-20140228234708-4680f319790e,h1:xCcwD5FOXul+j1dn8xD16nbrhJkkum/Cn+jTd/u1LhY=,d9134203da596f895c55c3a9fd0aea32ad26501ca88e646cbe9f82136f592c0f +github.com/hyperledger/fabric,v1.4.3,h1:6MmYhcDbxhd0TvpvHLR3c5m3fVjaX97690H8TRjpJNA=,067d2bd69094dc9f693d9b00c8bea810f61f6a8a3d0ac640830b468934e22023 +github.com/hyperonecom/h1-client-go,v0.0.0-20190122232013-cf38e8387775,h1:MIteIoIQ5nFoOmwEHPDsqng8d0dtKj3lCnQCwGvtxXc=,135625f81c1c6c62b296269829a74f1266928600545fedec0825cb97284264f6 +github.com/iancoleman/strcase,v0.0.0-20190422225806-e506e3ef7365,h1:ECW73yc9MY7935nNYXUkK7Dz17YuSUI9yqRqYS8aBww=,f93e74faf2e05699180c40ef21204629a1c6bd382658f1059c80631c377c5246 +github.com/ianlancetaylor/demangle,v0.0.0-20181102032728-5e5cf60278f6,h1:UDMh68UUwekSh5iP2OMhRRZJiiBccgV7axzUG8vi56c=,73ae40ed96af2703f85cd4c552cf6b14551ceb782348be8185b730f44c842ab9 +github.com/iij/doapi,v0.0.0-20190504054126-0bbf12d6d7df,h1:MZf03xP9WdakyXhOWuAD5uPK3wHh96wCsqe3hCMKh8E=,7e33155961c2cba072047deb34d19a7d863a713e502abe8bdc31ab91424bd226 +github.com/ijc/Gotty,v0.0.0-20170406111628-a8b993ba6abd,h1:anPrsicrIi2ColgWTVPk+TrN42hJIWlfPHSBP9S0ZkM=,b8b9a99b3632feb3449d1fb8950d292333f8a7f494b182320ecdb0479d78442f +github.com/imdario/mergo,v0.3.8,h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ=,579cad1ed913cfcb424deb97e7016749abcc9d585bad07d14f19550df052cec5 +github.com/imkira/go-interpol,v1.1.0,h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk=,de5111f7694700ea056beeb7c1ca1a827075d423422f251076ee17bd869477d9 +github.com/improbable-eng/grpc-web,v0.9.1,h1:tenDg9Lg+zYXeS/ojbKyfwVO5TVYh5FFGsrXNAblF1o=,3a287ae758b41feea9f26ec1b8757628d4742b87376fa40b29d878ee651bfe62 +github.com/imroc/req,v0.2.3,h1:ElMCifcqg/1GonGloyyTUrj6D6IITL6EiNEKHUl4xZM=,951172f0969fa0bad31ebbe9b17699ea3909b09eaf8df39ccd78e48097682c78 +github.com/inconshreveable/go-update,v0.0.0-20160112193335-8152e7eb6ccf,h1:WfD7VjIE6z8dIvMsI4/s+1qr5EL+zoIGev1BQj1eoJ8=,adf856fb49e7c5059b2edb42a31daf4a536dc698fe0728835b018150a884b678 +github.com/inconshreveable/log15,v0.0.0-20180818164646-67afb5ed74ec,h1:CGkYB1Q7DSsH/ku+to+foV4agt2F2miquaLUgF6L178=,31875747bcd198c39714d38747ac77e585620f2f37d1b1e1a03b164af6762995 +github.com/inconshreveable/mousetrap,v1.0.0,h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=,c3fa0813e78f5cef10dc0e9912c43e68e06ff970a98e98c4050fe14dbbfd18c7 +github.com/influxdata/changelog,v1.1.0,h1:HXhmLZDrbuC+Ca5YX7g8B8cH5DmJpaOjd844d9Y7aTQ=,19e60d9b658aaecca4e075126c996c1abd5e369003c14bbe575edc4ba2b9c182 +github.com/influxdata/flux,v0.52.0,h1:R91uUXbHzoiyYF7Xhm+wP3a0iSnl43iYJrN93nBhuP0=,e0121889c46cc4ad22f1662e68df7dbdfbb361c3da6809add4d1409cef764be9 +github.com/influxdata/influxdb,v1.7.9,h1:uSeBTNO4rBkbp1Be5FKRsAmglM9nlx25TzVQRQt1An4=,b49a72374a14f726229e71152e74e8a132c2913137c4457f31bae8c7735e812c +github.com/influxdata/influxdb1-client,v0.0.0-20190809212627-fc22c7df067e,h1:txQltCyjXAqVVSZDArPEhUTg35hKwVIuXwtQo7eAMNQ=,fc41ea93bf2b06b231823b116dc11b0ed89badf1ce6a4c848a33c77dcf2c123a +github.com/influxdata/influxql,v1.0.1,h1:6PGG0SunRmptIMIreNRolhQ38Sq4qDfi2dS3BS1YD8Y=,2a697984d1cd82656f69901bfe1771676493411c1370d77271bde3ab3c917a1e +github.com/influxdata/line-protocol,v0.0.0-20180522152040-32c6aa80de5e,h1:/o3vQtpWJhvnIbXley4/jwzzqNeigJK9z+LZcJZ9zfM=,6111b5e459106f7003477186aa2e34423dbe0c53983944a07d8b835ff8c7757c +github.com/influxdata/promql/v2,v2.12.0,h1:kXn3p0D7zPw16rOtfDR+wo6aaiH8tSMfhPwONTxrlEc=,b928626f2eb81eed0046ef23a83a77a28dd140d369a0d2538c94e85d1055877f +github.com/influxdata/tdigest,v0.0.0-20181121200506-bf2b5ad3c0a9,h1:MHTrDWmQpHq/hkq+7cw9oYAt2PqUw52TZazRA0N7PGE=,5d6b056d98d1e7e9cd884aea4e73934cc8ea89218eb43ee1d5140d3ccb34ed52 +github.com/influxdb/influxdb,v1.7.9,h1:KMBwwvyJyBppIwrg5t0662p+Yei/ucnIkqUl8txiQdQ=,ad251d4cc00aec767465dc60d6b702a3635b68402123a4ee5d1ee2b5006310b3 +github.com/iotexproject/go-pkgs,v0.1.1,h1:AyWJf8jqOg4aMSrxi+MInFFBZhTvSm0LCu1o08heijk=,c5099edde7450b4f8b9a0f49c42697f5e9bcb92d2bf58395aa0681f3ef6b583d +github.com/iotexproject/iotex-address,v0.2.1,h1:ZJH2ajx5OBrbaRJ0ZWlWUo685zr5kjWijVjtmUrm42E=,53c7ce4d7fbc55ee79e92e9e0b31ee3b3ba0e6e5d3e24cd43e0a58c766568c9d +github.com/iotexproject/iotex-proto,v0.2.5,h1:SYdl9Lqb0LYfFf3sfw92fN8GY3bthfCvGmltz+2uvDQ=,546cb070e92286601aee16d03383712172061c8fe78e53cf04498a9358470a78 +github.com/ipfs/bbloom,v0.0.4,h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=,92993c175552cc626ef6b1ab6cf887f0f640311748c47e7615df29a966c1b774 +github.com/ipfs/go-bitswap,v0.1.3,h1:jAl9Z/TYObpGeGATUemnOZ7RYb0F/kzNVlhcYZesz+0=,ee26d57b2765f808ebebca8aa18695bfa02b738f47b4b5db5efce5c91f28fbcd +github.com/ipfs/go-block-format,v0.0.2,h1:qPDvcP19izTjU8rgo6p7gTXZlkMkF5bz5G3fqIsSCPE=,02ad9fa29f97073ece45a5da7a92e59e6c6b856e9a03bd853361b8107296c020 +github.com/ipfs/go-blockservice,v0.1.2,h1:fqFeeu1EG0lGVrqUo+BVJv7LZV31I4ZsyNthCOMAJRc=,31c5ff02d71ee454bebea3944d7e06c2ffd6f1c4cfdddf71c5122e982f261c7d +github.com/ipfs/go-cid,v0.0.3,h1:UIAh32wymBpStoe83YCzwVQQ5Oy/H0FdxvUS6DJDzms=,f8bd60f8bbd79ed1fa5c8c113f6e17addb12257b0d925d3327ee7c25a7733591 +github.com/ipfs/go-datastore,v0.1.1,h1:F4k0TkTAZGLFzBOrVKDAvch6JZtuN4NHkfdcEZL50aI=,be724f5e3a459cf6ae9e68d2fa14e27cc92c53ae775979f2412b4f5b3f2b0336 +github.com/ipfs/go-detect-race,v0.0.1,h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=,c00c97cacb355cb0569bee75775eff6b656d95dd7d0855ed97c2ee44666b72cd +github.com/ipfs/go-ds-badger,v0.0.7,h1:NMyh88Q50HG6/S2YD58DLkq0c0/ZQPMbSojONH+PRf4=,26a453fc19eb26fe6077f12310ff1ad7230fe31b31a0c17fb47abba75379ee61 +github.com/ipfs/go-ds-leveldb,v0.1.0,h1:OsCuIIh1LMTk4WIQ1UJH7e3j01qlOP+KWVhNS6lBDZY=,43085f79b999edef0b8b49dea1ed35d47cc1c453ef401634825c0be5b62ac6d9 +github.com/ipfs/go-hamt-ipld,v0.0.13,h1:Jbt5ALTYnrzbcOBka11kAkgn3auvkQBGkKWjGRsQrio=,e16acbc3f203616ccd9119415b9db28a6f18c72f053259842f7db50aa1193cf8 +github.com/ipfs/go-ipfs-blockstore,v0.1.0,h1:V1GZorHFUIB6YgTJQdq7mcaIpUfCM3fCyVi+MTo9O88=,19a45734b2615632b180b59032d39c04c50fc735c7f9fd27c5547b0facb4ef8f +github.com/ipfs/go-ipfs-blocksutil,v0.0.1,h1:Eh/H4pc1hsvhzsQoMEP3Bke/aW5P5rVM1IWFJMcGIPQ=,3fcf4221d4d59af5807040f209ff0d28d81f6974d61ac279b43a44b2f46d8182 +github.com/ipfs/go-ipfs-chunker,v0.0.1,h1:cHUUxKFQ99pozdahi+uSC/3Y6HeRpi9oTeUHbE27SEw=,02a0e4766162345a5bea8962c315b4bab8f2550aa1b760dcece96794b3ba22ef +github.com/ipfs/go-ipfs-config,v0.0.11,h1:5/4nas2CQXiKr2/MLxU24GDGTBvtstQIQezuk7ltOQQ=,e26bdd6db98c4ccf932440aa22a1aa2d550903a0f6f9da82f1ff5902ebbe260e +github.com/ipfs/go-ipfs-delay,v0.0.1,h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ=,bc3a4494d27cd7fabdeb7036e2edadd27f0edbd2b7d3cf49d14e3402c17c3ab6 +github.com/ipfs/go-ipfs-ds-help,v0.0.1,h1:QBg+Ts2zgeemK/dB0saiF/ykzRGgfoFMT90Rzo0OnVU=,52d0d886ebb65366abb35f19b76c4f6f349464eaedf092da95c661a451b2bf06 +github.com/ipfs/go-ipfs-exchange-interface,v0.0.1,h1:LJXIo9W7CAmugqI+uofioIpRb6rY30GUu7G6LUfpMvM=,0a593df65586ff592255eb69923a43d413b24ad56454e14e94f5e722756fb102 +github.com/ipfs/go-ipfs-exchange-offline,v0.0.1,h1:P56jYKZF7lDDOLx5SotVh5KFxoY6C81I1NSHW1FxGew=,04b69dc6dd34a2c5c2d1f0df8777fcaa8590aa528b960cc26178af6f609e29cf +github.com/ipfs/go-ipfs-files,v0.0.6,h1:sMRtPiSmDrTA2FEiFTtk1vWgO2Dkg7bxXKJ+s8/cDAc=,442fa790aba0beff3a79503064a35dceab2a29dc4ab8edcca690c7f61ef6c6c0 +github.com/ipfs/go-ipfs-flags,v0.0.1,h1:OH5cEkJYL0QgA+bvD55TNG9ud8HA2Nqaav47b2c/UJk=,61ac13bc74f89286ac30db2ce79b26adfba63a0676cbc430ad750df2d516565a +github.com/ipfs/go-ipfs-posinfo,v0.0.1,h1:Esoxj+1JgSjX0+ylc0hUmJCOv6V2vFoZiETLR6OtpRs=,149f52f33d8ffd4f82056b4ea1dae2f25024a2e8df0ff555789c549468d998e7 +github.com/ipfs/go-ipfs-pq,v0.0.1,h1:zgUotX8dcAB/w/HidJh1zzc1yFq6Vm8J7T2F4itj/RU=,4eda59f4f898933265b82d381cc1ea5a3d3c75752618f46496a2d150c09aeb2d +github.com/ipfs/go-ipfs-routing,v0.1.0,h1:gAJTT1cEeeLj6/DlLX6t+NxD9fQe2ymTO6qWRDI/HQQ=,e2281e568eed0ee5621886d28802eefd8a9d0806cbd1db80c01550ad59ec54c7 +github.com/ipfs/go-ipfs-util,v0.0.1,h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50=,6d3af4d6dcb95047b64fc74972cdcd84f199c6bad467a7de3543c3eaa0d4ee49 +github.com/ipfs/go-ipld-cbor,v0.0.3,h1:ENsxvybwkmke7Z/QJOmeJfoguj6GH3Y0YOaGrfy9Q0I=,4087b9930a8e2899c3540e61bd8e7f04c8bdd8670f68ddbfcf10f45a0e619cef +github.com/ipfs/go-ipld-format,v0.0.2,h1:OVAGlyYT6JPZ0pEfGntFPS40lfrDmaDbQwNHEY2G9Zs=,3da08ede588080b6ec81c5ad8fbfb1c9ea306a038be41dc06b1f3a1a101ebe50 +github.com/ipfs/go-log,v0.0.1,h1:9XTUN/rW64BCG1YhPK9Hoy3q8nr4gOmHHBpgFdfw6Lc=,9165a91716b11b432f8bf303d59fc019bf91872f1b9ca7e12d666c11ba6e6676 +github.com/ipfs/go-merkledag,v0.2.4,h1:ZSHQSe9BENfixUjT+MaLeHEeZGxrZQfgo3KT3SLosF8=,ed269e045c613cc7b9bba3593797fe09cdf84c906726bef9261c74bd8c470404 +github.com/ipfs/go-metrics-interface,v0.0.1,h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg=,e83f0c01b084000492db0c0e1a28ff900c3f6d11eea8defdbe8bdd1a04c33fd0 +github.com/ipfs/go-mfs,v0.1.1,h1:tjYEWFIl0W6vRFuM/EnySHaaYzPmDcQWwTjtYWMGQ1A=,1db35113aff60e645544cc64cbbddbf0608332b1f2208615744098af59b97fee +github.com/ipfs/go-path,v0.0.7,h1:H06hKMquQ0aYtHiHryOMLpQC1qC3QwXwkahcEVD51Ho=,96c607c0253c24ed0cb37016007f34420a3a83c37cdd68b6d4391126418835c4 +github.com/ipfs/go-peertaskqueue,v0.1.1,h1:+gPjbI+V3NktXZOqJA1kzbms2pYmhjgQQal0MzZrOAY=,5fa92b0302d8e72e8c4d74517a68fad04c1d89d90f0a6314a5e30662dda5d359 +github.com/ipfs/go-unixfs,v0.2.2,h1:eTkDT9F0dn4qHmBMVRMZbziwyqLRcogjtPYqMgZYmQs=,77f7f6b2de604b592018dd914a6606084069d22efa70ea95e0dd623a04e4453c +github.com/ipfs/go-verifcid,v0.0.1,h1:m2HI7zIuR5TFyQ1b79Da5N9dnnCP1vcu2QqawmWlK2E=,1f808a29fcd38406325435c7a6a02b253aee28832704f0032600c2b41ef3b8f1 +github.com/ipfs/interface-go-ipfs-core,v0.2.4,h1:oQiJ3Mj3rqVJohdi316K3+VSyiADto3Z35ukj7z+UGg=,e1030de5fc1ee1868a87386708be313fc0fcbbe137d5a71d71f28621393f70a2 +github.com/ipfs/iptb,v1.4.0,h1:YFYTrCkLMRwk/35IMyC6+yjoQSHTEcNcefBStLJzgvo=,0b00d0279c700ad687cfbba073f504cc4c8a17ff731550c3784fcb3e24b0c6d5 +github.com/iris-contrib/blackfriday,v2.0.0+incompatible,h1:o5sHQHHm0ToHUlAJSTjW9UWicjJSDDauOOQ2AHuIVp4=,936679f49251da75fde84b8f38884dbce89747b96f8206f7a4675bfcc7dd165d +github.com/iris-contrib/formBinder,v5.0.0+incompatible,h1:jL+H+cCSEV8yzLwVbBI+tLRN/PpVatZtUZGK9ldi3bU=,6f1fef9e533a1f57a8b033f8c0a135ed038524d7535dd16ba22e9494e3096e3b +github.com/iris-contrib/go.uuid,v2.0.0+incompatible,h1:XZubAYg61/JwnJNbZilGjf3b3pB80+OQg2qf6c8BfWE=,c6bae86643c2d6047c68c25226a1e75c5331c03466532ee6c943705743949bd9 +github.com/issue9/assert,v1.3.2,h1:IaTa37u4m1fUuTH9K9ldO5IONKVDXjLiUO1T9vj0OF0=,f4349cbd5af134fce10b399717aa4b455b5c73df6c20c1057c6e45973f24a06d +github.com/issue9/identicon,v0.0.0-20160320065130-d36b54562f4c,h1:A/PDn117UYld5mlxe58EpMguqpkeTMw5/FCo0ZPS/Ko=,5a837560a10469ab524b185a092edf67be85aff5ed794e1fcaaa084cf4540336 +github.com/itchio/arkive,v0.0.0-20190702114012-1bb6c7241ec3,h1:UcZnU7qzWTmZf8v7F3mC79H98I0b77pZz+99vqHFwtI=,dad4e3a988e6834d4ce1c3fb650a8dbb9aedd116ba8b3556c8f8babecdd17ead +github.com/itchio/dskompress,v0.0.0-20190702113811-5e6f499be697,h1:u3Q2WkrIPYlGEw4fjcImSOrkivWd6SVb0BF0Ehoih9c=,d8379b7e4219f001b61e5c2b3b34b2a6b69f8a55dc1acde2919be3050a7c84f5 +github.com/itchio/go-brotli,v0.0.0-20190702114328-3f28d645a45c,h1:Jf20xV/yR/O6eSUqLTuXhka/+54YR59sGwN7b3MkxYk=,6bab2adfb10a8ae7132e02ed10823df2e91c42dd08a1f3e1835679390ea69927 +github.com/itchio/headway,v0.0.0-20190702175331-a4c65c5306de,h1:RQW9xPqYtvjdHHRZR95XsaEA9B4URCuNHK78IuJcc+Y=,54e63fd6f25217e272e196f6213915515196a5b17a1923a666c05b4f49c82ef3 +github.com/itchio/httpkit,v0.0.0-20190702184704-639fe5edf1f1,h1:mViP/A8hAP04YWbbZR7Kcm7rTkUeT2HLcn3BBiK+CwM=,e56bf70a53a305f6866631d1272a3f3543abd45a68c50d202ddc80796b58c461 +github.com/itchio/kompress,v0.0.0-20190702090658-5e2558a00102,h1:QXEwRXrrx+7CxU+Y+G4GpDk4mUeHbP7grMXHhydk8qU=,cadec4996aed4026c0e0321f90b5bb11d9b8d1de3665752b2e862c6ddbfa229d +github.com/itchio/ox,v0.0.0-20190925154941-b613e528fc7d,h1:EcmVffUYduCSFCEM12YpSXoVXvyeq8Ro4Q+rwc60TIo=,81c3dfe8e91eb13815bf5b7f159f24a3cb1bd7028a395f691e9cefc1c3a71d01 +github.com/itchio/randsource,v0.0.0-20190702184213-a7635a4cb94b,h1:fG+9RlMeggMG/C2FH80HTfJmm+eOjAve2pFSv6Uio8A=,2375b07785c2738527c864dfb1bee0082b1f89c51e200157165bcd36f5c2933f +github.com/itchio/savior,v0.0.0-20190925162935-b92976a0b402,h1:a51wRxkLoJWu5NqnVDkI6cE50S0mDpJfOXkCp4ltvr8=,1454524a51fa6492ee593fb7d648dc037fec7c32d90e2d21c149b6e724a74838 +github.com/iwind/TeaGo,v0.0.0-20191007090339-daba0bb6607e,h1:bxD34HpyJWx6bnGdahZo6uN6XnuOvMa8LrzfC+eZqes=,bec78c179e2676d51bb1a07122896661d4ae7727d325e9fa91682361e0321161 +github.com/jackc/chunkreader,v1.0.0,h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=,e204c917e2652ffe047f5c8b031192757321f568654e3df8408bf04178df1408 +github.com/jackc/chunkreader/v2,v2.0.0,h1:DUwgMQuuPnS0rhMXenUtZpqZqrR/30NWY+qQvTpSvEs=,cae1df6cc4f52abdf31d9c7c9869714f5c2e2dddc8047eb6d335409489e76031 +github.com/jackc/fake,v0.0.0-20150926172116-812a484cc733,h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc=,bf8b5b51ae03f572a70a0582dc663c5733bba9aca785d39bb0367797148e6d64 +github.com/jackc/pgconn,v1.0.1,h1:ZANo4pIkeHKIVD1cQMcxu8fwrwIICLblzi9HCjooZeQ=,4b7e033c80207f032275845f7d366b51b46e3434cafebd13599a351f01f68b86 +github.com/jackc/pgio,v1.0.0,h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=,1a83c03d53f6a40339364cafcbbabb44238203c79ca0c9b98bf582d0df0e0468 +github.com/jackc/pgmock,v0.0.0-20190831213851-13a1b77aafa2,h1:JVX6jT/XfzNqIjye4717ITLaNwV9mWbJx0dLCpcRzdA=,5d8117d8fb79d3a41998bec8dca93d450eba9edf3cf0b8c36881e0ea6140b406 +github.com/jackc/pgpassfile,v1.0.0,h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=,1cc79fb0b80f54b568afd3f4648dd1c349f746ad7c379df8d7f9e0eb1cac938b +github.com/jackc/pgproto3,v1.1.0,h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=,e3766bee50ed74e49a067b2c4797a2c69015cf104bf3f3624cd483a9e940b4ee +github.com/jackc/pgproto3/v2,v2.0.0,h1:FApgMJ/GtaXfI0s8Lvd0kaLaRwMOhs4VH92pwkwQQvU=,22635755552d1363817a9c9f192cf464034dfc31593e4975982a85de8295dcf4 +github.com/jackc/pgtype,v0.0.0-20190828014616-a8802b16cc59,h1:xOamcCJ9MFJTxR5bvw3ZXmiP8evQMohdt2VJ57C0W8Q=,30822259b27010e41850fde5f75166abc90028b9c57e2a77976cab119e01295f +github.com/jackc/pgx,v3.6.0+incompatible,h1:bJeo4JdVbDAW8KB2m8XkFeo8CPipREoG37BwEoKGz+Q=,07a0cc87069e38acac988cc48e5a6cfd1bfd02b4b843d0e8931e48bb8c25d821 +github.com/jackc/pgx/v4,v4.0.0-pre1.0.20190824185557-6972a5742186,h1:ZQM8qLT/E/CGD6XX0E6q9FAwxJYmWpJufzmLMaFuzgQ=,1782863d2118cd0e63cc50cca24bd79cbea5674bac3b798bf12148400590128d +github.com/jackc/puddle,v0.0.0-20190608224051-11cab39313c9,h1:KLBBPU++1T3DHtm1B1QaIHy80Vhu0wNMErIFCNgAL8Y=,a780306bb3ad76174eca1d83a6d925fb3f7a13981cda6249e51be64476c76f15 +github.com/jackmordaunt/icns,v0.0.0-20181231085925-4f16af745526,h1:NfuKjkj/Xc2z1xZIj+EmNCm5p1nKJPyw3F4E20usXvg=,06f511df7637fd1424b6f099d7ce7ecf7378e62adc9d13133ce7df419e51faf0 +github.com/jackpal/gateway,v1.0.5,h1:qzXWUJfuMdlLMtt0a3Dgt+xkWQiA5itDEITVJtuSwMc=,adab846630d73763e5a3b984c8264d6503c8cb0b2914df559dacd41f6380e4ef +github.com/jackpal/go-nat-pmp,v1.0.1,h1:i0LektDkO1QlrTm/cSuP+PyBCDnYvjPLGl4LdWEMiaA=,d7f2409f72895a01e0d11b457eac015dbcd94c2657f95d508e53867ca6b07db1 +github.com/jacobsa/crypto,v0.0.0-20190317225127-9f44e2d11115,h1:YuDUUFNM21CAbyPOpOP8BicaTD/0klJEKt5p8yuw+uY=,ec4d2a1fc28e1d99c68557e38cd77527df5a9f5090aa12876ab4aa6f9137a3d5 +github.com/jacobsa/oglematchers,v0.0.0-20150720000706-141901ea67cd,h1:9GCSedGjMcLZCrusBZuo4tyKLpKUPenUUqi34AkuFmA=,bcd70357107c45c3177c913b718624376b692d39672c157708fe2cd9aa78fcb5 +github.com/jacobsa/oglemock,v0.0.0-20150831005832-e94d794d06ff,h1:2xRHTvkpJ5zJmglXLRqHiZQNjUoOkhUyhTAhEQvPAWw=,5159f5f22d0e130b1fbfdbc96eb9d4653b32bd463439cb0f3c98e179de5daf80 +github.com/jacobsa/ogletest,v0.0.0-20170503003838-80d50a735a11,h1:BMb8s3ENQLt5ulwVIHVDWFHp8eIXmbfSExkvdn9qMXI=,69d96e3ea6e055d68ed46c0c1044a5dfa18064c9d45bc68d5946aa55e048af6b +github.com/jacobsa/reqtrace,v0.0.0-20150505043853-245c9e0234cb,h1:uSWBjJdMf47kQlXMwWEfmc864bA1wAC+Kl3ApryuG9Y=,a7efb54142e39f4acab39d22db692d5734f818723783646f6727269228deea83 +github.com/jaegertracing/jaeger,v1.14.0,h1:C0En+gfcxf3NsAriMAvQ6LcSFrQ5VQGXddqfty1EpTI=,5f6245d1b0c986c44cc37c7c950f3cf9c2cfd1e0d540905cd4fab9a164684ecd +github.com/jarcoal/httpmock,v1.0.4,h1:jp+dy/+nonJE4g4xbVtl9QdrUNbn6/3hDT5R4nDIZnA=,5c7d051f237633573a168713760758005724c268242484d982cb0c76dc3f3ee7 +github.com/jaytaylor/html2text,v0.0.0-20190408195923-01ec452cbe43,h1:jTkyeF7NZ5oIr0ESmcrpiDgAfoidCBF4F5kJhjtaRwE=,2369830967f1c18c382cbee77a510431b42275f1f368e3b5cbbdaa782ae24c0d +github.com/jbenet/go-base58,v0.0.0-20150317085156-6237cf65f3a6,h1:4zOlv2my+vf98jT1nQt4bT/yKWUImevYPJ2H344CloE=,e686d369d490d6728f6e63b1680db3b567c9e884545f8c47ca656f0d944299b7 +github.com/jbenet/go-cienv,v0.1.0,h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc=,3de5dadf2add50bf7fbdf88db4e6d008ba1848516585f7f9dfbf53cb6dc1705c +github.com/jbenet/go-context,v0.0.0-20150711004518-d14ea06fba99,h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=,4cd0955abeea43dc4b5a08b8769e696109e0376f2a113a9b8eff13cc90cac1c7 +github.com/jbenet/go-temp-err-catcher,v0.0.0-20150120210811-aac704a3f4f2,h1:vhC1OXXiT9R2pczegwz6moDvuRpggaroAXhPIseh57A=,9299671a264400f8f0e145da442aa3216394f324c50f045ef2ed2b898b3945c9 +github.com/jbenet/goprocess,v0.1.3,h1:YKyIEECS/XvcfHtBzxtjBBbWK+MbvA6dG8ASiqwvr10=,026bb36c2d4316ad327f8b2e623f172c01140f699d57ec8609f702df5cdf021d +github.com/jcmturner/gofork,v1.0.0,h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8=,5e015dd9b038f1dded0b2ded77e529d2f6ba0bed228a98831af5a3610eefcb52 +github.com/jdcloud-api/jdcloud-sdk-go,v1.9.1-0.20190605102154-3d81a50ca961,h1:a2/K4HRhg31A5vafiz5yYiGMjaCxwRpyjJStfVquKds=,93754c3fe6c00591fcd499cf73ad7f66e4ed864619579ff726872a2f50b53dfa +github.com/jdkato/prose,v1.1.0,h1:LpvmDGwbKGTgdCH3a8VJL56sr7p/wOFPw/R4lM4PfFg=,4e07b4f2012b46465fcc262d907b1cb81699bc61e6fb7a59ee47ea262e4986d1 +github.com/jeffchao/backoff,v0.0.0-20140404060208-9d7fd7aa17f2,h1:mex1izRBCD+7WjieGgRdy7e651vD/lvB1bD9vNE/3K4=,e6daeed2ffbf793cbdab5e21e9ba47ced708e7c594d4155e1964109903bd199f +github.com/jefferai/isbadcipher,v0.0.0-20190226160619-51d2077c035f,h1:E87tDTVS5W65euzixn7clSzK66puSt1H4I5SC0EmHH4=,c438b15316e4af2487ba2c818288aa15ba19e39b3bf2f83651dcc9d451af6c5b +github.com/jefferai/jsonx,v1.0.0,h1:Xoz0ZbmkpBvED5W9W1B5B/zc3Oiq7oXqiW7iRV3B6EI=,e8ccf27ffc8d4560e7db02f8a1663fd4605c5996a025f90721f8157fde332be7 +github.com/jellevandenhooff/dkim,v0.0.0-20150330215556-f50fe3d243e1,h1:ujPKutqRlJtcfWk6toYVYagwra7HQHbXOaS171b4Tg8=,8a3ba94d93fb61070bee24ffca5043eb32b4a6aafa9b84e4950a5f8f34328659 +github.com/jessevdk/go-flags,v1.4.0,h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=,a26e72c3f4c220df8b65ac6eb3d358a8ad2efc300b212318582893ea882726f9 +github.com/jfrazelle/go,v1.5.1-1,h1:EJWkn/L/VOoena+VQryO7xEkxz7J6lHvPXAe+Z3Q6Gc=,ff67181f47086da85e0d0896aeffb52142f6f45bd3bbf75b94cd7546365bf140 +github.com/jfrog/gofrog,v1.0.5,h1:pEJmKZ9XgvQH2a8WCqAEeUDSXBCKBMN90QzOiOhBTIs=,bb6267655de882922977dca0860020c4c781bf7b3d6aba3fddc206a21c13784c +github.com/jfrog/jfrog-client-go,v0.5.5,h1:dYoajyMXcmc13YpZ/NLye0KL7r+QfpP9l8+WriZNZbE=,3d62cf613d821eb41b8b62ff01e09d8d4eed781f4deb52d3dd96e5a636967732 +github.com/jhump/protoreflect,v1.5.0,h1:NgpVT+dX71c8hZnxHof2M7QDK7QtohIJ7DYycjnkyfc=,a6f0926d31ed98d63d04f2aa60a5579cca471e7544cb701202ba5a5fd3134256 +github.com/jimstudt/http-authentication,v0.0.0-20140401203705-3eca13d6893a,h1:BcF8coBl0QFVhe8vAMMlD+CV8EISiu9MGKLoj6ZEyJA=,0bcf35e1ca69658b70fe05050f436b18ae141a08863cf6011afb39edef5c4013 +github.com/jinzhu/copier,v0.0.0-20190924061706-b57f9002281a,h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o=,c05742c031370bace7c0d5b4101d437e59ad4613bb707fda49c365b3e6af8ad2 +github.com/jinzhu/gorm,v1.9.11,h1:gaHGvE+UnWGlbWG4Y3FUwY1EcZ5n6S9WtqBA/uySMLE=,87f36225e1108c93f299d9b7e4cda23c2f9469ce3db0de59df90691c1e740565 +github.com/jinzhu/inflection,v1.0.0,h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=,cf1087a6f6653ed5f366f85cf0110bbbf581d4e9bc8a4d1a9b56765d94b546c3 +github.com/jinzhu/now,v1.0.1,h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=,5900b34a1d8daa959798e342e684c4237f60ffaebd1aa4201e29a7d3a98d32b7 +github.com/jlaffaye/ftp,v0.0.0-20190126081051-8019e6774408,h1:9AeqmB6KVEJ7GQU985MGQc7Mtxz1+C+JZkgqBnUWqMU=,b1b8b0e10084219eaf1a829778c1b53c049eeb77249a5660b62291cc3b454e6b +github.com/jmcvetta/neoism,v1.3.1,h1:GCFSl/90OYwEQH5LML/Vy6UlwK4SZ2OIO278UI4K7DE=,93e9ce5946ab71d9d0970e3709716a2b9cc96b4d03cfc708dfba8f062e870885 +github.com/jmcvetta/randutil,v0.0.0-20150817122601-2bb1b664bcff,h1:6NvhExg4omUC9NfA+l4Oq3ibNNeJUdiAF3iBVB0PlDk=,742cb157c8eb74da05a7972de646034cf0ddaba7c89d8aac625ed73027e778c1 +github.com/jmespath/go-jmespath,v0.0.0-20180206201540-c2b33e8439af,h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=,5c18f15c2bcfbbdb4fd15c0598ea5d3a373991a7b46a8f2405d00ac8b6121629 +github.com/jmhodges/clock,v0.0.0-20160418191101-880ee4c33548,h1:dYTbLf4m0a5u0KLmPfB6mgxbcV7588bOCx79hxa5Sr4=,f66a541ce3f97b4696d65282a332e8d08dee3f15271b7c2066050aeb5b7334b7 +github.com/jmhodges/levigo,v1.0.0,h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U=,7f43feb409c9650336152a959d7dc4d8e5a260c92e0212b1d2e0f0a7d3de6d87 +github.com/jmoiron/sqlx,v1.2.0,h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=,c8000fe80e86eea575e0d3dd0737f6399c1880a420ce2a9d833ca0e0cfc9c875 +github.com/joefitzgerald/rainbow-reporter,v0.1.0,h1:AuMG652zjdzI0YCCnXAqATtRBpGXMcAnrajcaTrSeuo=,889ea7a751c043bd0ea0ee31734011938be19ecbf08e652d53fc41f3eade9435 +github.com/joeshaw/multierror,v0.0.0-20140124173710-69b34d4ec901,h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4=,e31f735c5f42ac65aef51a70ba1a32b5ac34067a7ba0624192dd41e5ea03aa1e +github.com/joho/godotenv,v1.3.0,h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=,acef5a394fbd1193f52d0d19690b0bfe82728d18dd3bf67730dc5031c22d563f +github.com/jonas-p/go-shp,v0.1.1,h1:LY81nN67DBCz6VNFn2kS64CjmnDo9IP8rmSkTvhO9jE=,ac1706c486b7ea7e83eecd1f773259098569d2fe3ad2a53cc32ff89a68915a8f +github.com/jonboulle/clockwork,v0.1.0,h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=,930d355d1ced60a668bcbca6154bb5671120ba11a34119505d1c0677f7bbbf97 +github.com/joncalhoun/qson,v0.0.0-20170526102502-8a9cab3a62b1,h1:lnrOS18wZBYrzdDmnUeg1OVk+kQ3rxG8mZWU89DpMIA=,062b14a6986be3fb833eb9dd907acb7e563d5b6cfcaee1a04120a9b1fcc2d451 +github.com/josephspurrier/goversioninfo,v0.0.0-20190124120936-8611f5a5ff3f,h1:wBb8/KQrr2tWYffdugrpxOdWyOPSBRNzAR76aF9Nn3Y=,50be4b48f9fb8fbe79a013a791c015c13d7294c5de8f9bee586eaadd6f479459 +github.com/joyent/triton-go,v0.0.0-20190112182421-51ffac552869,h1:BvV6PYcRz0yGnWXNZrd5wginNT1GfFfPvvWpPbjfFL8=,5e875a04efd7f844211b68657d21313ae16b479cb01dc7161811c2c39ac19b18 +github.com/jpillora/backoff,v1.0.0,h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=,f856692c725143c49b9cceabfbca8bc93d3dbde84a0aaa53fb26ed3774c220cc +github.com/jrick/logrotate,v1.0.0,h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI=,b87ee434f9e2cfda719b639cd5bd0a52523f920f64d23336f88070e9d3765d54 +github.com/jsimonetti/rtnetlink,v0.0.0-20190606172950-9527aa82566a,h1:84IpUNXj4mCR9CuCEvSiCArMbzr/TMbuPIadKDwypkI=,97d995d4ca858da8955aefcead01425d12a91188d6f9b36b5cb63aa35a4ea674 +github.com/json-iterator/go,v1.1.8,h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok=,0de8f316729fb05ba608361323b178aa32944154e77aa208ad2818848b0628e2 +github.com/jstemmer/go-junit-report,v0.0.0-20190106144839-af01ea7f8024,h1:rBMNdlhTLzJjJSDIjNEXX1Pz3Hmwmz91v+zycvx9PJc=,b623acfae0dcc440f81ae14f3c5bc3ca40b1a674660ad549127980f892ab165e +github.com/jteeuwen/go-bindata,v3.0.7+incompatible,h1:91Uy4d9SYVr1kyTJ15wJsog+esAZZl7JmEfTkwmhJts=,03f794b47c49da98a4eab6c3a7cc49d286f012d64ab832f783b76b9fcd3bd8b2 +github.com/jtolds/gls,v4.20.0+incompatible,h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=,2f51f8cb610e846dc4bd9b3c0fbf6bebab24bb06d866db7804e123a61b0bd9ec +github.com/jtolds/go-luar,v0.0.0-20170419063437-0786921db8c0,h1:UyVaeqfY1fLPMt1iUTaWsxUNxYAzZVyK+7G+a3sRfhk=,1ed97930b5dfc7f89c84ff3c5ea5a7de9964ccca970f45853d42a13a138b644e +github.com/jtolds/monkit-hw,v0.0.0-20190108155550-0f753668cf20,h1:XK96humQhnPbQ24uKtSHKbdShDgrKYqlWBNKJTcIKbg=,5d84e6f3f559b67e00b08a5e93e1017866695a4590b97ccb23a82e3ce792ad04 +github.com/juju/ansiterm,v0.0.0-20180109212912-720a0952cc2a,h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU=,17d1e05fd6f1c8fdce7ba7495af54f4dac1e155febff56bd6450593b016655c2 +github.com/juju/clock,v0.0.0-20190205081909-9c5c9712527c,h1:3UvYABOQRhJAApj9MdCN+Ydv841ETSoy6xLzdmmr/9A=,f57579c0c104add5228b279c4673f592d5756033d33b085185ef72a3d2f83bfe +github.com/juju/cmd,v0.0.0-20190815094254-0c5c82a8dfc6,h1:rPqkdymtMRLcCSYKOeIxuw5mmd8dWx8jSq+t9EGBgtA=,c603f2311cf6524a74535eb9d416a83959c03e6ad52ab4ec081cbc7343734af6 +github.com/juju/collections,v0.0.0-20180717171555-9be91dc79b7c,h1:m/Uo8B7nrH3K6nvk66Y67T7cbHcyY101rW24vGuMON8=,18275066d75835f37845565980c0ac818f9c29145f756b1eeacb6496dac3ebd3 +github.com/juju/errors,v0.0.0-20190930114154-d42613fe1ab9,h1:hJix6idebFclqlfZCHE7EUX7uqLCyb70nHNHH1XKGBg=,2519c885f89cfba663da3bd9a1ff2532e3ae948bdea3e44b42603d8f91cc0796 +github.com/juju/gnuflag,v0.0.0-20171113085948-2ce1bb71843d,h1:c93kUJDtVAXFEhsCh5jSxyOJmFHuzcihnslQiX8Urwo=,47cdfb1bf94a2719e97e03caf4e0dc1cb89ba27c35ed7ce7020701fe8ee2c353 +github.com/juju/gojsonpointer,v0.0.0-20150204194629-afe8b77aa08f,h1:QzpKmMsaP06HVZnYNlcy1CLIXPytsj2NuzfCHitxuus=,0e75303c5dc230f30a629963589376030c3c2a1152a40b9e2075a084224eb173 +github.com/juju/gojsonreference,v0.0.0-20150204194633-f0d24ac5ee33,h1:huRsqE0iXmVPTML75YvFBOiaNj4ZiCZgKVnkRQ06d3w=,d1648b2f71dfbb02acc4a18c55711c721e0f6b50a5280d852cd9c0a639e8ebe6 +github.com/juju/gojsonschema,v0.0.0-20150312170016-e1ad140384f2,h1:VqIDC6dRE0C7wEtTdT6zx2zP5omaoJiZXp2g/dBHRcE=,a9f736e7cb462ccf3b2cb03aa8a133db13dc8d938a2753329a7a1274bdca2656 +github.com/juju/httpprof,v0.0.0-20141217160036-14bf14c30767,h1:COsaGcfAONDdIDnGS8yFdxOyReP7zKQEr7jFzCHKDkM=,9a8c77f887765536c312c89d73d7568126393c7d38c473a50addbec30f8c80ec +github.com/juju/httprequest,v2.0.0+incompatible,h1:+WtiSbRkEwdqKRBi+4JH8PTdNxBa/h8U8RIzdYaMENI=,0d2ae765c01f7956da6896b7c7d8bb1ad4065e960b93c09a644e2e61a0acaa52 +github.com/juju/jsonschema,v0.0.0-20161102181919-a0ef8b74ebcf,h1:SGTxyCG74uh2dYdBJCUJOo2FSx0fRHP7nMRH7s5JVeQ=,a5681c88d87b34d10dcf701b10d149303fa6d152ee224dc1bd7bd7680da80bfa +github.com/juju/loggo,v0.0.0-20190526231331-6e530bcce5d8,h1:UUHMLvzt/31azWTN/ifGWef4WUqvXk0iRqdhdy/2uzI=,3db058c07ced25b8689f5d3e462d344ffb965c6f371eabc0396ce94d927e6206 +github.com/juju/lru,v0.0.0-20190314140547-92a0afabdc41,h1:/ucixsNZ+l94agL5LZioJ4ECyOz7kOYY+DKb/0NN6ME=,8f41907249beb66ba4dee5df1f53c37f387506e21568cc89db4b72493b970e85 +github.com/juju/os,v0.0.0-20191022170002-da411304426c,h1:iJZl5krsl2AqkgU7IiJ2/jNAchctLFa3BiKdyOUvK+g=,b236cb3d90b3fae0f83e767feef3a17b472ab0fe238ac08810c4f9c1d683c14d +github.com/juju/proxy,v0.0.0-20180523025733-5f8741c297b4,h1:y2eoq0Uof/dWLAXRyKKGOJuF0TEkauPscQI7Q1XQqvM=,443cd58a22392e66576d883b9d04c17faebafa37a406a346b671f7e994436c34 +github.com/juju/pubsub,v0.0.0-20190419131051-c1f7536b9cc6,h1:2aARJxmMC2IF9GqVtt5PYcIy4jyuAcR44byqwXKTK0o=,b908f7985f6250270708c2c46ca0ccfc17a3705fea4a27da6f1277a9f6b5404c +github.com/juju/qthttptest,v0.0.1,h1:pR8nTl6Uo/iI6/ynQf5Cxy9FEICXzaa83NtrBdGMCVQ=,4ba292a46e27af468c181118214f7eb1bfc015f289e90841d7746b954f20ba49 +github.com/juju/ratelimit,v1.0.1,h1:+7AIFJVQ0EQgq/K9+0Krm7m530Du7tIz0METWzN0RgY=,c9af5c6719ce3b6912579a029cb2a651707aa25daa1921488f9cae9c4f8ed334 +github.com/juju/retry,v0.0.0-20180821225755-9058e192b216,h1:/eQL7EJQKFHByJe3DeE8Z36yqManj9UY5zppDoQi4FU=,c5b2437ff128cf13f2d6f3cc3b7e226f2c0119e22caed286946245150b9428e7 +github.com/juju/schema,v1.0.0,h1:sZvJ7iQXHhMw/lJ4YfUmq+fe7R2ZSUzZzd/eSokaB3M=,746bcab557bed4e05456419e5012573dc8481dc8740309100e4bd901ff282a39 +github.com/juju/testing,v0.0.0-20191001232224-ce9dec17d28b,h1:Rrp0ByJXEjhREMPGTt3aWYjoIsUGCbt21ekbeJcTWv0=,317de254f343f9aff6e1226b4ea225cab92fee84667db8e72d541667715ea610 +github.com/juju/txn,v0.0.0-20190612234757-afeb83d59782,h1:FcaMWAFKHuxS7UAaB/GuLWrqI9L7f20m6aXaxg+t5lY=,4656c1c5f0e3dac641999feba77879c7206aff1d606513d7bdb3be7d17a6635c +github.com/juju/utils,v0.0.0-20180820210520-bf9cc5bdd62d,h1:irPlN9z5VCe6BTsqVsxheCZH99OFSmqSVyTigW4mEoY=,8edd8a74c692eb717156a2bb689e1e24a446656677760dc7dc06b761ee451df5 +github.com/juju/version,v0.0.0-20180108022336-b64dbd566305,h1:lQxPJ1URr2fjsKnJRt/BxiIxjLt9IKGvS+0injMHbag=,73312c50c8b4f6f8644aaccc09b71a2235c8083cfc6c99425540f3c0a3c29e64 +github.com/juju/webbrowser,v1.0.0,h1:JLdmbFtCGY6Qf2jmS6bVaenJFGIFkdF1/BjUm76af78=,7b38f053656e4a883bc122589994e4ec34eae3f833e899450650752d5b72eec8 +github.com/juliangruber/go-intersect,v1.0.0,h1:0XNPNaEoPd7PZljVNZLk4qrRkR153Sjk2ZL1426zFQ0=,e7f539e6b13470da34009d3ab44c6ba84a6b9bb9f6e92d315551919287a25e3c +github.com/julienschmidt/httprouter,v1.3.0,h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=,e457dccd7015f340664e3b8cfd41997471382da2f4a743ee55be539abc6ca1f9 +github.com/jung-kurt/gofpdf,v1.0.3-0.20190309125859-24315acbbda5,h1:PJr+ZMXIecYc1Ey2zucXdR73SMBtgjPgwa31099IMv0=,f0fa70ade137185bbff2f016831a2a456eaadc8d14bc7bf24f0229211820c078 +github.com/justinas/alice,v0.0.0-20171023064455-03f45bd4b7da,h1:5y58+OCjoHCYB8182mpf/dEsq0vwTKPOo4zGfH0xW9A=,3d6623831901bb973db882bbaffcff3f55849724100ee72c5bf8d0fdfa927ae4 +github.com/jzelinskie/whirlpool,v0.0.0-20170603002051-c19460b8caa6,h1:RyOL4+OIUc6u5ac2LclitlZvFES6k+sg18fBMfxFUUs=,ca0115fcfaaa03f1973f65d05c6d6aefdbdeca6507cdda4359fdf55fd0be2c48 +github.com/k0kubun/colorstring,v0.0.0-20150214042306-9440f1994b88,h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM=,32a2eac0ffb69c6882b32ccfcdd76968cb9dfee9d9dc3d469fc405775399167c +github.com/k0kubun/pp,v3.0.1+incompatible,h1:3tqvf7QgUnZ5tXO6pNAZlrvHgl6DvifjDrd9g2S9Z40=,2b91f559df17a49554094e4befd7e1c7d32ba4519417b1b36796d9b49d7328c5 +github.com/kami-zh/go-capturer,v0.0.0-20171211120116-e492ea43421d,h1:cVtBfNW5XTHiKQe7jDaDBSh/EVM4XLPutLAGboIXuM0=,fb1ef7d18f4cec39e9115fb200fbf7d5cff65674afe6ecc63ad57d413f503830 +github.com/kamilsk/retry/v4,v4.3.1,h1:hNQmK1xAgybAVsadNAGvCNutFLS2h+Ycpw317u4d+i0=,74181d82f9bba5b7c313c6b338f127668fffbede70f5495a4a2ef8fddaa6c20f +github.com/kardianos/osext,v0.0.0-20190222173326-2bc1f35cddc0,h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA=,10976c39b58f218a6e29687d19763845e7650d04ac86096cd67ace58f4e56346 +github.com/karrick/godirwalk,v1.13.0,h1:GJq8GHQEAPsjwqfGhLNXBO5P0dS2HYdDRVWe+P4E/EQ=,9652ac9eb85bf13594ba9c41a86864ec5236e429a65f6bbb19c6897d1e335092 +github.com/kataras/golog,v0.0.9,h1:J7Dl82843nbKQDrQM/abbNJZvQjS6PfmkkffhOTXEpM=,bb4d1476d5cbe33088190116a5af7b355fd62858127a8ea9d30d77701279350e +github.com/kataras/iris,v11.1.1+incompatible,h1:c2iRKvKLpTYMXKdVB8YP/+A67NtZFt9kFFy+ZwBhWD0=,9aba6b1128d42ee2b63a9319e28c1b665b7e82dde1b10763ee7510bcc6427a25 +github.com/kataras/pio,v0.0.0-20190103105442-ea782b38602d,h1:V5Rs9ztEWdp58oayPq/ulmlqJJZeJP6pP79uP3qjcao=,70a50855f07ff59d96db9633a0cf729280a8b9f7af72b936fe8a28e48406432f +github.com/kavu/go_reuseport,v1.4.0,h1:YIp/96RZ3sJfn0LN+FFkkXIq3H3dfVOdRUtNejhDcxc=,b08d4f774766e1136fd256484f2584d42cd568b5edc7dbc7b19e1259b5dbb75c +github.com/kballard/go-shellquote,v0.0.0-20180428030007-95032a82bc51,h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=,ae4cb7b097dc4eb0c248dff00ed3bbf0f36984c4162ad1d615266084e58bd6cc +github.com/kellydunn/golang-geo,v0.7.0,h1:A5j0/BvNgGwY6Yb6inXQxzYwlPHc6WVZR+MrarZYNNg=,4f4699636a450e20bd107fb81894fcdcc8ceeddbac7062e9457c67326c1fb036 +github.com/kelseyhightower/envconfig,v1.4.0,h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=,af674112c38290862e5f59fc2867b81f7b0e623ec2fd1465cd3812e538b351d3 +github.com/kennygrant/sanitize,v1.2.4,h1:gN25/otpP5vAsO2djbMhF/LQX6R7+O1TB4yv8NzpJ3o=,733211913a22ff6eb5843455345fde8c0c3cff25cc5e8e8225c330fb4c6a72df +github.com/kevinburke/ssh_config,v0.0.0-20190725054713-01f96b0aa0cd,h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY=,ebd98d4bfd0deb1825d9a54689560b42a17d87385222971117ad72e7ad2f36fa +github.com/keybase/go-crypto,v0.0.0-20190403132359-d65b6b94177f,h1:Gsc9mVHLRqBjMgdQCghN9NObCcRncDqxJvBvEaIIQEo=,a839bacd8eb0a61a72f84678d568d8df899b512510a326e06db0f191e8c1c5a1 +github.com/kisielk/errcheck,v1.2.0,h1:reN85Pxc5larApoH1keMBiu2GWtPqXQ1nc9gx+jOU+E=,709eeca978804f41720a94bc69ee3cfa8277f7d15016478a3ebda86606a286c5 +github.com/kisielk/gotool,v1.0.0,h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=,089dbba6e3aa09944fdb40d72acc86694e8bdde01cfc0f40fe0248309eb80a3f +github.com/kisielk/sqlstruct,v0.0.0-20150923205031-648daed35d49,h1:o/c0aWEP/m6n61xlYW2QP4t9424qlJOsxugn5Zds2Rg=,dbff9241f676de69e88bc006004da6087576433457b306f53cb952d0313ccb78 +github.com/kisom/goutils,v1.1.0,h1:z4HEOgAnFq+e1+O4QdVsyDPatJDu5Ei/7w7DRbYjsIA=,a0b58731f8e1144c013107294885891c44b7fd3235da0ec20776f4d644b4eaa4 +github.com/kkdai/bstream,v1.0.0,h1:Se5gHwgp2VT2uHfDrkbbgbgEvV9cimLELwrPJctSjg8=,dc1d546e0df6ef040963bc9d483834d6e56c77e0e4f6c48e574ac360e7723121 +github.com/klauspost/compress,v1.8.2,h1:Bx0qjetmNjdFXASH02NSAREKpiaDwkO1DRZ3dV2KCcs=,4dc2632696a9cd93cc32c1564e1a6aa4aecfcb5c995a077d45c6f92116e1711d +github.com/klauspost/cpuid,v1.2.1,h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w=,8367d6c97e74f88b149ba9de708ff321273e0114aeb71a45e62e5ac296412420 +github.com/klauspost/crc32,v0.0.0-20161016154125-cb6bfca970f6,h1:KAZ1BW2TCmT6PRihDPpocIy1QTtsAsrx6TneU/4+CMg=,6b632853a19f039138f251f94dbbdfdb72809adc3a02da08e4301d3d48275b06 +github.com/klauspost/pgzip,v1.2.1,h1:oIPZROsWuPHpOdMVWLuJZXwgjhrW8r1yEX8UqMyeNHM=,a482336aa4b0e4e9368b15d75629ae741b44ef290b7d16430ba05ce561846213 +github.com/klauspost/reedsolomon,v1.9.2,h1:E9CMS2Pqbv+C7tsrYad4YC9MfhnMVWhMRsTi7U0UB18=,ea8a4d6d994088dae0308843fd6bddb7541cf36306463a696fd4a29097496705 +github.com/knative/pkg,v0.0.0-20191031171713-d4ce00139499,h1:ha5eqzJaPg1CZroomqWxHqspOqpqpRMO3fDtgF1fvIM=,a8d19fc2196a1aec7869ca45df44ba9c5de5b81b6094f0579d25989eb7967660 +github.com/kniren/gota,v0.9.0,h1:ywFrdNxkBD5Xypk5BxjCaKiH507oQVXIf31pTvRhC4I=,062182a345c456c9c0fd7ce9644900708f7f9c08707d64fe2438b9d295dad6dd +github.com/knq/sysutil,v0.0.0-20191005231841-15668db23d08,h1:V0an7KRw92wmJysvFvtqtKMAPmvS5O0jtB0nYo6t+gs=,81ec4ac93dba6a6161264a0575f20235d8932abab0cd6b9777b4be936f5c2af5 +github.com/knqyf263/berkeleydb,v0.0.0-20190501065933-fafe01fb9662,h1:UGS0RbPHwXJkq8tcba8OD0nvVUWLf2h7uUJznuHPPB0=,1e575b5fdc170e0318ab06841873ae6d115978fbaffc3779290d7ba3aadbdf0e +github.com/knqyf263/go-deb-version,v0.0.0-20190517075300-09fca494f03d,h1:X4cedH4Kn3JPupAwwWuo4AzYp16P0OyLO9d7OnMZc/c=,4a09d0533768cf6f9d929858aa2e79b6942685569c2db00b8d4688590a89ba3d +github.com/knqyf263/go-rpmdb,v0.0.0-20190501070121-10a1c42a10dc,h1:pumO9pqmRAjvic6oove22RGh9wDZQnj96XQjJSbSEPs=,33a3568289d22672dfcb0ba7c5b8aa7f9223d5303003368e7dbe8c9718a803b4 +github.com/knqyf263/nested,v0.0.1,h1:Sv26CegUMhjt19zqbBKntjwESdxe5hxVPSk0+AKjdUc=,c0e123844a174b1e9929d4368d8a8bb2f5ecef578ee9dee692c5971a47a633ff +github.com/koki/structurederrors,v0.0.0-20180506174113-6b997eb5e2ca,h1:KmXUVzyPjXzd3kY0feNFsWOGVDYFT4MjjgG8QJx0m6k=,1efa717c181722fd1c6807919571dc559b48d17120f5eeb4638a322fb882411a +github.com/kolo/xmlrpc,v0.0.0-20190717152603-07c4ee3fd181,h1:TrxPzApUukas24OMMVDUMlCs1XCExJtnGaDEiIAR4oQ=,9d37c94f50784536aa8ef9a7623ec7bcac9e5bc67b18f7a801efc7cbbe6b1ab0 +github.com/konsorten/go-windows-terminal-sequences,v1.0.2,h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=,4d00d71b8de60bcaf454f8f867210ebcd05e75c0a7c2725904f71aa2f20fb08e +github.com/koron/go-ssdp,v0.0.0-20180514024734-4a0ed625a78b,h1:wxtKgYHEncAU00muMD06dzLiahtGM1eouRNOzVV7tdQ=,3a99f050b7a668291942cada4e38213965fa0ae3794469bb29ad0d6d9677db23 +github.com/kr/fs,v0.1.0,h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=,d376bd98e81aea34585fc3b04bab76363e9e87cde69383964e57e9779f2af81e +github.com/kr/logfmt,v0.0.0-20140226030751-b84e30acd515,h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=,ebd95653aaca6182184a1b9b309a65d55eb4c7c833c5e790aee11efd73d4722c +github.com/kr/pretty,v0.1.0,h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=,06063d21457e06dc2aba4a5bd09771147ec3d8ab40b224f26e55c5a76089ca43 +github.com/kr/pty,v1.1.8,h1:AkaSdXYQOWeaO3neb8EM634ahkXXe3jYbVh/F9lq+GI=,d66e6fbc65e772289a7ff8c58ab2cdfb886253053b0cea11ba3ca1738b2d6bc6 +github.com/kr/text,v0.1.0,h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=,9363a4c8f1f3387a36014de51b477b831a13981fc59a5665f9d21609bea9e77c +github.com/kshvakov/clickhouse,v1.3.4,h1:p/yqvOmeDRH+KyCH6NtwExelr4rimLBBfKW2a/wBN94=,01a0d1a90e0545da94350319a52c051257fee64c838e2632ec40ef8d89a2f153 +github.com/kylelemons/go-gypsy,v0.0.0-20160905020020-08cad365cd28,h1:mkl3tvPHIuPaWsLtmHTybJeoVEW7cbePK73Ir8VtruA=,321087246482a680bd3f06de64075fb843430da544596ad216a4a63d5b8dafa3 +github.com/kylelemons/godebug,v1.1.0,h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=,dbbd0ce8c2f4932bb03704d73026b21af12bd68d5b8f4798dbf10a487a2b6d13 +github.com/kyokomi/emoji,v2.1.0+incompatible,h1:+DYU2RgpI6OHG4oQkM5KlqD3Wd3UPEsX8jamTo1Mp6o=,0721a2fc643e49e002bd8a3e604b5d2f0f3e242cc279d14d76f90a55f8aeebf7 +github.com/labbsr0x/bindman-dns-webhook,v1.0.2,h1:I7ITbmQPAVwrDdhd6dHKi+MYJTJqPCK0jE6YNBAevnk=,d1a327ab22f62486250f50f98990c0d9e1a5fdece6a496fbbb85d4e123df3244 +github.com/labbsr0x/goh,v1.0.1,h1:97aBJkDjpyBZGPbQuOK5/gHcSFbcr5aRsq3RSRJFpPk=,84c91135623961c7c400bf8b646da76c0ce2941fe8706d5aef5650be9a5e37dd +github.com/labstack/echo,v3.3.10+incompatible,h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg=,29634743cf44c47079b74812ecf5aa7074630507886c4ff40b60c397c45af524 +github.com/labstack/gommon,v0.3.0,h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=,2783ed1c24d09a5539bc35954f71f41d270d78dc656be256c98a8ede2cbbe451 +github.com/lafriks/xormstore,v1.0.0,h1:P/IJzNSIpjXl/Up3o2Td5ZU/x4v6DEKLMaPQJGtmJCk=,0e347e24ab91f62e1b69bab5d78cbba77569f087b483569ef37761e1f93a3f46 +github.com/lann/builder,v0.0.0-20180802200727-47ae307949d0,h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=,1fe7a88079ff2bbe90fb4724fb5c353ecb6af4cd7e011440354c804f678895ee +github.com/lann/ps,v0.0.0-20150810152359-62de8c46ede0,h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=,76756d46634f44edd3facdb01e7271ddf23a1b51a8423de55d3a2bf685ff032a +github.com/leanovate/gopter,v0.2.4,h1:U4YLBggDFhJdqQsG4Na2zX7joVTky9vHaj/AGEwSuXU=,99b27788411d478764bf7c51e4f6e84e5ccd60f3959a88a03e96b2a1d519a45d +github.com/leodido/go-urn,v1.2.0,h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=,8a854d784171000a69b79babb2cd3da9b8fccb1e1b6bb102c7a6d2b52380d08a +github.com/lestrrat-go/jspointer,v0.0.0-20181205001929-82fadba7561c,h1:pGh5EFIfczeDHwgMHgfwjhZzL+8/E3uZF6T7vER/W8c=,a64de11dd2840c3251906c5fe5f61719713af52a41287411007434684745af39 +github.com/lestrrat-go/jsref,v0.0.0-20181205001954-1b590508f37d,h1:1eeFdKL5ySmmYevvKv7iECIc4dTATeKTtBqP4/nXxDk=,1acee9b59501460f5063a82bc2c05f1a11cd24077198fc08ba100ee642d3db72 +github.com/lestrrat-go/jsschema,v0.0.0-20181205002244-5c81c58ffcc3,h1:TSKrrGm89gmmVlrG34ZzCIOMNVk5kkSV1P88Dt38DiE=,1b7552a5ecd193bdd07995226f58fe48de0aadedbcb42f3a5b135fd7b3538ea4 +github.com/lestrrat-go/jsval,v0.0.0-20181205002323-20277e9befc0,h1:w4rIjeCV/gQpxtn3i1voyF6Hd7v1mRGIB63F7RZOk1U=,f060af1b36e0f156546436dcc9b1569600871185d69e9daf214f24e0e2934784 +github.com/lestrrat-go/pdebug,v0.0.0-20180220043849-39f9a71bcabe,h1:S7XSBlgc/eI2v47LkPPVa+infH3FuTS4tPJbqCtJovo=,17690c72219264e0a195dac69ae6ed12bbadf309242dbaa21609339dfa74b3a5 +github.com/lestrrat-go/structinfo,v0.0.0-20190212233437-acd51874663b,h1:YUFRoeHK/mvRjBR0bBRDC7ZGygYchoQ8j1xMENlObro=,8dd77f51595dea974553558e0d249059b9047a39354548b5bbd88b32cf3df75a +github.com/lestrrat/go-jsschema,v0.0.0-20181205002244-5c81c58ffcc3,h1:UaOmzcaCH2ziMcSbQFBq/3Iuz/E/Jr/GOGtV80jpFII=,ce0f1e04d70eadcc75f96d70703b53231e1c5be7d9fd832c144e0135bfd5afb4 +github.com/lib/pq,v1.2.0,h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=,cb1028c395747cacafb6c3c6ad5fa244563ce641aae45cf7742f98b6764b1fde +github.com/libp2p/go-addr-util,v0.0.1,h1:TpTQm9cXVRVSKsYbgQ7GKc3KbbHVTnbostgGaDEP+88=,d49a37e15540c8b95f845dde6cdf802e7af490bc13fd88fec3da318d08464f7b +github.com/libp2p/go-buffer-pool,v0.0.2,h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs=,fef932705b72198df3d50befd9d2aa157aea1b5f3d23712b09d627d02cfe841e +github.com/libp2p/go-conn-security,v0.0.1,h1:4kMMrqrt9EUNCNjX1xagSJC+bq16uqjMe9lk1KBMVNs=,e7b58f887c8a8a2ed0178d2f0d6b4ad36bdd7b8cf52ca4d66bafc108b80d095c +github.com/libp2p/go-conn-security-multistream,v0.1.0,h1:aqGmto+ttL/uJgX0JtQI0tD21CIEy5eYd1Hlp0juHY0=,597b249bd51de097142815318b13c339752532f15131887492d9d3e3407ab92e +github.com/libp2p/go-eventbus,v0.1.0,h1:mlawomSAjjkk97QnYiEmHsLu7E136+2oCWSHRUvMfzQ=,1b02c8340d2740f99d67078a8c8823c6b9212b92dd9ca7eaf2a38adf2bfd6b56 +github.com/libp2p/go-flow-metrics,v0.0.1,h1:0gxuFd2GuK7IIP5pKljLwps6TvcuYgvG7Atqi3INF5s=,f783542a7fce8382de9cea6940049b106cc35f9714126a1e3d61925c29db8617 +github.com/libp2p/go-libp2p-autonat,v0.1.0,h1:aCWAu43Ri4nU0ZPO7NyLzUvvfqd0nE3dX0R/ZGYVgOU=,11e86ef0b36125a7cd6aa447ffe488f7f3ab00e441bdf8cf30a832a41da4342c +github.com/libp2p/go-libp2p-blankhost,v0.1.4,h1:I96SWjR4rK9irDHcHq3XHN6hawCRTPUADzkJacgZLvk=,9cd5abe8ad2f137c13309a9dbdd213376bbec03f9685cf8cde7fbfe2e5783e7d +github.com/libp2p/go-libp2p-circuit,v0.1.0,h1:eniLL3Y9aq/sryfyV1IAHj5rlvuyj3b7iz8tSiZpdhY=,24ee6c7851f4f0072922ae497c230718a0f44beab890d0403261b38a2946a866 +github.com/libp2p/go-libp2p-core,v0.2.4,h1:Et6ykkTwI6PU44tr8qUF9k43vP0aduMNniShAbUJJw8=,d521cc1bffba8afc8b8057901cf22c2f6ffd88faec0274426e13c4e7c12c756c +github.com/libp2p/go-libp2p-crypto,v0.1.0,h1:k9MFy+o2zGDNGsaoZl0MA3iZ75qXxr9OOoAZF+sD5OQ=,14ef1867bd8b0ef8fc528f5069ef267270dd0de8cf89a235beb9fbd79e4bed8d +github.com/libp2p/go-libp2p-discovery,v0.2.0,h1:1p3YSOq7VsgaL+xVHPi8XAmtGyas6D2J6rWBEfz/aiY=,d1c0800b601cbe6833522727b249567379422e9f324b7d0a0866bd86c74fb930 +github.com/libp2p/go-libp2p-host,v0.1.0,h1:OZwENiFm6JOK3YR5PZJxkXlJE8a5u8g4YvAUrEV2MjM=,d26bf1db299917f080a13ace37ef4363c08c2407c126cee59e642b1372d2b211 +github.com/libp2p/go-libp2p-interface-connmgr,v0.0.5,h1:KG/KNYL2tYzXAfMvQN5K1aAGTYSYUMJ1prgYa2/JI1E=,fe1e74365cc5c155161e5500671a8e9a85a90efdad9f5630bdfdc15bdfc52fe5 +github.com/libp2p/go-libp2p-interface-pnet,v0.0.1,h1:7GnzRrBTJHEsofi1ahFdPN9Si6skwXQE9UqR2S+Pkh8=,9767f78f87f54bdf3fb1f0f9b5f67e907463b445a00a566402bacca85749c8fe +github.com/libp2p/go-libp2p-loggables,v0.1.0,h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8=,351c87c02c2b147193fac5c441d8767d2b247cd3f3c420fa205da2ccd1c3f00f +github.com/libp2p/go-libp2p-metrics,v0.1.0,h1:v7YMUTHNobFaQeqaMfJJMbnK3EPlZeb6/KFm4gE9dks=,a86fe0ae6cda820fd6a0e576bcd94a22360439819f344a9121086b31c651caaf +github.com/libp2p/go-libp2p-mplex,v0.2.1,h1:E1xaJBQnbSiTHGI1gaBKmKhu1TUKkErKJnE8iGvirYI=,f11961ef5114e57eb176740a066e1535132c8c238bd444ed53d94fad36ba7708 +github.com/libp2p/go-libp2p-nat,v0.0.4,h1:+KXK324yaY701On8a0aGjTnw8467kW3ExKcqW2wwmyw=,4c3db4e0f7f714439364ca0853f63d426bba67924da6fd050fd0184abdfec2df +github.com/libp2p/go-libp2p-net,v0.1.0,h1:3t23V5cR4GXcNoFriNoZKFdUZEUDZgUkvfwkD2INvQE=,4140afd418393c2a4ecccca97d80b4752d20da6f34fac15fbdc4f0566f7b8cea +github.com/libp2p/go-libp2p-netutil,v0.1.0,h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ=,c98ad0a3ffab37b6a0bc80aefba4e4cb442b09c01277a7dcc0086c4a004e649a +github.com/libp2p/go-libp2p-peer,v0.2.0,h1:EQ8kMjaCUwt/Y5uLgjT8iY2qg0mGUT0N1zUjer50DsY=,5b400d6b6337cc759846d7ddf50ec2d761148e1447a86982696687ef1e792c1a +github.com/libp2p/go-libp2p-peerstore,v0.1.4,h1:d23fvq5oYMJ/lkkbO4oTwBp/JP+I/1m5gZJobNXCE/k=,1606c0bb56c31d0249980b8a0c0e5dda9212687b1994ef47cfd42039d4cf1847 +github.com/libp2p/go-libp2p-protocol,v0.1.0,h1:HdqhEyhg0ToCaxgMhnOmUO8snQtt/kQlcjVk3UoJU3c=,4560018136a73817e03eed49af46d97dd561b3eeffb1ff00559152acf9a74627 +github.com/libp2p/go-libp2p-pubsub,v0.2.0,h1:4UXcjpQdpam/RsGhfWyT/4u5f6F42ods/WgDAaocYxA=,bde7bb50d950b8ea7902c523a696eff4ad7b5d0daac808356358ff6d53aecb14 +github.com/libp2p/go-libp2p-record,v0.1.1,h1:ZJK2bHXYUBqObHX+rHLSNrM3M8fmJUlUHrodDPPATmY=,27a3e94e144b893cbb5ceaddfa7a4e456052e173f807db52945e06920f62d0b3 +github.com/libp2p/go-libp2p-routing,v0.1.0,h1:hFnj3WR3E2tOcKaGpyzfP4gvFZ3t8JkQmbapN0Ct+oU=,4241980dadf216e937a42a572a9c5b5eb28ff62458380ad37892c5b5095de270 +github.com/libp2p/go-libp2p-secio,v0.2.0,h1:ywzZBsWEEz2KNTn5RtzauEDq5RFEefPsttXYwAWqHng=,979a82829f3188d4ca8d20d194923c5620ff12a161d13c945c1630b7b9d050ff +github.com/libp2p/go-libp2p-swarm,v0.2.2,h1:T4hUpgEs2r371PweU3DuH7EOmBIdTBCwWs+FLcgx3bQ=,b920f69fbfaa8805047b958c6d45d944a195181dd6dddab36bead5fe68f2f1e4 +github.com/libp2p/go-libp2p-testing,v0.1.0,h1:WaFRj/t3HdMZGNZqnU2pS7pDRBmMeoDx7/HDNpeyT9U=,e1c7fa467d88b33f2fc519542cc19aa48bcade304f579f10ab402a19c38d0aa6 +github.com/libp2p/go-libp2p-transport,v0.0.5,h1:pV6+UlRxyDpASSGD+60vMvdifSCby6JkJDfi+yUMHac=,df7bc96a5d76c351fd3a6ee29995f4974013d9709904edd9608b86f4fa089ad2 +github.com/libp2p/go-libp2p-transport-upgrader,v0.1.1,h1:PZMS9lhjK9VytzMCW3tWHAXtKXmlURSc3ZdvwEcKCzw=,60ea73fa42536178798c3d4a36c5f9cffb185b6c1629c23c3faff5919f9e9cad +github.com/libp2p/go-libp2p-yamux,v0.2.1,h1:Q3XYNiKCC2vIxrvUJL+Jg1kiyeEaIDNKLjgEjo3VQdI=,849f0097fd7203b5c6d590463b7fb17573af8d12136413768706188a39b34b21 +github.com/libp2p/go-maddr-filter,v0.0.5,h1:CW3AgbMO6vUvT4kf87y4N+0P8KUl2aqLYhrGyDUbLSg=,19c76e021879aab85a8858b53d706220e9e3277a96dead161db152f5a1d17219 +github.com/libp2p/go-mplex,v0.1.0,h1:/nBTy5+1yRyY82YaO6HXQRnO5IAGsXTjEJaR3LdTPc0=,3340a423ea89310360810973a77a97c217fe7b35e1c18189a3628e35fe1275e0 +github.com/libp2p/go-msgio,v0.0.4,h1:agEFehY3zWJFUHK6SEMR7UYmk2z6kC3oeCM7ybLhguA=,ec22f703203a2a443c57896b2082c02fe9c54d372aad091cdca144709d244721 +github.com/libp2p/go-nat,v0.0.3,h1:l6fKV+p0Xa354EqQOQP+d8CivdLM4kl5GxC1hSc/UeI=,d642c9dd697176ec69c4a5faeff1fc3b5472ef9f32c2c40e21c42f81ceef86b9 +github.com/libp2p/go-openssl,v0.0.3,h1:wjlG7HvQkt4Fq4cfH33Ivpwp0omaElYEi9z26qaIkIk=,f2eb05d710fe960ba12d5f640cefe7d31d24f1fab0d9a52faf5f2923a19c6f13 +github.com/libp2p/go-reuseport,v0.0.1,h1:7PhkfH73VXfPJYKQ6JwS5I/eVcoyYi9IMNGc6FWpFLw=,274ade934c7f26ffae86d3f4d34352371c3eca7ead080392f6f35698ec5f0a3f +github.com/libp2p/go-reuseport-transport,v0.0.2,h1:WglMwyXyBu61CMkjCCtnmqNqnjib0GIEjMiHTwR/KN4=,866f45bfa6c2e65d563955a28050bcfbc6ed11df6ded7c551e92ff98ba98a2d8 +github.com/libp2p/go-stream-muxer,v0.1.0,h1:3ToDXUzx8pDC6RfuOzGsUYP5roMDthbUKRdMRRhqAqY=,d42dab9fb102b3e56cc555eb9aacb742e4230120dd356078cc723f8817200d43 +github.com/libp2p/go-stream-muxer-multistream,v0.2.0,h1:714bRJ4Zy9mdhyTLJ+ZKiROmAFwUHpeRidG+q7LTQOg=,a4ca5d0422d55ee7b4e74b040ca85799365b05684b7b6687adfa79a345049a9d +github.com/libp2p/go-tcp-transport,v0.1.1,h1:yGlqURmqgNA2fvzjSgZNlHcsd/IulAnKM8Ncu+vlqnw=,147dc8d50aab944666c1a7a371ba3e351480506313be298ebf8dcdb9dc51b1b4 +github.com/libp2p/go-testutil,v0.1.0,h1:4QhjaWGO89udplblLVpgGDOQjzFlRavZOjuEnz2rLMc=,9fa6fa5741f541a6309e8a5fa6031c51f97fcd3086fe3a3b371b74f9d8e9a4b8 +github.com/libp2p/go-ws-transport,v0.1.0,h1:F+0OvvdmPTDsVc4AjPHjV7L7Pk1B7D5QwtDcKE2oag4=,30cfd8011bb8de03c23680d2249120ea9ba29879e855ca5c35311f8fa874d094 +github.com/libp2p/go-yamux,v1.2.3,h1:xX8A36vpXb59frIzWFdEgptLMsOANMFq2K7fPRlunYI=,97947a07c9430184c3be45e87580abcdea18c9b7435adb8048b08aebce0fea50 +github.com/liggitt/tabwriter,v0.0.0-20181228230101-89fcab3d43de,h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=,41b6869255915ffdfd32575ba14d52732d62d34b47d904df4890e165489ec77d +github.com/linkedin/goavro,v2.1.0+incompatible,h1:DV2aUlj2xZiuxQyvag8Dy7zjY69ENjS66bWkSfdpddY=,25d4ccde4ece770196fbf6f09ca4184df581944224be5d64a263eb2c7f9a24fc +github.com/linode/linodego,v0.10.0,h1:AMdb82HVgY8o3mjBXJcUv9B+fnJjfDMn2rNRGbX+jvM=,4c4e8829c0290c473e36bacdce8b490833d1f6247b1a4290062db30ba2b21568 +github.com/liquidweb/liquidweb-go,v1.6.0,h1:vIj1I/Wf97fUnyirD+bi6Y63c0GiXk9nKI1+sFFl3G0=,19e08fe2aa62655eb3cb209b37d532a267dd3078e5d262c4c45e7e09134b079c +github.com/lithammer/dedent,v1.1.0,h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY=,4ec56a3fef0d7dd1536046e540827e60419a935dde49d87d21f5856174cadba2 +github.com/logrusorgru/aurora,v0.0.0-20180419164547-d694e6f975a9,h1:KQdwUNlTDGyS6e+2rjAxfHSpBFIOHXqgDceNDqb55+4=,3b9d5caeede8553ead48405de57cd25bf6276b12531dae582c3ee089474aaf95 +github.com/loov/hrtime,v0.0.0-20181214195526-37a208e8344e,h1:UC+nLCm+w3WL+ibAW/wsWbQC3KAz7LLawR2hgX0eR9s=,f077796a9f39c579d356ac8f99831c56b3b2c52b70526f97730eccdc5ce558b2 +github.com/loov/plot,v0.0.0-20180510142208-e59891ae1271,h1:51ToN6N0TDtCruf681gufYuEhO9qFHQzM3RFTS/n6XE=,eb57dc24113d92cda1d0eecd6280603a2f1a98eececde895db4b060a7208659a +github.com/lovoo/gcloud-opentracing,v0.3.0,h1:nAeKG70rIsog0TelcEtt6KU0Y1s5qXtsDLnHp0urPLU=,7bead4937d23976e07caf4bf7a7f302724cda9155aa8ac4de7baa2e10976eacc +github.com/lsegal/gucumber,v0.0.0-20180127021336-7d5c79e832a2,h1:Gg0dt1q5bB+3R3qu+BucR+1f5ZhKm3OzPPo53dZ3Hxs=,2e5cd235f8c80ae078b3115b41fb765682c796d62fa54ecbb2096b159b0294bd +github.com/lucas-clemente/aes12,v0.0.0-20171027163421-cd47fb39b79f,h1:sSeNEkJrs+0F9TUau0CgWTTNEwF23HST3Eq0A+QIx+A=,074a3c40044c8f07dbe93129fe30bfd4a12f6283f393e7300664d59924a8af2b +github.com/lucas-clemente/quic-clients,v0.1.0,h1:/P9n0nICT/GnQJkZovtBqridjxU0ao34m7DpMts79qY=,b916edbd87d45fd375b0f81f905453102eb4e7e724ca0fc8ac5be323fe5958b8 +github.com/lucas-clemente/quic-go,v0.12.1,h1:BPITli+6KnKogtTxBk2aS4okr5dUHz2LtIDAP1b8UL4=,144443ffb6231cabbe6da1496c5851eb73f03fff33d7bd94aa394f8d1e3c73b3 +github.com/lucas-clemente/quic-go-certificates,v0.0.0-20160823095156-d2f86524cced,h1:zqEC1GJZFbGZA0tRyNZqRjep92K5fujFtFsu5ZW7Aug=,d9eff929a62711fc36f9655008e144863cd816ad2b59d25eb00a248c96178ce5 +github.com/lucasb-eyer/go-colorful,v1.0.2,h1:mCMFu6PgSozg9tDNMMK3g18oJBX7oYGrC09mS6CXfO4=,c0e388db91f217be87f8d508ac9f495adc5a33ffda78849e2d0a89a8e8dae28c +github.com/lunixbochs/struc,v0.0.0-20190916212049-a5c72983bc42,h1:PzBD7QuxXSgSu61TKXxRwVGzWO5d9QZ0HxFFpndZMCg=,8a7db31161ec3a3bcc7b52e25975d0299b9c0bb465f076014d303f112b5cb9e1 +github.com/lunixbochs/vtclean,v1.0.0,h1:xu2sLAri4lGiovBDQKxl5mrXyESr3gUr5m5SM5+LVb8=,4d73f9678abde21c67dd8cb4ed8d7f63bcdd9413b6093b53cec4d26ce1be5b88 +github.com/lunny/dingtalk_webhook,v0.0.0-20171025031554-e3534c89ef96,h1:uNwtsDp7ci48vBTTxDuwcoTXz4lwtDTe7TjCQ0noaWY=,b94d4c7cacca0c289b3fbbeae6cc9e66f2eec4a3210fbbfd208316337ff2f1e3 +github.com/lunny/levelqueue,v0.0.0-20190217115915-02b525a4418e,h1:GSprKUrG9wNgwQgROvjPGXmcZrg4OLslOuZGB0uJjx8=,8f62ece23811c3c2be0d1c8d10057ab564641b2f73dc5a9910dd5f8462954f19 +github.com/lunny/log,v0.0.0-20160921050905-7887c61bf0de,h1:nyxwRdWHAVxpFcDThedEgQ07DbcRc5xgNObtbTp76fk=,0d551b83dcb0c4a3e0f97febf74e8f69b58a419791e217a7d2fd3d79a1e5877b +github.com/lunny/nodb,v0.0.0-20160621015157-fc1ef06ad4af,h1:UaWHNBdukWrSG3DRvHFR/hyfg681fceqQDYVTBncKfQ=,a0f6632294f1eec60e2651fa2d4b3590f3a1a8e2f7692dcc77251b945906a701 +github.com/lusis/go-artifactory,v0.0.0-20160115162124-7e4ce345df82,h1:wnfcqULT+N2seWf6y4yHzmi7GD2kNx4Ute0qArktD48=,487d2ef1720bd49c5a36efc8893fdb0a76bd5f8b064c2a98974a78b3e35f5763 +github.com/lusis/go-slackbot,v0.0.0-20180109053408-401027ccfef5,h1:AsEBgzv3DhuYHI/GiQh2HxvTP71HCCE9E/tzGUzGdtU=,0bb7feaeb5a4e83486234c1c8fbe2f73b94213f511aaf6b8ef1f0fc96dd7b4fa +github.com/lusis/outputter,v0.0.0-20171130132426-5a3b464a163f,h1:JY0YSH+YvMGmq83g5qILMAkJDFv7qIiHalhlQXal9V0=,e3b54ad36707730681b10a3838d89c346bf2d2c52cb61a241b178bcb0fc96e0f +github.com/lusis/slack-test,v0.0.0-20190426140909-c40012f20018,h1:MNApn+Z+fIT4NPZopPfCc1obT6aY3SVM6DOctz1A9ZU=,019aa5a65d7fc369730c089a8af985f8d4760297a0058dd0c352fb662e8a0cfc +github.com/lyft/protoc-gen-star,v0.4.11,h1:zW6fJQBtCtVeSiO/Kbpzv32GO0J/Z8egSLeohES202w=,673c0c53ce301a5589d4aab2b389c6ab52c8312193bae9b491e75e4938475277 +github.com/lyft/protoc-gen-validate,v0.1.0,h1:NytKd9K7UW7Szxn+9PYNsaJ/98TL/WsDq4ro4ZVuh5o=,2e452d4298aa5f2be8d4eda3e55522a4c020d0f23dac6b33ecf9942be09bf082 +github.com/magefile/mage,v1.4.0,h1:RI7B1CgnPAuu2O9lWszwya61RLmfL0KCdo+QyyI/Bhk=,55862155e89367536d665080ac028decc98ce68c5651ccc4238d7e34ddf1cbc2 +github.com/magiconair/properties,v1.8.1,h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=,c0f0378f5949db2e7976d6822a0dfac1786acd34190e83ab253d6505542d0128 +github.com/mailgun/mailgun-go,v0.0.0-20171127222028-17e8bd11e87c,h1:5huPh/MfWW65cx8KWNVD4mCCnwIrNiX4bFJR5OeONg0=,33250edd00795e387f2de671003b8ef8f2d940d24b12a9ce90c6b49dd6094231 +github.com/mailgun/minheap,v0.0.0-20170619185613-3dbe6c6bf55f,h1:aOqSQstfwSx9+tcM/xiKTio3IVjs7ZL2vU8kI9bI6bM=,26930b2a6dc2f2b442e28ecc5dcbb22c2e7da3d151b3388d0bc604370bd9df77 +github.com/mailgun/multibuf,v0.0.0-20150714184110-565402cd71fb,h1:m2FGM8K2LC9Zyt/7zbQNn5Uvf/YV7vFWKtoMcC7hHU8=,7dbb280e8bc981732510ee72e124e931991d06c317531de709fd7922e38a5339 +github.com/mailgun/timetools,v0.0.0-20170619190023-f3a7b8ffff47,h1:jlyJPTyctWqANbaxi/nXRrxX4WeeAGMPaHPj9XlO0Rw=,a4d961cefbfbe858f4ba5a5824d91ad8713a736707f5c259cf0d7307a07ac83e +github.com/mailgun/ttlmap,v0.0.0-20170619185759-c1c17f74874f,h1:ZZYhg16XocqSKPGNQAe0aeweNtFxuedbwwb4fSlg7h4=,35308e95ed02635049d1804b85f16407f3109fc60c38df541f0401dbba66dc8d +github.com/mailru/easyjson,v0.7.0,h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=,c36c8ab36aab9ba2ca776d1c71cbd9c30fce7c4e8e62be6611f4c2d1e98e86ae +github.com/manucorporat/sse,v0.0.0-20160126180136-ee05b128a739,h1:ykXz+pRRTibcSjG1yRhpdSHInF8yZY/mfn+Rz2Nd1rE=,cd90f350cca3a6536432afb4cd2355ff25124ef89fc23a52392e5189733b0359 +github.com/manveru/faker,v0.0.0-20171103152722-9fbc68a78c4d,h1:Zj+PHjnhRYWBK6RqCDBcAhLXoi3TzC27Zad/Vn+gnVQ=,80bc3e8ca50e89d3a6139d1709fbf4680c26231079d297d237902d3c23f4c1e8 +github.com/manveru/gobdd,v0.0.0-20131210092515-f1a17fdd710b,h1:3E44bLeN8uKYdfQqVQycPnaVviZdBLbizFhU49mtbe4=,39811c3d6c7de66195a29a78b235dead57fb866e61082301fe68d51cf04a5200 +github.com/markbates/deplist,v1.3.0,h1:uPgoloPraPBPYtNSxj2UwZBh2EHW9TmMvQCP2FBiRlU=,e0b1903fb33c324721565076e2061d7f54e29ba098afb80af4fe2ccdd02ed178 +github.com/markbates/going,v1.0.3,h1:mY45T5TvW+Xz5A6jY7lf4+NLg9D8+iuStIHyR7M8qsE=,61efe687a56d3141284be7bdb83bb5ae86e1df694ababa5937c4d3e30f3b60f1 +github.com/markbates/goth,v1.49.0,h1:qQ4Ti4WaqAxNAggOC+4s5M85sMVfMJwQn/Xkp73wfgI=,39a0244d07f47d7b91215590900a7754c4700e875c0866b1e65568133471478a +github.com/markbates/grift,v1.1.0,h1:DsljFKUSK1ELpU22ZE+Gi93jiQI3cYD/RQ+vHM/PpY8=,29aa2fa782f9d8730bde2df024c40ba749f1812dd3bbab489b4197a1faa78627 +github.com/markbates/hmax,v1.1.0,h1:MswE0ks4Iv1UAQNlvAyFpsyFQSBHolckas95gRUkka4=,8c7557798a88c74594f27137be859e99195427e2e04f0835f48781b0bde5c73a +github.com/markbates/inflect,v1.0.4,h1:5fh1gzTFhfae06u3hzHYO9xe3l3v3nW5Pwt3naLTP5g=,0da6e75f6cd27672255a41f5dfab418d2746897239ad601e5d8d78d6354b5665 +github.com/markbates/oncer,v1.0.0,h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY=,9a774885bfa4c9a96c438fdb51768833e1c7003f35cd27961137ff4096b1a764 +github.com/markbates/refresh,v1.8.0,h1:ELMS9kKyO/H6cJrqFo6qCyE0cRx2JeHWC9yusDkVeM8=,7ac81390a898cfd1cdc097ffb1e05321c415183165b7341749de41160c47e504 +github.com/markbates/safe,v1.0.1,h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI=,d5a98e8242318d4e88844ddbbfebe91f67f41e5aa1f6a96a58fa2fa94e0ae9ef +github.com/markbates/sigtx,v1.0.0,h1:y/xtkBvNPRjD4KeEplf4w9rJVSc23/xl+jXYGowTwy0=,e3b591a1a2b4dcec7b86d59e504b0bbf87ec3663efad818cd9b00471a33a0345 +github.com/markbates/willie,v1.0.9,h1:394PpHImWjScL9X2VRCDXJAcc77sHsSr3w3sOnL/DVc=,a6c3eda44d765eeb1370b0ddeb739df86e900b78eb365688da143f1c0c0e9bc0 +github.com/marstr/guid,v1.1.0,h1:/M4H/1G4avsieL6BbUwCOBzulmoeKVP5ux/3mQNnbyI=,7db3cd8020c72ba260d1a20183bf5a030c696d6442eccaff2b31f72b194fc571 +github.com/marten-seemann/qpack,v0.1.0,h1:/0M7lkda/6mus9B8u34Asqm8ZhHAAt9Ho0vniNuVSVg=,46c42087e554edae4e19f79b785722d27316e23278889bf78a0c8f43fc387f2e +github.com/marten-seemann/qtls,v0.3.2,h1:O7awy4bHEzSX/K3h+fZig3/Vo03s/RxlxgsAk9sYamI=,ff5245b3d5a1e65754d4a740e09ff02c738e9043c6e2bc02c59d5851c1fc1e2d +github.com/martini-contrib/render,v0.0.0-20150707142108-ec18f8345a11,h1:YFh+sjyJTMQSYjKwM4dFKhJPJC/wfo98tPUc17HdoYw=,2edd7f64b2f1f053f86a51856cd0f02b1f762af61a458a2e282dab76ad093d70 +github.com/martinlindhe/unit,v0.0.0-20190604142932-3b6be53d49af,h1:4bEyeobv/dO+lT1Qp1hr+/DcNjy6Ob8BDaSrxX6nQsQ=,ee5001e908fb9997e5918c909dcb0cc078f1a91719f4df3d62243d5e88dc07c6 +github.com/martinusso/go-docs,v0.0.0-20161215163720-81905d575a58,h1:VmcrkkMjTdCGOsuuMnn7P2X9dGh3meUNASx6kHIpe7A=,70ad43a3172287882f904657184af77133a578c6d1ec968c5ce3e27259100a06 +github.com/maruel/panicparse,v0.0.0-20171209025017-c0182c169410,h1:1ROIrlLvFoHKX+i48KdRauq21irSOXPyfQw4T/PrINY=,5fd98b2b0a8346ffcba1858775e93db0582ead6b3329b974595d5ab448c95f28 +github.com/maruel/ut,v1.0.0,h1:Tg5f5waOijrohsOwnMlr1bZmv+wHEbuMEacNBE8kQ7k=,a7c90a5020071c66efe2ccae7f3859c60f17840d4ae2972ee9c9a38ae071fb3e +github.com/masterzen/azure-sdk-for-go,v0.0.0-20161014135628-ee4f0065d00c,h1:FMUOnVGy8nWk1cvlMCAoftRItQGMxI0vzJ3dQjeZTCE=,de40198aee773ecaf502d59b8f29fe5d1564fb9a68900b6bfed2369e169e193a +github.com/masterzen/simplexml,v0.0.0-20190410153822-31eea3082786,h1:2ZKn+w/BJeL43sCxI2jhPLRv73oVVOjEKZjKkflyqxg=,a9e4548a5c7e098c89273c470e4e9d18cb0beb530629f2e512f6f105fd9cbc88 +github.com/masterzen/winrm,v0.0.0-20190223112901-5e5c9a7fe54b,h1:/1RFh2SLCJ+tEnT73+Fh5R2AO89sQqs8ba7o+hx1G0Y=,28f8e69baadf7f220842a5cd4269ccebdb175a835c0b43819a6b15670ae5403c +github.com/matryer/moq,v0.0.0-20190312154309-6cfb0558e1bd,h1:HvFwW+cm9bCbZ/+vuGNq7CRWXql8c0y8nGeYpqmpvmk=,b9fb2bc3d0894dfaa3cc4298f49c97346ccb66f2f0e6911f4f224ffc9acc3972 +github.com/matryer/try,v0.0.0-20161228173917-9ac251b645a2,h1:JAEbJn3j/FrhdWA9jW8B5ajsLIjeuEHLi8xE4fk997o=,f1afa36a4bd0bf09a1290f3afef954058e334d6b275aae6a591d8dad276f5e2f +github.com/mattbaird/elastigo,v0.0.0-20170123220020-2fe47fd29e4b,h1:v29yPGHhOqw7VHEnTeQFAth3SsBrmwc8JfuhNY0G34k=,f6a94deccbe4d008d265bb4b5cbaee7893e5994a82bc49b44438675a0ca8d8f3 +github.com/mattbaird/jsonpatch,v0.0.0-20171005235357-81af80346b1a,h1:+J2gw7Bw77w/fbK7wnNJJDKmw1IbWft2Ul5BzrG1Qm8=,55abaf4d26d8ad7f81c230f38a6e482b6b416d9b5777a6c3b1a5c140465a5235 +github.com/mattermost/mattermost-server,v5.11.1+incompatible,h1:LPzKY0+2Tic/ik67qIg6VrydRCgxNXZQXOeaiJ2rMBY=,1f601d79e647a248f9e711891e015b1709f3af37e6a45d5e97827f074c40398e +github.com/mattn/go-colorable,v0.1.4,h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=,02ad42bc54adf7c52030b6ab903277af8fb7163aad4f7f8d8703ecfdc62597de +github.com/mattn/go-ieproxy,v0.0.0-20190805055040-f9202b1cfdeb,h1:hXqqXzQtJbENrsb+rsIqkVqcg4FUJL0SQFGw08Dgivw=,5914c18852b0be63008f7ccaf1bd3a8214a82fae78f8afe2e7d774ff96a410ff +github.com/mattn/go-isatty,v0.0.10,h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=,dca893515dccb58e21f9b08837470c5512e0ecd1275767ed996912bb46933c91 +github.com/mattn/go-mastodon,v0.0.5-0.20190517015615-8f6192e26b66,h1:TbnaLJhq+sFuqZ1wxdfF5Uk7A2J41iOobCCFnLI+RPE=,b290b77b6e5556bba70cf18ac815c13ed9a80ffa4cb03627d73187e99cd15d42 +github.com/mattn/go-oci8,v0.0.0-20190320171441-14ba190cf52d,h1:m+dSK37rFf2fqppZhg15yI2IwC9BtucBiRwSDm9VL8g=,eb3bd1fa93c8a341ad43176cb6e4d8540d7a91d3edd7eb98c1388cf2f4c3515c +github.com/mattn/go-runewidth,v0.0.5,h1:jrGtp51JOKTWgvLFzfG6OtZOJcK2sEnzc/U+zw7TtbA=,3b34033634b059bfa31ac552d2150d8c0d6e530dd1c0ead2ce0806e1d7cc754a +github.com/mattn/go-shellwords,v1.0.6,h1:9Jok5pILi5S1MnDirGVTufYGtksUs/V2BWUP3ZkeUUI=,374285b205f0659ab4be3f8ce346cfd3291cd42f47b12bda15174c42c462b1a6 +github.com/mattn/go-sqlite3,v1.11.0,h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q=,7fec79c50206f5faa759d1b64500fb0d082e22ef23f10e2d4cbce24e4fc2d5c1 +github.com/mattn/go-tty,v0.0.0-20190424173100-523744f04859,h1:smQbSzmT3EHl4EUwtFwFGmGIpiYgIiiPeVv1uguIQEE=,76f28f59927667d2d750fa6ffdefeb3f0c41034cb593e4545a206995c76c619f +github.com/mattn/go-xmpp,v0.0.0-20190124093244-6093f50721ed,h1:A1hEQg5M0b3Wg06pm3q/B0wdZsPjVQ/a2IgauQ8wCZo=,2c39b78184ea27890be56f593353c8fe6b3d6efa53db20e800ff8793bc665199 +github.com/mattn/go-zglob,v0.0.1,h1:xsEx/XUoVlI6yXjqBK062zYhRTZltCNmYPx6v+8DNaY=,8decd6c1916188ab4fa1001e3da3f22d7c9fb6218215fd25053c901979930feb +github.com/mattn/goveralls,v0.0.2,h1:7eJB6EqsPhRVxvwEXGnqdO2sJI0PTsrWoTMXEk9/OQc=,3df5b7ebfb61edd9a098895aae7009a927a2fe91f73f38f48467a7b9e6c006f7 +github.com/matttproud/golang_protobuf_extensions,v1.0.1,h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=,e64dc58023f4b8c4472d05a44f2719b84d6c2cc364cc682820c9f72b233c9cdc +github.com/maxbrunsfeld/counterfeiter/v6,v6.2.2,h1:g+4J5sZg6osfvEfkRZxJ1em0VT95/UOZgi/l7zi1/oE=,c185793a7e749ff2557f4557628f5b5d8d9edbf72ca6bd2cb94503f4817c01d2 +github.com/mcuadros/go-version,v0.0.0-20190830083331-035f6764e8d2,h1:YocNLcTBdEdvY3iDK6jfWXvEaM5OCKkjxPKoJRdB3Gg=,ff2364bda8605ad94051c576ffa601e1a9aedabc8a1fda588eb04c3371a845ea +github.com/mdlayher/dhcp6,v0.0.0-20190311162359-2a67805d7d0b,h1:r12blE3QRYlW1WBiBEe007O6NrTb/P54OjR5d4WLEGk=,fba7b2f01311e2d41bb4ebe15409d4e0a605a79d2f05156bb0f4adbc20f557bc +github.com/mdlayher/netlink,v0.0.0-20191009155606-de872b0d824b,h1:W3er9pI7mt2gOqOWzwvx20iJ8Akiqz1mUMTxU6wdvl8=,9be201b393fe866f855e5ebb20ef33e86a0e6a99b6b76209531b93615fcbac7c +github.com/mesos/mesos-go,v0.0.10,h1:+M/7Zlkvw4MolkLvXHfj6hkDsLLHOOU54CmOkOUaNBc=,f18d5601dc6a5234b9c2d65cb96b8d30ab877e3117dd52dd47e31a353ed887d1 +github.com/mgutz/ansi,v0.0.0-20170206155736-9520e82c474b,h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=,d7c0ff88c53dfca384bb82108a6e5fdc9e11b358d68b67144ff6a285be20a16a +github.com/mgutz/logxi,v0.0.0-20161027140823-aebf8a7d67ab,h1:n8cgpHzJ5+EDyDri2s/GC7a9+qK3/YEGnBsd0uS/8PY=,0a7837d5246591fe1fd341e48a72786c0b61fff8d3ebfea0e9c789176c3e75d5 +github.com/mgutz/str,v1.2.0,h1:4IzWSdIz9qPQWLfKZ0rJcV0jcUDpxvP4JVZ4GXQyvSw=,bf640c2048957f183e72664ff08745ae3d016f64072a5967f5269ccb5fc4b318 +github.com/mholt/archiver,v3.1.1+incompatible,h1:1dCVxuqs0dJseYEhi5pl7MYPH9zDa1wBi7mF09cbNkU=,6cbad83ecd8a2bcb013fb1ac163a6551e6f948b103df9b258788612c72551184 +github.com/mholt/certmagic,v0.7.5,h1:1ZGHwUI4+zg1S17tPUj5Xxb9Q1ghTjLcUZE5G4yV5SM=,a85c14ecbb135636c8e4701a25b8d2884f091d948269c0a3187918af83e11db3 +github.com/michaelklishin/rabbit-hole,v1.5.0,h1:Bex27BiFDsijCM9D0ezSHqyy0kehpYHuNKaPqq/a4RM=,1fdb62e985c4b1be24632875668720ed687455ece54cb2c77079488784e06e69 +github.com/micro-plat/gmq,v1.0.1,h1:ai1PiCEfgBmiqzmZ4iWE3l2Vuz7rOTWOakqRWqi/Hgo=,63c4a02b87b31c0f5cfcdfee5df2fa05e77eeaa2aab93b0ef217c57f6b37b38a +github.com/micro-plat/lib4go,v0.2.1,h1:NBTIq0DvpRzTChnYShBagPmsYM4k1NgvkE8OYhgMDt8=,ae1056cc76eee3fccb14b0d8723b6444d8f31d2575a0caa1d3723bc54b91496b +github.com/micro/cli,v0.2.0,h1:ut3rV5JWqZjsXIa2MvGF+qMUP8DAUTvHX9Br5gO4afA=,09e532e4616aa7827d1a1f249bc80ebb01fe8c63978f4b14605246c6be596b82 +github.com/micro/go-log,v0.1.0,h1:szYSR+yyTsomZM2jyinJC5562DlqffSjHmTZFaeZ2vY=,5ec9ba1cfb781edd3695dc9c28afb520cced5e1cf7eabb5faafd4bd8db6953ea +github.com/micro/go-micro,v1.14.0,h1:lptn9DBbsNCB3RC3PMwxTJGqCUgU8Rf23nAMaRuOcOA=,2278cfa86f7bf97df81ea79535127cf87bf03aba29e7603f2feeb48b2d1a3334 +github.com/micro/go-rcache,v0.2.0,h1:g51QJW+lj+dAOXwRlYNZPQQ8ueHLptgoUzZE3iRwJMg=,fa96add40dac8fb14cf08f7a8c96d05c902da40b27b2c4e586cf3304e4ef6533 +github.com/micro/h2c,v1.0.0,h1:ejw6MS5+WaUoMHRtqkVCCrrVzLMzOFEH52rEyd8Fl2I=,6fea0303cbaa2bc6c45098ce5ad0ae2aa7f9c54ce2ff90160549756f8c7a2b07 +github.com/micro/mdns,v0.3.0,h1:bYycYe+98AXR3s8Nq5qvt6C573uFTDPIYzJemWON0QE=,a40ecbd32a2170698f0f49f8961b39e88e7c3e958546a401a59653231b51f1b2 +github.com/micro/micro,v1.14.0,h1:Uol1+Yg5frzneACpzoHEDsyNTN+/+yLrlGMuxR3RVRQ=,0fd330788ad610cc2cb3eb2224f1ca403d9888ad40e78628f250c885373d739c +github.com/micro/util,v0.2.0,h1:6u0cPj1TeixEk5cAR9jbcVRUWDQsmCaZvDBiM3zFZuA=,3e61d5232a3a91d521ade483ab64b53a7b8760d0635978d72b4920eba52f8f79 +github.com/microcosm-cc/bluemonday,v1.0.2,h1:5lPfLTTAvAbtS0VqT+94yOtFnGfUWYyx0+iToC3Os3s=,9cfac37098da75ab1c278740e8f0f7741891d8843e14afb256574596ad786f83 +github.com/miekg/dns,v1.1.22,h1:Jm64b3bO9kP43ddLjL2EY3Io6bmy1qGb9Xxz6TqS6rc=,54f1f62de314150df163bbe1de91acc922cdce70c5c8a43dfeb7f4af24711d38 +github.com/miekg/mmark,v1.3.6,h1:t47x5vThdwgLJzofNsbsAl7gmIiJ7kbDQN5BxwBmwvY=,8d1b05ee1c0a28093c678af2ed9d0aac9dfc30dce728ccd21fe1506762b54cee +github.com/mindprince/gonvml,v0.0.0-20190828220739-9ebdce4bb989,h1:PS1dLCGtD8bb9RPKJrc8bS7qHL6JnW1CZvwzH9dPoUs=,6702f94187c4e2994ffbdc318c94a04d4bc67081a402e968a2c362a74c81263f +github.com/minio/blake2b-simd,v0.0.0-20160723061019-3f5f724cb5b1,h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g=,ab10edfe994b513e2d03cdd8122b352f31a1eb246fe884617b3f2f6195a3ca0c +github.com/minio/cli,v1.22.0,h1:VTQm7lmXm3quxO917X3p+el1l0Ca5X3S4PM2ruUYO68=,33533a4e0a2b1a698d0f899cb5b84d9fc199e7723b971d1408e4b5ee797c9a50 +github.com/minio/dsync,v0.0.0-20180124070302-439a0961af70,h1:pRHQdPOlUhelWqNUF3icFrBSC6VYH1hvF6HigVfgMoI=,850e5b400afc4301a1860debf934c5e8e67565d4937ac45f9a37132b31a09941 +github.com/minio/highwayhash,v0.0.0-20180501080913-85fc8a2dacad,h1:L+8skVz2lusCbtlalLXmJp+TK8XaGAsZ3utSC3k5Jc0=,7393dfe736668f9ab98fcf2d264f9bd20bbf4f98538f02ff15df9604f747cdb1 +github.com/minio/lsync,v0.0.0-20180328070428-f332c3883f63,h1:utJHim4C0K4CmD+Qgod/tgHvo7QNOlH6HN5O8QUvPEI=,417c4bdd4fc5d50da2d81e8890b03af4b80ce9fbd5e4c196731a3d76a09913c1 +github.com/minio/mc,v0.0.0-20180926130011-a215fbb71884,h1:co3kRW9cEI65yolYtcLcNxp2a9yk5T/eEt7gw14tJVs=,37300de5179e1085559c6f317b331d261cc4508ba0e4febbd93cbbfef42d7fc9 +github.com/minio/minio,v0.0.0-20180508161510-54cd29b51c38,h1:F7p0ZU9AQuxlA6SWwhXr0H/rYrA9fOiBk2OzOj7GtfM=,6421e5cf72b35a2948e5edd2b189f37ad1896b8637d5b9bcf7cd40b7ab63dfd4 +github.com/minio/minio-go,v6.0.14+incompatible,h1:fnV+GD28LeqdN6vT2XdGKW8Qe/IfjJDswNVuni6km9o=,3bc396d5e1c0c6f3497743140eaf16ebb97c5f1ca815ba12c4f431e804fb737d +github.com/minio/minio-go/v6,v6.0.27-0.20190529152532-de69c0e465ed,h1:g3DRJpu22jEjs14fSeJ7Crn9vdreiRsn4RtrEsXH/6A=,34d85b6b915ef5876f9c262f260583fabec147c37dcb82e1f42374dd088b9096 +github.com/minio/sha256-simd,v0.1.1,h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=,0ecfa6532265e139d5d9406c0a803c7ef45b1d8d0f0c1b1d55f7b81969294bfc +github.com/minio/sio,v0.0.0-20180327104954-6a41828a60f0,h1:ys4bbOlPvaUBlA0byjm6TqydsXZu614ZIUTfF+4MRY0=,6c46bc4a68353d7b41f6e91eb276c9b21560cad4f75419baaee01764927fb7e8 +github.com/mistifyio/go-zfs,v2.1.1+incompatible,h1:gAMO1HM9xBRONLHHYnu5iFsOJUiJdNZo6oqSENd4eW8=,545764e34ed40473380ea1b08af9f0aea1715d15a0a56fc937e6c3b1bda0d9a3 +github.com/mitchellh/cli,v1.0.0,h1:iGBIsUe3+HZ/AD/Vd7DErOt5sU9fa8Uj7A2s1aggv1Y=,74199f2c2e1735a45e9f5c2ca049d352b0cc73d945823540e54ca9975ce35752 +github.com/mitchellh/colorstring,v0.0.0-20190213212951-d06e56a500db,h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=,d0733284b20567055e374b420373f5508fa47e95204e59e4b8a66834e7e3964d +github.com/mitchellh/copystructure,v1.0.0,h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=,4a2c9eb367a7781864e8edbd3b11781897766bcf6120f77a717d54a575392eee +github.com/mitchellh/go-fs,v0.0.0-20180402234041-7b48fa161ea7,h1:PXPMDtfqV+rZJshQHOiwUFqlqErXaAcuWy+/ZmyRfNc=,21c34fee3df3dc1ddad5e774ddf9e05998061177420709fb68a958c6c113a90b +github.com/mitchellh/go-homedir,v1.1.0,h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=,fffec361fc7e776bb71433560c285ee2982d2c140b8f5bfba0db6033c0ade184 +github.com/mitchellh/go-linereader,v0.0.0-20190213213312-1b945b3263eb,h1:GRiLv4rgyqjqzxbhJke65IYUf4NCOOvrPOJbV/sPxkM=,7b83ef857c71fe8d4937b57923923176dd43c7b1b7632a9779bac411924e87e1 +github.com/mitchellh/go-ps,v0.0.0-20190716172923-621e5597135b,h1:9+ke9YJ9KGWw5ANXK6ozjoK47uI3uNbXv4YVINBnGm8=,06090b6c22dedf800259eb5d9b5f35bfb7b38e22888c0345631dc54366b21f89 +github.com/mitchellh/go-testing-interface,v1.0.0,h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=,255871a399420cd3513b12f50738d290e251637deb23e21a4332192584ecf9c7 +github.com/mitchellh/go-vnc,v0.0.0-20150629162542-723ed9867aed,h1:FI2NIv6fpef6BQl2u3IZX/Cj20tfypRF4yd+uaHOMtI=,2d65ac584e1a17421265fe97f83bd1cbff447ca6a911fa8d91414fa2115e3e74 +github.com/mitchellh/go-wordwrap,v1.0.0,h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=,9ea185f97dfe616da351b63b229a5a212b14ac0e23bd3f943e39590eadb38031 +github.com/mitchellh/gox,v1.0.1,h1:x0jD3dcHk9a9xPSDN6YEL4xL6Qz0dvNYm8yZqui5chI=,30a69e17ba5cafe6f1ac436bcc99368a5a34f0a0763926d2c6780a781f8e9e95 +github.com/mitchellh/hashstructure,v1.0.0,h1:ZkRJX1CyOoTkar7p/mLS5TZU4nJ1Rn/F8u9dGS02Q3Y=,3b79b07860631d05645ea3f54830b7e1997dbcf477e84a8adfe4979be3abdfde +github.com/mitchellh/iochan,v1.0.0,h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY=,f3eede01adb24c22945bf71b4f84ae25e3744a12b9d8bd7c016705adc0d778b8 +github.com/mitchellh/mapstructure,v1.1.2,h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=,cd86d8586cbc333de28f6a46989069487877fae437df4c2cc417668d203c7305 +github.com/mitchellh/panicwrap,v0.0.0-20190213213626-17011010aaa4,h1:jw9tsdJ1FQmUkyTXdIF/nByTX+mMnnp16glnvGZMsC4=,b9ab07bbacf733cc24f9f7f53eec19f9bf999cbb35180ad0b615fe437640de6e +github.com/mitchellh/pointerstructure,v0.0.0-20190430161007-f252a8fd71c8,h1:1CO5wil3HuiVLrUQ2ovSTO+6AfNOA5EMkHHVyHE9IwA=,658a3e14e4983f3c8a04c8da4a56d4d8a86e2b4fcaa6b1eefab150efcd742848 +github.com/mitchellh/prefixedio,v0.0.0-20190213213902-5733675afd51,h1:eD92Am0Qf3rqhsOeA1zwBHSfRkoHrt4o6uORamdmJP8=,d3209d88b3b5b05ecd48f469bc16811666f786685c49273664a5496d5dd69018 +github.com/mitchellh/reflectwalk,v1.0.1,h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE=,bf1d4540bf05ea244e65fca3e9f859d8129c381adaeebe7f22703959aadc4210 +github.com/mjibson/esc,v0.2.0,h1:k96hdaR9Z+nMcnDwNrOvhdBqtjyMrbVyxLpsRCdP2mA=,9f090786bd43dddb5c0d798b449d5e8aede4cb7d106f56dcac0aebd8fd1929cc +github.com/mndrix/ps,v0.0.0-20131111202200-33ddf69629c1,h1:kCroTjOY+wyp+iHA2lZOV5aJ6WfBVjGnW8bCYmXmLPo=,30b12b7a2467d4a1aa64aa31c715cb45d570d36e31ae70719101d686363d2685 +github.com/mndrix/tap-go,v0.0.0-20171203230836-629fa407e90b,h1:Ga1nclDSe8gOw37MVLMhfu2QKWtD6gvtQ298zsKVh8g=,c6f65bd8d977e53fa083d9d0309cffb0dbfaaae69a5a64a352fb2f7d079ce73d +github.com/modern-go/concurrent,v0.0.0-20180306012644-bacd9c7ef1dd,h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=,91ef49599bec459869d94ff3dec128871ab66bd2dfa61041f1e1169f9b4a8073 +github.com/modern-go/reflect2,v1.0.1,h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=,6af8268206d037428a4197bd421bbe5399c19450ef53ae8309a083f34fb7ac05 +github.com/mohae/deepcopy,v0.0.0-20170929034955-c48cc78d4826,h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=,41ba726508a213f4af89e7d58937263ff778e352d591edd422d3a3dc3272585c +github.com/mongodb/grip,v0.0.0-20191008181606-ee248dc03622,h1:pPoJByX3B56ydhWGUMard1QQ2skLNTw/s1W5VuLLAtA=,08fcfea928382f428dc1fceeada1c264e7f6dc7256dbe05c5c0ba41dca16a42c +github.com/monoculum/formam,v0.0.0-20190830100315-7ff9597b1407,h1:ZU5O9BawmEx9Mu1lxn9NLIwO9DrqRfjE+HWKU+e9GKQ=,5a04e3907fb1008c1e6640e8a0e9394c752aab4ebf7e3be01cd3ee55c2659121 +github.com/montanaflynn/stats,v0.5.0,h1:2EkzeTSqBB4V4bJwWrt5gIIrZmpJBcoIRGS2kWLgzmk=,05527945351f54f4e8c48666bce277fbace34026eed22ac7d88a50a6730767f1 +github.com/morikuni/aec,v1.0.0,h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=,c14eeff6945b854edd8b91a83ac760fbd95068f33dc17d102c18f2e8e86bcced +github.com/moul/anonuuid,v0.0.0-20160222162117-609b752a95ef,h1:E/seV1Rtsnr2juBw1Dfz4iDPT3/5s1H/BATx+ePmSyo=,ec103e75b93231b5b858a2fc9985da39d6b7c35644a689a20e60f3a6ad6b1396 +github.com/moul/gotty-client,v0.0.0-20180327180212-b26a57ebc215,h1:y6FZWUBBt1iPmJyGbGza3ncvVBMKzgd32oFChRZR7Do=,265c4cbad4789e267f283b9012ad174c89e378e59ad9c64ac28729402eb60afe +github.com/moul/http2curl,v0.0.0-20161031194548-4e24498b31db,h1:eZgFHVkk9uOTaOQLC6tgjkzdp7Ays8eEVecBcfHZlJQ=,2ff4e19b14d84f6d181afc79f28668c6171d6dea79c43a1918c0428a265137c1 +github.com/mozilla-services/heka,v0.10.0,h1:w+y6RPJkU6ZKeNbG1VvK9aSqJm0sru5TYcwOj6ejv8U=,f325891304f9acc654944d9a2297b8816a0a86440b2f035c4996ec38fcfa0eed +github.com/mozillazg/go-cos,v0.12.0,h1:b9hUd5HjrDe10BUfkyiLYI1+z4M2kAgKasktszx9pO4=,5376eaf13e10fed6d73b713fbabc4a159d204239579120c410ea74de33dd6d71 +github.com/mozillazg/go-httpheader,v0.2.1,h1:geV7TrjbL8KXSyvghnFm+NyTux/hxwueTSrwhe88TQQ=,50b7a36360fc1ec1a85fd40fe45f8db02fc734fc2af0514a60a068f0a2708122 +github.com/mozillazg/go-unidecode,v0.1.1,h1:uiRy1s4TUqLbcROUrnCN/V85Jlli2AmDF6EeAXOeMHE=,812d3bc9f03cb6a8552bfadd9e0d1b44a57807a3af2e8667a42861510bb2b20c +github.com/mpvl/unique,v0.0.0-20150818121801-cbe035fff7de,h1:D5x39vF5KCwKQaw+OC9ZPiLVHXz3UFw2+psEX+gYcto=,af2bcc8a61a6881e0703afee2217dd1e75c8b34f4e49947c0d7f6e87af574e0e +github.com/mr-tron/base58,v1.1.2,h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78=,c2b362db55d8266ce02a161b7f73cad646432d2dae98511385b88481380c4e86 +github.com/mreiferson/go-httpclient,v0.0.0-20160630210159-31f0106b4474,h1:oKIteTqeSpenyTrOVj5zkiyCaflLa8B+CD0324otT+o=,e94cbe43c052831323c59ff186c830ea2e271065f7f8b2794ade7aaf88a37a85 +github.com/mrjones/oauth,v0.0.0-20180629183705-f4e24b6d100c,h1:3wkDRdxK92dF+c1ke2dtj7ZzemFWBHB9plnJOtlwdFA=,4c1fef02b34241008ba6bc33fb5d01b4cfb3b7e7544fb7f70823fe74b9b21362 +github.com/mrunalp/fileutils,v0.0.0-20171103030105-7d4729fb3618,h1:7InQ7/zrOh6SlFjaXFubv0xX0HsuC9qJsdqm7bNQpYM=,c32d691ce15012ba21fbe69db3558df0c97326426c14ef747b8a1e02652ca7b3 +github.com/mschoch/smat,v0.0.0-20160514031455-90eadee771ae,h1:VeRdUYdCw49yizlSbMEn2SZ+gT+3IUKx8BqxyQdz+BY=,488e193897c7d8e3b3758cbeb8a5bc1b58b9619f3f14288a2ea9e0baa5ed9b3e +github.com/msteinert/pam,v0.0.0-20151204160544-02ccfbfaf0cc,h1:z1PgdCCmYYVL0BoJTUgmAq1p7ca8fzYIPsNyfsN3xAU=,315d911c41d88a22bf8831b174bbd15310bc403626507095f98b9780ddcf9174 +github.com/muesli/smartcrop,v0.0.0-20180228075044-f6ebaa786a12,h1:l0X/8IDy2UoK+oXcQFMRSIOcyuYb5iEPytPGplnM41Y=,5857e4d0ed238d8c6f8f41294b98771f1c21874a80ea5f2e75b4a49cbcf1d3e0 +github.com/multiformats/go-base32,v0.0.3,h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI=,658875e4980370db6180f99835b3a48158a697eef69e7c3eb86b0b4f5c1c19ed +github.com/multiformats/go-multiaddr,v0.1.1,h1:rVAztJYMhCQ7vEFr8FvxW3mS+HF2eY/oPbOMeS0ZDnE=,ba4849fc68453c3e812e850f40e6d5acef671060ed79f203c2d179d395d20fc5 +github.com/multiformats/go-multiaddr-dns,v0.0.2,h1:/Bbsgsy3R6e3jf2qBahzNHzww6usYaZ0NhNH3sqdFS8=,219f855f485aa198d36305f2f43012a73bd40f15caa3e606324cee9f117e5b89 +github.com/multiformats/go-multiaddr-fmt,v0.1.0,h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E=,d83537dc1f83185dfb60b190ea4b3c7b05c552a75ad7cfaddd0b987c00ff0cff +github.com/multiformats/go-multiaddr-net,v0.1.1,h1:jFFKUuXTXv+3ARyHZi3XUqQO+YWMKgBdhEvuGRfnL6s=,241c47d621bcb9a40d33284f407a7fdf458cb3f87ef02db68735cc6b9002afed +github.com/multiformats/go-multibase,v0.0.1,h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA=,ed39145efcf5e8c99deaa183071aed246239730f5781b291bad7de5d1fc12d81 +github.com/multiformats/go-multihash,v0.0.8,h1:wrYcW5yxSi3dU07n5jnuS5PrNwyHy0zRHGVoUugWvXg=,44fae6e8771331f54f267d9440a9d520e7daeb91817ff61e26b8494099ae046a +github.com/multiformats/go-multistream,v0.1.0,h1:UpO6jrsjqs46mqAK3n6wKRYFhugss9ArzbyUzU+4wkQ=,f720be6e29845f0a41c1241a24f19c08adf762f9e7e972b4096416776c603b15 +github.com/munnerz/goautoneg,v0.0.0-20191010083416-a7dc8b61c822,h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=,3d7ce17916779890be02ea6b3dd6345c3c30c1df502ad9d8b5b9b310e636afd9 +github.com/mwitkow/go-conntrack,v0.0.0-20190716064945-2f068394615f,h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=,d6fc513490d5c73e3f64ede3cf18ba973a4f8ef4c39c9816cc6080e39c8c480a +github.com/mwitkow/go-grpc-middleware,v1.0.0,h1:XraEe8LhUuB33YeV4NWfLh2KUZicskSZ2lMhVRnDvTQ=,074f46f92d7a0043c5b283f1af224123cc48e21f96b259e62f77b6da72240812 +github.com/mxk/go-flowrate,v0.0.0-20140419014527-cca7078d478f,h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=,bd0701ef9115469a661c07a3e9c2e572114126eb2d098b01eda34ebf62548492 +github.com/myesui/uuid,v1.0.0,h1:xCBmH4l5KuvLYc5L7AS7SZg9/jKdIFubM7OVoLqaQUI=,3055c4b167daeb9984ccd7c8eeba154e3d84afa6fdf06a3151280ef120d1633d +github.com/myitcv/gobin,v0.0.8,h1:hQORun03Mlnm8yp/OgKX8UYSIVZQ8ebTWf3aahY1u+s=,015311e9db646cb9e5f63a0586c466c9eb5bc5f45661282644f8a5b549607e72 +github.com/myitcv/vbash,v0.0.2,h1:8R+91eSlfcgoRjEbnUgvbXYOmfh+p0+7i5klFOM5VMA=,08dcf62b94843e7fd115cd0605158d948fb361ca8c958db1958c5d2feef9c2d1 +github.com/namedotcom/go,v0.0.0-20180403034216-08470befbe04,h1:o6uBwrhM5C8Ll3MAAxrQxRHEu7FkapwTuI2WmL1rw4g=,0c6ea2c994e982c25e44ccba2ead1a9655cd2f253986eedb73253c30ad21b42f +github.com/naoina/go-stringutil,v0.1.0,h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hzifhks=,4cfea6f0ebfecb5e6297f8a6eee0e9ef9fe254883eb75dd6179133995a219c58 +github.com/naoina/toml,v0.1.1,h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8=,8e34d510563d9e8b3f2dbdf0927bf5108b669144bdbe2fda4fcb44e7e2e55268 +github.com/natefinch/lumberjack,v2.0.0+incompatible,h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM=,1f6e7c9e0b915c45151d8780a8711426b19d16d04c9cf0e7995b29035d6b500f +github.com/nats-io/gnatsd,v1.3.0,h1:+5d80klu3QaJgNbdavVBjWJP7cHd11U2CLnRTFM9ICI=,85fa90b3eaef17698734d398a9939b8bb94df1b9f35bc92c8d31cb7a349c1e97 +github.com/nats-io/go-nats,v1.6.0,h1:FznPwMfrVwGnSCh7JTXyJDRW0TIkD4Tr+M1LPJt9T70=,8c63be6f10479802a40c66c0999f724e492bcb9863d5517038c6472e585a76aa +github.com/nats-io/go-nats-streaming,v0.4.2,h1:e7Fs4yxvFTs8N5xKFoJyw0sVW2heJwYvrUWfdf9VQlE=,62dd1d6ba18f3b7686766116e3beaaf9f62b89b58a6efb0b8f1ad04d3ddfb026 +github.com/nats-io/jwt,v0.3.0,h1:xdnzwFETV++jNc4W1mw//qFyJGb2ABOombmZJQS4+Qo=,e131314c7cf6a714ec10ca3b6f95f8af6a41f5cdaf72a364f7c71b33e97314db +github.com/nats-io/nats,v1.6.0,h1:U5b2apHOTZlUou+NGfCRWG4ZEeivbt2hpsZO4kHKIVU=,12cc70ed3477472d110d4b4bc109fbe20218e8199629669ad5f617c199fbf9d2 +github.com/nats-io/nats-server/v2,v2.1.0,h1:Yi0+ZhRPtPAGeIxFn5erIeJIV9wXA+JznfSxK621Fbk=,a5897b8f5302ae38894de2c240f31d33ab7b2f3d4e88a2c212fc9b31f2d4f444 +github.com/nats-io/nats-streaming-server,v0.12.2,h1:EpyLfUBZgwu5c0mdSSytQsapm615AyitPssq7jgafdw=,48605f61f74903ba1322f11aa17806b57f71cebf2557b7dd8620d4193abc868d +github.com/nats-io/nats.go,v1.9.1,h1:ik3HbLhZ0YABLto7iX80pZLPw/6dx3T+++MZJwLnMrQ=,34a735d158d70685faad1fc3153f08da0ddc21c0ae42f6a0cb09430d638364b2 +github.com/nats-io/nkeys,v0.1.0,h1:qMd4+pRHgdr1nAClu+2h/2a5F2TmKcCzjCDazVgRoX4=,dbc82abacf752e532ffd67db230a97f52a5f92070b04b4028cb79534d2ab0ef6 +github.com/nats-io/nuid,v1.0.1,h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=,809d144fbd16f91651a433e28d2008d339e19dafc450c5995e2ed92f1c17c1f3 +github.com/nats-io/stan.go,v0.5.0,h1:ZaSPMb6jnDXsSlOACynJrUiB3Evleg3ZyyX+rnf3TlQ=,1dcb14e2ef8ad30dd1ee61a63b0a3bfbaa48e9c3d13f69458a149956a14bbab7 +github.com/nbio/st,v0.0.0-20140626010706-e9e8d9816f32,h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4=,e6cd27bd360be27d0f7efd3c4c41c4e14e659e60086b0bc4f09fb09cfd02a50d +github.com/ncw/swift,v1.0.49,h1:eQaKIjSt/PXLKfYgzg01nevmO+CMXfXGRhB1gOhDs7E=,b2be24cad8923c9171835547df2d621d2aa2029ceb9fa770d6ecf3bf70c2c029 +github.com/neelance/astrewrite,v0.0.0-20160511093645-99348263ae86,h1:D6paGObi5Wud7xg83MaEFyjxQB1W5bz5d0IFppr+ymk=,815811c2140669e55e99d59d4bdd2fcf4c810610a9d278fd25cc2c3480c002d4 +github.com/neelance/sourcemap,v0.0.0-20151028013722-8c68805598ab,h1:eFXv9Nu1lGbrNbj619aWwZfVF5HBrm9Plte8aNptuTI=,ce5499f29779a604233bb76f36925c3326a8a8f270533df8d3dff1107b7aa066 +github.com/neurosnap/sentences,v1.0.6,h1:iBVUivNtlwGkYsJblWV8GGVFmXzZzak907Ci8aA0VTE=,9dbe86e291937eba92847454650d1c65338527ff89dec5daccb99aaf7e03865b +github.com/newrelic/go-agent,v2.15.0+incompatible,h1:IB0Fy+dClpBq9aEoIrLyQXzU34JyI1xVTanPLB/+jvU=,4c541c5f7b10055c37cf22843edbb9b0fcb06ad3504e8d6eae3d9c37ff3c64c6 +github.com/nf/cr2,v0.0.0-20140528043846-05d46fef4f2f,h1:nyKdx+jcykIdxGNrbgo/TGjdGi99EY9FKBCjYAUS4bU=,665afbe7830424dd9815cae42aa7762b657484686d671f88704257ea7c9736be +github.com/nfnt/resize,v0.0.0-20180221191011-83c6a9932646,h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=,b8e97cb14e5e5ef29d762d2dff890f6279a125990ddf9cb7ae5c4d2a015b109c +github.com/ngaut/pools,v0.0.0-20180318154953-b7bc8c42aac7,h1:7KAv7KMGTTqSmYZtNdcNTgsos+vFzULLwyElndwn+5c=,26342833d7a5b91a52f8451e8e34bc9ffc5069d342666ab0b478628c41a86d44 +github.com/ngaut/sync2,v0.0.0-20141008032647-7a24ed77b2ef,h1:K0Fn+DoFqNqktdZtdV3bPQ/0cuYh2H4rkg0tytX/07k=,2635d6120b6172c190f84b57b5fc878f9158b768b4bd6bd4468bfa98a73061a4 +github.com/nicksnyder/go-i18n,v2.0.2+incompatible,h1:Xt6dluut3s2zBUha8/3sj6atWMQbFioi9OMqUGH9khg=,687be9dc953545d390761e5464e07c38f313d19c1f695f7d7702d954afcf6b66 +github.com/nicolai86/scaleway-sdk,v1.10.2-0.20180628010248-798f60e20bb2,h1:BQ1HW7hr4IVovMwWg0E0PYcyW8CzqDcVmaew9cujU4s=,a2e992324edd4396f24e0b6a165c4d1057eeefdecdc9f7472b0de8a30f3be729 +github.com/niklasfasching/go-org,v0.1.6,h1:F521WcqRNl8OJumlgAnekZgERaTA2HpfOYYfVEKOeI8=,c938afb1ad7f567524686395c9de66da75220eaa60fe8917c02b97aa1e2cbbb1 +github.com/nkovacs/streamquote,v0.0.0-20170412213628-49af9bddb229,h1:E2B8qYyeSgv5MXpmzZXRNp8IAQ4vjxIjhpAf5hv/tAg=,679a789b4b1409ea81054cb12e5f8441199f5fb17d4a2d3510c51f3aa5f3f0cc +github.com/nlopes/slack,v0.6.0,h1:jt0jxVQGhssx1Ib7naAOZEZcGdtIhTzkP0nopK0AsRA=,048ddfddd4a66407f26b069a65d4d8f3d6d0368adcd52fd5a0dc6d86fe012f47 +github.com/nrdcg/auroradns,v1.0.0,h1:b+NpSqNG6HzMqX2ohGQe4Q/G0WQq8pduWCiZ19vdLY8=,81e3564b38ca27024b6e981a03ae70afcf435d5f8d35a2113321dfd3a220f00b +github.com/nrdcg/goinwx,v0.6.1,h1:AJnjoWPELyCtofhGcmzzcEMFd9YdF2JB/LgutWsWt/s=,8e1e3ea7d38f5b9b21603350d97a583c9108d380f5cc08bf93a4c69d6968dc8a +github.com/nrdcg/namesilo,v0.2.1,h1:kLjCjsufdW/IlC+iSfAqj0iQGgKjlbUUeDJio5Y6eMg=,e20a47d9257fcf7ce95254b14bb84ba290b5f4867e4d63027b669f5a55aaab6c +github.com/nsf/jsondiff,v0.0.0-20160203110537-7de28ed2b6e3,h1:OqFSgO6CJ8heZRAbXLpT+ojX+jnnGij4qZwUz/SJJ9I=,9652618358184592fb7a4657e2c51748cbe0bf5bbf97150a2c6e95ecf65b126b +github.com/nsf/termbox-go,v0.0.0-20190817171036-93860e161317,h1:hhGN4SFXgXo61Q4Sjj/X9sBjyeSa2kdpaOzCO+8EVQw=,a64e374836a25ab74ece4eb5314d79617d8b828bd6d13c654d95bed920c82784 +github.com/nsqio/go-nsq,v1.0.7,h1:O0pIZJYTf+x7cZBA0UMY8WxFG79lYTURmWzAAh48ljY=,5acb7902bf31355fa7d77f507ed42847368834eb378fbf407d82ae3e4211e248 +github.com/nu7hatch/gouuid,v0.0.0-20131221200532-179d4d0c4d8d,h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ=,0889a0ac13cfa9f32f986a88a82bb24380070932299131ae7d7180a389d08ca7 +github.com/nullstyle/go-xdr,v0.0.0-20180726165426-f4c839f75077,h1:A804awGqaW7i61y8KnbtHmh3scqbNuTJqcycq3u5ZAU=,0ab4f958f0420027d40b53c98bcb8f3cbe1e106dfb49d3e91415cb1c512a552c +github.com/nutmegdevelopment/sumologic,v0.0.0-20160817160817-42ed9b372fa3,h1:xOEJG5C3e8CvgAYsnkgoSBzCr0No+m++aB6v7A2WScY=,a33916e02e1159304145b621ffdf284120e50f618c684f38776a8bab7ae7b3fe +github.com/nwaples/rardecode,v0.0.0-20171029023500-e06696f847ae,h1:UF9xsJn7AeQ72TCus3eRO1lh08Id3AoF37vl+qigL/w=,5598a02308af3b04418b15854ff940be49cf31ce7238ce23c10409110364d40f +github.com/ogier/pflag,v0.0.1,h1:RW6JSWSu/RkSatfcLtogGfFgpim5p7ARQ10ECk5O750=,c4db0ecff32deb3205c705d72a616bce01e1f6a1948c851d30b52deeec3fbf91 +github.com/oklog/run,v1.0.0,h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=,108d409b7d235d61b82cfb6e1df139501123fcd8fa68fe94ddb024b53335cb48 +github.com/oklog/ulid,v1.3.1,h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=,40e502c064a922d5eb7f2bc2cda9c6a2a929ec0fc76c9aae4db54fb7b6b611ae +github.com/olekukonko/tablewriter,v0.0.1,h1:b3iUnf1v+ppJiOfNX4yxxqfWKMQPZR5yoh8urCTFX88=,7e5cc8a9b5a51126a0cb46ac96b274d92a8b1cc24b2321832c38d60c0ea4cc9c +github.com/oliamb/cutter,v0.2.2,h1:Lfwkya0HHNU1YLnGv2hTkzHfasrSMkgv4Dn+5rmlk3k=,9174c2374109a7d3aeb2c59b5f4b744ec5f65752aab797f0d50beb26cfc7d857 +github.com/olivere/elastic,v6.2.25+incompatible,h1:X34sPAlSpZVlnuSjOYwbMbiCMU+WKK7YUxrunuNSdG8=,bf3b4cc7ea89a716e91002a31b33f55ec3168ce5ab36ffe5c02ff68d94b9aad5 +github.com/olivere/env,v1.1.0,h1:owp/uwMwhru5668JjMDp8UTG3JGT27GTCk4ufYQfaTw=,f486deab73b3d7866e762e1ad34fe63c88e9ac38f41d811414361fb6490bbb2c +github.com/onsi/ginkgo,v1.10.3,h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY=,088314495acb90d1e520519b243f4dbdd17b43469e6fb83bd45d600796856e63 +github.com/onsi/gomega,v1.7.1,h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=,0a245e719f17cc2bc399aa7c2005cca84f1cfba5373b0c96f5c64673f758a712 +github.com/op/go-logging,v0.0.0-20160315200505-970db520ece7,h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=,c506eace74028656eb28677a4c162f9c023ce2f9c0207354ba80cca89f11b461 +github.com/openconfig/gnmi,v0.0.0-20190823184014-89b2bf29312c,h1:a380JP+B7xlMbEQOlha1buKhzBPXFqgFXplyWCEIGEY=,f52967c7b194daa57252042f6ccf9d26f8c599a7e13aca26043f948d5139b91a +github.com/openconfig/reference,v0.0.0-20190727015836-8dfd928c9696,h1:yHCGAHg2zMaW8olLrqEt3SAHGcEx2aJPEQWMRCyravY=,040cf32cee7256a08716313dd7ea4f8c44f1d644ae872ecf2dd381c35b12125c +github.com/opencontainers/go-digest,v1.0.0-rc1,h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=,25fd455029e8a1bbe15ed2eeafc67222372c6f305a47b4ec157d8a1a2849c15c +github.com/opencontainers/image-spec,v1.0.1,h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=,ebb2dca711a137fbfb717158b0368792f834000f4308d9ea259d06c6804c677c +github.com/opencontainers/runc,v0.1.1,h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y=,aa212163f009190d0f4f3dbe64f71fcda06d7896b67863d7f7b185fee6a68ea6 +github.com/opencontainers/runtime-spec,v1.0.1,h1:wY4pOY8fBdSIvs9+IDHC55thBuEulhzfSgKeC1yFvzQ=,1958458b00ce912425f5c7d2ee836431b296a3f9320d565512d8c96b107fffbf +github.com/opencontainers/runtime-tools,v0.9.0,h1:FYgwVsKRI/H9hU32MJ/4MLOzXWodKK5zsQavY8NPMkU=,53c720dbb7452cfb2fd3945e37c26b5a0140cb1012d35a2b72a5e035f28a32c4 +github.com/opencontainers/selinux,v1.3.0,h1:xsI95WzPZu5exzA6JzkLSfdr/DilzOhCJOqGe5TgR0g=,88286825b32cd46a0469e578f378a185032da2d5b03893623861ef3af59359d8 +github.com/openshift/client-go,v3.9.0+incompatible,h1:13k3Ok0B7TA2hA3bQW2aFqn6y04JaJWdk7ITTyg+Ek0=,661b7f28b4905f1936dd58e373374513d54663ec85aecafede1c7d9c260e9369 +github.com/openshift/library-go,v0.0.0-20191101161407-e7c97b468b83,h1:wwR+laNaFKVGiizoIDL/cAKIZVoKXJ9jbjUoUlq2p5I=,c74f8134013f978ef154d6accf9b4b0c5126941f2d45e6eb223db7098f7ab2a4 +github.com/opentracing-contrib/go-observer,v0.0.0-20170622124052-a52f23424492,h1:lM6RxxfUMrYL/f8bWEUqdXrANWtrL7Nndbm9iFN0DlU=,50023eee1ef04412410f43d8b5dcf3ef481c0fc39067add27799654705fa84b2 +github.com/opentracing-contrib/go-stdlib,v0.0.0-20190519235532-cf7a6c988dc9,h1:QsgXACQhd9QJhEmRumbsMQQvBtmdS0mafoVEBplWXEg=,966cdf6d869ff62c35edf1ea00113465cc9b90f34838c6a6990a1f776e7d1152 +github.com/opentracing/basictracer-go,v1.0.0,h1:YyUAhaEfjoWXclZVJ9sGoNct7j4TVk7lZWlQw5UXuoo=,a908957c8e55b7b036b4761fb64c643806fcb9b59d4e7c6fcd03fca1105a9156 +github.com/opentracing/opentracing-go,v1.1.0,h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=,3e0f42d035019fa037991d340da9677a802f8182792770c38e87906d33e06629 +github.com/openzipkin-contrib/zipkin-go-opentracing,v0.4.4,h1:bzTJRoOZEN7uI1gq594S5HhMYNSud4FKUEwd4aFbsEI=,8a4688f80cd67140aa4edb91506d440ecea4d8ec01634caab5c95991af011c5d +github.com/openzipkin/zipkin-go,v0.2.2,h1:nY8Hti+WKaP0cRsSeQ026wU03QsM762XBeCXBb9NAWI=,dfc610dc52d9299df49172a9e61fcc772d85450b6b6f82e8f43cf23562232a4c +github.com/oracle/oci-go-sdk,v7.0.0+incompatible,h1:oj5ESjXwwkFRdhZSnPlShvLWYdt/IZ65RQxveYM3maA=,941cd26813b22873477f1c6bb86fed929bdc85379d435bd9707d923f57d070dc +github.com/orcaman/concurrent-map,v0.0.0-20190826125027-8c72a8bb44f6,h1:lNCW6THrCKBiJBpz8kbVGjC7MgdCGKwuvBgc7LoD6sw=,ec80830c751199283290a8d398ebf28ca5169e866a70347b39856d2c1178f2cb +github.com/ory/dockertest,v3.3.4+incompatible,h1:VrpM6Gqg7CrPm3bL4Wm1skO+zFWLbh7/Xb5kGEbJRh8=,cbcc7ba21c846d38229aa06a2d7cf35b99ac219eb2694bd9a1ceeac89667e475 +github.com/ory/herodot,v0.6.2,h1:zOb5MsuMn7AH9/Ewc/EK83yqcNViK1m1l3C2UuP3RcA=,caf465ffb73c7537212ba4fd58a4c2c41fe7ca69737404a28e84ceff90c340ea +github.com/otiai10/copy,v0.0.0-20180813032824-7e9a647135a1,h1:A7kMXwDPBTfIVRv2l6XV3U6Su3SzLUzZjxnDDQVZDIY=,67d0e4f6ba369653e30257882fbbb20c28b560bc837e1847a42c48e868f1c81c +github.com/otiai10/curr,v0.0.0-20150429015615-9b4961190c95,h1:+OLn68pqasWca0z5ryit9KGfp3sUsW4Lqg32iRMJyzs=,7cf2143067d9bb3e7d54d2906766bb24c11d76f1bb0b0c5069574e9a0d8ae93d +github.com/otiai10/mint,v1.2.3,h1:PsrRBmrxR68kyNu6YlqYHbNlItc5vOkuS6LBEsNttVA=,0b82a05ca43810c9aa8299ddae1663feeb178d699aeb5242c3bdeb61cb5a54fb +github.com/outscale/osc-go,v0.0.1,h1:hvBtORyu7sWSKW1norGlfIP8C7c2aegI2Vkq75SRPCE=,2a988384c564fdba8b8c496024aafc212140e4b996654be7a92a3b0c7a962632 +github.com/ovh/go-ovh,v0.0.0-20181109152953-ba5adb4cf014,h1:37VE5TYj2m/FLA9SNr4z0+A0JefvTmR60Zwf8XSEV7c=,0fa35e8026a9b3aebd804739f31ffe07e553b84e2b8ea145b2f2ebaa0dd7c08f +github.com/oxtoacart/bpool,v0.0.0-20190530202638-03653db5a59c,h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=,6816ec3a6f197cbee0ba6ddb9ec70958bc28870e59864b24e43da0c858079a1b +github.com/packer-community/winrmcp,v0.0.0-20180921204643-0fd363d6159a,h1:A3QMuteviunoaY/8ex+RKFqwhcZJ/Cf3fCW3IwL2wx4=,4a48fa503853d129e7e32ca81f069b9e09a9e3249739781f61fae70bb02d098b +github.com/packethost/packngo,v0.1.1-0.20180711074735-b9cb5096f54c,h1:vwpFWvAO8DeIZfFeqASzZfsxuWPno9ncAebBEP0N3uE=,6dac4e55c104df58ace636ef31d5dd6173a36747c4fd79299252ba8826127491 +github.com/parnurzeal/gorequest,v0.2.16,h1:T/5x+/4BT+nj+3eSknXmCTnEVGSzFzPGdpqmUVVZXHQ=,cc7b7d56e2e4c3fa0709e0e547875807746ac067b2a5c4b740b3088c1fdf941d +github.com/pascaldekloe/goe,v0.1.0,h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=,37b73886f1eec9b093143e7b03f547b90ab55d8d5c9aa3966e90f9df2d07353c +github.com/patrickmn/go-cache,v2.1.0+incompatible,h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=,d5d1c13e3c9cfeb04a943f656333ec68627dd6ce136af67e2aa5881ad7353c55 +github.com/pborman/uuid,v1.2.0,h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=,b888ff5d33651a1f5f6b8094acc434dd6dc284e2fe5052754a7993cebd539437 +github.com/pelletier/go-buffruneio,v0.2.0,h1:U4t4R6YkofJ5xHm3dJzuRpPZ0mr5MMCoAWooScCR7aA=,70593688607f4d48192776fe257ab9298689267ebcdd7b155bfe40d893735f38 +github.com/pelletier/go-toml,v1.6.0,h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4=,cc6dce19df6c6c30abd67594d17ea6015d1210aa6dd8c6096c6429eec06fdab4 +github.com/peterbourgon/diskv,v2.0.1+incompatible,h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=,1eeff260bd1ad71cd1611078995db99e1c7eba28628e7d6f24c79039536ea1cb +github.com/peterbourgon/g2s,v0.0.0-20170223122336-d4e7ad98afea,h1:sKwxy1H95npauwu8vtF95vG/syrL0p8fSZo/XlDg5gk=,41526f42b4fe3019581ab3745afea18271d7f037eb55a6e9fb3e32fd09ff9b8d +github.com/petergtz/pegomock,v2.7.0+incompatible,h1:42rJ5wIOBAg9OGdkLaPW9PlF/RtqDc5aGl6PcTCXl3o=,dc93e4483e8de4eb429e007aad17348822197ea7a3adde283b7752bc4544dfbb +github.com/peterh/liner,v1.1.0,h1:f+aAedNJA6uk7+6rXsYBnhdo4Xux7ESLe+kcuVUF5os=,5cdc45c19901db8d8295c139bb382d7eea150e8fd96bd26de10384685728a461 +github.com/peterhellberg/link,v1.0.0,h1:mUWkiegowUXEcmlb+ybF75Q/8D2Y0BjZtR8cxoKhaQo=,d320f4204fbe886e1cefc0b677af2bfaba855e9e6556a6e92e43bcd80c3bb7a5 +github.com/petermattis/goid,v0.0.0-20180202154549-b0b1615b78e5,h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ=,5134a176e306f9b973ff670a33c7536b59bf4114d83fd94f74c736ff0cc10ef0 +github.com/phayes/freeport,v0.0.0-20180830031419-95f893ade6f2,h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=,4ac97358de55a9b1ac60f13fdb223c5309a129fb3fb7bf731062f9c095a0796c +github.com/philhofer/fwd,v1.0.0,h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ=,b4e79b1f5fdfe8c44bf6dae3dd593c62862930114411a30968f304084de1d0b3 +github.com/pierrec/lz4,v2.3.0+incompatible,h1:CZzRn4Ut9GbUkHlQ7jqBXeZQV41ZSKWFc302ZU6lUTk=,775487f2be5ddf23034b59bc862cb0d5767155c5e08d1186665d117092ceb50f +github.com/pingcap/check,v0.0.0-20190102082844-67f458068fc8,h1:USx2/E1bX46VG32FIw034Au6seQ2fY9NEILmNh/UlQg=,b8eeddacc35915d8c40b42e9af4db468ed309a506412a767ba6bb03bb7ce4627 +github.com/pingcap/errors,v0.11.4,h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=,df62e548162429501a88d936a3e8330f2379ddfcd4d23c22b78bc1b157e05b97 +github.com/pingcap/gofail,v0.0.0-20181217135706-6a951c1e42c3,h1:04yuCf5NMvLU8rB2m4Qs3rynH7EYpMno3lHkewIOdMo=,444866a53b7429e80a8a16791e39555de8103c7514cd322fe191c902b8071360 +github.com/pingcap/goleveldb,v0.0.0-20171020122428-b9ff6c35079e,h1:P73/4dPCL96rGrobssy1nVy2VaVpNCuLpCbr+FEaTA8=,08ec0ffe5d0d74bdc543695f975316af6a63c17e36644ae56d42e30b0d1f8777 +github.com/pingcap/kvproto,v0.0.0-20191101062931-76b56d6eb466,h1:C5nV9osqA+R/R2fxYxVfqAUlCi3Oo5yJ/JSKDeHSAOk=,0d834c10c217c5de2c9ef79049891a69e73e102c4dbcd130173c3650e96da570 +github.com/pingcap/log,v0.0.0-20191012051959-b742a5d432e9,h1:AJD9pZYm72vMgPcQDww9rkZ1DnWfl0pXV3BOWlkYIjA=,eaece6f27792a39ccff08152050d4eb7905c250bf36877cacdd7e74c79d80472 +github.com/pingcap/parser,v0.0.0-20191101070347-94a5ef60f10b,h1:TLljHrSTC9MCTiUA6nMhV68my/D/FI3VNkUs94Wo3DE=,94e6857f4d2bf653edf4c2881cb8fb6b3abdf9efaec7d1f49159deec77580df2 +github.com/pingcap/pd,v2.1.17+incompatible,h1:mpfJYffRC14jeAfiq0jbHkqXVc8ZGNV0Lr2xG1sJslw=,b75266cd20abe6b1ccbb777a2f71d74dfcf231a06276b602df08bf27a9ea36f1 +github.com/pingcap/tidb-tools,v2.1.4+incompatible,h1:dkB4FMJcSk9GYRB2ICupU/lsTLf4mHLfkBE6fAsLdJ4=,c5c8e2b5c69c21bba2050c75d3a4582eda26308a355557036f058365d4583e5f +github.com/pingcap/tipb,v0.0.0-20191030045153-07a0962bbc64,h1:wUSHIp4dura5/YAepdgDBEdf2zz20MHXyNtMi1TcaDE=,8ac8e775e3d5fd255b7a8f07460f3b19bebb04cb50a3c0f5d6f64cc2fd585177 +github.com/pkg/browser,v0.0.0-20180916011732-0a3d74bf9ce4,h1:49lOXmGaUpV9Fz3gd7TFZY106KVlPVa5jcYD1gaQf98=,b845f84fbf08bba75401a4eff94c01c9e2c668fa1b43016e835bd60c6a8b4e87 +github.com/pkg/errors,v0.8.1,h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=,4e47d021340b7396a7dee454f527552faf7360a9fc34038b1dc32ba3b5a951d8 +github.com/pkg/profile,v1.3.0,h1:OQIvuDgm00gWVWGTf4m4mCt6W1/0YqU7Ntg0mySWgaI=,5f20c007ac81019900f06cf1e4d451ce8e1d981460e39e04794fbcc60639f851 +github.com/pkg/sftp,v1.10.1,h1:VasscCm72135zRysgrJDKsntdmPN+OuU3+nnHYA9wyc=,4e30f0455865434be7b83d4010ab97667217dafd0017caa651faafa2cc6aed64 +github.com/pkg/term,v0.0.0-20180730021639-bffc007b7fd5,h1:tFwafIEMf0B7NlcxV/zJ6leBIa81D3hgGSgsE5hCkOQ=,165bb00eeab26fe65c64e0e13bc29abc7ea18ac28d288e2218c137cd0bd91d9b +github.com/plaid/plaid-go,v0.0.0-20161222051224-02b6af68061b,h1:Don6I/E8nLCT6gdBi1sKB9hYxkx/24YD7XWwSly8IEo=,bd900ff0acd2968150f60770ab4e870d9f6b92c129a49eac0c9620a8043f901e +github.com/pmezard/go-difflib,v1.0.0,h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=,de04cecc1a4b8d53e4357051026794bcbc54f2e6a260cfac508ce69d5d6457a0 +github.com/polydawn/refmt,v0.0.0-20190408063855-01bf1e26dd14,h1:2m16U/rLwVaRdz7ANkHtHTodP3zTP3N451MADg64x5k=,a92440a944006fd3e0b6f1717fce4c2ea490cf2c4af93b56675216204f138c3a +github.com/portworx/kvdb,v0.0.0-20190911174000-a0108bddd091,h1:DqGiNhvCpvhWW/HJ1naJa0DudtlckvzQ9hEXSsOyv8Y=,d6fa957e1469a1b47ccbebc805034bafc5ed24798a1bef8675f751f9c4ed961e +github.com/portworx/sched-ops,v0.0.0-20191101005636-ded833c86f1e,h1:emQnaLwLEYN3Hner2ekVuZfrcChdN3H3J4Lxu5mPe64=,43ff366e97ff640a34a566c81dd7d63537c2864da85d33b49d5261417cd8d4b0 +github.com/posener/complete,v1.2.1,h1:LrvDIY//XNo65Lq84G/akBuMGlawHvGBABv8f/ZN6DI=,a97f73829e0b71ae7a8f17a4884d5dcbb2c3499d8d3a077c2a8d7c2596f68d37 +github.com/pquerna/cachecontrol,v0.0.0-20180517163645-1555304b9b35,h1:J9b7z+QKAmPf4YLrFg6oQUotqHQeUNWwkvo7jZp1GLU=,0e5185ab4dab1bb2241e9e23e36ebde5713f3fb1e47767c3eb44001b7e17644f +github.com/pquerna/ffjson,v0.0.0-20190930134022-aa0246cd15f7,h1:xoIK0ctDddBMnc74udxJYBqlo9Ylnsp1waqjLsnef20=,377b4667540f620eae19722b5346f6f1efdea5688f9eedda97f2c659dad131f9 +github.com/pquerna/otp,v1.1.0,h1:q2gMsMuMl3JzneUaAX1MRGxLvOG6bzXV51hivBaStf0=,d46d289853f801387dfc514fd50133de30b684a6af34031b27caa877cbb7f687 +github.com/profitbricks/profitbricks-sdk-go,v4.0.2+incompatible,h1:ZoVHH6voxW9Onzo6z2yLtocVoN6mBocyDoqoyAMHokE=,b0baf185752eb96f8890f3e9adf856b13f5c43b5346387b659e2b1deb1d087c7 +github.com/project-flogo/core,v0.9.3,h1:uZXHR9j1Byqt+x3faNnOqB8NlEfwE2gpCh40iQ+44oA=,d1c43e3bc517bb438a9d313d976e327ba219232418064d439fb20671341832a2 +github.com/projectcalico/libcalico-go,v1.7.3,h1:qcbxAhsq/5zqZqpHE24VqMHfmoBVdXZV0Kf82+5rbqU=,4f638d56eb47ff8e1763f65131050294f7d2c828139276fe86127a803245ae8c +github.com/prometheus/alertmanager,v0.18.0,h1:sPppYFge7kdf9O96KIh3fd093D1xN8JxIp03wW6yAEE=,45e122e7c2ac69577d63844313798060673a28b2e86ec8a0197f330c584b379b +github.com/prometheus/client_golang,v1.2.1,h1:JnMpQc6ppsNgw9QPAGF6Dod479itz7lvlsMzzNayLOI=,174c921fe3e154adddd8e0dc572323dd04901bcad0965de614174241981da57c +github.com/prometheus/client_model,v0.0.0-20190812154241-14fe0d1b01d4,h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=,5d4719be47f4f69ab5bf36a04c75eb078a0f69b43a335f400c2d688ac9e61795 +github.com/prometheus/common,v0.7.0,h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY=,f2640a94b18b115552df41ee33effa013e10536aca51e09a971d1503a20e186a +github.com/prometheus/procfs,v0.0.5,h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8=,f45b90c72f8c2e4c84e5314092ee1ccf7d6ace1cc14b2f483c82f7c1e6d0d0d4 +github.com/prometheus/prom2json,v1.1.0,h1:/fEL2DK7EEyHVeGMG4TV+gSS9Sw53yYKt//QRL0IIYE=,166f5f98c62d0b90139947d1464ee747f8143772b9e926c7b51c53a4420380ff +github.com/prometheus/prometheus,v2.5.0+incompatible,h1:7QPitgO2kOFG8ecuRn9O/4L9+10He72rVRJvMXrE9Hg=,ede73f6ccabd60365549986a6c7ae152c1952129006c8ae521c86ff45c4aadcc +github.com/prometheus/tsdb,v0.10.0,h1:If5rVCMTp6W2SiRAQFlbpJNgVlgMEd+U2GZckwK38ic=,34e98f0e9ba55e7290774ee40569737745b395e32811e5940d2ed124a20f927c +github.com/pyinx/gorocket,v0.0.0-20170810024322-78ae1353729f,h1:N1r6pSlez3lLsqaNHbtrHW9ZuzrilETIabr9jPNj3Zs=,dcd920b789a98157bbe1ed7fff249255c1dd4d2fd80f7edc39b3a49fc08db13a +github.com/qor/admin,v0.0.0-20191021122103-f3db8244d2d2,h1:IWw22+hlihdss/qI93QH48jTBUEOD/fsBqj+0z61z/Y=,722e243550878791adcdb3bcea66ab8e7a185637c8a7ad0a752713951aef2a91 +github.com/qor/assetfs,v0.0.0-20170713023933-ff57fdc13a14,h1:JRpyNNSRAkwNHd4WgyPcalTAhxOCh3eFNMoQkxWhjSw=,7fe36875e7e59afd9154f827babbffaa7f67ac54b7790df5a4a4a376c78b2282 +github.com/qor/middlewares,v0.0.0-20170822143614-781378b69454,h1:+WCc1IigwWpWBxMFsmLUsIF230TakGHstDajd8aKDAc=,4c2ed9a2f7b24dfa64464091b2c01ce9fc947524bb834d77aeb9ceaf8610e5fc +github.com/qor/qor,v0.0.0-20191022064424-b3deff729f68,h1:MSbP9P4HnmEyH+uGQAW+V0HoTzlZ9SRq7kdCaRiZEmU=,9053796b8a7afe21483262affaf5b35bac8bf3387e24531448a4833d7b758978 +github.com/qor/render,v1.1.1,h1:DaGaKlf0OzpOB+hJUEiOTbZ40mg+n+LlSJx20/KUfes=,8f957a13173ef1a22d0caeea1cc6d198b064d242676444e00e2f597c405928c9 +github.com/qor/responder,v0.0.0-20171031032654-b6def473574f,h1:sKELSAyL+z5BRHFe97Bx71z197cBEobVJ6rASKTMSqU=,b69784649ec65ec2580d7640af25ec66973d59d82ec5391498cfe4c3076e5f6f +github.com/qor/roles,v0.0.0-20171127035124-d6375609fe3e,h1:F0BNcPJKfubM/+IIILu/GbrH9v2vPZWQ5/StSRKUfK4=,1a35a5480c7169e86025eb19dbcddc13fd00472e6b4ade7574e62c290cf09100 +github.com/qor/session,v0.0.0-20170907035918-8206b0adab70,h1:8l21EEdlZ9R0AA3FbeUAANc5NAx8Y3tn1VKbyAgjYlI=,7c759bc736c4936a602ca1f0ebad9a324d8332ffd342e1e3acd80355180fc858 +github.com/qor/validations,v0.0.0-20171228122639-f364bca61b46,h1:dRlsVUhwD1pwrasuVbNooGQITYjKzmXK5eYoEEvBGQI=,b29360c4a4e9cc8d0ff682d8bf1f446a5d61d5a4f8d3cf2fc6d8cc077e5d810f +github.com/racker/perigee,v0.1.0,h1:8RjBm1YGJKVVjUfO02Uok+npegz8lSSEVqjimDqlFYc=,d43613102ed67445c9fc81b621959b58f827c187189b09cec236c3bac5ce1ccb +github.com/raff/goble,v0.0.0-20190909174656-72afc67d6a99,h1:JtoVdxWJ3tgyqtnPq3r4hJ9aULcIDDnPXBWxZsdmqWU=,ef5dde1af55d451c37ddf13e17ae339d299903cb7e67567fc6d1e69688a789e1 +github.com/rai-project/config,v0.0.0-20190926180509-3bd01e698aad,h1:o0056EwcQBeyaVb2my+T0TvMR5FpEY0CGNgWkbj/xEo=,27c2311ad1fdc185e08f2e1703893482b7d26caf64854ed371bf38f3a9303f92 +github.com/rai-project/godotenv,v0.0.0-20180619160704-a501614c3b8d,h1:reVy+ViZcrx1ILo+L8wa3dGf6hSd4qlY62VqxZxEgWs=,f4d9ecb56f20667fbb09bd5256d0c6b81b9e8cbca8f6476240c5d1800ffb07ed +github.com/rai-project/logger,v0.0.0-20190701163301-49978a80bf96,h1:GeXSVSRfXOBN5XHNA+wq5G+sfq99mhpwn6U5kcGwSeg=,53d7677e7d7dab6b1f83591ec10491301289752e337641403f8413c0749b84d8 +github.com/rai-project/utils,v0.0.0-20180619204045-c582bb171808,h1:cHOS6oMEt8wi93zm5V7cHVnWgOhaAUCpjRDEZHBsckg=,6d43ccc901ad2f19744696f6c3d04ee28b4496cef7fe72ce7eccb89af0d8bfac +github.com/rai-project/vipertags,v0.0.0-20190404224953-d63b0a674aa9,h1:3o86f/tK0DBZdPcUBjzFu1mEZsRCzjSgi5PNHope4AQ=,9aa8cdd1a3369382d28bad0f4581250fbecae51602aa8566cbe68dfadc8f7785 +github.com/raintank/schema,v1.0.0,h1:tK0zKHceZd5nkCUI5Soip1pA2BAvoc4qzloVEsK0y+Q=,9ffc30e882b1cfed3152bab9c8c95e00c984dc0d8895426c95d96a184e09ffe3 +github.com/rainycape/memcache,v0.0.0-20150622160815-1031fa0ce2f2,h1:dq90+d51/hQRaHEqRAsQ1rE/pC1GUS4sc2rCbbFsAIY=,2d42bb018c6b0531f93e2dc862c87374966c64c9a88863612ab5e676a32661fa +github.com/rainycape/unidecode,v0.0.0-20150907023854-cb7f23ec59be,h1:ta7tUOvsPHVHGom5hKW5VXNc2xZIkfCKP8iaqOyYtUQ=,0ab56010a3ef93c20bb6d8c486e3b447b4004052053e280ea6eabf2a5138bdce +github.com/rakyll/statik,v0.1.6,h1:uICcfUXpgqtw2VopbIncslhAmE5hwc4g20TEyEENBNs=,58cc0c07f8e9dd17ad5c4e0f89c03d8a3ed420aac0e76b79adf7ebd1d48c5893 +github.com/rcrowley/go-metrics,v0.0.0-20190826022208-cac0b30c2563,h1:dY6ETXrvDG7Sa4vE8ZQG4yqWg6UnOcbqTAahkV813vQ=,22e944d960aec1a1e62e8cc2daaa70abefbbe989dd9c233060ab533de5f6e724 +github.com/remyoudompheng/bigfft,v0.0.0-20190512091148-babf20351dd7,h1:FUL3b97ZY2EPqg2NbXKuMHs5pXJB9hjj1fDHnF2vl28=,73f78c7e36c32822221f9f676b65ebe7ccb92ab6ff221035ace35c184e165c0d +github.com/renier/xmlrpc,v0.0.0-20170708154548-ce4a1a486c03,h1:Wdi9nwnhFNAlseAOekn6B5G/+GMtks9UKbvRU/CMM/o=,f9c07652c6de1aecf5baaa3b93c1e6c23379458e30553400d5f96ac8b3ea85c4 +github.com/renstrom/fuzzysearch,v0.0.0-20160331204855-2d205ac6ec17,h1:4qPms2txLWMLXKzqlnYSulKRS4cS9aYgPtAEpUelQok=,01782a5d1682a72614126da402171253030c0de60485bc18a3e63b07d977c094 +github.com/retr0h/go-gilt,v0.0.0-20190206215556-f73826b37af2,h1:vZ42M1tDiMLtirFA1K5k2QVFhWRqR4BjdSw0IMclzH4=,e7956b01b3ccea41395f1f641a0f9045f214c1075d7ecc25553b72383009274e +github.com/revel/config,v0.21.0,h1:Bw4iXLGAuD/Di2HEhPSOyDywrTlFIXUMbds91lXTtTU=,22842698f6c646b9b89649b432d0f24deae1c5a3779c49819ec99c5db6e4b5a0 +github.com/revel/log15,v2.11.20+incompatible,h1:JkA4tbwIo/UGEMumY50zndKq816RQW3LQ0wIpRc+32U=,28e4263b0320a07dd2ae71ba09aef1f9b4af44258a8c0f1dfb1d63300f93c401 +github.com/revel/pathtree,v0.0.0-20140121041023-41257a1839e9,h1:/d6kfjzjyx19ieWqMOXHSTLFuRxLOH15ZubtcAXExKw=,de658b8de908c9c090343447e66e6bbdfe99656fcfa5889997486b0594c2a719 +github.com/revel/revel,v0.21.0,h1:E6kDJmpJSDb0F8XwbyG5h4ayzpZ+8Wcw2IiPZW/2qSc=,c66570c338f37e95626646909af1086f0bf31d8432fe982d24c415d14bc1dc9c +github.com/rivo/tview,v0.0.0-20191018125527-685bf6da76c2,h1:GVXSfgXOMAeLvFH7IrpY3yYM8H3YekZEFcZ14q9gQXM=,000538d9517bd5f28cfe377e63183f7093043acf8bb913eb493adb29518eb6b8 +github.com/rivo/uniseg,v0.1.0,h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY=,cb701df81f36acfbb2627a78662fdcaa150ee1ac00d0796a7f3eafbdb6218128 +github.com/rjeczalik/notify,v0.9.2,h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8=,e8b9b93870f7ed17f30c617acb55f5fa78e7931518c88999c3d1b5b048f51482 +github.com/rkt/rkt,v1.30.0,h1:ZI5RQtSibfjicSttV/HLiHuWreYClEJA2Or5XKAdJb0=,ca2e00335dbeae7e0fbe2c45535d2bb8fce72c2bb6045b0bdf25bc6b8b59179e +github.com/robertkrimen/otto,v0.0.0-20180617131154-15f95af6e78d,h1:1VUlQbCfkoSGv7qP7Y+ro3ap1P1pPZxgdGVqiTVy5C4=,7adbe73b0db5319bae0421a0ed7fc5619002d6e9a2be87dc8c673c8541dfd949 +github.com/robfig/cron,v1.2.0,h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=,0811a1a5a4e1f45824ac520deb2002326a659dbb4918cdfea47d80560a23211d +github.com/robfig/cron/v3,v3.0.0,h1:kQ6Cb7aHOHTSzNVNEhmp8EcWKLb4CbiMW9h9VyIhO4E=,5e29b4f7f4ba62293420b918fb2309823523a583c2adaf6eddb059f525f05496 +github.com/rogpeppe/fastuuid,v1.2.0,h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s=,f9b8293f5e20270e26fb4214ca7afec864de92c73d03ff62b5ee29d1db4e72a1 +github.com/rogpeppe/go-charset,v0.0.0-20180617210344-2471d30d28b4,h1:BN/Nyn2nWMoqGRA7G7paDNDqTXE30mXGqzzybrfo05w=,a28b06534aa71873d08578d69b08512dab54caa0ffd9e2943b3479166049eddd +github.com/rogpeppe/go-internal,v1.4.0,h1:LUa41nrWTQNGhzdsZ5lTnkwbNjj6rXTdazA1cSdjkOY=,fb7d843253301d3ea9793f90e6bea16a8f2970a01b361f490ee66b36f81e03a5 +github.com/rpcx-ecosystem/quic-conn,v0.0.0-20190920095804-3967ef162525,h1:Awv5A28rrxuHf1+9+N08cnBa6JuKbhHswmNdfj65Bzo=,b40886ad7129eff9e517187b527467330db3705207349cdaa8f35c0dc8445c08 +github.com/rs/cors,v1.7.0,h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=,67815316761fddc4acfaad852965cf04ec88674abe3a05c6c332519556c55855 +github.com/rs/xhandler,v0.0.0-20160618193221-ed27b6fd6521,h1:3hxavr+IHMsQBrYUPQM5v0CgENFktkkbg1sfpgM3h20=,665ae95533e1a046cf470c7341c59e64b3e2a795cdaaf307368f69a0ba547f2c +github.com/rs/xid,v1.2.1,h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc=,4abdedc4de69adcb9a4575f99c59d8ab542191e1800b6a91e12a4e9ea8da0026 +github.com/rs/zerolog,v1.16.0,h1:AaELmZdcJHT8m6oZ5py4213cdFK8XGXkB3dFdAQ+P7Q=,64e248c1fa3c62e2d904868b49acf906d0cb04a00a323d2562ea9ce7c6f154e1 +github.com/rubenv/sql-migrate,v0.0.0-20191025130928-9355dd04f4b3,h1:lwDYefgiwhjuAuVnMVUYknoF+Yg9CBUykYGvYoPCNnQ=,4d4e9e2c7387542b26a1cd9fbfcbdab7b75dce807877d5a0a501180b584c60f2 +github.com/rubyist/circuitbreaker,v2.2.1+incompatible,h1:KUKd/pV8Geg77+8LNDwdow6rVCAYOp8+kHUyFvL6Mhk=,fc1125d9260a471d349c94a251340c437f98743b42324706482596f303c28b11 +github.com/russross/blackfriday,v2.0.0+incompatible,h1:cBXrhZNUf9C+La9/YpS+UHpUT8YD6Td9ZMSU9APFcsk=,836047aa9cbd223efba85b892e6897cf7a3b5ee3f2e6ad36b189d40842f703df +github.com/russross/blackfriday/v2,v2.0.1,h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=,496079bbc8c4831cd0507213e059a925d2c22bd1ea9ada4dd85815d51b485228 +github.com/rwcarlsen/goexif,v0.0.0-20190401172101-9e8deecbddbd,h1:CmH9+J6ZSsIjUK3dcGsnCnO41eRBOnY12zwkn5qVwgc=,98e8ce7bf484716bdf272f31ee01354599f4ec4b4ece7c04156c15b264d8f6ec +github.com/ryanuber/columnize,v2.1.0+incompatible,h1:j1Wcmh8OrK4Q7GXY+V7SVSY8nUWQxHW5TkBe7YUl+2s=,ff687e133db2e470640e511c90cf474154941537a94cd97bb0cf7a28a7d00dc7 +github.com/ryanuber/go-glob,v1.0.0,h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=,2084f36ead38a505489fdb46329502fb627f568224dcc22ef11ec173b61fc2cf +github.com/ryszard/goskiplist,v0.0.0-20150312221310-2dfbae5fcf46,h1:GHRpF1pTW19a8tTFrMLUcfWwyC0pnifVo2ClaLq+hP8=,12c65729fc31d5a9bf246eb387bd4c268d0d68bf33b913cccd81bebd47d6f80d +github.com/sacloud/libsacloud,v1.26.1,h1:td3Kd7lvpSAxxHEVpnaZ9goHmmhi0D/RfP0Rqqf/kek=,4f0e24194ce3566707df5862177cb0f697debe3d5b799decb2685ee8d07dbe11 +github.com/saintfish/chardet,v0.0.0-20120816061221-3af4cd4741ca,h1:NugYot0LIVPxTvN8n+Kvkn6TrbMyxQiuvKdEwFdR9vI=,d9cb0e35c88fbf91a409db0626f2e8ae9db305cf95dc3469dc7d089a8432c9c3 +github.com/samuel/go-zookeeper,v0.0.0-20190923202752-2cc03de413da,h1:p3Vo3i64TCLY7gIfzeQaUJ+kppEO5WQG3cL8iE8tGHU=,499f8144de8a6839b2d70c8869d88f294604188ec501e928ca17446043147d40 +github.com/sanity-io/litter,v1.1.0,h1:BllcKWa3VbZmOZbDCoszYLk7zCsKHz5Beossi8SUcTc=,c4bbddbf1bd7bb4ef74a3c2cac98f4a78a2a3a5a6b8dd140bd31a5d38c459217 +github.com/santhosh-tekuri/jsonschema,v1.2.4,h1:hNhW8e7t+H1vgY+1QeEQpveR6D4+OwKPXCfD2aieJis=,1c946415ee3395181090664a37779c296b540ca7eec58844ad0283fef11fec00 +github.com/sasha-s/go-deadlock,v0.2.0,h1:lMqc+fUb7RrFS3gQLtoQsJ7/6TV/pAIFvBsqX73DK8Y=,6c3f90c7947da1090f545438f4b3fd461cfeec79ee1c6e5e83a0eed7258622b1 +github.com/sassoftware/go-rpmutils,v0.0.0-20190420191620-a8f1baeba37b,h1:+gCnWOZV8Z/8jehJ2CdqB47Z3S+SREmQcuXkRFLNsiI=,88264dbd268c88bc8a57e4b4a261f22058fa6e03eb2883b0a82375f854e15188 +github.com/satori/go.uuid,v1.2.0,h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=,4f741306a0cbe97581e34a638531bcafe3c2848150539a2ec2ba12c5e3e6cbdd +github.com/satori/uuid,v1.2.0,h1:6TFY4nxn5XwBx0gDfzbEMCNT6k4N/4FNIuN8RACZ0KI=,bfd4d3d619e3ad4dd915e05fec5bf10949d8af9bc5c19b840db35ec0f21172ad +github.com/scaleway/scaleway-cli,v0.0.0-20180921094345-7b12c9699d70,h1:DaqC32ZwOuO4ctgg9qAdKnlQxwFPkKmCOEqwSNwYy7c=,05566d6711de08738803132b8522f7051fccd3b3bf2c739dde421fffdfa75eaf +github.com/sclevine/agouti,v3.0.0+incompatible,h1:8IBJS6PWz3uTlMP3YBIR5f+KAldcGuOeFkFbUWfBgK4=,b20c8a6a2c1fda0ae6a9cd6d319e78a7a5afea4bc90810cd46b99246d8219d23 +github.com/sclevine/spec,v1.2.0,h1:1Jwdf9jSfDl9NVmt8ndHqbTZ7XCCPbh1jI3hkDBHVYA=,582017cd824cf3cdf6803ec7db2250304f66efea705feb69cbabab416928b8f4 +github.com/sean-/conswriter,v0.0.0-20180208195008-f5ae3917a627,h1:Tn2Iev07a4oOcAuFna8AJxDOF/M+6OkNbpEZLX30D6M=,0637d2fc0eb4627827e4b73dbe3a72479708641df8fc71a06e7bc481f6a7f39b +github.com/sean-/pager,v0.0.0-20180208200047-666be9bf53b5,h1:D07EBYJLI26GmLRKNtrs47p8vs/5QqpUX3VcwsAPkEo=,a4288f9116ea01c34efd65b7dce4357ba6f9c02ad984ca758fea0d0aebb605c9 +github.com/sean-/seed,v0.0.0-20170313163322-e2103e2c3529,h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=,0bc8e6e0a07e554674b0bb92ef4eb7de1650056b50878eed8d5d631aec9b6362 +github.com/sebest/xff,v0.0.0-20150611211316-7a36e3a787b5,h1:MqIPVG2sHTgcQxFwZ+iHZSQ869PVP42SgEEeI1+X4Y8=,8cbe518a78ab7998550c509bd9fadc95a1aef8e86b1022cb3d265348ad370cde +github.com/seccomp/libseccomp-golang,v0.9.1,h1:NJjM5DNFOs0s3kYE1WUOr6G8V97sdt46rlXTMfXGWBo=,5989692d87ef4c377fbc60d441795a90d9453b9e357d019e44d9033ab39ca888 +github.com/segmentio/go-loggly,v0.5.1-0.20171222203950-eb91657e62b2,h1:S4OC0+OBKz6mJnzuHioeEat74PuQ4Sgvbf8eus695sc=,5e071d0b6923a0fa78895bf7e673f5a4e482d39d4603b7dabd4056a506923ca7 +github.com/segmentio/go-prompt,v1.2.1-0.20161017233205-f0d19b6901ad,h1:EqOdoSJGI7CsBQczPcIgmpm3hJE7X8Hj3jrgI002whs=,b86fcda4b8afd5a3893ea333431368e60ea5ebee302a3014aee6d2020233bf31 +github.com/segmentio/kafka-go,v0.1.0,h1:IXCHG+sXPNiIR5pC/vTEItZduPKu4cnpr85YgxpxlW0=,e0b749b974d3277438d09dd6178928c3ad6c3760313f7ad45ec5cd88d8eb14b9 +github.com/serenize/snaker,v0.0.0-20171204205717-a683aaf2d516,h1:ofR1ZdrNSkiWcMsRrubK9tb2/SlZVWttAfqUjJi6QYc=,67272dde9cf92af80704869dea59346be1c37098373200dd8eea6e0e034079b4 +github.com/sergi/go-diff,v1.0.0,h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=,287218ffcd136dbb28ce99a2f162048d8dfa6f97b524c17797964aacde2f8f52 +github.com/serialx/hashring,v0.0.0-20180504054112-49a4782e9908,h1:RRpyb4kheanCQVyYfOhkZoD/cwClvn12RzHex2ZmHxw=,4184e14faf8e39222109eb2b7fa3aee2e0a544b66785ad0b7058318483ff76bb +github.com/sethgrid/pester,v0.0.0-20190127155807-68a33a018ad0,h1:X9XMOYjxEfAYSy3xK1DzO5dMkkWhs9E9UCcS1IERx2k=,ddcaf31e63aaf1ac003af97e667bedaa0fc89956e19aeb032c5658629da29800 +github.com/shiena/ansicolor,v0.0.0-20151119151921-a422bbe96644,h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo=,60da6dc53662eb72063784f3bf609edb7aa317c552f81651164bc657754902a6 +github.com/shirou/gopsutil,v2.19.10+incompatible,h1:lA4Pi29JEVIQIgATSeftHSY0rMGI9CLrl2ZvDLiahto=,e5afa6f0b690ecc3ff12458663c6337920a759f27c3d9692a0836644337e4e85 +github.com/shirou/w32,v0.0.0-20160930032740-bb4de0191aa4,h1:udFKJ0aHUL60LboW/A+DfgoHVedieIzIXE8uylPue0U=,3ed6741a7e1470feffb50031ecf9919f30b5f573f993683b6574488756ef65c1 +github.com/shopspring/decimal,v0.0.0-20191009025716-f1972eb1d1f5,h1:Gojs/hac/DoYEM7WEICT45+hNWczIeuL5D21e5/HPAw=,91a0ee539fb6f3de1550cdf93c73434fc8a16bab37be693997b20317510331a9 +github.com/shurcooL/component,v0.0.0-20170202220835-f88ec8f54cc4,h1:Fth6mevc5rX7glNLpbAMJnqKlfIkcTjZCSHEeqvKbcI=,2dd1cfac518def9fc8c6ac69022a85b0413269caf93d9532f77dca7375e1d645 +github.com/shurcooL/events,v0.0.0-20181021180414-410e4ca65f48,h1:vabduItPAIz9px5iryD5peyx7O3Ya8TBThapgXim98o=,1dcade8d00ba3945f5d1bc56c09a84e2d51fa20d20ef4fa6f867e5e4cd918e9d +github.com/shurcooL/github_flavored_markdown,v0.0.0-20181002035957-2122de532470,h1:qb9IthCFBmROJ6YBS31BEMeSYjOscSiG+EO+JVNTz64=,d984dc45e823f4c99e89841d675e34d2d35d3b334f1b3690fde05de30a66929f +github.com/shurcooL/githubv4,v0.0.0-20191006152017-6d1ea27df521,h1:ARaYJO1zp2afVv0s28fq7uxgee4WLop35FWrOoSZyak=,7f5c88b38760c5090bffe582a40abe7dc17a789f9041549e5c17e3d71df2d75d +github.com/shurcooL/go,v0.0.0-20180423040247-9e1955d9fb6e,h1:MZM7FHLqUHYI0Y/mQAt3d2aYa0SiNms/hFqC9qJYolM=,350e4c547dbeb657bb3b2eab428f1c29a80808e8096ff87324fd84744f914766 +github.com/shurcooL/go-goon,v0.0.0-20170922171312-37c2f522c041,h1:llrF3Fs4018ePo4+G/HV/uQUqEI1HMDjCeOf2V6puPc=,31cb3f736521597c56f962b9d7d21073620fbb1da845305aba743960f09e4115 +github.com/shurcooL/gofontwoff,v0.0.0-20180329035133-29b52fc0a18d,h1:Yoy/IzG4lULT6qZg62sVC+qyBL8DQkmD2zv6i7OImrc=,685dedb79602bb41403a7b5198f5c9d0ffbc99a68d7f99160ecf08a71475e5f4 +github.com/shurcooL/gopherjslib,v0.0.0-20160914041154-feb6d3990c2c,h1:UOk+nlt1BJtTcH15CT7iNO7YVWTfTv/DNwEAQHLIaDQ=,ea6c396c92724a8028793bde957dbe9a1c594b8af085035e652d4335e6aa30e1 +github.com/shurcooL/graphql,v0.0.0-20181231061246-d48a9a75455f,h1:tygelZueB1EtXkPI6mQ4o9DQ0+FKW41hTbunoXZCTqk=,eb1b45dc90aed0edcfc4cacffdc2645121dda8155702440eada1bcafefddcbba +github.com/shurcooL/highlight_diff,v0.0.0-20170515013008-09bb4053de1b,h1:vYEG87HxbU6dXj5npkeulCS96Dtz5xg3jcfCgpcvbIw=,b4bcb7f3e50a99623d5f39c4e054964fc60d5e4b34543408582a0a984a67b630 +github.com/shurcooL/highlight_go,v0.0.0-20181028180052-98c3abbbae20,h1:7pDq9pAMCQgRohFmd25X8hIH8VxmT3TaDm+r9LHxgBk=,9f879b051c8eadb6dc063ca3ff6856d0e64cd30b5ad545e580b77b4f8ef9ddd7 +github.com/shurcooL/home,v0.0.0-20181020052607-80b7ffcb30f9,h1:MPblCbqA5+z6XARjScMfz1TqtJC7TuTRj0U9VqIBs6k=,0042d859afa3221fd4b4049b350a2d6ffcc674e4c4177bb0c232dc120b410ee6 +github.com/shurcooL/htmlg,v0.0.0-20190503024804-b6326af49ef6,h1:kXXs9Xnfv5gU7KLKiOE3AQgaRUUXchcXnO2rP3fZ5Ao=,52485f17bba8920b37a70124b90eea9d43037a9764a785c97a7e531ca09ed5a5 +github.com/shurcooL/httperror,v0.0.0-20190506043526-2e76094aa70e,h1:QTph/PpT1aDtFHk0sVJoVG/Vfox0YZkq70sW/tvXJM0=,7807129d1577611bdf803b7a4dd3253f45e4b63a77c1a73bed48a0c838c463c6 +github.com/shurcooL/httpfs,v0.0.0-20190707220628-8d4bc4ba7749,h1:bUGsEnyNbVPw06Bs80sCeARAlK8lhwqGyi6UT8ymuGk=,a2079dbd8c236262ecbb22312467265fbbddd9b5ee789531c5f7f24fbdda174b +github.com/shurcooL/httpgzip,v0.0.0-20190720172056-320755c1c1b0,h1:mj/nMDAwTBiaCqMEs4cYCqF7pO6Np7vhy1D1wcQGz+E=,70ef73fce2f89d622f828cb439fd6c7b48a7fe63600410a8c0a936042c0e4631 +github.com/shurcooL/issues,v0.0.0-20190705005435-6a96395fbb66,h1:kls/E9JqtKEj8tWx2PwKCWqEWmwzsX7cnj9QkaEhUpM=,dd1ace2ad69b6c130a9294c3eb4032090e73c3b7dace098a5a7e1ad154f8e911 +github.com/shurcooL/issuesapp,v0.0.0-20180602232740-048589ce2241,h1:Y+TeIabU8sJD10Qwd/zMty2/LEaT9GNDaA6nyZf+jgo=,ac947684d3f13beef9433724deddc2c7ddb6d19921d6902f4789dd4ce1af5f3c +github.com/shurcooL/notifications,v0.0.0-20181111060504-bcc2b3082a7a,h1:bQX0+HfDylIQCtf1tzyrxQ+BqIV08ZjkjgspFWiIYhc=,c1c77700f490d0211cec00fd5fd0ee80debf66e0e41de1dc68b24dc726db5409 +github.com/shurcooL/octicon,v0.0.0-20190930024621-43309dfb482e,h1:C2+alklsN4yRHXaOX3v9TuCGlTSwZQjSnN88nLGVhg8=,88953a9951a14e24afd2d1040e9de0b4fbe194805fdc7ec9d9d9bbcd8c2f3448 +github.com/shurcooL/reactions,v0.0.0-20181222204718-145cd5e7f3d1,h1:hHIhW4KrmPQ/hJ7AuKNNvVPVE2k/LVE5NTFsQ68taBw=,fd5f9a0c6e7e292bdfa81fcad767f61c95dc84f18bf4f9f02a4fe02f75327d37 +github.com/shurcooL/sanitized_anchor_name,v1.0.0,h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=,0af034323e0627a9e94367f87aa50ce29e5b165d54c8da2926cbaffd5834f757 +github.com/shurcooL/users,v0.0.0-20180125191416-49c67e49c537,h1:YGaxtkYjb8mnTvtufv2LKLwCQu2/C7qFB7UtrOlTWOY=,3f17089e996438a88a478d38807ce4f3c045a91114830946a1bdc760eb2b7c58 +github.com/shurcooL/vfsgen,v0.0.0-20181202132449-6a9ea43bcacd,h1:ug7PpSOB5RBPK1Kg6qskGBoP3Vnj/aNYFTznWvlkGo0=,8a093681b21159514a1742b1a49e88fa2cf562673a5a0055e9abeb7ff590ee19 +github.com/shurcooL/webdavfs,v0.0.0-20170829043945-18c3829fa133,h1:JtcyT0rk/9PKOdnKQzuDR+FSjh7SGtJwpgVpfZBRKlQ=,bb70104152800cbb490c480bead0d2ef24176be9e1304e6701ab161115484863 +github.com/siddontang/go,v0.0.0-20180604090527-bdc77568d726,h1:xT+JlYxNGqyT+XcU8iUrN18JYed2TvG9yN5ULG2jATM=,ef97fabc8a96a758fac273b01dff6be7957ed44c4b6c6a8316f43741329a0049 +github.com/siddontang/go-snappy,v0.0.0-20140704025258-d8f7bb82a96d,h1:qQWKKOvHN7Q9c6GdmUteCef2F9ubxMpxY1IKwpIKz68=,faf83d6459d06f5f4a9acd09e23e284e11792d14de331bd7b87852b18f9cf5c3 +github.com/siddontang/ledisdb,v0.0.0-20190202134119-8ceb77e66a92,h1:qvsJwGToa8rxb42cDRhkbKeX2H5N8BH+s2aUikGt8mI=,dab81c0bdfc62063a340f61dfab19c065d2d10b1245cd56cc04832130a6bbea5 +github.com/siddontang/rdb,v0.0.0-20150307021120-fc89ed2e418d,h1:NVwnfyR3rENtlz62bcrkXME3INVUa4lcdGt+opvxExs=,93bf89960d84b8732e648cb413dced692c1d3d9000997e99826538a5f20b1d82 +github.com/sigurn/crc8,v0.0.0-20160107002456-e55481d6f45c,h1:hk0Jigjfq59yDMgd6bzi22Das5tyxU0CtOkh7a9io84=,12916a0da94e747b99653138a25112e24b082db53bc0d5cffe62214ce3fb884d +github.com/sigurn/utils,v0.0.0-20190728110027-e1fefb11a144,h1:ccb8W1+mYuZvlpn/mJUMAbsFHTMCpcJBS78AsBQxNcY=,694bb4cbe9dd17447c1e0054ef327eebd9bed8682aa39f5f4d282fb9b1717299 +github.com/sirupsen/logrus,v1.4.2,h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=,9a8e55830261a4b1c9350d7c45db029c8586c0b2d934d1224cde469425031edd +github.com/skratchdot/open-golang,v0.0.0-20190402232053-79abb63cd66e,h1:VAzdS5Nw68fbf5RZ8RDVlUvPXNU6Z3jtPCK/qvm4FoQ=,242db3338b172ecb58bdf3406b4cafecfa738cfb7b8cd71698d23831aedd94b0 +github.com/skyrings/skyring-common,v0.0.0-20160929130248-d1c0bb1cbd5e,h1:jrZSSgPUDtBeJbGXqgGUeupQH8I+ZvGXfhpIahye2Bc=,d5010d4900d7417c05d4863399e5509e82dfaca9c09c31ac9e5ebdcaf109e833 +github.com/smallnest/libkv-etcdv3-store,v0.0.0-20191101045330-f92940446965,h1:YQtdLz+7JQdKn7f5cG+xSrSbI7X4jObx0Jy6ZzffGew=,b9fb22d7d67e16cd3a1d7c7a5b2faf6c35c690ae1c3bcf70dbf77813db7dc563 +github.com/smallnest/rpcx,v0.0.0-20191101045608-2a801682117a,h1:Fzp1HLqyYg8koEELgwfSEUgkE6QPvrN9qCkHZ8tikFY=,0d2255c9ffc429e32936dbb9e51c79bbf2b76a7dec95c5d9dc1668053d5642bc +github.com/smallnest/valkeyrie,v0.0.0-20191030064635-54a884e4b303,h1:NDOAHb1sE8pYWd0Dge8W6bGQ63FHfa0/QjClXG2hrgw=,b846d492aaf7053115b2e143b7c7696299b852ec670d261bd78b5cd996eacde3 +github.com/smartystreets/assertions,v1.0.1,h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w=,2e3d9f61f68cdf7b48653582640ef88744c1a3bdd4257ac68f621579a2f807dd +github.com/smartystreets/go-aws-auth,v0.0.0-20180515143844-0c1422d1fdb9,h1:hp2CYQUINdZMHdvTdXtPOY2ainKl4IoMcpAXEf2xj3Q=,d9441cfbef2c680269ced67f8e1d99af9cf649e11a7f133a5b0685be0277ca7d +github.com/smartystreets/goconvey,v0.0.0-20190731233626-505e41936337,h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8=,fd90be078397b45806e4dfaca367235aef6d6133871c8a6cc6d3d579280d8d03 +github.com/smartystreets/gunit,v1.0.0,h1:RyPDUFcJbvtXlhJPk7v+wnxZRY2EUokhEYl2EJOPToI=,36cf43529cfadeb297ce1537c7d0fca8373a95936806121ce7ce0bf653e959ee +github.com/smola/gocompat,v0.2.0,h1:6b1oIMlUXIpz//VKEDzPVBK8KG7beVwmHIUEBIs/Pns=,7812934f407beeab20aa289b0056234ae6637b30b301ebf97a5d7a9fd8e665fc +github.com/snikch/goodman,v0.0.0-20171125024755-10e37e294daa,h1:YJfZp12Z3AFhSBeXOlv4BO55RMwPn2NoQeDsrdWnBtY=,ab939c56cb7afcff213aef4568f40c9ddeae30166e34a2fa7f5718a47227c2e1 +github.com/softlayer/softlayer-go,v0.0.0-20180806151055-260589d94c7d,h1:bVQRCxQvfjNUeRqaY/uT0tFuvuFY0ulgnczuR684Xic=,63ad57bc2d4c27db3dcab7cf545a075bb4d7ea66aba57c284c07a2c938220f8c +github.com/soheilhy/cmux,v0.1.4,h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=,6d6cadade0e186f84b5f8e7ddf8f4256601b21e49b0ca49fd003a7e570ae1885 +github.com/songtianyi/rrframework,v0.0.0-20180901111106-4caefe307b3f,h1:o3QHyJEW1U+8oyEZeaXFcYqdhhiZjrs25/8AZmsWjiU=,b1cf04474a48de1ed7ae535ae4a2d5b17a0df4ce0d3b953c5268f42ee34cb17d +github.com/soniakeys/unit,v1.0.0,h1:UMIgu6dxDQaK6tYaQV6dJn5oovB6035KRxCS0O7Jiec=,565c64fe777e1140d82422e9b8d29ce8de82d7916e50dac2f7591d2c6f2d79e7 +github.com/sony/gobreaker,v0.4.1,h1:oMnRNZXX5j85zso6xCPRNPtmAycat+WcoKbklScLDgQ=,eab9bf8f98b16b051d7d13c4f5c70d6d1039347e380e0a12cb9ff6e33200d784 +github.com/sourcegraph/annotate,v0.0.0-20160123013949-f4cad6c6324d,h1:yKm7XZV6j9Ev6lojP2XaIshpT4ymkqhMeSghO5Ps00E=,2a58cbf2485b2e97e49d7c3e83e81385d1418bfbab2b846dabec041a3d402b3e +github.com/sourcegraph/syntaxhighlight,v0.0.0-20170531221838-bd320f5d308e,h1:qpG93cPwA5f7s/ZPBJnGOYQNK/vKsaDaseuKT5Asee8=,c0e6323ed7a5dcddcdd7686f2d7c68dff44a8ecbfd6818db3bdb33a7af422792 +github.com/spacemonkeygo/errors,v0.0.0-20171212215202-9064522e9fd1,h1:xHQewZjohU9/wUsyC99navCjQDNHtTgUOM/J1jAbzfw=,b360a46f9534dd46d2b2c27c84ba8bbe3942832e74aa4ceb16acaa6ba30620be +github.com/spacemonkeygo/monotime,v0.0.0-20180824235756-e3f48a95f98a,h1:8+cCjxhToanKmxLIbuyBNe2EnpgwhiivsIaRJstDRFA=,4a55e556811ab93b23b46907b354e53fc553eb93314cf0b524933f37ac1437f8 +github.com/spacemonkeygo/openssl,v0.0.0-20181017203307-c2dcc5cca94a,h1:/eS3yfGjQKG+9kayBkj0ip1BGhq6zJ3eaVksphxAaek=,23031c8d37bbaa5aace338eed65af68c7d72bf134d7d0e09c963ed4974c56e58 +github.com/spacemonkeygo/spacelog,v0.0.0-20180420211403-2296661a0572,h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU=,91eb98e80c44d42e6f3ff7ddf84f825d20eb55669452d752fb8ed3adeb723be7 +github.com/spaolacci/murmur3,v1.1.0,h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=,60bd43ada88cc70823b31fd678a8b906d48631b47145300544d45219ee6a17bc +github.com/spf13/afero,v1.2.2,h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=,81d51799397212c9adb2cea6cf3a96a2b50f1baff8aff7bd410128a84f2a9e73 +github.com/spf13/cast,v1.3.0,h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=,001ed519a3ec007e76e639f72bd9560be70497d499acbf1a32ccf32dc4647d91 +github.com/spf13/cobra,v0.0.5,h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=,6c6739f11d69fa1e5b60ba1e04529f355f8a30e1aa2b137ba26260de8fa7a647 +github.com/spf13/fsync,v0.9.0,h1:f9CEt3DOB2mnHxZaftmEOFWjABEvKM/xpf3cUwJrGOY=,d470c73c6e821d6c8f47ce05be3360f4d686d9079dd5af1585420c73e4725c56 +github.com/spf13/jwalterweatherman,v1.1.0,h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=,43cc5f056caf66dc8225dca36637bfc18509521b103a69ca76fbc2b6519194a3 +github.com/spf13/pflag,v1.0.5,h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=,fc6e704f2f6a84ddcdce6de0404e5340fa20c8676181bf5d381b17888107ba84 +github.com/spf13/viper,v1.5.0,h1:GpsTwfsQ27oS/Aha/6d1oD7tpKIqWnOA6tgOX9HHkt4=,7f3513d0a1186b765937c788f0ac751076067b7a0abc82420171b6f262787ac5 +github.com/src-d/envconfig,v1.0.0,h1:/AJi6DtjFhZKNx3OB2qMsq7y4yT5//AeSZIe7rk+PX8=,c694b1440b6969dfd4ebcba669faea8a05bdc7791ac78dcfbe29f153b0a8f0cd +github.com/src-d/gcfg,v1.4.0,h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4=,2aa52404cbeec89c0a976d333448d1a4a6e113f03e000a715ce9006c84eb2e32 +github.com/srwiley/oksvg,v0.0.0-20190829233741-58e08c8fe40e,h1:LJUrNHytcMXWKxnULIHPe5SCb1jDpO9o672VB1x2EuQ=,e29e85accb2169d2f0f4dc90c22c446c24d244d68e0bbe038ba9df63381916c5 +github.com/srwiley/rasterx,v0.0.0-20181219215540-696f7edb7a7e,h1:FFotfUvew9Eg02LYRl8YybAnm0HCwjjfY5JlOI1oB00=,8a4b0686258a3e1b4f8b3e5f25efbaaefe7919d4e47e89eb36a6779504f8b116 +github.com/ssdb/gossdb,v0.0.0-20180723034631-88f6b59b84ec,h1:q6XVwXmKvCRHRqesF3cSv6lNqqHi0QWOvgDlSohg8UA=,2c20531d93416fa34ee9039308166c869c72c16fff715c73c05a3977157fdc2d +github.com/ssor/bom,v0.0.0-20170718123548-6386211fdfcf,h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo=,7622ce25bbc5d5376ccb113f267f3d68bf2363963b02d04c053dfbc252f62c4a +github.com/steakknife/bloomfilter,v0.0.0-20180922174646-6819c0d2a570,h1:gIlAHnH1vJb5vwEjIp5kBj/eu99p/bl0Ay2goiPe5xE=,fb001f6df1197d462e7dfdbeded863aebd85bb904da5075117174a027a1b8cb1 +github.com/steakknife/hamming,v0.0.0-20180906055917-c99c65617cd3,h1:njlZPzLwU639dk2kqnCPPv+wNjq7Xb6EfUxe/oX0/NM=,e42bd1bc7073772613c2b4879110dd5330fded46a8cdf9269ff03cb6a82d1108 +github.com/stellar/go,v0.0.0-20191031165136-ed88b67b723d,h1:0pucQZ9fngYUl/tIGO/H96N3F5NL5ySjM3fuz+XEFSY=,d9d23bd5fc8cae6e65d4bb0d87e3cb582bc684eac1a519ca787b187a175999a5 +github.com/stellar/go-xdr,v0.0.0-20180917104419-0bc96f33a18e,h1:n/hfey8pO+RYMoGXyvyzuw5pdO8IFDoyAL/g5OiCesY=,5122e57a861bd0c38a3a3607f13576a150face8cacf9cafaf24e21e38a104b87 +github.com/stellar/throttled,v2.2.3-0.20190823235211-89d75816f59d+incompatible,h1:jMXXAcz6xTarGDQ4VtVbtERogcmDQw4RaE85Cr9CgoQ=,a89e929d8d8ba24e621c479708378263714861d8fce137085108da9f0cc8805a +github.com/steveyen/gtreap,v0.0.0-20150807155958-0abe01ef9be2,h1:JNEGSiWg6D3lcBCMCBqN3ELniXujt+0QNHLhNnO0w3s=,64b6a1f094784f1a843a6787bd159a103b9bebd2e85cc09a7e8445cc9e3ffc03 +github.com/streadway/amqp,v0.0.0-20190827072141-edfb9018d271,h1:WhxRHzgeVGETMlmVfqhRn8RIeeNoPr2Czh33I4Zdccw=,66bd109504bf565a4a777c20a8cf6a1c5d05cd87b59baa50da8b6f2b0da4c494 +github.com/stretchr/objx,v0.2.0,h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=,5517d43cfb7e628b9c2c64010b934e346cd24726e3d6eaf02b7f86e10752e968 +github.com/stretchr/testify,v1.4.0,h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=,0400c42ab95389bb4f4577bc09917a040a97f0f4251db2a54a7f6f5e65065b73 +github.com/stripe/stripe-go,v66.1.1+incompatible,h1:D8qUD1rxv+RdXi2qo+IdDELkDevxYUQDfje20bGQPiw=,471de64dbc99da2b83fc1822ff9b4627b1b0738a8e3ee9ffb038510ce84e4baf +github.com/struCoder/pidusage,v0.1.2,h1:fFPTThlcWFQyizv3xKs5Lyq1lpG5lZ36arEGNhWz2Vs=,6ae03cd6cab9014ca7c0326fc233b27d942556c9753d2da87a93dd0fecbb9986 +github.com/stumble/gorocksdb,v0.0.3,h1:9UU+QA1pqFYJuf9+5p7z1IqdE5k0mma4UAeu2wmX8kA=,8bf18874189196133dabeb8fb7444633a0961e8983f8b2d8588d522d6aa679de +github.com/subosito/gotenv,v1.2.0,h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=,21474df92536f36de6f91dfbf466995289445cc4e5a5900d9c40ae8776b8b0cf +github.com/svanharmelen/jsonapi,v0.0.0-20180618144545-0c0828c3f16d,h1:Z4EH+5EffvBEhh37F0C0DnpklTMh00JOkjW5zK3ofBI=,482b13f426a15f3cb64ae5cb1a5fd2f27ca142465a174e24a2cc356812a3ed28 +github.com/swaggo/files,v0.0.0-20190704085106-630677cd5c14,h1:PyYN9JH5jY9j6av01SpfRMb+1DWg/i3MbGOKPxJ2wjM=,e1fe1ffca3a181bede3787e75797345bc69a583a67d8bb10b934f7a140516162 +github.com/swaggo/gin-swagger,v1.2.0,h1:YskZXEiv51fjOMTsXrOetAjrMDfFaXD79PEoQBOe2W0=,7ba6476ca79affa95429821a187b7cb3458305737ac2d1b86340814c3f276f71 +github.com/swaggo/swag,v1.6.3,h1:N+uVPGP4H2hXoss2pt5dctoSUPKKRInr6qcTMOm0usI=,1adbe98538a3f1b5e64fdf08f86cea4502a2c0d0cf1b047a27af6acf764f8c17 +github.com/syndtr/gocapability,v0.0.0-20180916011248-d98352740cb2,h1:b6uOv7YOFK0TYG7HtkIgExQo+2RdLuwRft63jn2HWj8=,ece41bcca6ca06202649ccee0d2ab62667217ceb70f3a84794c3751c16b75cee +github.com/syndtr/goleveldb,v1.0.1-0.20190318030020-c3a204f8e965,h1:1oFLiOyVl+W7bnBzGhf7BbIv9loSFQcieWWYIjLqcAw=,b0dbd1bdec73ea70eb1db85322046d202bcbfe901bc821d6a50ffc182c276306 +github.com/tarm/serial,v0.0.0-20180830185346-98f6abe2eb07,h1:UyzmZLoiDWMRywV4DUYb9Fbt8uiOSooupjTq10vpvnU=,cd962b3b9ef46158abad455c95ed92f2632cdb9217df2b7690171cc3db507add +github.com/tatsushid/go-fastping,v0.0.0-20160109021039-d7bb493dee3e,h1:nt2877sKfojlHCTOBXbpWjBkuWKritFaGIfgQwbQUls=,1c25333d4ca05ca13828835e07876c0efdd90a1c32a715527aa722b3c63c2d48 +github.com/tchap/go-patricia,v2.3.0+incompatible,h1:GkY4dP3cEfEASBPPkWd+AmjYxhmDkqO9/zg7R0lSQRs=,19db63cf16ba944ea853c18397e4336342f1e95e4b2cb12127405bb64c67cf73 +github.com/tdewolff/minify,v2.3.6+incompatible,h1:2hw5/9ZvxhWLvBUnHE06gElGYz+Jv9R4Eys0XUzItYo=,8cabb8163bd65e43b42c5842b700d55e2daeae60c82b019007aceb1ae63638d5 +github.com/tdewolff/minify/v2,v2.5.2,h1:If/q1brvT+91oWiWnIMEGuFcwWtpB6AtLTxba78tvMs=,0af37ec252d094917a1ff4178659fe9f4539fdc3dca108bbeb9c0c2f86499eb9 +github.com/tdewolff/parse,v2.3.4+incompatible,h1:x05/cnGwIMf4ceLuDMBOdQ1qGniMoxpP46ghf0Qzh38=,f290dda8150ebdc2b9586f509770a6c82093ac9027329aeb9f3004a0b26de8e9 +github.com/tdewolff/parse/v2,v2.3.9,h1:d8/K6XOLy5JVpLTG9Kx+SxA72rlm5OowFmVSVgtOlmM=,5f517cbecd071b97ed822e8f88f96ba7d8b5a8accc49fc515298210ac088e7ef +github.com/tdewolff/test,v1.0.4,h1:ih38SXuQJ32Hng5EtSW32xqEsVeMnPp6nNNRPhBBDE8=,807205136d8f39bb7533d10b72932a183f15b45c385cd5464ae9d06e4af43337 +github.com/tealeg/xlsx,v1.0.5,h1:+f8oFmvY8Gw1iUXzPk+kz+4GpbDZPK1FhPiQRd+ypgE=,ff32f4336aed03df7c9cb7a4df9f1f42a1c64fe5d17c34566159511943d24bde +github.com/tecbot/gorocksdb,v0.0.0-20181010114359-8752a9433481,h1:HOxvxvnntLiPn123Fk+twfUhCQdMDaqmb0cclArW0T0=,26c0e94162340c7b4d1da3ee4c71ca03f9d6638711cf440d6835e1a8f07e4fb4 +github.com/technoweenie/multipartstreamer,v1.0.1,h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=,5a9aff85522275b125767b746869d24f4e2f776d5031631bf6e29641d99344dc +github.com/tedsuo/ifrit,v0.0.0-20191009134036-9a97d0632f00,h1:mujcChM89zOHwgZBBNr5WZ77mBXP1yR+gLThGCYZgAg=,1c502a5584dfbce25ff99c1a5689e2d106a138989e4a03249221ca4818674098 +github.com/tedsuo/rata,v1.0.0,h1:Sf9aZrYy6ElSTncjnGkyC2yuVvz5YJetBIUKJ4CmeKE=,f6745fd8ef8ee098410b31b1219def2c4e86c337ba6ff1319f086419b928f134 +github.com/temoto/robotstxt,v1.1.1,h1:Gh8RCs8ouX3hRSxxK7B1mO5RFByQ4CmJZDwgom++JaA=,c37f16f826a27512b7ae683ed32be5124a0252d1c7a8c4a00fd4e27d01c563d4 +github.com/templexxx/cpufeat,v0.0.0-20180724012125-cef66df7f161,h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU=,c29bd644943d69b238da1936593421373d2db675a0fce54090d1c8b7eab7397b +github.com/templexxx/xor,v0.0.0-20181023030647-4e92f724b73b,h1:mnG1fcsIB1d/3vbkBak2MM0u+vhGhlQwpeimUi7QncM=,578ab42785a74d1a5dd3e65bf0979138b3a98bf877de4767b8eae5701a2342e1 +github.com/tencentcloud/tencentcloud-sdk-go,v3.0.71+incompatible,h1:9sIWfe6ZC7xoSlshYWNGicPqomK7N+CsHMa1YFWBCWU=,33a9526ee0244844270e532358a22616d821cc7f8f0638e33c60f722f84c5e42 +github.com/tendermint/btcd,v0.1.1,h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s=,1967aa3cbabfb9e9780c0371a5359cc21ed77e5673b64e7dd5b234e838c82e62 +github.com/tendermint/crypto,v0.0.0-20180820045704-3764759f34a5,h1:u8i49c+BxloX3XQ55cvzFNXplizZP/q00i+IlttUjAU=,49ad334d452402d59757d3a415602f57bd7b66962d6115262f5c7413112d61bb +github.com/tendermint/ed25519,v0.0.0-20171027050219-d8387025d2b9,h1:zccWau0P8FELSb4HTDJ88hRo+WVNMbIbg27rFqDrhCE=,7c4a6e57c787df7c6e990c35bb31df3f4a5aa89f45c3b3df4a25dfb70c01f7e3 +github.com/tendermint/go-amino,v0.15.1,h1:D2uk35eT4iTsvJd9jWIetzthE5C0/k2QmMFkCN+4JgQ=,e91cde0d10d5a8ea6ab726fbab02ef737ba52f47e207cf675440f625153d3205 +github.com/tendermint/iavl,v0.12.2,h1:Ls5p5VINCM1HRT9g5Vvs2zmDOCU/CCIvIHzd/pZ8P0E=,a56011434929c4003fd735cbef8147e8aca3d241983c5fa7a006f5753e123020 +github.com/tendermint/tendermint,v0.32.7,h1:Szu5Fm1L3pvn3t4uQxPAcP+7ndZEQKgLie/yokM56rU=,495a31dc762d79a689ce00cdd52f66b6b4071fc2b738ce4b3d1c2a9447389ecc +github.com/tendermint/tm-db,v0.2.0,h1:rJxgdqn6fIiVJZy4zLpY1qVlyD0TU6vhkT4kEf71TQQ=,99b7c1a00ee483b97e73126a25327b75da9a5bc6e34bf9fb1ecd6b83832fe13e +github.com/tent/http-link-go,v0.0.0-20130702225549-ac974c61c2f9,h1:/Bsw4C+DEdqPjt8vAqaC9LAqpAQnaCQQqmolqq3S1T4=,a4fe19fdbf8fbc30fe866e2cbb8761ee179f4a83bda63a0a6d30a651f3700ec2 +github.com/terraform-providers/terraform-provider-openstack,v1.15.0,h1:adpjqej+F8BAX9dHmuPF47sUIkgifeqBu6p7iCsyj0Y=,9c7419845747d0c4e3a9432f50788d8adec7ed6fca93ec9ffbf99e8c8b1cf0c3 +github.com/testcontainers/testcontainers-go,v0.0.8,h1:71E+jJpE9dSgydCfn5aWESVM7+l8giw/DBWaTy35TTU=,bceec8989a3beb9f14802c13c496c9158509f6b4cee6f855c0fb06b01e7da150 +github.com/tevino/abool,v0.0.0-20170917061928-9b9efcf221b5,h1:hNna6Fi0eP1f2sMBe/rJicDmaHmoXGe1Ta84FPYHLuE=,924168edd97fe37d4af80990d69c1d11d06b8e9236ebae65b9b68ba0261baaf1 +github.com/tgulacsi/picago,v0.0.0-20171229130838-9e1ac2306c70,h1:elvpffAnrLcWnsunBkvTwxr+Q79bPSNT1+2/pOFkCj0=,68e0cb434718215eae670723ce9327ec16d462a6403007ca22b6af71346445c5 +github.com/thanos-io/thanos,v0.3.2,h1:gNWga6sqv5kZp6ltaA7oUIFj+tTG2ohq4W9SQ4YU6ds=,99491658e5ed421ba1563818dd7c01034803fa1e0c4e5d7c28b06f3d3ed2a570 +github.com/theplant/cldr,v0.0.0-20190423050709-9f76f7ce4ee8,h1:di0cR5qqo2DllBMwmP75kZpUX6dAXhsn1O2dshQfMaA=,214ea2cc1e66f278928d0b5b1b40a3e12358b7a71e0fa6d6ea606c4d687e8eef +github.com/theupdateframework/notary,v0.6.1,h1:7wshjstgS9x9F5LuB1L5mBI2xNMObWqjz+cjWoom6l0=,f921dfb3d54538118367d9018d9abacc3c0c026951442140d669443977180b66 +github.com/thoj/go-ircevent,v0.0.0-20180816043103-14f3614f28c3,h1:389FrrKIAlxqQMTscCQ7VH3JAVuxb/pe53v2LBiA7z8=,32edd7a9e219bdff36d2aac0c6c5f3ac982c2daf4869e6e0718e917efb23b3de +github.com/tiancaiamao/appdash,v0.0.0-20181126055449-889f96f722a2,h1:mbAskLJ0oJfDRtkanvQPiooDH8HvJ2FBh+iKT/OmiQQ=,a9961e6079339aec983f97fdb39d5d7258bf8d2031da68482e58e17b27a93a78 +github.com/tidwall/gjson,v1.3.3,h1:wM/XREVc9c0LbRLcNMgVcGpI16r0pbbTJpltR4jJjh0=,17da724ffc86cfb3132bd9c7ac3eb860ca43a2748be519a59aa50b436c147bc6 +github.com/tidwall/match,v1.0.1,h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc=,a1b9d52b9a4c7574f46068665279522f2084be26bac71594630786f6ee9a70f2 +github.com/tidwall/pretty,v1.0.0,h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=,3b25a1a0fe7688989326aaa1ca1c74c972b30152ef2a756fbf2d217a827fc07d +github.com/tidwall/sjson,v1.0.4,h1:UcdIRXff12Lpnu3OLtZvnc03g4vH2suXDXhBwBqmzYg=,cb47595016d45d72e6ee0f5585a86247aaeb93d9efa74e07676d32f60e8a7398 +github.com/tildeleb/cuckoo,v0.0.0-20190627040100-71059d5a2b62,h1:rXSNik45VDd1hfRLUAZwDLCY0FWvn2KlCeXjbd1yAI0=,f81f44544ec771ab630ddd5d65f4735ba2acc7619e41ccbc4bfad2473c21dc2f +github.com/timewasted/linode,v0.0.0-20160829202747-37e84520dcf7,h1:CpHxIaZzVy26GqJn8ptRyto8fuoYOd1v0fXm9bG3wQ8=,9a3190b3751964a3d47449265d48e2d3a76b23c66a7cb402cc9bdf3d732d82b4 +github.com/tinylib/msgp,v1.1.0,h1:9fQd+ICuRIu/ue4vxJZu6/LzxN0HwMds2nq/0cFvxHU=,61bd58489c555b30abffbe1175565b6f8460583349118e9ee12025fd17b67ea4 +github.com/tj/assert,v0.0.0-20171129193455-018094318fb0,h1:Rw8kxzWo1mr6FSaYXjQELRe88y2KdfynXdnK72rdjtA=,59a81d1883aac9635ac15d8a6a6e0630cf0a4122328116f921289dab840374b7 +github.com/tj/cobra,v0.0.0-20160702192511-5e2db986a612,h1:eiUtRvCN5HSnOg9AyX5z5od5VWy/ukyJ2oTboInm9MM=,493ac2ac61730652fcdd0b9b4c1e0c63855666df7fcaa02821b63982a5a7ccdf +github.com/tj/go-elastic,v0.0.0-20171221160941-36157cbbebc2,h1:eGaGNxrtoZf/mBURsnNQKDR7u50Klgcf2eFDQEnc8Bc=,a0df933432e9c7ec276cbc0edbb941375726cf5a39c663aafe0e945f9ba3079f +github.com/tj/go-kinesis,v0.0.0-20171128231115-08b17f58cb1b,h1:m74UWYy+HBs+jMFR9mdZU6shPewugMyH5+GV6LNgW8w=,0885f4631d33a20b5447ebbe12a0d23eb5ea3394de4bbc849cfe54ad19cadb2a +github.com/tj/go-spin,v1.1.0,h1:lhdWZsvImxvZ3q1C5OIB7d72DuOwP4O2NdBg9PyzNds=,060d09c35b1db5992747cde71ccbdaefe596ada06a6fe146e0ef10dc67d817dd +github.com/tj/pflag,v0.0.0-20160702191705-e367e44eec04,h1:RAPJe7XUQhTjVUKvYegzhXnWkJd/1daXdoiXjvkSURU=,2156357bb17b30ccb893b8f7013168c85c1eb265b7156aca845d06fb35805257 +github.com/tjfoc/gmsm,v1.0.1,h1:R11HlqhXkDospckjZEihx9SW/2VW0RgdwrykyWMFOQU=,f8fe3c4d02f0dc90fd873278957d57c4c45f1c53b1fee3969216b67844efabb1 +github.com/tmc/grpc-websocket-proxy,v0.0.0-20190109142713-0ad062ec5ee5,h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ=,dadf62266d259ffb6aa1d707892b97fa36c3f39df5cae99f54d3ef7682995376 +github.com/tomnomnom/linkheader,v0.0.0-20180905144013-02ca5825eb80,h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y=,558504ea96d4312be0fe5faa6de13fb6abd8f1b2ac154123c67b623a5f219cdb +github.com/toqueteos/webbrowser,v1.2.0,h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9rrstGQ=,1227d3ebeab16d8232a304a10b087984a96ad30f7439b6687bab2f5747d308cf +github.com/transip/gotransip,v0.0.0-20190812104329-6d8d9179b66f,h1:clyOmELPZd2LuFEyuo1mP6RXpbAW75PwD+RfDj4kBm0=,38b593cbdeb59e64d042533c1ce6196d89662de3282373de0d3c0749fe4c4856 +github.com/trivago/tgo,v1.0.5,h1:ihzy8zFF/LPsd8oxsjYOE8CmyOTNViyFCy0EaFreUIk=,06dc60662735374365cd525e2f4f4d1580f348125546e1f3e0d92d2deca4fa9a +github.com/tstranex/u2f,v1.0.0,h1:HhJkSzDDlVSVIVt7pDJwCHQj67k7A5EeBgPmeD+pVsQ=,325e3db32035ce38a5981bfaa35fb6d9b5cb4b960cfa0285b92448d21d29f379 +github.com/tsuru/config,v0.0.0-20180418191556-87403ee7da02,h1:mHuZ6JOixltE9fJmS+W1xLi4t/uDuR6Nl7w/e4uj0+I=,0255268934770d67b9d101a030ed7ed578938e346a279a273ab3983b0eee53fb +github.com/ttacon/chalk,v0.0.0-20160626202418-22c06c80ed31,h1:OXcKh35JaYsGMRzpvFkLv/MEyPuL49CThT1pZ8aSml4=,325521131515e4840e0083bc62cd9553da0b8d2480820f7e92ca89ae324f4c23 +github.com/tus/tusd,v1.0.1,h1:jb0SDf8zCUvlWv5SuHalOuRn684aW6WIvhfWRHC/XB8=,9a91d59123262b9bb1c43d39588a26d7560513b9e3c18254cd321890e8975083 +github.com/tv42/httpunix,v0.0.0-20150427012821-b75d8614f926,h1:G3dpKMzFDjgEh2q1Z7zUUtKa8ViPtH+ocF0bE0g00O8=,8246ebc82e0d9d3142f5aeb50d4fcd67f3f435fb5464120c356a4e5d57ef4aa0 +github.com/twinj/uuid,v1.0.0,h1:fzz7COZnDrXGTAOHGuUGYd6sG+JMq+AoE7+Jlu0przk=,842c314d6d2ef9cb95b0f3f1b4cf998715680e836cfab8c2a7f75e351765a345 +github.com/twitchtv/twirp,v5.8.0+incompatible,h1:DTfGS9u/jHbo34cBB+qhzVHRaAq+tRois71j8pvjQ5M=,a4137792083eedd9ac04e88918d8952a841120b11e71161d2d444065b8e65d79 +github.com/tyler-smith/go-bip39,v1.0.2,h1:+t3w+KwLXO6154GNJY+qUtIxLTmFjfUmpguQT1OlOT8=,6173ded455fa17cddd889bf3bc123be2343a09aeb60f83e2b63823dd9ce94e09 +github.com/tylerb/graceful,v1.2.15,h1:B0x01Y8fsJpogzZTkDg6BDi6eMf03s01lEKGdrv83oA=,770bd36defb9463ebe8b190f508e47c37bbb6bedf23a32c675066f8edbd7aa8d +github.com/u-root/dhcp4,v0.0.0-20190206235119-03363dc71ec8,h1:F9cRXeXZ95CzG7352mm+yfgloHFrjpr1L+CQFiCH/iU=,1db09816d65071cfc5dbf25d5dbf11b2b48c3442495d30777cc0714bb4cf4163 +github.com/u-root/u-root,v6.0.0+incompatible,h1:YqPGmRoRyYmeg17KIWFRSyVq6LX5T6GSzawyA6wG6EE=,f3ec29d4b285e50d7b3116e121caca0d722535346a0ddf189d4c7d8e7e0a07d3 +github.com/uber-go/atomic,v1.4.0,h1:yOuPqEq4ovnhEjpHmfFwsqBXDYbQeT6Nb0bwD6XnD5o=,f380292d46ebec89bf53939e4d7d19d617327cbcdf2978e30e6c39bc77df5e73 +github.com/uber/jaeger-client-go,v2.19.0+incompatible,h1:pbwbYfHUoaase0oPQOdZ1GcaUjImYGimUXSQ/+8+Z8Q=,d4928d51ce4440c825df67b4a54f851ead075701e67ece4b07fbc5c5857c091c +github.com/uber/jaeger-lib,v2.2.0+incompatible,h1:MxZXOiR2JuoANZ3J6DE/U0kSFv/eJ/GfSYVCjK7dyaw=,496f63f6df32c28ceb6574959c70969da2b609abc8f9f3b3a709466f862054bf +github.com/uber/tchannel-go,v1.16.0,h1:B7dirDs15/vJJYDeoHpv3xaEUjuRZ38Rvt1qq9g7pSo=,64a37a5e89dd111ab943d94a1670f9addc0d2d41d34d630c95b0a756df916e01 +github.com/ucloud/ucloud-sdk-go,v0.8.7,h1:BmXOb5RivI0Uu4oZRpjI6SQ9/y7n/H9wxTGR1txIE8o=,d94766624c6f676880de354d4ed5c62c9ee7755c3d59cdf106ac0f5a070c0ece +github.com/ugorji/go,v1.1.7,h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=,d02959e71c59b273d5b099697c058426941a862feef66c191c63e2934db7a2ff +github.com/ugorji/go/codec,v1.1.7,h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=,8d482061c55b4c4fbf78de9fbf98a8d1b295f5904769679c73a2dc0b06a1a102 +github.com/ulikunitz/xz,v0.5.6,h1:jGHAfXawEGZQ3blwU5wnWKQJvAraT7Ftq9EXjnXYgt8=,19ebb331e7ae7a542ed58597d13ab703fc423acf93a1e3c4db86476b0322049a +github.com/unixpickle/anyvec,v0.0.0-20170908190750-59aa66ba0472,h1:eVBSKiY98Zth6cEYVzeu0CYagakYqbSWgpWqjZFiUvI=,4159f95762f7a99ee540397e78c7a60da788e6775ad9eca7fc1bd07d332a88f1 +github.com/unixpickle/autofunc,v0.0.0-20170112172612-f27a3f82164a,h1:ZUrHljv3rPkFyTYzUmBH8gBFjDwCIHc4a2DdPCWRjl0=,b39c092ab522c2ca3e8889dfbff281223628c08590b361242e72cc29015da9df +github.com/unixpickle/essentials,v0.0.0-20180916162721-ae02bc395f1d,h1:mRwAxGRBEFcoKSWDoX5CROMJo6xmXBh4rNqOmyhpRi0=,7aa26b2cbcbac91669e88903f1e05b7696b32a6d8194d66c0fe7d93c613c2f5f +github.com/unixpickle/num-analysis,v0.0.0-20161229165253-c45203c63047,h1:gipJz9DZGU3fgBjoaiNg+5CG9UdE7MmlBvSwNp1ulnY=,c1dac9bfeb72d39bb0b445f0f0b2af61753e5b11ff66e69bc196886189b7d50a +github.com/unixpickle/serializer,v0.0.0-20170723202158-c6c092dc55bb,h1:kdurEYFZ2P58xnfWtmxKWkVtFPyK80BMIaJ2zW5uskY=,2cbf6cce1b2a57307c2c675a283ce9b46adcb9d18c3a9317d3ee20772175ae40 +github.com/unknwon/com,v1.0.1,h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs=,f6264780f210f130a0edeafe4ffb0753c64b5168771f2d6cd1613999a7b79cd1 +github.com/unrolled/render,v1.0.1,h1:VDDnQQVfBMsOsp3VaCJszSO0nkBIVEYoPWeRThk9spY=,5b0ace5c3798f8989322a32b75c3eeabce7f6568533f808065cacf92425dd867 +github.com/unrolled/secure,v0.0.0-20190103195806-76e6d4e9b90c,h1:ZY4dowVsuIAQtXXwKJ9ezfonDQ2YT7pcXRpPF2iAy3Y=,1aba4f13fe4199198f9b59bbfd337773d049bad06f68360483a5f4c5431bdce4 +github.com/urfave/cli,v1.22.1,h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY=,116fc1fba7db091617cd47c2b83c78d22489deeaf8390a6d3509da7fc9217d57 +github.com/urfave/cli/v2,v2.0.0-alpha.2,h1:2OVOKijPPhkA1cJA5SABACE8TT3Cwx9T0N6VtI8LJSI=,57250f97530fcb6fef7abc87cde3fbaf11ea45830adf98e3f1c986e2674e3b5f +github.com/urfave/negroni,v1.0.0,h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc=,7b50615961d34d748866565b8885edd7013e33812acdbaed47502d7cc73a4bbd +github.com/valyala/bytebufferpool,v1.0.0,h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=,7f59f32c568539afee9a21a665a4156962b019beaac8404e26ba37af056b4f1e +github.com/valyala/fasthttp,v1.6.0,h1:uWF8lgKmeaIewWVPwi4GRq2P6+R46IgYZdxWtM+GtEY=,b15a953ed5395599871097c94977d21c026205e6ca7ad6e340cd595096d5840e +github.com/valyala/fastrand,v1.0.0,h1:LUKT9aKer2dVQNUi3waewTbKV+7H17kvWFNKs2ObdkI=,ed2166483141b4f3d59ee07975a5d91990e4c17f36c919565b8063c0cb02f7ed +github.com/valyala/fasttemplate,v1.0.1,h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=,b4d9f77c6c15a0404952925ad59b759102c0ff48426b6fc88d6bfd347fe243b8 +github.com/valyala/tcplisten,v0.0.0-20161114210144-ceec8f93295a,h1:0R4NLDRDZX6JcmhJgXi5E4b8Wg84ihbmUKp/GvSPEzc=,07066d5b879a94d6bc1feed20ad4003c62865975dd1f4c062673178be406206a +github.com/vbatts/tar-split,v0.11.1,h1:0Odu65rhcZ3JZaPHxl7tCI3V/C/Q9Zf82UFravl02dE=,73136db95ff35c2547c49be43727aa3f67da2d8837e1475954db910b41b1fa18 +github.com/veandco/go-sdl2,v0.3.3,h1:4/TirgB2MQ7oww3pM3Yfgf1YbChMlAQAmiCPe5koK0I=,d19e162daa2a6cc72569eb052adfd3d757fd069ee461a64803e9e8f2e9bb87a7 +github.com/vektah/dataloaden,v0.2.1-0.20190515034641-a19b9a6e7c9e,h1:+w0Zm/9gaWpEAyDlU1eKOuk5twTjAjuevXqcJJw8hrg=,92fe72fa4962bb2f375fae83f7a44a804e398ec08818f7d018724e0a23394ae3 +github.com/vektah/gqlparser,v1.1.2,h1:ZsyLGn7/7jDNI+y4SEhI4yAxRChlv15pUHMjijT+e68=,cdd0119855b98641e7af60dce5b2848b31f8ef03dfcf097c06912309b86fc97c +github.com/viant/assertly,v0.4.8,h1:5x1GzBaRteIwTr5RAGFVG14uNeRFxVNbXPWrK2qAgpc=,253a5e53bb09bf94be7131d5034a6ba19c6eb1f9b8c7fa66182d577bd7b2d6cd +github.com/viant/toolbox,v0.24.0,h1:6TteTDQ68CjgcCe8wH3D3ZhUQQOJXMTbj/D9rkk2a1k=,d6773a06b59de043eff2003bb97567056a1910eb0fd514f5503873b8f23309f4 +github.com/vimeo/go-util,v1.2.0,h1:YHzwOnM+V2tc6r67K9fXpYqUiRwXp0TgFKuyj+A5bsg=,85e52371bcf8299d47d8242546bc06e9e0c9c555b719008096889cd081a69173 +github.com/vincent-petithory/dataurl,v0.0.0-20160330182126-9a301d65acbb,h1:lyL3z7vYwTWXf4/bI+A01+cCSnfhKIBhy+SQ46Z/ml8=,5d5fa46ce0f88ba0734f52d0b0bcaa8a427770ef13cd1bfd7995e4d2a8439abb +github.com/vishvananda/netlink,v1.0.0,h1:bqNY2lgheFIu1meHUFSH3d7vG93AFyqg3oGbJCOJgSM=,6fb7184280eb1321e1857171862bdb624eae29876496f1cb56932fbc0064020f +github.com/vishvananda/netns,v0.0.0-20190625233234-7109fa855b0f,h1:nBX3nTcmxEtHSERBJaIo1Qa26VwRaopnZmfDQUXsF4I=,a99a67e03a35e1d02d1a17900185a1c38c513a79b2b325ad826553dc078a90de +github.com/vivint/infectious,v0.0.0-20190108171102-2455b059135b,h1:dLkqBELopfQNhe8S9ucnSf+HhiUCgK/hPIjVG0f9GlY=,f5d948bf34ac58786ad20df4fd6e99f990f72458dd2825558bf2e3c871f3f37a +github.com/vmihailenco/msgpack,v4.0.4+incompatible,h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=,918f7dd7883105b9c55728c704a3bc54c80568b2b09583890b51508c03391356 +github.com/vmware/govmomi,v0.21.0,h1:jc8uMuxpcV2xMAA/cnEDlnsIjvqcMra5Y8onh/U3VuY=,75ca40f34da851e95d7e63685adbaf1ec5c7f659fb0b47096c85da44f098c4a3 +github.com/vmware/vic,v1.5.4,h1:y546pkye0aes2j2h2n6fWz++v8WxMZTLFl1mLOMzqYQ=,2a6f0c20be8acb3b467c78d3de18009ccd0ab2429a997266089d14341e43115c +github.com/vmware/vmw-guestinfo,v0.0.0-20170707015358-25eff159a728,h1:sH9mEk+flyDxiUa5BuPiuhDETMbzrt9A20I2wktMvRQ=,29c73ba44ac315461640797d6ebfda2d906c28dbe21c20656c6e5fa1f515f220 +github.com/vulcand/oxy,v1.0.0,h1:7vL5/pjDFzHGbtBEhmlHITUi6KLH4xXTDF33/wrdRKw=,148843b55ed01813f8920aab70a799aa10cfdccc0bbd55e270cde78e1ad23b88 +github.com/vulcand/predicate,v1.1.0,h1:Gq/uWopa4rx/tnZu2opOSBqHK63Yqlou/SzrbwdJiNg=,3dd716f2436651429ce7f5fdd59fa1a9944ab4d57fdbae5fef00ef01baf7c4be +github.com/vultr/govultr,v0.1.4,h1:UnNMixYFVO0p80itc8PcweoVENyo1PasfvwKhoasR9U=,7281fa718c076b84610b155fb0dec34503ea1ae5f2930cc714ed7772e475bb08 +github.com/warpfork/go-wish,v0.0.0-20190328234359-8b3e70f8e830,h1:8kxMKmKzXXL4Ru1nyhvdms/JjWt+3YLpvRb/bAjO/y0=,77a9eefa3edf38cb90eba443f282bd73ffcb6f1b87aebe8f891d8c8b38124d95 +github.com/weaveworks/common,v0.0.0-20190917143411-a2b2a6303c33,h1:UAh7j96ZXQID3shhQsrtfJsrQ2uO3tyRxCuXvh+kipw=,e1ceacd5b24c6414ae664f4b09e295dc25e48d3a1dcd5100d8c98dd405a0d162 +github.com/weaveworks/mesh,v0.0.0-20191031093817-8e3db2fe8f47,h1:RUdrWPah1Xu+efIGqN0YGTv7gQeyR5qwBq9uL4HloKw=,05f5d769f7ff6af1c098f0e42983227d6a86f5d8d1f8453cb0566450cad49358 +github.com/wellington/go-libsass,v0.9.3-0.20181113175235-c63644206701,h1:9vG9vvVNVupO4Y7uwFkRgIMNe9rdaJMCINDe8vhAhLo=,2ae95ed360950fab28eff3bedf1c1a6f5f81b73078000d3a0bd67443d38df87f +github.com/wendal/errors,v0.0.0-20130201093226-f66c77a7882b,h1:0Ve0/CCjiAiyKddUMUn3RwIGlq2iTW4GuVzyoKBYO/8=,f7722558c5c450fa02e800ce7bf4d0bc1d2a0e1696d3fc50ff1489bcd02ff3b3 +github.com/weppos/publicsuffix-go,v0.5.0,h1:rutRtjBJViU/YjcI5d80t4JAVvDltS6bciJg2K1HrLU=,bd8365c8501b307a1fbd62501bc3332ff97721bef51921a99e67a3f8b96318fc +github.com/whyrusleeping/cbor-gen,v0.0.0-20190910031516-c1cbffdb01bb,h1:8yBVx6dgk1GfkiWOQ+RbeDDBLCOZxOtmZ949O2uj5H4=,9d5ab8362eaffa07bc2700d9a9e967c1ecf394e3233a6e7141efb48970bfd4e5 +github.com/whyrusleeping/chunker,v0.0.0-20181014151217-fe64bd25879f,h1:jQa4QT2UP9WYv2nzyawpKMOCl+Z/jW7djv2/J50lj9E=,b28fdb03b69be216c423967e9dee2481aa10c3e39c71d3bfc8911940dadb26a9 +github.com/whyrusleeping/go-keyspace,v0.0.0-20160322163242-5b898ac5add1,h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k=,9416f8227e6c516294b9b938fcf2347bebe2cdab4377454150ba60dcd86c2990 +github.com/whyrusleeping/go-logging,v0.0.0-20170515211332-0457bb6b88fc,h1:9lDbC6Rz4bwmou+oE6Dt4Cb2BGMur5eR/GYptkKUVHo=,125b1a836936436354791583be42ae19f7c04a636b5c0c96135645d52aaa72ea +github.com/whyrusleeping/go-notifier,v0.0.0-20170827234753-097c5d47330f,h1:M/lL30eFZTKnomXY6huvM6G0+gVquFNf6mxghaWlFUg=,08dddb594554c3b35791893207e66dd3c04e4da24d0e0df001bb185f97dec6cc +github.com/whyrusleeping/go-smux-multiplex,v3.0.16+incompatible,h1:iqksILj8STw03EJQe7Laj4ubnw+ojOyik18cd5vPL1o=,e16e3da58e283e71955b21725c384d180a2999bc2a50cb0490b5e2f7a74b5fc6 +github.com/whyrusleeping/go-smux-multistream,v2.0.2+incompatible,h1:BdYHctE9HJZLquG9tpTdwWcbG4FaX6tVKPGjCGgiVxo=,9a783c4a1b69f6002ac4e0af684f4d5c4d360b7107fbbdde48faf38f7e23e998 +github.com/whyrusleeping/go-smux-yamux,v2.0.9+incompatible,h1:nVkExQ7pYlN9e45LcqTCOiDD0904fjtm0flnHZGbXkw=,3f44f41fc7b133085bba08d52e7615e9a8eb92f55fde6a07d3cd7804117e9985 +github.com/whyrusleeping/mafmt,v1.2.8,h1:TCghSl5kkwEE0j+sU/gudyhVMRlpBin8fMBBHg59EbA=,e5d5783d2bc35f7c23f2034fd52c5750ad0590773115c10b4e15360575322c69 +github.com/whyrusleeping/mdns,v0.0.0-20180901202407-ef14215e6b30,h1:nMCC9Pwz1pxfC1Y6mYncdk+kq8d5aLx0Q+/gyZGE44M=,fc2e4d2365ba40d52d03126ea490e712762b4ad398c8d6adb2a1a08699a10eb1 +github.com/whyrusleeping/multiaddr-filter,v0.0.0-20160516205228-e903e4adabd7,h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds=,14e8963464dab0f6277f596985be5ea419bc3bae8bf4f4f139cce456e1815faf +github.com/whyrusleeping/timecache,v0.0.0-20160911033111-cfcb2f1abfee,h1:lYbXeSvJi5zk5GLKVuid9TVjS9a0OmLIDKTfoZBL6Ow=,c33dfc5ac935582261bf5ddbab31bb07febc471a9c26eb3e1a895eddd574d3e8 +github.com/whyrusleeping/yamux,v1.1.5,h1:4CK3aUUJQu0qpKZv5gEWJjNOQtdbdDhVVS6PJ+HimdE=,658f9e704cbe1cac295ed34471bb096a4d2713f69ffbb8140fbf50b8ff6420e0 +github.com/willf/bitset,v1.1.9,h1:GBtFynGY9ZWZmEC9sWuu41/7VBXPFCOAbCbqTflOg9c=,ddd687772ccfd6774e55e7e9d9e71dab86d85a64b98ce1d864d9661f5b0767e4 +github.com/x-cray/logrus-prefixed-formatter,v0.5.2,h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg=,00719eeb4f9eadb9431dd9f763fa4013dc52b37a8803a973c6d0c1ce8281e14b +github.com/xanzy/go-cloudstack,v0.0.0-20190526095453-42f262b63ed0,h1:NJrcIkdzq0C3I8ypAZwFE9RHtGbfp+mJvqIcoFATZuk=,34b46eae351e4916015ce2a43ed501403937e4079cf69dae98a9544bfeec8092 +github.com/xanzy/go-gitlab,v0.21.0,h1:Ru55sR4TBoDNsAKwCOpzeaGtbiWj7xTksVmzBJbLu6c=,12ae6fa35c19fffc31d1fa2891f386875caac8077d19f3f09f49b5e2e51b1755 +github.com/xanzy/ssh-agent,v0.2.1,h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=,7011c1771f8ad9b65795f8a85113e4518c9a2c7493029c4c988bc802b63d9e28 +github.com/xdg/scram,v0.0.0-20180814205039-7eeb5667e42c,h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk=,33884d438b686676ceaa2a439634a108f7fe763ce974342d2aa811c22b34112c +github.com/xdg/stringprep,v1.0.0,h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0=,2b262e4e8e9655100c98e2b7e75b517e3e83e2155818174c63ea09d3cce22721 +github.com/xeipuuv/gojsonpointer,v0.0.0-20180127040702-4e3ac2762d5f,h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=,5b1a4bcc8e003f214c92b3fa52959d9eb0e3af1c0c529efa55815db951146e48 +github.com/xeipuuv/gojsonreference,v0.0.0-20180127040603-bd5ef7bd5415,h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=,7ec98f4df894413f4dc58c8df330ca8b24ff425b05a8e1074c3028c99f7e45e7 +github.com/xeipuuv/gojsonschema,v1.2.0,h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=,55c8ce068257aa0d263aad7470113dafcd50f955ee754fc853c2fdcd31ad096f +github.com/xenolf/lego,v2.7.2+incompatible,h1:aGxxYqhnQLQ71HsvEAjJVw6ao14APwPpRk0mpFroPXk=,25c2495e4fc2f5fea8c70b442add86c049f2f8810235e1ee94f29d8e0267ad2c +github.com/xeonx/timeago,v1.0.0-rc4,h1:9rRzv48GlJC0vm+iBpLcWAr8YbETyN9Vij+7h2ammz4=,b06f4ede554b35387394827ca0350b628a72228a8002653817826991867e1fdd +github.com/xi2/xz,v0.0.0-20171230120015-48954b6210f8,h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=,1ffe8f24af5118966084d41eca2c9bee7a831a07deb4356e4d707d208da22e8e +github.com/xiang90/probing,v0.0.0-20190116061207-43a291ad63a2,h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=,437bdc666239fda4581b592b068001f08269c68c70699a721bff9334412d4181 +github.com/xlab/treeprint,v0.0.0-20181112141820-a009c3971eca,h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI=,d14ebea967caa835f25e4c3980c60719e07f0e36375b74dc48928613fca5b2ff +github.com/xo/dburl,v0.0.0-20191005012637-293c3298d6c0,h1:6DtWz8hNS4qbq0OCRPhdBMG9E2qKTSDKlwnP3dmZvuA=,1fb150cf2144a4b7a571360af52d9b22dfe53e2ba9ab3e56584fdb0eb282d315 +github.com/xordataexchange/crypt,v0.0.3-0.20170626215501-b2862e3d0a77,h1:ESFSdwYZvkeru3RtdrYueztKhOBCSAAzS4Gf+k0tEow=,46dc29ef77d77a2bc3e7bd70c94dbaeec0062dd3bd6fcacbaab785c15dcd625b +github.com/xtaci/kcp-go,v5.4.5+incompatible,h1:CdPonwNu3RKu7HcXSno5r0GXfTViDY2iFV2RDOao/4U=,98e77493d94b33bfec990bd5791d15a09add1a0ba2f3281f26bdc98c1815d9a7 +github.com/xtaci/lossyconn,v0.0.0-20190602105132-8df528c0c9ae,h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM=,75cc8c3e14cf812dcc56a1e8cecafd8affd9b2843d39540ab67929f7ce3d1abc +github.com/xtgo/set,v1.0.0,h1:6BCNBRv3ORNDQ7fyoJXRv+tstJz3m1JVFQErfeZz2pY=,6b70026a5ea66bc0be7efb2247afa53ae970b9535c7a8541795750ef9b640217 +github.com/yalp/jsonpath,v0.0.0-20150812003900-31a79c7593bb,h1:06WAhQa+mYv7BiOk13B/ywyTlkoE/S7uu6TBKU6FHnE=,d2041be5f19a3dbcd4b384dbbf5782cdb96d80ad9c60c8c9b887f2c5170cb25f +github.com/yandex-cloud/go-genproto,v0.0.0-20190928220815-a36c849d0fc1,h1:GDyRNvsi/tOZj1ssPkk+kocO1djpbmLSpDKg4XeRPy4=,5502c680146902518514935af5ab5b554a80f5ebe2e79d491db3120911f5498d +github.com/yandex-cloud/go-sdk,v0.0.0-20190916101744-c781afa45829,h1:2FGwbx03GpP1Ulzg/L46tSoKh9t4yg8BhMKQl/Ff1x8=,4b375b871ce7501943a26ba02c348ad4fdf2cb112520513628566a15a98a4796 +github.com/yohcop/openid-go,v0.0.0-20160914080427-2c050d2dae53,h1:HsIQ6yAjfjQ3IxPGrTusxp6Qxn92gNVq2x5CbvQvx3w=,8c4f676193e3aa5ec012e0661d0e552a3e5d5d96086a73901dcfbf0bd4a6d2e9 +github.com/yookoala/realpath,v1.0.0,h1:7OA9pj4FZd+oZDsyvXWQvjn5oBdcHRTV44PpdMSuImQ=,9fe8b06f8efabb7df08608f18edc77d284e04ad06d490af9f55196e4184c339f +github.com/yosssi/ace,v0.0.5,h1:tUkIP/BLdKqrlrPwcmH0shwEEhTRHoGnc1wFIWmaBUA=,96157dbef72f2f69a900e09b3e58093ee24f7df341ac287bddfb15f8c3f530db +github.com/yosssi/gmq,v0.0.1,h1:GhlDVaAQoi3Mvjul/qJXXGfL4JBeE0GQwbWp3eIsja8=,d06bbe96ba0e8c3c79bfb0b9191a02a19d8d3d3c181eba62df6d94c0602c784e +github.com/youtube/vitess,v2.1.1+incompatible,h1:SE+P7DNX/jw5RHFs5CHRhZQjq402EJFCD33JhzQMdDw=,2eb3c516c8b24a72b8cb14f76f39562638acf0cd7fc3858002163d28047607f2 +github.com/yudai/gojsondiff,v0.0.0-20170107030110-7b1b7adf999d,h1:yJIizrfO599ot2kQ6Af1enICnwBD3XoxgX3MrMwot2M=,3f61230fe62a6fe2e93a75264d176bda3f62323063c1e9bfb87c0be31ac5d269 +github.com/yudai/golcs,v0.0.0-20150405163532-d1c525dea8ce,h1:888GrqRxabUce7lj4OaoShPxodm3kXOMpSa85wdYzfY=,ff1f3899e710574a08aaa51051a36c523ecf850180ad0564d55eec611c3cff72 +github.com/yudai/pp,v2.0.1+incompatible,h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI=,ecfda4152182e295f2b21a7b2726e2865a9415fc135a955ce42e039db29e7a20 +github.com/yuin/gopher-lua,v0.0.0-20190514113301-1cd887cd7036,h1:1b6PAtenNyhsmo/NKXVe34h7JEZKva1YB/ne7K7mqKM=,fd157d5d26c336c44837eceef5c6fc4b442a56b25931d4afae3c4080932a7aa7 +github.com/zach-klippenstein/goregen,v0.0.0-20160303162051-795b5e3961ea,h1:CyhwejzVGvZ3Q2PSbQ4NRRYn+ZWv5eS1vlaEusT+bAI=,6f523a11fcb80dca31c3bae99c8c4a59b7e5a4176e36cad0e3f1e64e1b9a7b11 +github.com/zclconf/go-cty,v1.1.0,h1:uJwc9HiBOCpoKIObTQaLR+tsEXx1HBHnOsOOpcdhZgw=,024660decfe11e74a9fab80f1447b79c61e328baf6418629a15c74e183b95e95 +github.com/zclconf/go-cty-yaml,v1.0.1,h1:up11wlgAaDvlAGENcFDnZgkn0qUJurso7k6EpURKNF8=,2502da37ac6d9105b07748c4252f970aa6a7ffc8929b92a0b85abb81b804e9b7 +github.com/zeebo/admission,v0.0.0-20180821192747-f24f2a94a40c,h1:WoYvMZp+keiJz+ZogLAhwsUZvWe81W+mCnpfdgEUOl4=,b62a80509cfa84e697b23dd6b1b314a264e6f68586661ecd84026625f7753cb1 +github.com/zeebo/assert,v1.0.0,h1:qw3LXzO7lbptWIQ6DsemJIUOoaqyKbgY3M8b8yvlaaY=,bb31d428cc59a322975ab6b5757832e62507655f3e2c467a88345b21d7431d98 +github.com/zeebo/errs,v1.2.2,h1:5NFypMTuSdoySVTqlNs1dEoU21QVamMQJxW/Fii5O7g=,d2fa293e275c21bfb413e2968d79036931a55f503d8b62381563ed189b523cd2 +github.com/zeebo/float16,v0.1.0,h1:kRqxv5og6z1emEyz5FpW0/BVHe5VfxEAw6b1ljCZlUc=,ffc6b2a7bce5e37798bc3ac53448b6190039a77f2e7d589779680fbd3cb53a48 +github.com/zeebo/incenc,v0.0.0-20180505221441-0d92902eec54,h1:+cwNE5KJ3pika4HuzmDHkDlK5myo0G9Sv+eO7WWxnUQ=,141b997c5ece8f136f43644f5a2526305563128c4ecce280d9a54ce1ae506ba2 +github.com/zeebo/structs,v1.0.2,h1:kvcd7s2LqXuO9cdV5LqrGHCOAfCBXaZpKCA3jD9SJIc=,0495c69abfeb2ffa0911f4c44ba145d81b04ec76d2311e2eedfc2b3e2efd66c9 +github.com/zenazn/goji,v0.9.0,h1:RSQQAbXGArQ0dIDEq+PI6WqN6if+5KHu6x2Cx/GXLTQ=,0807a255d9d715d18427a6eedd8e4f5a22670b09e5f45fddd229c1ae38da25a9 +github.com/ziutek/mymysql,v1.5.4,h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=,1ea104186e0990a3d97a1e67fcd31177849c975de4abd9399270ab0a04c025de +github.com/zkfy/cron,v0.0.0-20170309132418-df38d32658d8,h1:jxPemXnLeekMXItoaw4jZtDfe8HmvFmviUm2L5tEBhE=,81a903448f6bc140e07bc4ff70762f0a46e750388f4b92f700d358331b1ca8d5 +github.com/zkfy/go-metrics,v0.0.0-20161128210544-1f30fe9094a5,h1:Rb2qQMbEon+BI3IXGh4eW3u/iTLPA3+Y6kNK+gHO32w=,07f9078cbc233559128dc4ae80d69505dd1a07d47d33135fc8f4969829fd6ee8 +github.com/zkfy/jwt-go,v3.0.0+incompatible,h1:5hZNIkrRRa0mrkRiXoPFdLJWpMDByIZ6VIbX9aWhwmk=,8306a4a65059e17be035dd47f45d83aac503c50c954716c83e481d0b6530aed6 +github.com/zkfy/log,v0.0.0-20180312054228-b2704c3ef896,h1:nktyhX5ycnu+WA489Ei7SUi00bF+LW8TF2N7se5gQ/o=,dd0acb5ccceb2225c89f0f50dc8eea9f1cae0971b731750ea7a1b186c194d9bc +github.com/zkfy/stompngo,v0.0.0-20170803022748-9378e70ca481,h1:dqbWcJVZJv06ZR7zK8yN9w8oNOHL23eylL4o9Xj9Zn0=,9e643fbfd166421cb186275742bafc663fc350da83e59e9d88c06feb12ec4462 +github.com/zmap/rc2,v0.0.0-20131011165748-24b9757f5521,h1:kKCF7VX/wTmdg2ZjEaqlq99Bjsoiz7vH6sFniF/vI4M=,fd70713ed40c95220e95c7c47f7e15051e8dc909d39253f403bb694f45fbe789 +github.com/zmap/zcertificate,v0.0.0-20180516150559-0e3d58b1bac4,h1:17HHAgFKlLcZsDOjBOUrd5hDihb1ggf+1a5dTbkgkIY=,7dc2c0bedccfdeb9c42ef41ef502f404befa9ef073c35db3b15c99cae6697b41 +github.com/zmap/zcrypto,v0.0.0-20190729165852-9051775e6a2e,h1:mvOa4+/DXStR4ZXOks/UsjeFdn5O5JpLUtzqk9U8xXw=,871979cf16453ddb4db7f153f449af4e346f68b51355c74b5eee832225618ff0 +github.com/zmap/zlint,v0.0.0-20190806154020-fd021b4cfbeb,h1:vxqkjztXSaPVDc8FQCdHTaejm2x747f6yPbnu1h2xkg=,e62f5cd5f434d84f53d336261e3a6e50c8902152ce8f2f5ce918270d6d201cab +github.com/zondax/hid,v0.9.0,h1:eiT3P6vNxAEVxXMw66eZUAAnU2zD33JBkfG/EnfAKl8=,9c72a6bdbf03d9465dfdf1ba876eabf5fa923d5bb9e726c9e4a994098dc9bd79 +github.com/zondax/ledger-go,v0.9.0,h1:oTrtFqPFA4VdCPRvqMaN45mQnJxkPc0JxoVZfCoUpjI=,6c6a7e036f9a621ce951939d7d13ae1f0c098f58829307c78f9312e02e78e438 +github.com/zquestz/grab,v0.0.0-20190224022517-abcee96e61b1,h1:1qKTeMTSIEvRIjvVYzgcRp0xVp0eoiRTTiHSncb5gD8=,4decd67f1252df4ee34968cb0cb4e7dc6010302b24ce8edd418f1c2520f1c351 +gitlab.com/NebulousLabs/errors,v0.0.0-20171229012116-7ead97ef90b8,h1:gZfMjx7Jr6N8b7iJO4eUjDsn6xJqoyXg8D+ogdoAfKY=,b355474f1a2ef2722ae450ef6df7209d223188ae413706be122b472fcc053c48 +gitlab.com/NebulousLabs/fastrand,v0.0.0-20181126182046-603482d69e40,h1:dizWJqTWjwyD8KGcMOwgrkqu1JIkofYgKkmDeNE7oAs=,a56acdda993c7a4795028fe38844d54de9b1877d22e8ae09f205e488ce2284bc +go.bug.st/serial.v1,v0.0.0-20180827123349-5f7892a7bb45,h1:mACY1anK6HNCZtm/DK2Rf2ZPHggVqeB0+7rY9Gl6wyI=,f0ea4cd4c51228f1a3cf14c6b92888169944f267e1ee778909512a4c8ac4762f +go.cryptoscope.co/luigi,v0.3.4,h1:eDrtCoUL5Vl2Atr5ty2dq0uFbzFCc6Pz1HEqU1e7I1I=,949612e92dcb2fc919e506740f36d0cfe0797c1f85579a98763aad0135a4580a +go.dedis.ch/fixbuf,v1.0.3,h1:hGcV9Cd/znUxlusJ64eAlExS+5cJDIyTyEG+otu5wQs=,dfa737543a5873b14cdfd0eec675c63044b16d3dbe481b2289c758ae4186ae95 +go.dedis.ch/kyber/v3,v3.0.8,h1:qnHzOBaxEO3+ZYuZAfwPTOPzX+F6QMmWGo8YJvENh68=,d69db17bd37bf14c4e508eb84974c3df9a82b8cb30b55ddc3ac0ee2784abcbac +go.dedis.ch/kyber/v4,v4.0.0-pre1,h1:1f5OPESkyxK6kPaCSV3J9BlpnoysIpbGLNujX9Ov8m4=,d082a41e2178f7e18c088e414e020928794245a9dae41d07da842ebb667a337e +go.dedis.ch/onet/v3,v3.0.26,h1:wQhVGB+SCdG7B0tbo6ZeZINQKWkU4u9TNMkGBH16EEM=,a41978897a3371f2eaaab5c84c354c95b4fdbd7b8207afa7c79f32b85f857d5d +go.elastic.co/apm,v1.5.0,h1:arba7i+CVc36Jptww3R1ttW+O10ydvnBtidyd85DLpg=,447a5954db3f7fc61575c83782be0b6d69e453f1e667b0534d3bf5336039238a +go.elastic.co/apm/module/apmhttp,v1.5.0,h1:sxntP97oENyWWi+6GAwXUo05oEpkwbiarZLqrzLRA4o=,1e6bc42b2e3ab10165036afd95a8a4d910acadce451c0b4e7c998cbb5c06da73 +go.elastic.co/apm/module/apmot,v1.5.0,h1:rPyHRI6Ooqjwny67au6e2eIxLZshqd7bJfAUpdgOw/4=,235fb0c1d0e107ffb7c5056e49226152063ac87ebc657428ea410d5170804d2e +go.elastic.co/fastjson,v1.0.0,h1:ooXV/ABvf+tBul26jcVViPT3sBir0PvXgibYB1IQQzg=,451e29b2854f9e09c58e3fe4c1b3a72d9b2ee293628ab4c4323e8192af015c6c +go.etcd.io/bbolt,v1.3.3,h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=,1ea076dbe18dabe78909e1fb7ec2954fc2d58cd72e7730ad69b35248a30049fd +go.etcd.io/etcd,v3.3.17+incompatible,h1:g8iRku1SID8QAW8cDlV0L/PkZlw63LSiYEHYHoE6j/s=,7bd292878f70e154a061ed6b85fc70502aa270fcf0072340cbde1a0cb35b0d2d +go.mongodb.org/mongo-driver,v1.1.2,h1:jxcFYjlkl8xaERsgLo+RNquI0epW6zuy/ZRQs6jnrFA=,6b3141ced32d7a41ebd0539df957b76331fc3efdca22eae68da54d41aad23fed +go.opencensus.io,v0.22.1,h1:8dP3SGL7MPB94crU3bEPplMPe83FI4EouesJUeFHv50=,b8d9a5fca5e714c4bf66f6497dd905992113cfd6aae948bb7fad5ce987a520ed +go.starlark.net,v0.0.0-20191021185836-28350e608555,h1:FhmD1D59MmncMfRVTRa889iERZG3jdaKj/1FtOQB1G0=,add124cd355e714f076a385eb3f2ddcfb8ce0c7c8e6611e2e03acc427a4c32bf +go.uber.org/atomic,v1.5.0,h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=,7e32f8f75b2029aa53399c2cd6e581398ac4e971c17a763980377279ede95c77 +go.uber.org/automaxprocs,v1.2.0,h1:+RUihKM+nmYUoB9w0D0Ov5TJ2PpFO2FgenTxMJiZBZA=,4c7bf41eab5dd7781c69130aa37011427531dee231ffbdc3c9ed4267c06aa93c +go.uber.org/multierr,v1.3.0,h1:sFPn2GLc3poCkfrpIXGhBD2X0CMIo4Q/zSULXrj/+uc=,29b25df332dea2dbfaaa308013fc6d3673ecd3d9ee09c666c69df504533d0714 +go.uber.org/ratelimit,v0.1.0,h1:U2AruXqeTb4Eh9sYQSTrMhH8Cb7M0Ian2ibBOnBcnAw=,78f82854809625c784088b9dec5dfb4810fbbd09c24891b8aaf2c2679212dfd8 +go.uber.org/thriftrw,v1.20.2,h1:0JlCE7dOyWHEQdfDm0MWIbgTn6vXkiMA6LNIe8FQXjw=,148b93f97a6ab865e2dbe0eb09b9f9504248808efc437e20efc1bf9b7896de9a +go.uber.org/tools,v0.0.0-20190618225709-2cfd321de3ee,h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=,988dba9c5074080240d33d98e8ce511532f728698db7a9a4ac316c02c94030d6 +go.uber.org/zap,v1.12.0,h1:dySoUQPFBGj6xwjmBzageVL8jGi8uxc6bEmJQjA06bw=,d4b304046a3f9443e4abe217889b5b2a4ecef35d52f175bcacf2baff18646595 +go4.org,v0.0.0-20191010144846-132d2879e1e9,h1:zHLoVtbywceo2hE4Wqv8CmIufe7jDERQ2KJHZoSDfCU=,21811f50d48c55047df1d6bf68db778087afe9116f1f32faf79f8ca459d29d89 +gobot.io/x/gobot,v1.14.0,h1:IJv4A9f5/lUz4JQaS37UW8bRVl3lG+jCGUcNmJ2F0vE=,95ad64d1bf33ee46816b2c87edb10d7b3bfe118b6f7026bf4b5f762867d1e776 +gocloud.dev,v0.17.0,h1:UuDiCphYsiNhRNLtgHVL/eZheQeCt00hL3XjDfbt820=,0df8e26a2356735d596e8a3917ec4b69f61fb5e9f6f291b51f6145a51b646a9b +gocv.io/x/gocv,v0.21.0,h1:dVjagrupZrfCRY0qPEaYWgoNMRpBel6GYDH4mvQOK8Y=,9e1a70258d72b873d9605a2939b38f9e560650472d70b97f5dd0fc2657eaf35f +golang.org/x/arch,v0.0.0-20191101135251-a0d8588395bd,h1:e1iK2rWppIPlzzqtjXT/p6WR/+ritGZ8xkfL8uDZb0g=,daba41c9150ebf192ce54952d69ef12fe47c5c6250a33c01f0624befea35354e +golang.org/x/build,v0.0.0-20191031202223-0706ea4fce0c,h1:jjNoDZTS0vmbqBhqD5MPXauZW+kcGyflfDDFBNCPSVI=,a675f674bcee677f1dc9a15ca4d84bb2e842c29d745b165ba3e5423c09367d29 +golang.org/x/crypto,v0.0.0-20191029031824-8986dd9e96cf,h1:fnPsqIDRbCSgumaMCRpoIoF2s4qxv0xSSS0BVZUE/ss=,0a303100f9afba8628988bef45404b23c2e0c6aa73b5ad4ac9259af14a0e53ae +golang.org/x/exp,v0.0.0-20191030013958-a1ab85dbe136,h1:A1gGSx58LAGVHUUsOf7IiR0u8Xb6W51gRwfDBhkdcaw=,18ff05b39d29a3fd4c7f9071e7013264994ac18f7faa72f66b2f514fcdd141b0 +golang.org/x/image,v0.0.0-20191009234506-e7c1f5e7dbb8,h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U=,aebca4c096dac7c20d9024b73bd0b4a87a85f4c6b50aae7615dec504c5f478c8 +golang.org/x/lint,v0.0.0-20190930215403-16217165b5de,h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=,91323fe1a77f13de722a0ce8efc5c5f2da4f26216d858acec64cb23c956fa163 +golang.org/x/mobile,v0.0.0-20191031020345-0945064e013a,h1:CrJ8+QyIm2tcw/zt9Rp/vGFsey+jndL1y5EnFwzgGOg=,5ee0c7eed83b64cc851d6ddb76346413d7c43213ea1241385b588c66e2169854 +golang.org/x/mod,v0.1.0,h1:sfUMP1Gu8qASkorDVjnMuvgJzwFbTZSeXFiGBYAVdl4=,e0d9b32f6f66103f777e8357b5b60f94a486330d46c6c8ea87789dab1a14cefa +golang.org/x/net,v0.0.0-20191101175033-0deb6923b6d9,h1:DPz9iiH3YoKiKhX/ijjoZvT0VFwK2c6CWYWQ7Zyr8TU=,b07094a5589a436fd98c6700cd5898f2094d9c02f8385f9331a7ace46305c7ae +golang.org/x/oauth2,v0.0.0-20190604053449-0f29369cfe45,h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=,f72b6c3c2b734ad053fadf5fa2adb2ad23024cfeacd567fec31a751526d1dfe0 +golang.org/x/perf,v0.0.0-20180704124530-6e6d33e29852,h1:xYq6+9AtI+xP3M4r0N1hCkHrInHDBohhquRgx9Kk6gI=,a2c7d02cc94c4ba767b6322f70ddcba4941cb5f60fed1bada3aa7a4d3a8128f1 +golang.org/x/sync,v0.0.0-20190911185100-cd5d95a43a6e,h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=,9c63fe51b0c533b258d3acc30d9319fe78679ce1a051109c9dea3105b93e2eef +golang.org/x/sys,v0.0.0-20191029155521-f43be2a4598c,h1:S/FtSvpNLtFBgjTqcKsRpsa6aVsI6iztaz1bQd9BJwE=,c5a8efb84e706e4ec1e1fa5cda44d1d571e8b3f46afe165d5e93b90e777a15fc +golang.org/x/text,v0.3.2,h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=,f755c0e7f4693f170e2f03c161f500b33f82accb8184a38dcfda63fed883f13c +golang.org/x/time,v0.0.0-20191024005414-555d28b269f0,h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=,e0ca5eceb4840bcc264237408ff8942044e19b503d6e8e5546ed9f7e1f4bf82e +golang.org/x/tools,v0.0.0-20191101200257-8dbcdeb83d3f,h1:+QO45yvqhfD79HVNFPAgvstYLFye8zA+rd0mHFsGV9s=,c3beb2acb726571e4cca3e922dd1eb037dcb6ef66ca562e9544716a53b6a1026 +golang.org/x/xerrors,v0.0.0-20191011141410-1b5146add898,h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=,5059c7b7e95f139b8c42d9001972fa5fa688b3581ef946c912c1dbc52415ff16 +gomodules.xyz/envconfig,v1.3.0,h1:w1laMNVtP05uOKqmRAY6Vx7HvfPL9yc388gcVtUiI/M=,ae5b4ee26eeb143c16bfb5316eb97e8ff4418bce379ae74e2a0bba367706d69c +gomodules.xyz/jsonpatch/v2,v2.0.1,h1:xyiBuvkD2g5n7cYzx6u2sxQvsAy4QJsZFCzGVdzOXZ0=,3c97ac5b7cfa3388f3dc157e20e6ad7b7a5789a4df1d5257a39589cf66edd462 +gonum.org/v1/gonum,v0.6.0,h1:DJy6UzXbahnGUf1ujUNkh/NEtK14qMo2nvlBPs4U5yw=,98857b431471c87facf3cd779eadc5d33760c9edee4b56a8228af4b383b90aa2 +gonum.org/v1/netlib,v0.0.0-20190331212654-76723241ea4e,h1:jRyg0XfpwWlhEV8mDfdNGBeSJM2fuyh9Yjrnd8kF2Ts=,ed4dca5026c9ab5410d23bbe21c089433ca58a19bd2902311c6a91791142a687 +gonum.org/v1/plot,v0.0.0-20191004082913-159cd04f920c,h1:Ssc2Jy4xun3/JMt2asledr/xSPAvX7ZZ7HimX2Gwz1w=,9246b6f7a9299061b31d99e50b2ac2685853dc478a6c2c730fada016c7268ea1 +google.golang.org/api,v0.13.0,h1:Q3Ui3V3/CVinFWFiW39Iw0kMuVrRzYX0wN6OPFp0lTA=,4c853034281c673829b7a7f3e39c62640d01895d20a666f003f855ad5f55ec30 +google.golang.org/appengine,v1.6.5,h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=,24ddb4adf72189738dc8340b28f9493a385515e680eb0bfbffe08951412b6655 +google.golang.org/genproto,v0.0.0-20191028173616-919d9bdd9fe6,h1:UXl+Zk3jqqcbEVV7ace5lrt4YdA4tXiz3f/KbmD29Vo=,cb4eec9cf94aa450efbb0d131cf1484f6334f1e8c1e1475b76c3ab2dea76c72a +google.golang.org/grpc,v1.24.0,h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s=,eb4433685a85e20f934c2a98e35d104db2d77abe438a242d75d5aae9f78898fb +google.golang.org/protobuf,v0.0.0-20191101204728-ef19a2a99470,h1:wSgCzfaFwg6Q4Eh+T7XknFfgswhFaeYkEs8t5endA/c=,73a49a6e5fd3330de7364564ab0954146e25ad8bbdff0ea6180f8ace153b0c1b +gopkg.in/Acconut/lockfile.v1,v1.1.0,h1:c5AMZOxgM1y+Zl8eSbaCENzVYp/LCaWosbQSXzb3FVI=,66e89c98908e2b9295de1a32cdd90f626a2468c256ce6182d6339e6659548e71 +gopkg.in/AlecAivazis/survey.v1,v1.8.7,h1:oBJqtgsyBLg9K5FK9twNUbcPnbCPoh+R9a+7nag3qJM=,c924df9f9d79f015cc619b1ecede52c92618c0ab8d020cd63e2c783f46b3907d +gopkg.in/DataDog/dd-trace-go.v1,v1.19.0,h1:aFSFd6oDMdvPYiToGqTv7/ERA6QrPhGaXSuueRCaM88=,f8eb14519d62c80eea88fca1daa69b274a0b492aa8b775890424b48d362c32b3 +gopkg.in/Shopify/sarama.v1,v1.18.0,h1:f9aTXuIEFEjVvLG9p+kMSk01dMfFumHsySRk1okTdqU=,beeb8546c4202289f282529630bc3db4452dc5f7eb69c3d8546196470c7d8be3 +gopkg.in/VividCortex/ewma.v1,v1.1.1,h1:tWHEKkKq802K/JT9RiqGCBU5fW3raAPnJGTE9ostZvg=,fe7800182ce944f2b28834d6cf60c620de0cbba1d691d9442f3473baf2a3d50d +gopkg.in/airbrake/gobrake.v2,v2.0.9,h1:7z2uVWwn7oVeeugY1DtlPAy5H+KYgB1KeKTnqjNatLo=,2db903664908e5a9afafefba94821b9579bbf271e2929c1f0b7b1fdd23f7bbcf +gopkg.in/alecthomas/gometalinter.v2,v2.0.12,h1:/xBWwtjmOmVxn8FXfIk9noV8m2E2Id9jFfUY/Mh9QAI=,7e6b56f4b985a08d11c1494f9dcc2b595676e787afe7a1caa9c522d41cab9487 +gopkg.in/alecthomas/kingpin.v2,v2.2.6,h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=,638080591aefe7d2642f2575b627d534c692606f02ea54ba89f42db112ba8839 +gopkg.in/alecthomas/kingpin.v3-unstable,v3.0.0-20180810215634-df19058c872c,h1:vTxShRUnK60yd8DZU+f95p1zSLj814+5CuEh7NjF2/Y=,0e35a5bb02770611e4c53c611529b95b96d0bc573f05d10bb43f7441abef2fde +gopkg.in/alexcesaro/quotedprintable.v3,v3.0.0-20150716171945-2caba252f4dc,h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=,1a310c5e55038937be3e69765276449601ca582f681129f7d9d47e052846cafc +gopkg.in/asn1-ber.v1,v1.0.0-20181015200546-f715ec2f112d,h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM=,fee158570ba9cbfc11156afbe9b9ab0833ab00d0f1a2a2af29a6325984a79903 +gopkg.in/bblfsh/sdk.v1,v1.17.0,h1:Ez/4P0S0Zaq30iZKfiTlhOtqMx6dfQHMTYpqKFvnv4A=,172521b9f2bdd4180751ed5122971c9c37a8c0bca2e0710bc255bc0e5ff8c106 +gopkg.in/bblfsh/sdk.v2,v2.16.4,h1:Ta/kBVRGXf8UOBYDw/ih8mw13/8NND+AdR0JiXBQrOw=,eb7a8a7d08bd80cd0673a6b9c90fa524bda9db24242bd6ef82fb414941c4ef0f +gopkg.in/bsm/ratelimit.v1,v1.0.0-20160220154919-db14e161995a,h1:stTHdEoWg1pQ8riaP5ROrjS6zy6wewH/Q2iwnLCQUXY=,fea8af18591a0ac50d29c8db124d13a43da6bee7a624c411b7449a99ee87b489 +gopkg.in/bufio.v1,v1.0.0-20140618132640-567b2bfa514e,h1:wGA78yza6bu/mWcc4QfBuIEHEtc06xdiU0X8sY36yUU=,9d63fe986f79edba7fca9bcd3bee0c7dcff7787cd30b43b5f2ae8a59feae512c +gopkg.in/check.v1,v1.0.0-20190902080502-41f04d3bba15,h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=,004537cb19dbe45954ec1605f331705f6685ccc267eddd4289c1eb27513ab817 +gopkg.in/cheggaaa/pb.v1,v1.0.28,h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk=,39725f9f37aac44dd55bdc9ade65a2d066953a090456298d34203257fc7e8ee9 +gopkg.in/cheggaaa/pb.v2,v2.0.7,h1:beaAg8eacCdMQS9Y7obFEtkY7gQl0uZ6Zayb3ry41VY=,a6ba73f81893f0eca8c0a60c238a705a12bae499a44fe6217a4471687766ef02 +gopkg.in/clog.v1,v1.2.0,h1:BHfwHRNQy497iBNsRBassPixSAxRbn2z5KVkdBFbwxc=,51eb8901943d1cec850b55556a9989e21488a9636ac692d6f7575db057804f3d +gopkg.in/editorconfig/editorconfig-core-go.v1,v1.3.0,h1:oxOEwvhxLMpWpN+0pb2r9TWrM0DCFBHxbuIlS27tmFg=,b5371885f56b40c03da4fd05006c717fabdfb8ee9ea1ceef4cc5b7caeda35041 +gopkg.in/errgo.v1,v1.0.1,h1:oQFRXzZ7CkBGdm1XZm/EbQYaYNNEElNBOd09M6cqNso=,32f45f7cfacfc04ae9e7e8c9fc55a53812554799da7c2bd17b043068b5fd5171 +gopkg.in/errgo.v2,v2.1.0,h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8=,6b8954819a20ec52982a206fd3eb94629ff53c5790aa77534e6d8daf7de01bee +gopkg.in/fatih/color.v1,v1.7.0,h1:bYGjb+HezBM6j/QmgBfgm1adxHpzzrss6bj4r9ROppk=,ed20c58de8c575144c2cc1c924121ee1a240e0621c77918231547b576d46d3ce +gopkg.in/fatih/set.v0,v0.2.1,h1:Xvyyp7LXu34P0ROhCyfXkmQCAoOUKb1E2JS9I7SE5CY=,d743141e21d20f6d5ae8e784dd4644c0947948103b63404a878b0298f14a9e62 +gopkg.in/fsnotify.v1,v1.4.7,h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=,ce003d540f42b3c0a3dec385deb387b255b536b25ea4438baa65b89458b28f75 +gopkg.in/fsnotify/fsnotify.v1,v1.4.7,h1:XNNYLJHt73EyYiCZi6+xjupS9CpvmiDgjPTAjrBlQbo=,6f74f844c970ff3059d1639c8a850d9ba7029dd059b5d9a305f87bd307c05491 +gopkg.in/gavv/httpexpect.v1,v1.0.0-20170111145843-40724cf1e4a0,h1:r5ptJ1tBxVAeqw4CrYWhXIMr0SybY3CDHuIbCg5CFVw=,4fe4a5e78a26ac5b60fc16405d3a5918d83cd645d36bd9dc0d558824136930b6 +gopkg.in/gcfg.v1,v1.2.3,h1:m8OOJ4ccYHnx2f4gQwpno8nAX5OGOh7RLaaz0pj3Ogs=,06cdad29610507bafb35e2e73d64fd7aa6c5c2ce1e5feff30a622af5475bca3b +gopkg.in/gemnasium/logrus-airbrake-hook.v2,v2.1.2,h1:OAj3g0cR6Dx/R07QgQe8wkA9RNjB2u4i700xBkIT4e0=,ce35c69d2a1f49d8672447bced4833c02cc7af036aa9df94d5a6a0f5d871cccd +gopkg.in/go-playground/assert.v1,v1.2.1,h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=,11da2f608d82304df2384a2301e0155fe72e8414e1a17776f1966c3a4c403bc4 +gopkg.in/go-playground/validator.v8,v8.18.2,h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=,fea7482c7122c2573d964b7d294a78f2162fa206ccd4b808d0c82f3d87b4d159 +gopkg.in/go-playground/validator.v9,v9.30.0,h1:Wk0Z37oBmKj9/n+tPyBHZmeL19LaCoK3Qq48VwYENss=,f4769db84ddc2db880bc190a5420762ef45f80ebbce678b622c4fa82b422b890 +gopkg.in/gobwas/glob.v0,v0.2.3,h1:uLMy+ys6BqRCutdUNyWLlmEnd7VULqh1nsxxV1kj0qQ=,3a5fe045be1ff9b47c5e21a9f97bdefaada31463f365503d6b176b76e18a0257 +gopkg.in/gographics/imagick.v3,v3.2.0,h1:eUwlkCw2fa20OGu47G39Im8c50S9n/CVkh8PwtOKExA=,99695d22cf7d5609887609cc9dc63ca1031b5a3238c26f6b779f32e39d572a01 +gopkg.in/gomail.v2,v2.0.0-20160411212932-81ebce5c23df,h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=,08b3372836aef3a403b0a01e6867a3a2252a07f65c28e0d33fe9c4b1b3ac517a +gopkg.in/gorp.v1,v1.7.2,h1:j3DWlAyGVv8whO7AcIWznQ2Yj7yJkn34B8s63GViAAw=,eaad3325e8b5358d5d54a1ca8b1e6aa19d16968a1f11f3dc45671588d914ef25 +gopkg.in/guregu/null.v3,v3.4.0,h1:AOpMtZ85uElRhQjEDsFx21BkXqFPwA7uoJukd4KErIs=,b38d62a816c5905933396a02eb11e23cbe2c17f8837563cc10794274e5af7e6e +gopkg.in/h2non/gentleman.v2,v2.0.3,h1:exsUPKJDFwNjJykboVj8+BKPWMNOxR/AmPL3f7Hutwo=,7a71dc2dd74e413832782e4478f85cc0617aed125e078e308b46207f34d6a500 +gopkg.in/h2non/gock.v1,v1.0.15,h1:SzLqcIlb/fDfg7UvukMpNcWsu7sI5tWwL+KCATZqks0=,c6a3d33e638b56ddd050c1dc6c1c6c8e9007c70cacfcc29e778fcf421f1fc029 +gopkg.in/httprequest.v1,v1.2.0,h1:YTGV1oXzaoKI6oPzQ0knoIPcrrVzeRG3amkoxoP7Xng=,3960019870090d0de3fca818633111186d46a908b4bcac6d87e5f08e7fb58770 +gopkg.in/inconshreveable/log15.v2,v2.0.0-20180818164646-67afb5ed74ec,h1:RlWgLqCMMIYYEVcAR5MDsuHlVkaIPDAF+5Dehzg8L5A=,799307ed46ca30ca0ac2dc0332f3673814b8ff6cc1ee905a462ccfd438e8e695 +gopkg.in/inf.v0,v0.9.1,h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=,08abac18c95cc43b725d4925f63309398d618beab68b4669659b61255e5374a0 +gopkg.in/ini.v1,v1.49.0,h1:MW0aLMiezbm/Ray0gJJ+nQFE2uOC9EpK2p5zPN3NqpM=,579074067ceacbf11e938940d65647094da4f23f627645b5c58218bf05c060f0 +gopkg.in/jarcoal/httpmock.v1,v1.0.0-20181117152235-275e9df93516,h1:H6trpavCIuipdInWrab8l34Mf+GGVfphniHostMdMaQ=,5b896c9e5e44146260a066533409c1b86268458301a7155624ef27f784e5d94a +gopkg.in/jcmturner/aescts.v1,v1.0.1,h1:cVVZBK2b1zY26haWB4vbBiZrfFQnfbTVrE3xZq6hrEw=,8bfd83c7204032fb16946202d5d643bd9a7e618005bd39578f29030a7d51dcf9 +gopkg.in/jcmturner/dnsutils.v1,v1.0.1,h1:cIuC1OLRGZrld+16ZJvvZxVJeKPsvd5eUIvxfoN5hSM=,4fb8b6a5471cb6dda1d0aabd1e01e4d54cb5ee83c395849916392b19153f5203 +gopkg.in/jcmturner/goidentity.v3,v3.0.0,h1:1duIyWiTaYvVx3YX2CYtpJbUFd7/UuPYCfgXtQ3VTbI=,1be44bee93d9080ce89f40827c57e8a396b7c801e2d19a1f5446a4325afa755e +gopkg.in/jcmturner/gokrb5.v7,v7.2.3,h1:hHMV/yKPwMnJhPuPx7pH2Uw/3Qyf+thJYlisUc44010=,3eec5b25adb89633174beb9798d8092e91ff4eed146a4b4cb950dd02414bd75e +gopkg.in/jcmturner/rpc.v1,v1.1.0,h1:QHIUxTX1ISuAv9dD2wJ9HWQVuWDX/Zc0PfeC2tjc4rU=,83d897b60ecb5a66d25232b775ed04c182ca8e02431f351b3768d4d2876d07ae +gopkg.in/jmcvetta/napping.v3,v3.2.0,h1:NpSZLAL6VgiyhdqaOkxwVtHXOLrQJZ6fFOMQgp7G8PQ=,887358529a8cd287b6a8232b43cc48636463fa266bac5ba48328cb0609d1dcb6 +gopkg.in/juju/charm.v6,v6.0.0-20191031115626-f595bfd8a049,h1:+isWLR3tDZyDacru13gHH0ooIuuDB28kuZJjSc8kOqU=,8d404b146f31d35148015de3f5bd4d25260f0a4b9f22a540a9167864d9e5d082 +gopkg.in/juju/charmrepo.v3,v3.0.1,h1:mm7/CwCczsO7JYHlYkw4iCUYR7X8upEOaY5bYj7eUkw=,8f673109a6d98e4abe4ef612f85dea26bdbd7de5c66b6722c546a08aefb548fc +gopkg.in/juju/environschema.v1,v1.0.0,h1:51vT1bzbP9fntQ0I9ECSlku2p19Szj/N2beZFeIH2kM=,46ae8efc5a450745fea959dc8532d2a013aa741ab7193d3cea8b0735f09c6e8a +gopkg.in/juju/names.v2,v2.0.0-20190813004204-e057c73bd1be,h1:xDxN+Fe8olIH8sTqvFJBMsuflBYzeHVeYC4Iz97+f5M=,72ac554c125260751aadf6d41eb82d85de22ef8bff1d59c6602e9e0f5b84a28c +gopkg.in/juju/worker.v1,v1.0.0-20191018043616-19a698a7150f,h1:UAHa7z4EdrOcMN+9p5P+ojJshcIC34vwi0hCmEL6Qf8=,2e0da8053029ca9da961f8e6f1037a9d7ba12623e5c16fc5f88bf1a724c5dd23 +gopkg.in/karalabe/cookiejar.v2,v2.0.0-20150724131613-8dcd6a7f4951,h1:DMTcQRFbEH62YPRWwOI647s2e5mHda3oBPMHfrLs2bw=,07aae15601f54a5806705d218e313794118d54d9dda7addc1bf4bda4332dfc16 +gopkg.in/kothar/go-backblaze.v0,v0.0.0-20190520213052-702d4e7eb465,h1:DKgyTtKkmpZZesLue2fz/LxEhzBDUWg4N8u/BVRJqlA=,215300ce3726c40f51ee43c41a27c204441e756c8cb4f4b76b1a4dd08f509eef +gopkg.in/ldap.v2,v2.5.1,h1:wiu0okdNfjlBzg6UWvd1Hn8Y+Ux17/u/4nlk4CQr6tU=,4fd426691e674164a701ef3ec3548596574f95447cde1fa331018f7d73f8399b +gopkg.in/ldap.v3,v3.0.2,h1:R6RBtabK6e1GO0eQKtkyOFbAHO73QesLzI2w2DZ6b9w=,f79d1cb87a0a6d571e671c2028409056d65e6bfa7d3d0563ded0edbe8ff0998e +gopkg.in/macaron.v1,v1.3.4,h1:HvIscOwxhFhx3swWM/979wh2QMYyuXrNmrF9l+j3HZs=,f9aca15b099dada4382e47898516d500876aae45d36895314cde86700636c05c +gopkg.in/macaroon-bakery.v2,v2.1.0,h1:9Jw/+9XHBSutkaeVpWhDx38IcSNLJwWUICkOK98DHls=,0a12f46df7290b131ee74ec6a4d4760170192920a091939aa2d7a39a4d0fb310 +gopkg.in/macaroon-bakery.v2-unstable,v2.0.0-20171026135619-38b77b89a624,h1:FIOL4YpoNbXH6K+LnOoAEMa/1ebliK7B9mj5NuJHmiA=,51476e40e03bd1f64fd3cdf936d1cde4b8c1395884af9376ff65755041c247aa +gopkg.in/macaroon.v2,v2.1.0,h1:HZcsjBCzq9t0eBPMKqTN/uSN6JOm78ZJ2INbqcBQOUI=,ae47a93d20ce5c053eafc9d6a76c01b2b06784f9886137dc73a99302928046eb +gopkg.in/macaroon.v2-unstable,v2.0.0-20180319203259-5c9beabe0e9e,h1:yPxshueS06kvTVlsymSbHvk6VQ1WhX1Ou3hCqqWBp/s=,e09a1f8268d65e3dc28da85c75e78f15f1f742d1dcd31cce427fd885b1962bc4 +gopkg.in/mail.v2,v2.0.0-20180731213649-a0242b2233b4,h1:a3llQg4+Czqaf+QH4diHuHiKv4j1abMwuRXwaRNHTPU=,d7d60701b95fd7f62d3f83bc026f42c0fa69c3f16cc445d2b20497c9dd182ff6 +gopkg.in/mattes/migrate.v1,v1.3.2,h1:tWus4MPMhDY/htX+NCvASiQVRU2pj4Jyj4T8AIv6vUw=,c50f590108871c25d55631addd6bc267f311830d4306ff4d36a6feaad0b23255 +gopkg.in/mattn/go-colorable.v0,v0.1.0,h1:WYuADWvfvYC07fm8ygYB3LMcsc5CunpxfMGKawHkAos=,337a25f7f87a87097e5fb853313c1fac3d3126ed0eb9bb88511d52ba9a0eb4e0 +gopkg.in/mattn/go-isatty.v0,v0.0.4,h1:NtS1rQGQr4IaFWBGz4Cz4BhB///gyys4gDVtKA7hIsc=,18500935e08e5b74487537b8b78a30778a5b2304a138f53aa8758b86266773ff +gopkg.in/mattn/go-runewidth.v0,v0.0.4,h1:r0P71TnzQDlNIcizCqvPSSANoFa3WVGtcNJf3TWurcY=,e0307a435e39658f761b7526dda9149e7664b7250958494c1a4eebd14884b82d +gopkg.in/mcuadros/go-syslog.v2,v2.2.1,h1:60g8zx1BijSVSgLTzLCW9UC4/+i1Ih9jJ1DR5Tgp9vE=,1f444e24504b6a21c0d204441a84336ab1240f77a1280b60e48f68ea1b99da7b +gopkg.in/mgo.v2,v2.0.0-20190816093944-a6b53ec6cb22,h1:VpOs+IwYnYBaFnrNAeB8UUWtL3vEUnzSCL1nVjPhqrw=,14edbec0d97107b0e0980b66166400f8a4c3844b03bd3240fc57be2b82734b16 +gopkg.in/natefinch/lumberjack.v2,v2.0.0,h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=,8c268e36660d6ce36af808d74b9be80207c05463679703e93d857e954c637aaa +gopkg.in/neurosnap/sentences.v1,v1.0.6,h1:v7ElyP020iEZQONyLld3fHILHWOPs+ntzuQTNPkul8E=,e3df38d6fc6097f9d1d76ee13e24fec69103c43248ca6a7f3ade2afec5e85bdd +gopkg.in/ns1/ns1-go.v2,v2.0.0-20190730140822-b51389932cbc,h1:GAcf+t0o8gdJAdSFYdE9wChu4bIyguMVqz0RHiFL5VY=,c51d0889ff5eb72df2f9e4adc28e9f3602e6eb567c3824bebb3c7d315a60710a +gopkg.in/olivere/elastic.v2,v2.0.61,h1:7cpl3MW8ysa4GYFBXklpo5mspe4NK0rpZTdyZ+QcD4U=,0a20d84f6003850343937ef79179cabe99feef9b038c281fd65ec32ec6c7e85c +gopkg.in/olivere/elastic.v5,v5.0.82,h1:QH7ere4lvOAWnnOd0VLJ54W8LzExZszoGIRijnb1h2Y=,3c66a7606b226d19f61651b3ad58aecda3155edc802029bd21cd4b8724bd0c9f +gopkg.in/ory-am/dockertest.v3,v3.3.4,h1:oen8RiwxVNxtQ1pRoV4e4jqh6UjNsOuIZ1NXns6jdcw=,73b01a1d025d30c8f11def182179b873410eae72f7b2fd9f9394b0fcf4683c93 +gopkg.in/redis.v2,v2.3.2,h1:GPVIIB/JnL1wvfULefy3qXmPu1nfNu2d0yA09FHgwfs=,abe2fa39afa36f8186ee287bcf82f9f4bc083aa35d17dd82a2ccbf5850ecdde8 +gopkg.in/redis.v3,v3.6.4,h1:u7XgPH1rWwsdZnR+azldXC6x9qDU2luydOIeU/l52fE=,749ef3e08eb4eda43969f88135040ae4517b450b27dbd48aefb9bf5e72465621 +gopkg.in/redis.v4,v4.2.4,h1:y3XbwQAiHwgNLUng56mgWYK39vsPqo8sT84XTEcxjr0=,6403d2b45edf2804bfd07b6d697184fc97377168589ad43ad19b2433e1dcee34 +gopkg.in/redis.v5,v5.2.9,h1:MNZYOLPomQzZMfpN3ZtD1uyJ2IDonTTlxYiV/pEApiw=,3c30e42670d1ef5f0b33876928b3bd5693ef3b5be1df6b2710d48c2667ca7133 +gopkg.in/resty.v1,v1.12.0,h1:CuXP0Pjfw9rOuY6EP+UvtNvt5DSqHpIxILZKT/quCZI=,43487bb0bb40626d16502b1fe9e719cf751e7a5b4e4233276971873e7863d3cf +gopkg.in/robfig/cron.v2,v2.0.0-20150107220207-be2e0b0deed5,h1:E846t8CnR+lv5nE+VuiKTDG/v1U2stad0QzddfJC7kY=,b25da9b8747e664334044e581d1a8fb700237239e7f182fd226d6296e6180bc0 +gopkg.in/satori/go.uuid.v1,v1.2.0,h1:AH9uksa7bGe9rluapecRKBCpZvxaBEyu0RepitcD0Hw=,794cefc3062e09b17f4300eb6b02622ac348af9d368341ff71a655a15884547f +gopkg.in/sourcemap.v1,v1.0.5,h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=,05b5f382bfa60212f444c7207168e9eb0c722e26b57a688123cb8bbf234de692 +gopkg.in/spacemonkeygo/monkit.v2,v2.0.0-20190623001553-09813957f0a8,h1:nyw4hxw2zz4S0EHqr5nQfA3zGbMFJDRJlQPM4PCb7O4=,4a8e607c4f16b32bb9ee380627716979b19ac3df74ca2a4f80aefbaf0b411784 +gopkg.in/square/go-jose.v2,v2.4.0,h1:0kXPskUMGAXXWJlP05ktEMOV0vmzFQUWw6d+aZJQU8A=,d00c4af5a633ab9cf7645b68f6fa389c8f0d9ffebc486742c7a5292280cae84b +gopkg.in/src-d/go-billy.v4,v4.3.2,h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg=,c49871e1d08bba07b2261626b929096b6dc5c839e781adfc24fcc410067cc2bf +gopkg.in/src-d/go-cli.v0,v0.0.0-20181105080154-d492247bbc0d,h1:mXa4inJUuWOoA4uEROxtJ3VMELMlVkIxIfcR0HBekAM=,86042ffc0c8492845917453682c5bdba46beb2f0c067b61e495a92b9a8621076 +gopkg.in/src-d/go-errors.v1,v1.0.0,h1:cooGdZnCjYbeS1zb1s6pVAAimTdKceRrpn7aKOnNIfc=,f7d9f00c057d4b49bc6e57167561a7fb508ebb113a1946cb2b6f71dac5b14cfb +gopkg.in/src-d/go-git-fixtures.v3,v3.5.0,h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg=,282dc6474c5ecf62c1169d04ad1f6d75e6058922897b4709a16a1007a5f22eb7 +gopkg.in/src-d/go-git.v4,v4.13.1,h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE=,13364fe60f2316a179e912fb4eb6c576e2aabd67e8d390651a155e85c69146d2 +gopkg.in/src-d/go-log.v1,v1.0.1,h1:heWvX7J6qbGWbeFS/aRmiy1eYaT+QMV6wNvHDyMjQV4=,48f6c8a7bdc5436d296f388cd5d40ffb9c749e1e4ab1e455984efc61008fd5d7 +gopkg.in/stack.v0,v0.0.0-20141108040640-9b43fcefddd0,h1:lMH45EKqD8Nf6LwoF+43YOKjOAEEHQRVgDyG8RCV4MU=,a88c4cb4af34bb5c4dd69d0c771829331be7416d2f18d58ff599126f7b291984 +gopkg.in/stretchr/testify.v1,v1.2.2,h1:yhQC6Uy5CqibAIlk1wlusa/MJ3iAN49/BsR/dCCKz3M=,0126e73e5f2ce5687dec597bb276e11dc4031dbdf199e68de735bc67bf808149 +gopkg.in/telegram-bot-api.v3,v3.0.0,h1:Y6QmqOMwRKv5NUdlvzEBtEZChjsrqdTS6O858cvuCww=,03c58e32567a5cc4ec631cc226ecc99dd1113a7a98bab4778b02cde073ab5ed4 +gopkg.in/telegram-bot-api.v4,v4.6.4,h1:hpHWhzn4jTCsAJZZ2loNKfy2QWyPDRJVl3aTFXeMW8g=,01a91b240fb416bf83bcaaa07133cafac28fd8eb8f0f251f6a616beec88c92ac +gopkg.in/testfixtures.v2,v2.5.0,h1:N08B7l2GzFQenyYbzqthDnKAA+cmb17iAZhhFxr7JHw=,05baac4af6e2855d296a5c045b27deb1b33d0a04cd0df96f029927f0742765a3 +gopkg.in/tomb.v1,v1.0.0-20141024135613-dd632973f1e7,h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=,34898dc0e38ba7a792ab74a3e0fa113116313fd9142ffb444b011fd392762186 +gopkg.in/tomb.v2,v2.0.0-20161208151619-d5d1b5820637,h1:yiW+nvdHb9LVqSHQBXfZCieqV4fzYhNBql77zY0ykqs=,15d93d96e1e8b2d8daf7b9e57a2a9193c0e676a2c6b63d9325bf34b53e93db00 +gopkg.in/tylerb/graceful.v1,v1.2.15,h1:1JmOyhKqAyX3BgTXMI84LwT6FOJ4tP2N9e2kwTCM0nQ=,0a8639cfe62508438ebf2cae721468b64d8cd2992fc0f80439c83c718f4608e0 +gopkg.in/urfave/cli.v1,v1.20.0,h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0=,413704688402027dc0f51666bac42152eb1668a73fa0e33858c3d2123c0592e5 +gopkg.in/warnings.v0,v0.1.2,h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=,c412b1f704c1e8ba59b6cfdb1072f8be847c03f77d6507c692913d6d9454e51c +gopkg.in/yaml.v1,v1.0.0-20140924161607-9f9df34309c0,h1:POO/ycCATvegFmVuPpQzZFJ+pGZeX22Ufu6fibxDVjU=,7abff7973fdab7386de5a1e9e197d8dc50d41ded9d24ff914685900caa0eb742 +gopkg.in/yaml.v2,v2.2.4,h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=,815be785649ae218b51efd8e40b3b75de8f9b57dd43162386ffe3e76709f2a5d +gorgonia.org/tensor,v0.9.2,h1:bVTWB68apbLfdrAlz5Ev3daGhfOhKuPkVFacMSNzpHs=,17562e7c1c6477b8b530d6236ab9a61228edbabe01c1cfb9ba23286c2394ba4c +gorgonia.org/vecf32,v0.9.0,h1:PClazic1r+JVJ1dEzRXgeiVl4g1/Hf/w+wUSqnco1Xg=,618df2e604236a2d143958a3571f9939c8264ab2aaae7d8c71b897b728240a23 +gorgonia.org/vecf64,v0.9.0,h1:bgZDP5x0OzBF64PjMGC3EvTdOoMEcmfAh1VCUnZFm1A=,f57695832a12a6f1fbcc04cdaa267ed01fb6b8105f518590d64b2c63b9ac4c61 +gotest.tools,v2.2.0+incompatible,h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=,55fab831b2660201183b54d742602563d4e17e7125ee75788a309a4f6cb7285e +grpc.go4.org,v0.0.0-20170609214715-11d0a25b4919,h1:tmXTu+dfa+d9Evp8NpJdgOy6+rt8/x4yG7qPBrtNfLY=,58b5c3cccf3e765d0f42918d458cddcd03fc28ff5d701790783677513a8446e3 +h12.io/socks,v1.0.0,h1:oiFI7YXv4h/0kBNcmAb5EkkoFJgYsOF88EQjMBxjitc=,3bf83125284ccabf811aa238954b442e39f53e3e068d4ddb6bf679ba2be28bbe +honnef.co/go/js/dom,v0.0.0-20190526011328-ebc4cf92d81f,h1:b3Q9PqH+5NYHfIjNUEN+f8lYvBh9A25AX+kPh8dpYmc=,a65720d9c0339450c8818226693a85986549fb156ee4df65913682c350bd4d60 +honnef.co/go/js/util,v0.0.0-20150216223935-96b8dd9d1621,h1:QBApQyt1KyR3SvDWU8sHcIXeWTSCUamO7xQopvwuLWI=,db5638addc7638cc5cf2245cb9bcb19cf04a5912120330560149b54b4575ae50 +honnef.co/go/js/xhr,v0.0.0-20150307031022-00e3346113ae,h1:2dIKMawnBWvHzZrS8STyu/KdhYIOpnKQpp1WZm+K7TE=,d2a4a85c43fb4ccd9b5be6521450d272406a1722f7547f188f4a1d0cc65c4e13 +honnef.co/go/tools,v0.0.1-2019.2.3,h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=,539825114c487680f99df80f6107410e1e53bbfd5deb931b84d1faf2d221638e +howett.net/plist,v0.0.0-20181124034731-591f970eefbb,h1:jhnBjNi9UFpfpl8YZhA9CrOqpnJdvzuiHsl/dnxl11M=,58c94cd949be714c0ee320d1be0cff3116fc829c412b9e7b816b03fb3c85f463 +istio.io/api,v0.0.0-20191029012234-9fe6a7da3673,h1:wxFykuQoScKAnEtKujAPqjwR8Aqo2LNtkoIvodxyCSs=,9ba545b9c5411725b709287b590082d140d3b29d924be351e38942f46c33ff55 +istio.io/gogo-genproto,v0.0.0-20190930162913-45029607206a,h1:w7zILua2dnYo9CxImhpNW4NE/8ZxEoc/wfBfHrhUhrE=,3b5a81f1807f48117d6691c8d007402a94b648f45f4446841a3f56229aa94aba +istio.io/pkg,v0.0.0-20191029184635-5c2f5ef63692,h1:MT7e5hpQ8cGtKCeWIjtdluEVkIhkN2tw4iVkAzhWHYA=,887882f7e721e6d00dee301f0b029792bd04bd38c455ab7e5cf4f2bc5bf309df +k8s.io/api,v0.0.0-20191031065753-b19d8caf39be,h1:X0MqzqUHuZj50SrMQFExejJfy67RKPf30Vt2nnpa4AA=,00a67ed9b84be18f621701796b42cee630c770c858582753fe0eb9c146ef93ff +k8s.io/apiextensions-apiserver,v0.0.0-20191028232452-c47e10e6d5a3,h1:XxkWdWvPKTParJ1sXpUIvHJsJ2iIIj5Ebjxxy5YU1Zo=,2cb12eb8b2b0f95fb5d69b1f80b754b32ae46ef1f9636333fe27c6b17b1a6e19 +k8s.io/apimachinery,v0.0.0-20191030190112-bb31b70367b7,h1:81UYA9Qq3JXPpZMmRBnq6T3qU+b71Dvnm6sV3NSQTVk=,4c16a440acf7559b0974d99650c876969ad4811ddc76f9f5b7aa43afc34f66ec +k8s.io/apiserver,v0.0.0-20191031110436-8cb875160ee0,h1:BGkQMPpKpx07hvq9AW64gifbf+zbAh/xUbB5OYXPvQ0=,baefad9177a1f8077c94a2d88b7e85deb7df79317d3d6d6afe8ca0be8261b1ae +k8s.io/cli-runtime,v0.0.0-20191025231729-08207da42a69,h1:05z+vSvn9yPr7GTAt3MXpVc9VeU4D80HHwvJU6jC3D4=,46264219a6e1c8263acd610841a156086bbbdd43436a836effcd7285c37b0e8a +k8s.io/client-go,v11.0.0+incompatible,h1:LBbX2+lOwY9flffWlJM7f1Ct8V2SRNiMRDFeiwnJo9o=,70925f536d409accf4f6ae3f20dafd81370ac096f848e99009141bea971103c2 +k8s.io/cloud-provider,v0.0.0-20191025232453-66dd06a864dd,h1:CxSfhPPmLwYFZquskmKvODMeEm82ZLc4eph47AdUp+o=,55623701c005f824ae847ecad409c6e61ef5fcfc6588b8dd2995a4a0991eeae8 +k8s.io/cluster-bootstrap,v0.0.0-20191025232351-410fafc3baf5,h1:P1mMVQngKW9pj1haVjyAtqViIBqkJmsITXsfuaHGRko=,ff50816340cdb73313e7233c3ff6df383c350102762b88ea0cc744910053c7bd +k8s.io/code-generator,v0.0.0-20191029223907-9f431a56fdbc,h1:klQ4aWfZ3uk4UiSLkZZt5qQDI+7DwSdvbvyL5QUBHsQ=,1f63d3191c255d8fcc47ad24b3bd979865a3c12eca678b39f278c194c2ae560a +k8s.io/component-base,v0.0.0-20191029070825-5e0e35147053,h1:W9/+uFw7olz+qQOCmSOG92c6j2YgIwagxqR9RWai/cE=,45bd9877048a57c3dfe7eb9c98bc1939775c73fdd6451afd055d7e4f7b9659bc +k8s.io/cri-api,v0.0.0-20191025232916-446748cffdda,h1:HVTA1bXCQek+NF0xTZkryScnkGYWHkoeYAQVEVs73r8=,7aea277309740df8d1fad1c620901d60633569d755d2d0715d97bc553988d7be +k8s.io/csi-api,v0.0.0-20190313123203-94ac839bf26c,h1:m3xih+9aI7l7Z/PvwzizV1J4vBvaUpkHrmagnGa5UNg=,0579fba2111dfd5b3cb62d7d234e52c54051176d9564ae3f0f2fdc69b31872b0 +k8s.io/gengo,v0.0.0-20191010091904-7fa3014cb28f,h1:eW/6wVuHNZgQJmFesyAxu0cvj0WAHHUuGaLbPcmNY3Q=,7fe69109e947204ee0b95705626e3c3b540faefb947d3426260f2991d1e4c036 +k8s.io/helm,v2.15.2+incompatible,h1:UjEb+c5BUZDGR9zU3dWG3OXASLIeqLeY0FCIx6ZyfTY=,377860d9db9fb1d45ffa90fe6ee79d7cfc4e91e5bc04183921480a823cf79ede +k8s.io/klog,v1.0.0,h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=,a564b06078ddf014c5b793a7d36643d6fda31fc131e36b95cdea94ff838b99be +k8s.io/kube-aggregator,v0.0.0-20191025230902-aa872b06629d,h1:ls0BmbSFkF5BhZN7grE+W5/X49QMU42RH6J9DWdP7UQ=,9a51f29a98f603acde33e3a10625e9ab603d7db29b3c2b2256d145adf7396393 +k8s.io/kube-controller-manager,v0.0.0-20191025232249-6de08162fd59,h1:bTAKwqwK2HvJVmpowb/ccyeV3wsxQZUtFQE1AqhMZ6I=,a1183bb172f19f6ae319da09c111a3f5dded663a9be85e18b9bceb131f03a342 +k8s.io/kube-openapi,v0.0.0-20190918143330-0270cf2f1c1d,h1:Xpe6sK+RY4ZgCTyZ3y273UmFmURhjtoJiwOMbQsXitY=,fb1dcd1508144991be0a243cea9a066944775ba4e9fa23c7ea038822e4e8e232 +k8s.io/kubelet,v0.0.0-20191025232041-e9c3b1e8a9ed,h1:ISiRMWhiLjmSsx24QQ6NJSgW1oKmAN59LCFzB7llrSk=,8c409ac5922dfb4cb0b8e6bb52823b2132e82faa3756dc3a94cdeabeaa3ff51e +k8s.io/kubernetes,v1.11.10,h1:wCo67+wmguioiYv0ipIiTaXbVPfFBBjOTgIngeGGG+A=,7c8ca4ca473e9f2b5c6586a714209e98d99f193af84cdb3e8536a3d1e26be4bf +k8s.io/metrics,v0.0.0-20191026071343-a166cc0bce8f,h1:D4AcfwGLY2gFDQaeK2QVyb8g4fy4Xzs0GopdwAgfSGc=,f4243455881a38d4962483ba5f2888220743a6ddece179c2b8f706815b75778f +k8s.io/node-api,v0.0.0-20191025232816-761e5a80fde0,h1:V3FaBxwSQWPjPScXd5ioFx9+aREXGU24yFl8Gm7ib8w=,cb8718b6e148a66097f8cae4e4544dc55c674748202f9c21d07a2139b6e83fd1 +k8s.io/sample-apiserver,v0.0.0-20191030110742-cbfc6c263d7e,h1:9bsKcUCncu1Qg3A4pB5ZySTM0JMEZW4qgybjVhmaS4A=,91d701af12da2ff6cde6f07d53547885faafa32c2eadfa8d4614b4d814a854b9 +k8s.io/sample-controller,v0.0.0-20191025231305-d7b8b8302943,h1:ZYb6if7+Qa5kXFidUsQRLFDyZjCjRyG1sFf6GpZaA70=,07c3e3a95d0fac07a247a98c38448a8fc4ab0069ad599ec06ac9405df88b470b +k8s.io/utils,v0.0.0-20191030222137-2b95a09bc58d,h1:1P0iBJsBzxRmR+dIFnM+Iu4aLxnoa7lBqozW/0uHbT8=,e21be6d971127d4650bd13525a2d2627b2a98dbb8589f168b734a45d50f3ea22 +launchpad.net/gocheck,v0.0.0-20140225173054-000000000087,h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54=,1a1d9b10f2c69564e69993e4340d5299392a518d895ec06502e842e6c69f4857 +layeh.com/radius,v0.0.0-20190322222518-890bc1058917,h1:BDXFaFzUt5EIqe/4wrTc4AcYZWP6iC6Ult+jQWLh5eU=,5eb6b6a05a5f89bc114f37085deda268f895a46621aee2e36649b8d80061357e +leb.io/aeshash,v0.0.0-20190627052759-9e6b40329b3b,h1:MG17Tc0pA3XmFTsPwklMMEfcos3pTFnVYM4A0YfVSbU=,a78b48ac18e98ea68dacce16cd94c9074688a0b125f824f047313a33b264ea88 +leb.io/hashland,v0.0.0-20171003003232-07375b562dea,h1:s9IkzZTqYqw77voO6taUZHc0C1B096h4T/kQtujGApE=,0698177f24cbde0a7b45495e7fe976fe7623f2b9205995b7d91fd2e7b0f0e243 +leb.io/hrff,v0.0.0-20170927164517-757f8bd43e20,h1:9CHS8LIq9MDwUsAaCHUsbUq7zb5lSjLQYWlJ/AbMZKg=,538008712599401a903a7982714c0a9ae745221042d3dfb1437bc508d8fb9e96 +modernc.org/cc,v1.0.0,h1:nPibNuDEx6tvYrUAtvDTTw98rx5juGsa5zuDnKwEEQQ=,24711e9b28b0d79dd32438eeb7debd86b850350f5f7749b7af640422ecf6b93b +modernc.org/golex,v1.0.0,h1:wWpDlbK8ejRfSyi0frMyhilD3JBvtcx2AdGDnU+JtsE=,335133038991d7feaba5349ac2385db7b49601bba0904abf680803ee2d3c99df +modernc.org/mathutil,v1.0.0,h1:93vKjrJopTPrtTNpZ8XIovER7iCIH1QU7wNbOQXC60I=,766ad95195543fe1ac217ce9f54e1fb43119c25db2b89013b9ef5477ad2dd9d1 +modernc.org/strutil,v1.0.0,h1:XVFtQwFVwc02Wk+0L/Z/zDDXO81r5Lhe6iMKmGX3KhE=,4bbca362df97450c6f24b90b7dc80b97ecf19e5f0f5954655b26f335a0b8f378 +modernc.org/xc,v1.0.0,h1:7ccXrupWZIS3twbUGrtKmHS2DXY6xegFua+6O3xgAFU=,ef80e60acacc023cd294eef2555bd348f74c1bcd22c8cfbbd2472cb91e35900d +moul.io/http2curl,v1.0.0,h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8=,422e2b8833089b001da02c6d7235ecb4c0591bb585fee125cbd0d72b1371dba5 +mvdan.cc/sh,v2.6.0+incompatible,h1:BLDuJ+D75OCaBF7W70+2oALi8aKAjcAiDBNmmwR8BQA=,c5c335f4ae8f1c4228a01710b84ba8f847709b1920d2beeddc4648e62cdd25f7 +mvdan.cc/sh/v3,v3.0.0-alpha1,h1:ao/4li6H9nZe5HDXA14cynXoq90+DLZz0HmjZE/qjhA=,5da16556569786a039c24229b55eb0f76049c2293ac96a9b978cede87676962e +mvdan.cc/xurls/v2,v2.0.0,h1:r1zSOSNS/kqtpmATyMMMvaZ4/djsesbYz5kr0+qMRWc=,67e609a744e93b7ba05adee985d7e3471e6d414cea611ac73206e007a5e03082 +myitcv.io,v0.0.0-20190927111909-7837eed0ff8e,h1:aTqeLMcNZAhWxtvBgs0fbjTxg5BuNvHYnLo1lhSq9hE=,0d734b4e576c5c34dd9788481761864faef6cacdd735296d22f885b211fe9c70 +pack.ag/amqp,v0.11.2,h1:cuNDWLUTbKRtEZwhB0WQBXf9pGbm87pUBXQhvcFxBWg=,7cdc81d1aeef4ad24c4a49f6227aac060ee193587c95d48bfe4437beaf08310a +periph.io/x/periph,v3.6.2+incompatible,h1:B9vqhYVuhKtr6bXua8N9GeBEvD7yanczCvE0wU2LEqw=,aeb77a51a9e20e0414e7ea7c9a3a30302fcb5ffc5cf4dd41c3455ec0c3d7b1bc +perkeep.org,v0.0.0-20190926184543-d342b0e26632,h1:6ZKRr0VZtsfdHyYDJ/G9rCy7z8jGfrpmYANf0BR+vJM=,fd9e06dfc30d3bcb49399fd062094dfdf364a8344d409541896cb96d36465ade +rsc.io/binaryregexp,v0.2.0,h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE=,b3e706aa278fa7f880d32fa1cc40ef8282d1fc7d6e00356579ed0db88f3b0047 +rsc.io/goversion,v1.2.0,h1:SPn+NLTiAG7w30IRK/DKp1BjvpWabYgxlLp/+kx5J8w=,f8426f6078b1d1b4e29a8c6223603680169c7c0a8789d2aee7e401a46ff6343f +rsc.io/pdf,v0.1.1,h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4=,79bf310e399cf0e2d8aa61536750d2a6999c5ca884e7a27faf88d3701cd5ba8f +rsc.io/qr,v0.1.0,h1:M/sAxsU2J5mlQ4W84Bxga2EgdQqOaAliipcjPmMUM5Q=,fd09c124eb71d01dab3a0116eac47a6fce78f34bbdd84620b2dc01b90582b11c +sigs.k8s.io/cluster-api,v0.2.7,h1:WjhtuvyjnMgo62kKlVizhI/nYs4DJxHNf+ZMSk/uUsM=,1e3767e7d0f655b72a52eab40e122779ccd1f734c06b9c6488ea9615a3db7b24 +sigs.k8s.io/controller-runtime,v0.3.0,h1:ZtdgqJXVHsIytjdmDuk0QjagnzyLq9FjojXRqIp+dU4=,f37a21668e57315e7248169bec6d4a71f86bcf53d7528c9752e7b459ee74efe0 +sigs.k8s.io/kustomize,v2.0.3+incompatible,h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0=,e0f6ad3aaaf7160abcb5e7b16f711c13aebe876833ae9e6ad6f858f31641bf62 +sigs.k8s.io/structured-merge-diff,v0.0.0-20191023203907-336d3378ca53,h1:WCMuuk4OLJ1WdEK3fx+hroiutCODdAGwDlL2Dj4mpa0=,b389a2eafcce0dcef4ca1052942980f26b62030da007b3a84a653de5c0f91668 +sigs.k8s.io/testing_frameworks,v0.1.2-0.20190130140139-57f07443c2d4,h1:GtDhkj3cF4A4IW+A9LScsuxvJqA9DE7G7PGH1f8B07U=,bfb65beb3dda386efc0c0ff9237a07877cec71922f4d3dc1f4a40d5fcaa090a9 +sigs.k8s.io/yaml,v1.1.0,h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=,a0d39252e8665a428a8cb9d4dfc9cbea07b7ae90ae62e7cf3651be719adf515a +sofastack.io/sofa-mosn,v0.0.0-20191101130505-becc7a6dc50c,h1:8IAozA6SkwfqCAF7fVyy8gu4FdyJvH5iBC12WhiocB8=,0ed9cc5b20e6233051bb4de2ffee5c7f3365704fe01d28e87237d9e8041a786d +sourcegraph.com/sourcegraph/appdash,v0.0.0-20190107175209-d9ea5c54f7dc,h1:lmf242UNy8ucQUSUse9oXtyxHb6kaF82XRLqeVDXXhA=,49e3fd73d6218c97f49266f0e32bbdab1b6352f2f40da8d1aa98ee8dfdeec072 +sourcegraph.com/sourcegraph/appdash-data,v0.0.0-20151005221446-73f23eafcf67,h1:e1sMhtVq9AfcEy8AXNb8eSg6gbzfdpYhoNqnPJa+GzI=,382adefecd62bb79172e2552bcfb7d45f47122f9bd22259b0566b26fb2627b87 +sourcegraph.com/sourcegraph/go-diff,v0.5.0,h1:eTiIR0CoWjGzJcnQ3OkhIl/b9GJovq4lSAVRt0ZFEG8=,2c5eaad1d3743b3d4bd6de70459a413e62d1753673d5b96402dda27508454b3b +sourcegraph.com/sqs/pbtypes,v0.0.0-20180604144634-d3ebe8f20ae4,h1:JPJh2pk3+X4lXAkZIk2RuE/7/FoK9maXw+TNPJhVS/c=,6750f8618ecbde1668de332800ec01d713debb145dee395c23fc9a373c207fe3 +storj.io/drpc,v0.0.7-0.20191021224058-08e7133752cd,h1:Oh7Nww1cgFA3fhrCOheDwQ0VcUKFcO1LsBSJEgiGgUQ=,51befd9e6e3aa6cfb9f5b56e47b3cd59715dbe656d0a12cfbb0282609b5456dd +storj.io/storj,v0.24.5,h1:dWqApMsdhPoUufrljPQC1gZWkYcSTjRr5AoZ7mrSjCw=,ce0628bdcce2b8f0241d27993431d343d212b2e55323510bf657928001c2fb26 +strk.kbt.io/projects/go/libravatar,v0.0.0-20160628055650-5eed7bff870a,h1:8q33ShxKXRwQ7JVd1ZnhIU3hZhwwn0Le+4fTeAackuM=,be48b3949775d6ba0dd3105d7d31d338fede9fbd1471b41fe861f1cfcabbf85c +v.io/x/lib,v0.1.4,h1:PCDfluqBeRbA7OgDIs9tIpT+z6ZNZ5VMeR+t7h/K2ig=,411c5ded56ba1b69269c37748d184954089c320f43ee76beb0c53f7c598baeaf +vbom.ml/util,v0.0.0-20180919145318-efcd4e0f9787,h1:O69FD9pJA4WUZlEwYatBEEkRWKQ5cKodWpdKTrCS/iQ=,abbc7a9ac1d820f336ccbe247404800d0f79859b4e4412f0d107aebbb564f920 +vitess.io/vitess,v2.1.1+incompatible,h1:nuuGHiWYWpudD3gOCLeGzol2EJ25e/u5Wer2wV1O130=,8f823ede6775b4f5b3f6cd4c04b3b6be453416e124362a8d68fa2e829429fa68 +xorm.io/builder,v0.3.6,h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8=,8f16bb96bf2f75b4813be77072a966d1f2248a38f2c7afff4132b666876310a7 +xorm.io/core,v0.7.2,h1:mEO22A2Z7a3fPaZMk6gKL/jMD80iiyNwRrX5HOv3XLw=,24c93962a78b2a177ff5c66cd43921eb1e8b13290d0e8a4d87c6f075a81c4531 diff --git a/src/cmd/go/internal/modfetch/zip_sum_test/zip_sum_test.go b/src/cmd/go/internal/modfetch/zip_sum_test/zip_sum_test.go new file mode 100644 index 0000000..d9ba8ef --- /dev/null +++ b/src/cmd/go/internal/modfetch/zip_sum_test/zip_sum_test.go @@ -0,0 +1,230 @@ +// Copyright 2019 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 zip_sum_test tests that the module zip files produced by modfetch +// have consistent content sums. Ideally the zip files themselves are also +// stable over time, though this is not strictly necessary. +// +// This test loads a table from testdata/zip_sums.csv. The table has columns +// for module path, version, content sum, and zip file hash. The table +// includes a large number of real modules. The test downloads these modules +// in direct mode and verifies the zip files. +// +// This test is very slow, and it depends on outside modules that change +// frequently, so this is a manual test. To enable it, pass the -zipsum flag. +package zip_sum_test + +import ( + "context" + "crypto/sha256" + "encoding/csv" + "encoding/hex" + "flag" + "fmt" + "internal/testenv" + "io" + "os" + "path/filepath" + "strings" + "testing" + + "cmd/go/internal/cfg" + "cmd/go/internal/modfetch" + "cmd/go/internal/modload" + + "golang.org/x/mod/module" +) + +var ( + updateTestData = flag.Bool("u", false, "when set, tests may update files in testdata instead of failing") + enableZipSum = flag.Bool("zipsum", false, "enable TestZipSums") + debugZipSum = flag.Bool("testwork", false, "when set, TestZipSums will preserve its test directory") + modCacheDir = flag.String("zipsumcache", "", "module cache to use instead of temp directory") + shardCount = flag.Int("zipsumshardcount", 1, "number of shards to divide TestZipSums into") + shardIndex = flag.Int("zipsumshard", 0, "index of TestZipSums shard to test (0 <= zipsumshard < zipsumshardcount)") +) + +const zipSumsPath = "testdata/zip_sums.csv" + +type zipSumTest struct { + m module.Version + wantSum, wantFileHash string +} + +func TestZipSums(t *testing.T) { + if !*enableZipSum { + // This test is very slow and heavily dependent on external repositories. + // Only run it explicitly. + t.Skip("TestZipSum not enabled with -zipsum") + } + if *shardCount < 1 { + t.Fatal("-zipsumshardcount must be a positive integer") + } + if *shardIndex < 0 || *shardCount <= *shardIndex { + t.Fatal("-zipsumshard must be between 0 and -zipsumshardcount") + } + + testenv.MustHaveGoBuild(t) + testenv.MustHaveExternalNetwork(t) + testenv.MustHaveExecPath(t, "bzr") + testenv.MustHaveExecPath(t, "git") + // TODO(jayconrod): add hg, svn, and fossil modules to testdata. + // Could not find any for now. + + tests, err := readZipSumTests() + if err != nil { + t.Fatal(err) + } + + if *modCacheDir != "" { + cfg.BuildContext.GOPATH = *modCacheDir + } else { + tmpDir, err := os.MkdirTemp("", "TestZipSums") + if err != nil { + t.Fatal(err) + } + if *debugZipSum { + fmt.Fprintf(os.Stderr, "TestZipSums: modCacheDir: %s\n", tmpDir) + } else { + defer os.RemoveAll(tmpDir) + } + cfg.BuildContext.GOPATH = tmpDir + } + + cfg.GOPROXY = "direct" + cfg.GOSUMDB = "off" + modload.Init() + + // Shard tests by downloading only every nth module when shard flags are set. + // This makes it easier to test small groups of modules quickly. We avoid + // testing similarly named modules together (the list is sorted by module + // path and version). + if *shardCount > 1 { + r := *shardIndex + w := 0 + for r < len(tests) { + tests[w] = tests[r] + w++ + r += *shardCount + } + tests = tests[:w] + } + + // Download modules with a rate limit. We may run out of file descriptors + // or cause timeouts without a limit. + needUpdate := false + for i := range tests { + test := &tests[i] + name := fmt.Sprintf("%s@%s", strings.ReplaceAll(test.m.Path, "/", "_"), test.m.Version) + t.Run(name, func(t *testing.T) { + t.Parallel() + zipPath, err := modfetch.DownloadZip(context.Background(), test.m) + if err != nil { + if *updateTestData { + t.Logf("%s: could not download module: %s (will remove from testdata)", test.m, err) + test.m.Path = "" // mark for deletion + needUpdate = true + } else { + t.Errorf("%s: could not download module: %s", test.m, err) + } + return + } + + sum := modfetch.Sum(test.m) + if sum != test.wantSum { + if *updateTestData { + t.Logf("%s: updating content sum to %s", test.m, sum) + test.wantSum = sum + needUpdate = true + } else { + t.Errorf("%s: got content sum %s; want sum %s", test.m, sum, test.wantSum) + return + } + } + + h := sha256.New() + f, err := os.Open(zipPath) + if err != nil { + t.Errorf("%s: %v", test.m, err) + } + defer f.Close() + if _, err := io.Copy(h, f); err != nil { + t.Errorf("%s: %v", test.m, err) + } + zipHash := hex.EncodeToString(h.Sum(nil)) + if zipHash != test.wantFileHash { + if *updateTestData { + t.Logf("%s: updating zip file hash to %s", test.m, zipHash) + test.wantFileHash = zipHash + needUpdate = true + } else { + t.Errorf("%s: got zip file hash %s; want hash %s (but content sum matches)", test.m, zipHash, test.wantFileHash) + } + } + }) + } + + if needUpdate { + // Remove tests marked for deletion + r, w := 0, 0 + for r < len(tests) { + if tests[r].m.Path != "" { + tests[w] = tests[r] + w++ + } + r++ + } + tests = tests[:w] + + if err := writeZipSumTests(tests); err != nil { + t.Error(err) + } + } +} + +func readZipSumTests() ([]zipSumTest, error) { + f, err := os.Open(filepath.FromSlash(zipSumsPath)) + if err != nil { + return nil, err + } + defer f.Close() + r := csv.NewReader(f) + + var tests []zipSumTest + for { + line, err := r.Read() + if err == io.EOF { + break + } else if err != nil { + return nil, err + } else if len(line) != 4 { + return nil, fmt.Errorf("%s:%d: malformed line", f.Name(), len(tests)+1) + } + test := zipSumTest{m: module.Version{Path: line[0], Version: line[1]}, wantSum: line[2], wantFileHash: line[3]} + tests = append(tests, test) + } + return tests, nil +} + +func writeZipSumTests(tests []zipSumTest) (err error) { + f, err := os.Create(filepath.FromSlash(zipSumsPath)) + if err != nil { + return err + } + defer func() { + if cerr := f.Close(); err == nil && cerr != nil { + err = cerr + } + }() + w := csv.NewWriter(f) + line := make([]string, 0, 4) + for _, test := range tests { + line = append(line[:0], test.m.Path, test.m.Version, test.wantSum, test.wantFileHash) + if err := w.Write(line); err != nil { + return err + } + } + w.Flush() + return nil +} diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go new file mode 100644 index 0000000..5a98408 --- /dev/null +++ b/src/cmd/go/internal/modget/get.go @@ -0,0 +1,1687 @@ +// 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 + +// The arguments to 'go get' are patterns with optional version queries, with +// the version queries defaulting to "upgrade". +// +// The patterns are normally interpreted as package patterns. However, if a +// pattern cannot match a package, it is instead interpreted as a *module* +// pattern. For version queries such as "upgrade" and "patch" that depend on the +// selected version of a module (or of the module containing a package), +// whether a pattern denotes a package or module may change as updates are +// applied (see the example in mod_get_patchmod.txt). +// +// There are a few other ambiguous cases to resolve, too. A package can exist in +// two different modules at the same version: for example, the package +// example.com/foo might be found in module example.com and also in module +// example.com/foo, and those modules may have independent v0.1.0 tags — so the +// input 'example.com/foo@v0.1.0' could syntactically refer to the variant of +// the package loaded from either module! (See mod_get_ambiguous_pkg.txt.) +// If the argument is ambiguous, the user can often disambiguate by specifying +// explicit versions for *all* of the potential module paths involved. + +import ( + "context" + "errors" + "fmt" + "os" + "path/filepath" + "reflect" + "runtime" + "sort" + "strings" + "sync" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/imports" + "cmd/go/internal/load" + "cmd/go/internal/modload" + "cmd/go/internal/par" + "cmd/go/internal/search" + "cmd/go/internal/work" + + "golang.org/x/mod/modfile" + "golang.org/x/mod/module" + "golang.org/x/mod/semver" +) + +var CmdGet = &base.Command{ + // Note: -d -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] [-t] [-u] [-v] [-insecure] [build flags] [packages]", + Short: "add dependencies to current module and install them", + Long: ` +Get resolves its command-line arguments to packages at specific module versions, +updates go.mod to require those versions, downloads source code into the +module cache, then builds and installs the named packages. + +To add a dependency for a package or upgrade it to its latest version: + + go get example.com/pkg + +To upgrade or downgrade a package to a specific version: + + go get example.com/pkg@v1.2.3 + +To remove a dependency on a module and downgrade modules that require it: + + go get example.com/mod@none + +See https://golang.org/ref/mod#go-get for details. + +The 'go install' command may be used to build and install packages. When a +version is specified, 'go install' runs in module-aware mode and ignores +the go.mod file in the current directory. For example: + + go install example.com/pkg@v1.2.3 + go install example.com/pkg@latest + +See 'go help install' or https://golang.org/ref/mod#go-install for details. + +In addition to build flags (listed in 'go help build') 'go get' accepts the +following flags. + +The -t flag instructs get to consider modules needed to build tests of +packages specified on the command line. + +The -u flag instructs get to update modules providing dependencies +of packages named on the command line to use newer minor or patch +releases when available. + +The -u=patch flag (not -u patch) also instructs get to update dependencies, +but changes the default to select patch releases. + +When the -t and -u flags are used together, get will update +test dependencies as well. + +The -insecure flag permits fetching from repositories and resolving +custom domains using insecure schemes such as HTTP, and also bypassess +module sum validation using the checksum database. Use with caution. +This flag is deprecated and will be removed in a future version of go. +To permit the use of insecure schemes, use the GOINSECURE environment +variable instead. To bypass module sum validation, use GOPRIVATE or +GONOSUMDB. See 'go help environment' for details. + +The -d flag instructs get not to build or install packages. get will only +update go.mod and download source code needed to build packages. + +Building and installing packages with get is deprecated. In a future release, +the -d flag will be enabled by default, and 'go get' will be only be used to +adjust dependencies of the current module. To install a package using +dependencies from the current module, use 'go install'. To install a package +ignoring the current module, use 'go install' with an @version suffix like +"@latest" after each argument. + +For more about modules, see https://golang.org/ref/mod. + +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 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 HelpVCS = &base.Command{ + UsageLine: "vcs", + Short: "controlling version control with GOVCS", + Long: ` +The 'go get' command can run version control commands like git +to download imported code. This functionality is critical to the decentralized +Go package ecosystem, in which code can be imported from any server, +but it is also a potential security problem, if a malicious server finds a +way to cause the invoked version control command to run unintended code. + +To balance the functionality and security concerns, the 'go get' command +by default will only use git and hg to download code from public servers. +But it will use any known version control system (bzr, fossil, git, hg, svn) +to download code from private servers, defined as those hosting packages +matching the GOPRIVATE variable (see 'go help private'). The rationale behind +allowing only Git and Mercurial is that these two systems have had the most +attention to issues of being run as clients of untrusted servers. In contrast, +Bazaar, Fossil, and Subversion have primarily been used in trusted, +authenticated environments and are not as well scrutinized as attack surfaces. + +The version control command restrictions only apply when using direct version +control access to download code. When downloading modules from a proxy, +'go get' uses the proxy protocol instead, which is always permitted. +By default, the 'go get' command uses the Go module mirror (proxy.golang.org) +for public packages and only falls back to version control for private +packages or when the mirror refuses to serve a public package (typically for +legal reasons). Therefore, clients can still access public code served from +Bazaar, Fossil, or Subversion repositories by default, because those downloads +use the Go module mirror, which takes on the security risk of running the +version control commands using a custom sandbox. + +The GOVCS variable can be used to change the allowed version control systems +for specific packages (identified by a module or import path). +The GOVCS variable applies when building package in both module-aware mode +and GOPATH mode. When using modules, the patterns match against the module path. +When using GOPATH, the patterns match against the import path corresponding to +the root of the version control repository. + +The general form of the GOVCS setting is a comma-separated list of +pattern:vcslist rules. The pattern is a glob pattern that must match +one or more leading elements of the module or import path. The vcslist +is a pipe-separated list of allowed version control commands, or "all" +to allow use of any known command, or "off" to disallow all commands. +Note that if a module matches a pattern with vcslist "off", it may still be +downloaded if the origin server uses the "mod" scheme, which instructs the +go command to download the module using the GOPROXY protocol. +The earliest matching pattern in the list applies, even if later patterns +might also match. + +For example, consider: + + GOVCS=github.com:git,evil.com:off,*:git|hg + +With this setting, code with a module or import path beginning with +github.com/ can only use git; paths on evil.com cannot use any version +control command, and all other paths (* matches everything) can use +only git or hg. + +The special patterns "public" and "private" match public and private +module or import paths. A path is private if it matches the GOPRIVATE +variable; otherwise it is public. + +If no rules in the GOVCS variable match a particular module or import path, +the 'go get' command applies its default rule, which can now be summarized +in GOVCS notation as 'public:git|hg,private:all'. + +To allow unfettered use of any version control system for any package, use: + + GOVCS=*:all + +To disable all use of version control, use: + + GOVCS=*:off + +The 'go env -w' command (see 'go help env') can be used to set the GOVCS +variable for future go command invocations. +`, +} + +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 cfg.Insecure + // -v is cfg.BuildV +) + +// upgradeFlag is a custom flag.Value for -u. +type upgradeFlag struct { + rawVersion string + version string +} + +func (*upgradeFlag) IsBoolFlag() bool { return true } // allow -u + +func (v *upgradeFlag) Set(s string) error { + if s == "false" { + v.version = "" + v.rawVersion = "" + } else if s == "true" { + v.version = "upgrade" + v.rawVersion = "" + } else { + v.version = s + v.rawVersion = s + } + return nil +} + +func (v *upgradeFlag) String() string { return "" } + +func init() { + work.AddBuildFlags(CmdGet, work.OmitModFlag) + CmdGet.Run = runGet // break init loop + CmdGet.Flag.BoolVar(&cfg.Insecure, "insecure", cfg.Insecure, "") + CmdGet.Flag.Var(&getU, "u", "") +} + +func runGet(ctx context.Context, cmd *base.Command, args []string) { + switch getU.version { + case "", "upgrade", "patch": + // ok + default: + base.Fatalf("go get: unknown upgrade flag -u=%s", getU.rawVersion) + } + 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 *getM { + base.Fatalf("go get: -m flag is no longer supported; consider -d to skip building packages") + } + if cfg.Insecure { + fmt.Fprintf(os.Stderr, "go get: -insecure flag is deprecated; see 'go help get' for details\n") + } + load.ModResolveTests = *getT + + // 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() + + // Allow looking up modules for import paths when outside of a module. + // 'go get' is expected to do this, unlike other commands. + modload.AllowMissingModuleImports() + + modload.LoadModFile(ctx) // Initializes modload.Target. + + queries := parseArgs(ctx, args) + + r := newResolver(ctx, queries) + r.performLocalQueries(ctx) + r.performPathQueries(ctx) + + for { + r.performWildcardQueries(ctx) + r.performPatternAllQueries(ctx) + + if changed := r.resolveCandidates(ctx, queries, nil); changed { + // 'go get' arguments can be (and often are) package patterns rather than + // (just) modules. A package can be provided by any module with a prefix + // of its import path, and a wildcard can even match packages in modules + // with totally different paths. Because of these effects, and because any + // change to the selected version of a module can bring in entirely new + // module paths as dependencies, we need to reissue queries whenever we + // change the build list. + // + // The result of any version query for a given module — even "upgrade" or + // "patch" — is always relative to the build list at the start of + // the 'go get' command, not an intermediate state, and is therefore + // dederministic and therefore cachable, and the constraints on the + // selected version of each module can only narrow as we iterate. + // + // "all" is functionally very similar to a wildcard pattern. The set of + // packages imported by the main module does not change, and the query + // result for the module containing each such package also does not change + // (it is always relative to the initial build list, before applying + // queries). So the only way that the result of an "all" query can change + // is if some matching package moves from one module in the build list + // to another, which should not happen very often. + continue + } + + // When we load imports, we detect the following conditions: + // + // - missing transitive depencies that need to be resolved from outside the + // current build list (note that these may add new matches for existing + // pattern queries!) + // + // - transitive dependencies that didn't match any other query, + // but need to be upgraded due to the -u flag + // + // - ambiguous import errors. + // TODO(#27899): Try to resolve ambiguous import errors automatically. + upgrades := r.findAndUpgradeImports(ctx, queries) + if changed := r.resolveCandidates(ctx, nil, upgrades); changed { + continue + } + + r.findMissingWildcards(ctx) + if changed := r.resolveCandidates(ctx, r.wildcardQueries, nil); changed { + continue + } + + break + } + + r.checkWildcardVersions(ctx) + + var pkgPatterns []string + for _, q := range queries { + if q.matchesPackages { + pkgPatterns = append(pkgPatterns, q.pattern) + } + } + r.checkPackagesAndRetractions(ctx, pkgPatterns) + + // We've already downloaded modules (and identified direct and indirect + // dependencies) by loading packages in findAndUpgradeImports. + // So if -d is set, we're done after the module work. + // + // Otherwise, we need to build and install the packages matched by + // command line arguments. + // Note that 'go get -u' without arguments is equivalent to + // 'go get -u .', so we'll typically build the package in the current + // directory. + if !*getD && len(pkgPatterns) > 0 { + work.BuildInit() + pkgs := load.PackagesAndErrors(ctx, pkgPatterns) + load.CheckPackageErrors(pkgs) + work.InstallPackages(ctx, pkgPatterns, pkgs) + // TODO(#40276): After Go 1.16, print a deprecation notice when building and + // installing main packages. 'go install pkg' or 'go install pkg@version' + // should be used instead. Give the specific argument to use if possible. + } + + if !modload.HasModRoot() { + return + } + + // Everything succeeded. Update go.mod. + oldReqs := reqsFromGoMod(modload.ModFile()) + + modload.AllowWriteGoMod() + modload.WriteGoMod() + modload.DisallowWriteGoMod() + + newReqs := reqsFromGoMod(modload.ModFile()) + r.reportChanges(oldReqs, newReqs) +} + +// parseArgs parses command-line arguments and reports errors. +// +// The command-line arguments are of the form path@version or simply path, with +// implicit @upgrade. path@none is "downgrade away". +func parseArgs(ctx context.Context, rawArgs []string) []*query { + defer base.ExitIfErrors() + + var queries []*query + for _, arg := range search.CleanPatterns(rawArgs) { + q, err := newQuery(arg) + if err != nil { + base.Errorf("go get: %v", err) + continue + } + + // If there were no arguments, CleanPatterns returns ".". Set the raw + // string back to "" for better errors. + if len(rawArgs) == 0 { + q.raw = "" + } + + // Guard against 'go get x.go', a common mistake. + // Note that package and module paths may end with '.go', so only print an error + // if the argument has no version and either has no slash or refers to an existing file. + if strings.HasSuffix(q.raw, ".go") && q.rawVersion == "" { + if !strings.Contains(q.raw, "/") { + base.Errorf("go get %s: arguments must be package or module paths", q.raw) + continue + } + if fi, err := os.Stat(q.raw); err == nil && !fi.IsDir() { + base.Errorf("go get: %s exists as a file, but 'go get' requires package arguments", q.raw) + continue + } + } + + queries = append(queries, q) + } + + return queries +} + +type resolver struct { + localQueries []*query // queries for absolute or relative paths + pathQueries []*query // package path literal queries in original order + wildcardQueries []*query // path wildcard queries in original order + patternAllQueries []*query // queries with the pattern "all" + + // Indexed "none" queries. These are also included in the slices above; + // they are indexed here to speed up noneForPath. + nonesByPath map[string]*query // path-literal "@none" queries indexed by path + wildcardNones []*query // wildcard "@none" queries + + // resolvedVersion maps each module path to the version of that module that + // must be selected in the final build list, along with the first query + // that resolved the module to that version (the “reason”). + resolvedVersion map[string]versionReason + + buildList []module.Version + buildListResolvedVersions int // len(resolvedVersion) when buildList was computed + buildListVersion map[string]string // index of buildList (module path → version) + + initialVersion map[string]string // index of the initial build list at the start of 'go get' + + missing []pathSet // candidates for missing transitive dependencies + + work *par.Queue + + matchInModuleCache par.Cache +} + +type versionReason struct { + version string + reason *query +} + +func newResolver(ctx context.Context, queries []*query) *resolver { + buildList := modload.LoadAllModules(ctx) + initialVersion := make(map[string]string, len(buildList)) + for _, m := range buildList { + initialVersion[m.Path] = m.Version + } + + r := &resolver{ + work: par.NewQueue(runtime.GOMAXPROCS(0)), + resolvedVersion: map[string]versionReason{}, + buildList: buildList, + buildListVersion: initialVersion, + initialVersion: initialVersion, + nonesByPath: map[string]*query{}, + } + + for _, q := range queries { + if q.pattern == "all" { + r.patternAllQueries = append(r.patternAllQueries, q) + } else if q.patternIsLocal { + r.localQueries = append(r.localQueries, q) + } else if q.isWildcard() { + r.wildcardQueries = append(r.wildcardQueries, q) + } else { + r.pathQueries = append(r.pathQueries, q) + } + + if q.version == "none" { + // Index "none" queries to make noneForPath more efficient. + if q.isWildcard() { + r.wildcardNones = append(r.wildcardNones, q) + } else { + // All "@none" queries for the same path are identical; we only + // need to index one copy. + r.nonesByPath[q.pattern] = q + } + } + } + + return r +} + +// initialSelected returns the version of the module with the given path that +// was selected at the start of this 'go get' invocation. +func (r *resolver) initialSelected(mPath string) (version string) { + v, ok := r.initialVersion[mPath] + if !ok { + return "none" + } + return v +} + +// selected returns the version of the module with the given path that is +// selected in the resolver's current build list. +func (r *resolver) selected(mPath string) (version string) { + v, ok := r.buildListVersion[mPath] + if !ok { + return "none" + } + return v +} + +// noneForPath returns a "none" query matching the given module path, +// or found == false if no such query exists. +func (r *resolver) noneForPath(mPath string) (nq *query, found bool) { + if nq = r.nonesByPath[mPath]; nq != nil { + return nq, true + } + for _, nq := range r.wildcardNones { + if nq.matchesPath(mPath) { + return nq, true + } + } + return nil, false +} + +// queryModule wraps modload.Query, substituting r.checkAllowedOr to decide +// allowed versions. +func (r *resolver) queryModule(ctx context.Context, mPath, query string, selected func(string) string) (module.Version, error) { + current := r.initialSelected(mPath) + rev, err := modload.Query(ctx, mPath, query, current, r.checkAllowedOr(query, selected)) + if err != nil { + return module.Version{}, err + } + return module.Version{Path: mPath, Version: rev.Version}, nil +} + +// queryPackage wraps modload.QueryPackage, substituting r.checkAllowedOr to +// decide allowed versions. +func (r *resolver) queryPackages(ctx context.Context, pattern, query string, selected func(string) string) (pkgMods []module.Version, err error) { + results, err := modload.QueryPackages(ctx, pattern, query, selected, r.checkAllowedOr(query, selected)) + if len(results) > 0 { + pkgMods = make([]module.Version, 0, len(results)) + for _, qr := range results { + pkgMods = append(pkgMods, qr.Mod) + } + } + return pkgMods, err +} + +// queryPattern wraps modload.QueryPattern, substituting r.checkAllowedOr to +// decide allowed versions. +func (r *resolver) queryPattern(ctx context.Context, pattern, query string, selected func(string) string) (pkgMods []module.Version, mod module.Version, err error) { + results, modOnly, err := modload.QueryPattern(ctx, pattern, query, selected, r.checkAllowedOr(query, selected)) + if len(results) > 0 { + pkgMods = make([]module.Version, 0, len(results)) + for _, qr := range results { + pkgMods = append(pkgMods, qr.Mod) + } + } + if modOnly != nil { + mod = modOnly.Mod + } + return pkgMods, mod, err +} + +// checkAllowedOr is like modload.CheckAllowed, but it always allows the requested +// and current versions (even if they are retracted or otherwise excluded). +func (r *resolver) checkAllowedOr(requested string, selected func(string) string) modload.AllowedFunc { + return func(ctx context.Context, m module.Version) error { + if m.Version == requested { + return modload.CheckExclusions(ctx, m) + } + if (requested == "upgrade" || requested == "patch") && m.Version == selected(m.Path) { + return nil + } + return modload.CheckAllowed(ctx, m) + } +} + +// matchInModule is a caching wrapper around modload.MatchInModule. +func (r *resolver) matchInModule(ctx context.Context, pattern string, m module.Version) (packages []string, err error) { + type key struct { + pattern string + m module.Version + } + type entry struct { + packages []string + err error + } + + e := r.matchInModuleCache.Do(key{pattern, m}, func() interface{} { + match := modload.MatchInModule(ctx, pattern, m, imports.AnyTags()) + if len(match.Errs) > 0 { + return entry{match.Pkgs, match.Errs[0]} + } + return entry{match.Pkgs, nil} + }).(entry) + + return e.packages, e.err +} + +// queryNone adds a candidate set to q for each module matching q.pattern. +// Each candidate set has only one possible module version: the matched +// module at version "none". +// +// We interpret arguments to 'go get' as packages first, and fall back to +// modules second. However, no module exists at version "none", and therefore no +// package exists at that version either: we know that the argument cannot match +// any packages, and thus it must match modules instead. +func (r *resolver) queryNone(ctx context.Context, q *query) { + if search.IsMetaPackage(q.pattern) { + panic(fmt.Sprintf("internal error: queryNone called with pattern %q", q.pattern)) + } + + if !q.isWildcard() { + q.pathOnce(q.pattern, func() pathSet { + if modload.HasModRoot() && q.pattern == modload.Target.Path { + // The user has explicitly requested to downgrade their own module to + // version "none". This is not an entirely unreasonable request: it + // could plausibly mean “downgrade away everything that depends on any + // explicit version of the main module”, or “downgrade away the + // package with the same path as the main module, found in a module + // with a prefix of the main module's path”. + // + // However, neither of those behaviors would be consistent with the + // plain meaning of the query. To try to reduce confusion, reject the + // query explicitly. + return errSet(&modload.QueryMatchesMainModuleError{Pattern: q.pattern, Query: q.version}) + } + + return pathSet{mod: module.Version{Path: q.pattern, Version: "none"}} + }) + } + + for _, curM := range r.buildList { + if !q.matchesPath(curM.Path) { + continue + } + q.pathOnce(curM.Path, func() pathSet { + if modload.HasModRoot() && curM == modload.Target { + return errSet(&modload.QueryMatchesMainModuleError{Pattern: q.pattern, Query: q.version}) + } + return pathSet{mod: module.Version{Path: curM.Path, Version: "none"}} + }) + } +} + +func (r *resolver) performLocalQueries(ctx context.Context) { + for _, q := range r.localQueries { + q.pathOnce(q.pattern, func() pathSet { + absDetail := "" + if !filepath.IsAbs(q.pattern) { + if absPath, err := filepath.Abs(q.pattern); err == nil { + absDetail = fmt.Sprintf(" (%s)", absPath) + } + } + + // Absolute paths like C:\foo and relative paths like ../foo... are + // restricted to matching packages in the main module. + pkgPattern := modload.DirImportPath(q.pattern) + if pkgPattern == "." { + return errSet(fmt.Errorf("%s%s is not within module rooted at %s", q.pattern, absDetail, modload.ModRoot())) + } + + match := modload.MatchInModule(ctx, pkgPattern, modload.Target, imports.AnyTags()) + if len(match.Errs) > 0 { + return pathSet{err: match.Errs[0]} + } + + if len(match.Pkgs) == 0 { + if q.raw == "" || q.raw == "." { + return errSet(fmt.Errorf("no package in current directory")) + } + if !q.isWildcard() { + return errSet(fmt.Errorf("%s%s is not a package in module rooted at %s", q.pattern, absDetail, modload.ModRoot())) + } + search.WarnUnmatched([]*search.Match{match}) + return pathSet{} + } + + return pathSet{pkgMods: []module.Version{modload.Target}} + }) + } +} + +// performWildcardQueries populates the candidates for each query whose pattern +// is a wildcard. +// +// The candidates for a given module path matching (or containing a package +// matching) a wildcard query depend only on the initial build list, but the set +// of modules may be expanded by other queries, so wildcard queries need to be +// re-evaluated whenever a potentially-matching module path is added to the +// build list. +func (r *resolver) performWildcardQueries(ctx context.Context) { + for _, q := range r.wildcardQueries { + q := q + r.work.Add(func() { + if q.version == "none" { + r.queryNone(ctx, q) + } else { + r.queryWildcard(ctx, q) + } + }) + } + <-r.work.Idle() +} + +// queryWildcard adds a candidate set to q for each module for which: +// - some version of the module is already in the build list, and +// - that module exists at some version matching q.version, and +// - either the module path itself matches q.pattern, or some package within +// the module at q.version matches q.pattern. +func (r *resolver) queryWildcard(ctx context.Context, q *query) { + // For wildcard patterns, modload.QueryPattern only identifies modules + // matching the prefix of the path before the wildcard. However, the build + // list may already contain other modules with matching packages, and we + // should consider those modules to satisfy the query too. + // We want to match any packages in existing dependencies, but we only want to + // resolve new dependencies if nothing else turns up. + for _, curM := range r.buildList { + if !q.canMatchInModule(curM.Path) { + continue + } + q.pathOnce(curM.Path, func() pathSet { + if _, hit := r.noneForPath(curM.Path); hit { + // This module is being removed, so it will no longer be in the build list + // (and thus will no longer match the pattern). + return pathSet{} + } + + if curM.Path == modload.Target.Path && !versionOkForMainModule(q.version) { + if q.matchesPath(curM.Path) { + return errSet(&modload.QueryMatchesMainModuleError{ + Pattern: q.pattern, + Query: q.version, + }) + } + + packages, err := r.matchInModule(ctx, q.pattern, curM) + if err != nil { + return errSet(err) + } + if len(packages) > 0 { + return errSet(&modload.QueryMatchesPackagesInMainModuleError{ + Pattern: q.pattern, + Query: q.version, + Packages: packages, + }) + } + + return r.tryWildcard(ctx, q, curM) + } + + m, err := r.queryModule(ctx, curM.Path, q.version, r.initialSelected) + if err != nil { + if !isNoSuchModuleVersion(err) { + // We can't tell whether a matching version exists. + return errSet(err) + } + // There is no version of curM.Path matching the query. + + // We haven't checked whether curM contains any matching packages at its + // currently-selected version, or whether curM.Path itself matches q. If + // either of those conditions holds, *and* no other query changes the + // selected version of curM, then we will fail in checkWildcardVersions. + // (This could be an error, but it's too soon to tell.) + // + // However, even then the transitive requirements of some other query + // may downgrade this module out of the build list entirely, in which + // case the pattern will no longer include it and it won't be an error. + // + // Either way, punt on the query rather than erroring out just yet. + return pathSet{} + } + + return r.tryWildcard(ctx, q, m) + }) + } + + // Even if no modules matched, we shouldn't query for a new module to provide + // the pattern yet: some other query may yet induce a new requirement that + // will match the wildcard. Instead, we'll check in findMissingWildcards. +} + +// tryWildcard returns a pathSet for module m matching query q. +// If m does not actually match q, tryWildcard returns an empty pathSet. +func (r *resolver) tryWildcard(ctx context.Context, q *query, m module.Version) pathSet { + mMatches := q.matchesPath(m.Path) + packages, err := r.matchInModule(ctx, q.pattern, m) + if err != nil { + return errSet(err) + } + if len(packages) > 0 { + return pathSet{pkgMods: []module.Version{m}} + } + if mMatches { + return pathSet{mod: m} + } + return pathSet{} +} + +// findMissingWildcards adds a candidate set for each query in r.wildcardQueries +// that has not yet resolved to any version containing packages. +func (r *resolver) findMissingWildcards(ctx context.Context) { + for _, q := range r.wildcardQueries { + if q.version == "none" || q.matchesPackages { + continue // q is not “missing” + } + r.work.Add(func() { + q.pathOnce(q.pattern, func() pathSet { + pkgMods, mod, err := r.queryPattern(ctx, q.pattern, q.version, r.initialSelected) + if err != nil { + if isNoSuchPackageVersion(err) && len(q.resolved) > 0 { + // q already resolved one or more modules but matches no packages. + // That's ok: this pattern is just a module pattern, and we don't + // need to add any more modules to satisfy it. + return pathSet{} + } + return errSet(err) + } + + return pathSet{pkgMods: pkgMods, mod: mod} + }) + }) + } + <-r.work.Idle() +} + +// checkWildcardVersions reports an error if any module in the build list has a +// path (or contains a package) matching a query with a wildcard pattern, but +// has a selected version that does *not* match the query. +func (r *resolver) checkWildcardVersions(ctx context.Context) { + defer base.ExitIfErrors() + + for _, q := range r.wildcardQueries { + for _, curM := range r.buildList { + if !q.canMatchInModule(curM.Path) { + continue + } + if !q.matchesPath(curM.Path) { + packages, err := r.matchInModule(ctx, q.pattern, curM) + if len(packages) == 0 { + if err != nil { + reportError(q, err) + } + continue // curM is not relevant to q. + } + } + + rev, err := r.queryModule(ctx, curM.Path, q.version, r.initialSelected) + if err != nil { + reportError(q, err) + continue + } + if rev.Version == curM.Version { + continue // curM already matches q. + } + + if !q.matchesPath(curM.Path) { + m := module.Version{Path: curM.Path, Version: rev.Version} + packages, err := r.matchInModule(ctx, q.pattern, m) + if err != nil { + reportError(q, err) + continue + } + if len(packages) == 0 { + // curM at its original version contains a path matching q.pattern, + // but at rev.Version it does not, so (somewhat paradoxically) if + // we changed the version of curM it would no longer match the query. + var version interface{} = m + if rev.Version != q.version { + version = fmt.Sprintf("%s@%s (%s)", m.Path, q.version, m.Version) + } + reportError(q, fmt.Errorf("%v matches packages in %v but not %v: specify a different version for module %s", q, curM, version, m.Path)) + continue + } + } + + // Since queryModule succeeded and either curM or one of the packages it + // contains matches q.pattern, we should have either selected the version + // of curM matching q, or reported a conflict error (and exited). + // If we're still here and the version doesn't match, + // something has gone very wrong. + reportError(q, fmt.Errorf("internal error: selected %v instead of %v", curM, rev.Version)) + } + } +} + +// performPathQueries populates the candidates for each query whose pattern is +// a path literal. +// +// The candidate packages and modules for path literals depend only on the +// initial build list, not the current build list, so we only need to query path +// literals once. +func (r *resolver) performPathQueries(ctx context.Context) { + for _, q := range r.pathQueries { + q := q + r.work.Add(func() { + if q.version == "none" { + r.queryNone(ctx, q) + } else { + r.queryPath(ctx, q) + } + }) + } + <-r.work.Idle() +} + +// queryPath adds a candidate set to q for the package with path q.pattern. +// The candidate set consists of all modules that could provide q.pattern +// and have a version matching q, plus (if it exists) the module whose path +// is itself q.pattern (at a matching version). +func (r *resolver) queryPath(ctx context.Context, q *query) { + q.pathOnce(q.pattern, func() pathSet { + if search.IsMetaPackage(q.pattern) || q.isWildcard() { + panic(fmt.Sprintf("internal error: queryPath called with pattern %q", q.pattern)) + } + if q.version == "none" { + panic(`internal error: queryPath called with version "none"`) + } + + if search.IsStandardImportPath(q.pattern) { + stdOnly := module.Version{} + packages, _ := r.matchInModule(ctx, q.pattern, stdOnly) + if len(packages) > 0 { + if q.rawVersion != "" { + return errSet(fmt.Errorf("can't request explicit version %q of standard library package %s", q.version, q.pattern)) + } + + q.matchesPackages = true + return pathSet{} // No module needed for standard library. + } + } + + pkgMods, mod, err := r.queryPattern(ctx, q.pattern, q.version, r.initialSelected) + if err != nil { + return errSet(err) + } + return pathSet{pkgMods: pkgMods, mod: mod} + }) +} + +// performPatternAllQueries populates the candidates for each query whose +// pattern is "all". +// +// The candidate modules for a given package in "all" depend only on the initial +// build list, but we cannot follow the dependencies of a given package until we +// know which candidate is selected — and that selection may depend on the +// results of other queries. We need to re-evaluate the "all" queries whenever +// the module for one or more packages in "all" are resolved. +func (r *resolver) performPatternAllQueries(ctx context.Context) { + if len(r.patternAllQueries) == 0 { + return + } + + findPackage := func(ctx context.Context, path string, m module.Version) (versionOk bool) { + versionOk = true + for _, q := range r.patternAllQueries { + q.pathOnce(path, func() pathSet { + pkgMods, err := r.queryPackages(ctx, path, q.version, r.initialSelected) + if len(pkgMods) != 1 || pkgMods[0] != m { + // There are candidates other than m for the given path, so we can't + // be certain that m will actually be the module selected to provide + // the package. Don't load its dependencies just yet, because they + // might no longer be dependencies after we resolve the correct + // version. + versionOk = false + } + return pathSet{pkgMods: pkgMods, err: err} + }) + } + return versionOk + } + + r.loadPackages(ctx, []string{"all"}, findPackage) + + // Since we built up the candidate lists concurrently, they may be in a + // nondeterministic order. We want 'go get' to be fully deterministic, + // including in which errors it chooses to report, so sort the candidates + // into a deterministic-but-arbitrary order. + for _, q := range r.patternAllQueries { + sort.Slice(q.candidates, func(i, j int) bool { + return q.candidates[i].path < q.candidates[j].path + }) + } +} + +// findAndUpgradeImports returns a pathSet for each package that is not yet +// in the build list but is transitively imported by the packages matching the +// given queries (which must already have been resolved). +// +// If the getU flag ("-u") is set, findAndUpgradeImports also returns a +// pathSet for each module that is not constrained by any other +// command-line argument and has an available matching upgrade. +func (r *resolver) findAndUpgradeImports(ctx context.Context, queries []*query) (upgrades []pathSet) { + patterns := make([]string, 0, len(queries)) + for _, q := range queries { + if q.matchesPackages { + patterns = append(patterns, q.pattern) + } + } + if len(patterns) == 0 { + return nil + } + + // mu guards concurrent writes to upgrades, which will be sorted + // (to restore determinism) after loading. + var mu sync.Mutex + + findPackage := func(ctx context.Context, path string, m module.Version) (versionOk bool) { + version := "latest" + if m.Path != "" { + if getU.version == "" { + // The user did not request that we upgrade transitive dependencies. + return true + } + if _, ok := r.resolvedVersion[m.Path]; ok { + // We cannot upgrade m implicitly because its version is determined by + // an explicit pattern argument. + return true + } + version = getU.version + } + + // Unlike other queries, the "-u" flag upgrades relative to the build list + // after applying changes so far, not the initial build list. + // This is for two reasons: + // + // - The "-u" flag intentionally applies to transitive dependencies, + // which may not be known or even resolved in advance of applying + // other version changes. + // + // - The "-u" flag, unlike other arguments, does not cause version + // conflicts with other queries. (The other query always wins.) + + pkgMods, err := r.queryPackages(ctx, path, version, r.selected) + for _, u := range pkgMods { + if u == m { + // The selected package version is already upgraded appropriately; there + // is no need to change it. + return true + } + } + + if err != nil { + if isNoSuchPackageVersion(err) || (m.Path == "" && module.CheckPath(path) != nil) { + // We can't find the package because it doesn't — or can't — even exist + // in any module at the latest version. (Note that invalid module paths + // could in general exist due to replacements, so we at least need to + // run the query to check those.) + // + // There is no version change we can make to fix the package, so leave + // it unresolved. Either some other query (perhaps a wildcard matching a + // newly-added dependency for some other missing package) will fill in + // the gaps, or we will report an error (with a better import stack) in + // the final LoadPackages call. + return true + } + } + + mu.Lock() + upgrades = append(upgrades, pathSet{path: path, pkgMods: pkgMods, err: err}) + mu.Unlock() + return false + } + + r.loadPackages(ctx, patterns, findPackage) + + // Since we built up the candidate lists concurrently, they may be in a + // nondeterministic order. We want 'go get' to be fully deterministic, + // including in which errors it chooses to report, so sort the candidates + // into a deterministic-but-arbitrary order. + sort.Slice(upgrades, func(i, j int) bool { + return upgrades[i].path < upgrades[j].path + }) + return upgrades +} + +// loadPackages loads the packages matching the given patterns, invoking the +// findPackage function for each package that may require a change to the +// build list. +// +// loadPackages invokes the findPackage function for each package loaded from a +// module outside the main module. If the module or version that supplies that +// package needs to be changed due to a query, findPackage may return false +// and the imports of that package will not be loaded. +// +// loadPackages also invokes the findPackage function for each imported package +// that is neither present in the standard library nor in any module in the +// build list. +func (r *resolver) loadPackages(ctx context.Context, patterns []string, findPackage func(ctx context.Context, path string, m module.Version) (versionOk bool)) { + opts := modload.PackageOpts{ + Tags: imports.AnyTags(), + LoadTests: *getT, + SilenceErrors: true, // May be fixed by subsequent upgrades or downgrades. + } + + opts.AllowPackage = func(ctx context.Context, path string, m module.Version) error { + if m.Path == "" || m == modload.Target { + // Packages in the standard library and main module are already at their + // latest (and only) available versions. + return nil + } + if ok := findPackage(ctx, path, m); !ok { + return errVersionChange + } + return nil + } + + _, pkgs := modload.LoadPackages(ctx, opts, patterns...) + for _, path := range pkgs { + const ( + parentPath = "" + parentIsStd = false + ) + _, _, err := modload.Lookup(parentPath, parentIsStd, path) + if err == nil { + continue + } + if errors.Is(err, errVersionChange) { + // We already added candidates during loading. + continue + } + + var ( + importMissing *modload.ImportMissingError + ambiguous *modload.AmbiguousImportError + ) + if !errors.As(err, &importMissing) && !errors.As(err, &ambiguous) { + // The package, which is a dependency of something we care about, has some + // problem that we can't resolve with a version change. + // Leave the error for the final LoadPackages call. + continue + } + + path := path + r.work.Add(func() { + findPackage(ctx, path, module.Version{}) + }) + } + <-r.work.Idle() +} + +// errVersionChange is a sentinel error indicating that a module's version needs +// to be updated before its dependencies can be loaded. +var errVersionChange = errors.New("version change needed") + +// resolveCandidates resolves candidates sets that are attached to the given +// queries and/or needed to provide the given missing-package dependencies. +// +// resolveCandidates starts by resolving one module version from each +// unambiguous pathSet attached to the given queries. +// +// If no unambiguous query results in a change to the build list, +// resolveCandidates modifies the build list by adding one module version from +// each pathSet in missing, but does not mark those versions as resolved +// (so they can still be modified by other queries). +// +// If that still does not result in any changes to the build list, +// resolveCandidates revisits the ambiguous query candidates and resolves them +// arbitrarily in order to guarantee forward progress. +// +// If all pathSets are resolved without any changes to the build list, +// resolveCandidates returns with changed=false. +func (r *resolver) resolveCandidates(ctx context.Context, queries []*query, upgrades []pathSet) (changed bool) { + defer base.ExitIfErrors() + + // Note: this is O(N²) with the number of pathSets in the worst case. + // + // We could perhaps get it down to O(N) if we were to index the pathSets + // by module path, so that we only revisit a given pathSet when the + // version of some module in its containingPackage list has been determined. + // + // However, N tends to be small, and most candidate sets will include only one + // candidate module (so they will be resolved in the first iteration), so for + // now we'll stick to the simple O(N²) approach. + + resolved := 0 + for { + prevResolved := resolved + + for _, q := range queries { + unresolved := q.candidates[:0] + + for _, cs := range q.candidates { + if cs.err != nil { + reportError(q, cs.err) + resolved++ + continue + } + + filtered, isPackage, m, unique := r.disambiguate(cs) + if !unique { + unresolved = append(unresolved, filtered) + continue + } + + if m.Path == "" { + // The query is not viable. Choose an arbitrary candidate from + // before filtering and “resolve” it to report a conflict. + isPackage, m = r.chooseArbitrarily(cs) + } + if isPackage { + q.matchesPackages = true + } + r.resolve(q, m) + resolved++ + } + + q.candidates = unresolved + } + + base.ExitIfErrors() + if resolved == prevResolved { + break // No unambiguous candidate remains. + } + } + + if changed := r.updateBuildList(ctx, nil); changed { + // The build list has changed, so disregard any missing packages: they might + // now be determined by requirements in the build list, which we would + // prefer to use instead of arbitrary "latest" versions. + return true + } + + // Arbitrarily add a "latest" version that provides each missing package, but + // do not mark the version as resolved: we still want to allow the explicit + // queries to modify the resulting versions. + var tentative []module.Version + for _, cs := range upgrades { + if cs.err != nil { + base.Errorf("go get: %v", cs.err) + continue + } + + filtered, _, m, unique := r.disambiguate(cs) + if !unique { + _, m = r.chooseArbitrarily(filtered) + } + if m.Path == "" { + // There is no viable candidate for the missing package. + // Leave it unresolved. + continue + } + tentative = append(tentative, m) + } + base.ExitIfErrors() + if changed := r.updateBuildList(ctx, tentative); changed { + return true + } + + // The build list will be the same on the next iteration as it was on this + // iteration, so any ambiguous queries will remain so. In order to make + // progress, resolve them arbitrarily but deterministically. + // + // If that results in conflicting versions, the user can re-run 'go get' + // with additional explicit versions for the conflicting packages or + // modules. + for _, q := range queries { + for _, cs := range q.candidates { + isPackage, m := r.chooseArbitrarily(cs) + if isPackage { + q.matchesPackages = true + } + r.resolve(q, m) + } + } + return r.updateBuildList(ctx, nil) +} + +// disambiguate eliminates candidates from cs that conflict with other module +// versions that have already been resolved. If there is only one (unique) +// remaining candidate, disambiguate returns that candidate, along with +// an indication of whether that result interprets cs.path as a package +// +// Note: we're only doing very simple disambiguation here. The goal is to +// reproduce the user's intent, not to find a solution that a human couldn't. +// In the vast majority of cases, we expect only one module per pathSet, +// but we want to give some minimal additional tools so that users can add an +// extra argument or two on the command line to resolve simple ambiguities. +func (r *resolver) disambiguate(cs pathSet) (filtered pathSet, isPackage bool, m module.Version, unique bool) { + if len(cs.pkgMods) == 0 && cs.mod.Path == "" { + panic("internal error: resolveIfUnambiguous called with empty pathSet") + } + + for _, m := range cs.pkgMods { + if _, ok := r.noneForPath(m.Path); ok { + // A query with version "none" forces the candidate module to version + // "none", so we cannot use any other version for that module. + continue + } + + if m.Path == modload.Target.Path { + if m.Version == modload.Target.Version { + return pathSet{}, true, m, true + } + // The main module can only be set to its own version. + continue + } + + vr, ok := r.resolvedVersion[m.Path] + if !ok { + // m is a viable answer to the query, but other answers may also + // still be viable. + filtered.pkgMods = append(filtered.pkgMods, m) + continue + } + + if vr.version != m.Version { + // Some query forces the candidate module to a version other than this + // one. + // + // The command could be something like + // + // go get example.com/foo/bar@none example.com/foo/bar/baz@latest + // + // in which case we *cannot* resolve the package from + // example.com/foo/bar (because it is constrained to version + // "none") and must fall through to module example.com/foo@latest. + continue + } + + // Some query forces the candidate module *to* the candidate version. + // As a result, this candidate is the only viable choice to provide + // its package(s): any other choice would result in an ambiguous import + // for this path. + // + // For example, consider the command + // + // go get example.com/foo@latest example.com/foo/bar/baz@latest + // + // If modules example.com/foo and example.com/foo/bar both provide + // package example.com/foo/bar/baz, then we *must* resolve the package + // from example.com/foo: if we instead resolved it from + // example.com/foo/bar, we would have two copies of the package. + return pathSet{}, true, m, true + } + + if cs.mod.Path != "" { + vr, ok := r.resolvedVersion[cs.mod.Path] + if !ok || vr.version == cs.mod.Version { + filtered.mod = cs.mod + } + } + + if len(filtered.pkgMods) == 1 && + (filtered.mod.Path == "" || filtered.mod == filtered.pkgMods[0]) { + // Exactly one viable module contains the package with the given path + // (by far the common case), so we can resolve it unambiguously. + return pathSet{}, true, filtered.pkgMods[0], true + } + + if len(filtered.pkgMods) == 0 { + // All modules that could provide the path as a package conflict with other + // resolved arguments. If it can refer to a module instead, return that; + // otherwise, this pathSet cannot be resolved (and we will return the + // zero module.Version). + return pathSet{}, false, filtered.mod, true + } + + // The query remains ambiguous: there are at least two different modules + // to which cs.path could refer. + return filtered, false, module.Version{}, false +} + +// chooseArbitrarily returns an arbitrary (but deterministic) module version +// from among those in the given set. +// +// chooseArbitrarily prefers module paths that were already in the build list at +// the start of 'go get', prefers modules that provide packages over those that +// do not, and chooses the first module meeting those criteria (so biases toward +// longer paths). +func (r *resolver) chooseArbitrarily(cs pathSet) (isPackage bool, m module.Version) { + // Prefer to upgrade some module that was already in the build list. + for _, m := range cs.pkgMods { + if r.initialSelected(m.Path) != "none" { + return true, m + } + } + + // Otherwise, arbitrarily choose the first module that provides the package. + if len(cs.pkgMods) > 0 { + return true, cs.pkgMods[0] + } + + return false, cs.mod +} + +// checkPackagesAndRetractions reloads packages for the given patterns and +// reports missing and ambiguous package errors. It also reports loads and +// reports retractions for resolved modules and modules needed to build +// named packages. +// +// We skip missing-package errors earlier in the process, since we want to +// resolve pathSets ourselves, but at that point, we don't have enough context +// to log the package-import chains leading to each error. +func (r *resolver) checkPackagesAndRetractions(ctx context.Context, pkgPatterns []string) { + defer base.ExitIfErrors() + + // Build a list of modules to load retractions for. Start with versions + // selected based on command line queries. + // + // This is a subset of the build list. If the main module has a lot of + // dependencies, loading retractions for the entire build list would be slow. + relevantMods := make(map[module.Version]struct{}) + for path, reason := range r.resolvedVersion { + relevantMods[module.Version{Path: path, Version: reason.version}] = struct{}{} + } + + // Reload packages, reporting errors for missing and ambiguous imports. + if len(pkgPatterns) > 0 { + // LoadPackages will print errors (since it has more context) but will not + // exit, since we need to load retractions later. + pkgOpts := modload.PackageOpts{ + LoadTests: *getT, + ResolveMissingImports: false, + AllowErrors: true, + } + matches, pkgs := modload.LoadPackages(ctx, pkgOpts, pkgPatterns...) + for _, m := range matches { + if len(m.Errs) > 0 { + base.SetExitStatus(1) + break + } + } + for _, pkg := range pkgs { + if dir, _, err := modload.Lookup("", false, pkg); err != nil { + if dir != "" && errors.Is(err, imports.ErrNoGo) { + // Since dir is non-empty, we must have located source files + // associated with either the package or its test — ErrNoGo must + // indicate that none of those source files happen to apply in this + // configuration. If we are actually building the package (no -d + // flag), the compiler will report the problem; otherwise, assume that + // the user is going to build or test it in some other configuration + // and suppress the error. + continue + } + + base.SetExitStatus(1) + if ambiguousErr := (*modload.AmbiguousImportError)(nil); errors.As(err, &ambiguousErr) { + for _, m := range ambiguousErr.Modules { + relevantMods[m] = struct{}{} + } + } + } + if m := modload.PackageModule(pkg); m.Path != "" { + relevantMods[m] = struct{}{} + } + } + } + + // Load and report retractions. + type retraction struct { + m module.Version + err error + } + retractions := make([]retraction, 0, len(relevantMods)) + for m := range relevantMods { + retractions = append(retractions, retraction{m: m}) + } + sort.Slice(retractions, func(i, j int) bool { + return retractions[i].m.Path < retractions[j].m.Path + }) + for i := 0; i < len(retractions); i++ { + i := i + r.work.Add(func() { + err := modload.CheckRetractions(ctx, retractions[i].m) + if retractErr := (*modload.ModuleRetractedError)(nil); errors.As(err, &retractErr) { + retractions[i].err = err + } + }) + } + <-r.work.Idle() + var retractPath string + for _, r := range retractions { + if r.err != nil { + fmt.Fprintf(os.Stderr, "go: warning: %v\n", r.err) + if retractPath == "" { + retractPath = r.m.Path + } else { + retractPath = "" + } + } + } + if retractPath != "" { + fmt.Fprintf(os.Stderr, "go: to switch to the latest unretracted version, run:\n\tgo get %s@latest\n", retractPath) + } +} + +// reportChanges logs version changes to os.Stderr. +// +// reportChanges only logs changes to modules named on the command line and to +// explicitly required modules in go.mod. Most changes to indirect requirements +// are not relevant to the user and are not logged. +// +// reportChanges should be called after WriteGoMod. +func (r *resolver) reportChanges(oldReqs, newReqs []module.Version) { + type change struct { + path, old, new string + } + changes := make(map[string]change) + + // Collect changes in modules matched by command line arguments. + for path, reason := range r.resolvedVersion { + old := r.initialVersion[path] + new := reason.version + if old != new && (old != "" || new != "none") { + changes[path] = change{path, old, new} + } + } + + // Collect changes to explicit requirements in go.mod. + for _, req := range oldReqs { + path := req.Path + old := req.Version + new := r.buildListVersion[path] + if old != new { + changes[path] = change{path, old, new} + } + } + for _, req := range newReqs { + path := req.Path + old := r.initialVersion[path] + new := req.Version + if old != new { + changes[path] = change{path, old, new} + } + } + + sortedChanges := make([]change, 0, len(changes)) + for _, c := range changes { + sortedChanges = append(sortedChanges, c) + } + sort.Slice(sortedChanges, func(i, j int) bool { + return sortedChanges[i].path < sortedChanges[j].path + }) + for _, c := range sortedChanges { + if c.old == "" { + fmt.Fprintf(os.Stderr, "go get: added %s %s\n", c.path, c.new) + } else if c.new == "none" || c.new == "" { + fmt.Fprintf(os.Stderr, "go get: removed %s %s\n", c.path, c.old) + } else if semver.Compare(c.new, c.old) > 0 { + fmt.Fprintf(os.Stderr, "go get: upgraded %s %s => %s\n", c.path, c.old, c.new) + } else { + fmt.Fprintf(os.Stderr, "go get: downgraded %s %s => %s\n", c.path, c.old, c.new) + } + } + + // TODO(golang.org/issue/33284): attribute changes to command line arguments. + // For modules matched by command line arguments, this probably isn't + // necessary, but it would be useful for unmatched direct dependencies of + // the main module. +} + +// resolve records that module m must be at its indicated version (which may be +// "none") due to query q. If some other query forces module m to be at a +// different version, resolve reports a conflict error. +func (r *resolver) resolve(q *query, m module.Version) { + if m.Path == "" { + panic("internal error: resolving a module.Version with an empty path") + } + + if m.Path == modload.Target.Path && m.Version != modload.Target.Version { + reportError(q, &modload.QueryMatchesMainModuleError{ + Pattern: q.pattern, + Query: q.version, + }) + return + } + + vr, ok := r.resolvedVersion[m.Path] + if ok && vr.version != m.Version { + reportConflict(q, m, vr) + return + } + r.resolvedVersion[m.Path] = versionReason{m.Version, q} + q.resolved = append(q.resolved, m) +} + +// updateBuildList updates the module loader's global build list to be +// consistent with r.resolvedVersion, and to include additional modules +// provided that they do not conflict with the resolved versions. +// +// If the additional modules conflict with the resolved versions, they will be +// downgraded to a non-conflicting version (possibly "none"). +func (r *resolver) updateBuildList(ctx context.Context, additions []module.Version) (changed bool) { + if len(additions) == 0 && len(r.resolvedVersion) == r.buildListResolvedVersions { + return false + } + + defer base.ExitIfErrors() + + resolved := make([]module.Version, 0, len(r.resolvedVersion)) + for mPath, rv := range r.resolvedVersion { + if mPath != modload.Target.Path { + resolved = append(resolved, module.Version{Path: mPath, Version: rv.version}) + } + } + + if err := modload.EditBuildList(ctx, additions, resolved); err != nil { + var constraint *modload.ConstraintError + if !errors.As(err, &constraint) { + base.Errorf("go get: %v", err) + return false + } + + reason := func(m module.Version) string { + rv, ok := r.resolvedVersion[m.Path] + if !ok { + panic(fmt.Sprintf("internal error: can't find reason for requirement on %v", m)) + } + return rv.reason.ResolvedString(module.Version{Path: m.Path, Version: rv.version}) + } + for _, c := range constraint.Conflicts { + base.Errorf("go get: %v requires %v, not %v", reason(c.Source), c.Dep, reason(c.Constraint)) + } + return false + } + + buildList := modload.LoadAllModules(ctx) + r.buildListResolvedVersions = len(r.resolvedVersion) + if reflect.DeepEqual(r.buildList, buildList) { + return false + } + r.buildList = buildList + r.buildListVersion = make(map[string]string, len(r.buildList)) + for _, m := range r.buildList { + r.buildListVersion[m.Path] = m.Version + } + return true +} + +func reqsFromGoMod(f *modfile.File) []module.Version { + reqs := make([]module.Version, len(f.Require)) + for i, r := range f.Require { + reqs[i] = r.Mod + } + return reqs +} + +// isNoSuchModuleVersion reports whether err indicates that the requested module +// does not exist at the requested version, either because the module does not +// exist at all or because it does not include that specific version. +func isNoSuchModuleVersion(err error) bool { + var noMatch *modload.NoMatchingVersionError + return errors.Is(err, os.ErrNotExist) || errors.As(err, &noMatch) +} + +// isNoSuchPackageVersion reports whether err indicates that the requested +// package does not exist at the requested version, either because no module +// that could contain it exists at that version, or because every such module +// that does exist does not actually contain the package. +func isNoSuchPackageVersion(err error) bool { + var noPackage *modload.PackageNotInModuleError + return isNoSuchModuleVersion(err) || errors.As(err, &noPackage) +} diff --git a/src/cmd/go/internal/modget/query.go b/src/cmd/go/internal/modget/query.go new file mode 100644 index 0000000..1a5a60f --- /dev/null +++ b/src/cmd/go/internal/modget/query.go @@ -0,0 +1,357 @@ +// Copyright 2020 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 + +import ( + "fmt" + "path/filepath" + "regexp" + "strings" + "sync" + + "cmd/go/internal/base" + "cmd/go/internal/modload" + "cmd/go/internal/search" + "cmd/go/internal/str" + + "golang.org/x/mod/module" +) + +// A query describes a command-line argument and the modules and/or packages +// to which that argument may resolve.. +type query struct { + // raw is the original argument, to be printed in error messages. + raw string + + // rawVersion is the portion of raw corresponding to version, if any + rawVersion string + + // pattern is the part of the argument before "@" (or the whole argument + // if there is no "@"), which may match either packages (preferred) or + // modules (if no matching packages). + // + // The pattern may also be "-u", for the synthetic query representing the -u + // (“upgrade”)flag. + pattern string + + // patternIsLocal indicates whether pattern is restricted to match only paths + // local to the main module, such as absolute filesystem paths or paths + // beginning with './'. + // + // A local pattern must resolve to one or more packages in the main module. + patternIsLocal bool + + // version is the part of the argument after "@", or an implied + // "upgrade" or "patch" if there is no "@". version specifies the + // module version to get. + version string + + // matchWildcard, if non-nil, reports whether pattern, which must be a + // wildcard (with the substring "..."), matches the given package or module + // path. + matchWildcard func(path string) bool + + // canMatchWildcard, if non-nil, reports whether the module with the given + // path could lexically contain a package matching pattern, which must be a + // wildcard. + canMatchWildcardInModule func(mPath string) bool + + // conflict is the first query identified as incompatible with this one. + // conflict forces one or more of the modules matching this query to a + // version that does not match version. + conflict *query + + // candidates is a list of sets of alternatives for a path that matches (or + // contains packages that match) the pattern. The query can be resolved by + // choosing exactly one alternative from each set in the list. + // + // A path-literal query results in only one set: the path itself, which + // may resolve to either a package path or a module path. + // + // A wildcard query results in one set for each matching module path, each + // module for which the matching version contains at least one matching + // package, and (if no other modules match) one candidate set for the pattern + // overall if no existing match is identified in the build list. + // + // A query for pattern "all" results in one set for each package transitively + // imported by the main module. + // + // The special query for the "-u" flag results in one set for each + // otherwise-unconstrained package that has available upgrades. + candidates []pathSet + candidatesMu sync.Mutex + + // pathSeen ensures that only one pathSet is added to the query per + // unique path. + pathSeen sync.Map + + // resolved contains the set of modules whose versions have been determined by + // this query, in the order in which they were determined. + // + // The resolver examines the candidate sets for each query, resolving one + // module per candidate set in a way that attempts to avoid obvious conflicts + // between the versions resolved by different queries. + resolved []module.Version + + // matchesPackages is true if the resolved modules provide at least one + // package mathcing q.pattern. + matchesPackages bool +} + +// A pathSet describes the possible options for resolving a specific path +// to a package and/or module. +type pathSet struct { + // path is a package (if "all" or "-u" or a non-wildcard) or module (if + // wildcard) path that could be resolved by adding any of the modules in this + // set. For a wildcard pattern that so far matches no packages, the path is + // the wildcard pattern itself. + // + // Each path must occur only once in a query's candidate sets, and the path is + // added implicitly to each pathSet returned to pathOnce. + path string + + // pkgMods is a set of zero or more modules, each of which contains the + // package with the indicated path. Due to the requirement that imports be + // unambiguous, only one such module can be in the build list, and all others + // must be excluded. + pkgMods []module.Version + + // mod is either the zero Version, or a module that does not contain any + // packages matching the query but for which the module path itself + // matches the query pattern. + // + // We track this module separately from pkgMods because, all else equal, we + // prefer to match a query to a package rather than just a module. Also, + // unlike the modules in pkgMods, this module does not inherently exclude + // any other module in pkgMods. + mod module.Version + + err error +} + +// errSet returns a pathSet containing the given error. +func errSet(err error) pathSet { return pathSet{err: err} } + +// newQuery returns a new query parsed from the raw argument, +// which must be either path or path@version. +func newQuery(raw string) (*query, error) { + pattern := raw + rawVers := "" + if i := strings.Index(raw, "@"); i >= 0 { + pattern, rawVers = raw[:i], raw[i+1:] + if strings.Contains(rawVers, "@") || rawVers == "" { + return nil, fmt.Errorf("invalid module version syntax %q", raw) + } + } + + // If no version suffix is specified, assume @upgrade. + // If -u=patch was specified, assume @patch instead. + version := rawVers + if version == "" { + if getU.version == "" { + version = "upgrade" + } else { + version = getU.version + } + } + + q := &query{ + raw: raw, + rawVersion: rawVers, + pattern: pattern, + patternIsLocal: filepath.IsAbs(pattern) || search.IsRelativePath(pattern), + version: version, + } + if strings.Contains(q.pattern, "...") { + q.matchWildcard = search.MatchPattern(q.pattern) + q.canMatchWildcardInModule = search.TreeCanMatchPattern(q.pattern) + } + if err := q.validate(); err != nil { + return q, err + } + return q, nil +} + +// validate reports a non-nil error if q is not sensible and well-formed. +func (q *query) validate() error { + if q.patternIsLocal { + if q.rawVersion != "" { + return fmt.Errorf("can't request explicit version %q of path %q in main module", q.rawVersion, q.pattern) + } + return nil + } + + if q.pattern == "all" { + // If there is no main module, "all" is not meaningful. + if !modload.HasModRoot() { + return fmt.Errorf(`cannot match "all": %v`, modload.ErrNoModRoot) + } + if !versionOkForMainModule(q.version) { + // TODO(bcmills): "all@none" seems like a totally reasonable way to + // request that we remove all module requirements, leaving only the main + // module and standard library. Perhaps we should implement that someday. + return &modload.QueryMatchesMainModuleError{ + Pattern: q.pattern, + Query: q.version, + } + } + } + + if search.IsMetaPackage(q.pattern) && q.pattern != "all" { + if q.pattern != q.raw { + return fmt.Errorf("can't request explicit version of standard-library pattern %q", q.pattern) + } + } + + return nil +} + +// String returns the original argument from which q was parsed. +func (q *query) String() string { return q.raw } + +// ResolvedString returns a string describing m as a resolved match for q. +func (q *query) ResolvedString(m module.Version) string { + if m.Path != q.pattern { + if m.Version != q.version { + return fmt.Sprintf("%v (matching %s@%s)", m, q.pattern, q.version) + } + return fmt.Sprintf("%v (matching %v)", m, q) + } + if m.Version != q.version { + return fmt.Sprintf("%s@%s (%s)", q.pattern, q.version, m.Version) + } + return q.String() +} + +// isWildcard reports whether q is a pattern that can match multiple paths. +func (q *query) isWildcard() bool { + return q.matchWildcard != nil || (q.patternIsLocal && strings.Contains(q.pattern, "...")) +} + +// matchesPath reports whether the given path matches q.pattern. +func (q *query) matchesPath(path string) bool { + if q.matchWildcard != nil { + return q.matchWildcard(path) + } + return path == q.pattern +} + +// canMatchInModule reports whether the given module path can potentially +// contain q.pattern. +func (q *query) canMatchInModule(mPath string) bool { + if q.canMatchWildcardInModule != nil { + return q.canMatchWildcardInModule(mPath) + } + return str.HasPathPrefix(q.pattern, mPath) +} + +// pathOnce invokes f to generate the pathSet for the given path, +// if one is still needed. +// +// Note that, unlike sync.Once, pathOnce does not guarantee that a concurrent +// call to f for the given path has completed on return. +// +// pathOnce is safe for concurrent use by multiple goroutines, but note that +// multiple concurrent calls will result in the sets being added in +// nondeterministic order. +func (q *query) pathOnce(path string, f func() pathSet) { + if _, dup := q.pathSeen.LoadOrStore(path, nil); dup { + return + } + + cs := f() + + if len(cs.pkgMods) > 0 || cs.mod != (module.Version{}) || cs.err != nil { + cs.path = path + q.candidatesMu.Lock() + q.candidates = append(q.candidates, cs) + q.candidatesMu.Unlock() + } +} + +// reportError logs err concisely using base.Errorf. +func reportError(q *query, err error) { + errStr := err.Error() + + // If err already mentions all of the relevant parts of q, just log err to + // reduce stutter. Otherwise, log both q and err. + // + // TODO(bcmills): Use errors.As to unpack these errors instead of parsing + // strings with regular expressions. + + patternRE := regexp.MustCompile("(?m)(?:[ \t(\"`]|^)" + regexp.QuoteMeta(q.pattern) + "(?:[ @:;)\"`]|$)") + if patternRE.MatchString(errStr) { + if q.rawVersion == "" { + base.Errorf("go get: %s", errStr) + return + } + + versionRE := regexp.MustCompile("(?m)(?:[ @(\"`]|^)" + regexp.QuoteMeta(q.version) + "(?:[ :;)\"`]|$)") + if versionRE.MatchString(errStr) { + base.Errorf("go get: %s", errStr) + return + } + } + + if qs := q.String(); qs != "" { + base.Errorf("go get %s: %s", qs, errStr) + } else { + base.Errorf("go get: %s", errStr) + } +} + +func reportConflict(pq *query, m module.Version, conflict versionReason) { + if pq.conflict != nil { + // We've already reported a conflict for the proposed query. + // Don't report it again, even if it has other conflicts. + return + } + pq.conflict = conflict.reason + + proposed := versionReason{ + version: m.Version, + reason: pq, + } + if pq.isWildcard() && !conflict.reason.isWildcard() { + // Prefer to report the specific path first and the wildcard second. + proposed, conflict = conflict, proposed + } + reportError(pq, &conflictError{ + mPath: m.Path, + proposed: proposed, + conflict: conflict, + }) +} + +type conflictError struct { + mPath string + proposed versionReason + conflict versionReason +} + +func (e *conflictError) Error() string { + argStr := func(q *query, v string) string { + if v != q.version { + return fmt.Sprintf("%s@%s (%s)", q.pattern, q.version, v) + } + return q.String() + } + + pq := e.proposed.reason + rq := e.conflict.reason + modDetail := "" + if e.mPath != pq.pattern { + modDetail = fmt.Sprintf("for module %s, ", e.mPath) + } + + return fmt.Sprintf("%s%s conflicts with %s", + modDetail, + argStr(pq, e.proposed.version), + argStr(rq, e.conflict.version)) +} + +func versionOkForMainModule(version string) bool { + return version == "upgrade" || version == "patch" +} diff --git a/src/cmd/go/internal/modinfo/info.go b/src/cmd/go/internal/modinfo/info.go new file mode 100644 index 0000000..897be56 --- /dev/null +++ b/src/cmd/go/internal/modinfo/info.go @@ -0,0 +1,58 @@ +// 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 + GoVersion string `json:",omitempty"` // go version used in module + Retracted []string `json:",omitempty"` // retraction information, if any (with -retracted or -u) + Error *ModuleError `json:",omitempty"` // error loading module +} + +type ModuleError struct { + Err string // error text +} + +func (m *ModulePublic) String() string { + s := m.Path + versionString := func(mm *ModulePublic) string { + v := mm.Version + if len(mm.Retracted) == 0 { + return v + } + return v + " (retracted)" + } + + if m.Version != "" { + s += " " + versionString(m) + if m.Update != nil { + s += " [" + versionString(m.Update) + "]" + } + } + if m.Replace != nil { + s += " => " + m.Replace.Path + if m.Replace.Version != "" { + s += " " + versionString(m.Replace) + if m.Replace.Update != nil { + s += " [" + versionString(m.Replace.Update) + "]" + } + } + } + return s +} diff --git a/src/cmd/go/internal/modload/build.go b/src/cmd/go/internal/modload/build.go new file mode 100644 index 0000000..8ad5f83 --- /dev/null +++ b/src/cmd/go/internal/modload/build.go @@ -0,0 +1,361 @@ +// 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" + "context" + "encoding/hex" + "errors" + "fmt" + "internal/goroot" + "os" + "path/filepath" + "strings" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/modfetch" + "cmd/go/internal/modinfo" + "cmd/go/internal/search" + + "golang.org/x/mod/module" + "golang.org/x/mod/semver" +) + +var ( + infoStart, _ = hex.DecodeString("3077af0c9274080241e1c107e6d618e6") + infoEnd, _ = hex.DecodeString("f932433186182072008242104116d8f2") +) + +func isStandardImportPath(path string) bool { + return findStandardImportPath(path) != "" +} + +func findStandardImportPath(path string) string { + if path == "" { + panic("findStandardImportPath called with empty path") + } + if search.IsStandardImportPath(path) { + if goroot.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, path) { + return filepath.Join(cfg.GOROOT, "src", path) + } + } + return "" +} + +// PackageModuleInfo returns information about the module that provides +// a given package. If modules are not enabled or if the package is in the +// standard library or if the package was not successfully loaded with +// LoadPackages or ImportFromFiles, nil is returned. +func PackageModuleInfo(pkgpath string) *modinfo.ModulePublic { + if isStandardImportPath(pkgpath) || !Enabled() { + return nil + } + m, ok := findModule(pkgpath) + if !ok { + return nil + } + fromBuildList := true + listRetracted := false + return moduleInfo(context.TODO(), m, fromBuildList, listRetracted) +} + +func ModuleInfo(ctx context.Context, path string) *modinfo.ModulePublic { + if !Enabled() { + return nil + } + + listRetracted := false + if i := strings.Index(path, "@"); i >= 0 { + m := module.Version{Path: path[:i], Version: path[i+1:]} + fromBuildList := false + return moduleInfo(ctx, m, fromBuildList, listRetracted) + } + + for _, m := range buildList { + if m.Path == path { + fromBuildList := true + return moduleInfo(ctx, m, fromBuildList, listRetracted) + } + } + + 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(ctx context.Context, m *modinfo.ModulePublic) { + if m.Version == "" { + return + } + + if info, err := Query(ctx, m.Path, "upgrade", m.Version, CheckAllowed); err == nil && semver.Compare(info.Version, m.Version) > 0 { + m.Update = &modinfo.ModulePublic{ + Path: m.Path, + Version: info.Version, + Time: &info.Time, + } + } +} + +// addVersions fills in m.Versions with the list of known versions. +// Excluded versions will be omitted. If listRetracted is false, retracted +// versions will also be omitted. +func addVersions(ctx context.Context, m *modinfo.ModulePublic, listRetracted bool) { + allowed := CheckAllowed + if listRetracted { + allowed = CheckExclusions + } + m.Versions, _ = versions(ctx, m.Path, allowed) +} + +// addRetraction fills in m.Retracted if the module was retracted by its author. +// m.Error is set if there's an error loading retraction information. +func addRetraction(ctx context.Context, m *modinfo.ModulePublic) { + if m.Version == "" { + return + } + + err := CheckRetractions(ctx, module.Version{Path: m.Path, Version: m.Version}) + var rerr *ModuleRetractedError + if errors.As(err, &rerr) { + if len(rerr.Rationale) == 0 { + m.Retracted = []string{"retracted by module author"} + } else { + m.Retracted = rerr.Rationale + } + } else if err != nil && m.Error == nil { + m.Error = &modinfo.ModuleError{Err: err.Error()} + } +} + +func moduleInfo(ctx context.Context, m module.Version, fromBuildList, listRetracted bool) *modinfo.ModulePublic { + if m == Target { + info := &modinfo.ModulePublic{ + Path: m.Path, + Version: m.Version, + Main: true, + } + if HasModRoot() { + info.Dir = ModRoot() + info.GoMod = ModFilePath() + 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 v, ok := rawGoVersion.Load(m); ok { + info.GoVersion = v.(string) + } + + // completeFromModCache fills in the extra fields in m using the module cache. + completeFromModCache := func(m *modinfo.ModulePublic) { + mod := module.Version{Path: m.Path, Version: m.Version} + + if m.Version != "" { + if q, err := Query(ctx, m.Path, m.Version, "", nil); err != nil { + m.Error = &modinfo.ModuleError{Err: err.Error()} + } else { + m.Version = q.Version + m.Time = &q.Time + } + + 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 { + m.Dir = dir + } + + if listRetracted { + addRetraction(ctx, m) + } + } + + if m.GoVersion == "" { + if summary, err := rawGoModSummary(mod); err == nil && summary.goVersionV != "" { + m.GoVersion = summary.goVersionV[1:] + } + } + } + + if !fromBuildList { + // If this was an explicitly-versioned argument to 'go mod download' or + // 'go list -m', report the actual requested version, not its replacement. + completeFromModCache(info) // Will set m.Error in vendor mode. + return info + } + + r := Replacement(m) + if r.Path == "" { + if cfg.BuildMod == "vendor" { + // It's tempting to fill in the "Dir" field to point within the vendor + // directory, but that would be misleading: the vendor directory contains + // a flattened package tree, not complete modules, and it can even + // interleave packages from different modules if one module path is a + // prefix of the other. + } else { + completeFromModCache(info) + } + return info + } + + // Don't hit the network to fill in extra data for replaced modules. + // The original resolved Version and Time don't matter enough to be + // worth the cost, and we're going to overwrite the GoMod and Dir from the + // replacement anyway. See https://golang.org/issue/27859. + info.Replace = &modinfo.ModulePublic{ + Path: r.Path, + Version: r.Version, + } + if v, ok := rawGoVersion.Load(m); ok { + info.Replace.GoVersion = v.(string) + } + if r.Version == "" { + if filepath.IsAbs(r.Path) { + info.Replace.Dir = r.Path + } else { + info.Replace.Dir = filepath.Join(ModRoot(), r.Path) + } + info.Replace.GoMod = filepath.Join(info.Replace.Dir, "go.mod") + } + if cfg.BuildMod != "vendor" { + completeFromModCache(info.Replace) + info.Dir = info.Replace.Dir + info.GoMod = info.Replace.GoMod + info.Retracted = info.Replace.Retracted + } + info.GoVersion = info.Replace.GoVersion + return info +} + +// PackageBuildInfo returns a string containing module version information +// for modules providing packages named by path and deps. path and deps must +// name packages that were resolved successfully with LoadPackages. +func PackageBuildInfo(path string, deps []string) string { + if isStandardImportPath(path) || !Enabled() { + return "" + } + + target := mustFindModule(path, path) + mdeps := make(map[module.Version]bool) + for _, dep := range deps { + if !isStandardImportPath(dep) { + mdeps[mustFindModule(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) + + writeEntry := func(token string, m module.Version) { + mv := m.Version + if mv == "" { + mv = "(devel)" + } + fmt.Fprintf(&buf, "%s\t%s\t%s", token, m.Path, mv) + if r := Replacement(m); r.Path == "" { + fmt.Fprintf(&buf, "\t%s\n", modfetch.Sum(m)) + } else { + fmt.Fprintf(&buf, "\n=>\t%s\t%s\t%s\n", r.Path, r.Version, modfetch.Sum(r)) + } + } + + writeEntry("mod", target) + for _, mod := range mods { + writeEntry("dep", mod) + } + + return buf.String() +} + +// mustFindModule is like findModule, but it calls base.Fatalf if the +// module can't be found. +// +// TODO(jayconrod): remove this. Callers should use findModule and return +// errors instead of relying on base.Fatalf. +func mustFindModule(target, path string) module.Version { + pkg, ok := loaded.pkgCache.Get(path).(*loadPkg) + if ok { + if pkg.err != nil { + base.Fatalf("build %v: cannot load %v: %v", target, path, pkg.err) + } + return pkg.mod + } + + if path == "command-line-arguments" { + return Target + } + + base.Fatalf("build %v: cannot find module for path %v", target, path) + panic("unreachable") +} + +// findModule searches for the module that contains the package at path. +// If the package was loaded, its containing module and true are returned. +// Otherwise, module.Version{} and false are returend. +func findModule(path string) (module.Version, bool) { + if pkg, ok := loaded.pkgCache.Get(path).(*loadPkg); ok { + return pkg.mod, pkg.mod != module.Version{} + } + if path == "command-line-arguments" { + return Target, true + } + return module.Version{}, false +} + +func ModInfoProg(info string, isgccgo bool) []byte { + // Inject a variable with the debug information as runtime.modinfo, + // but compile it in package main so that it is specific to the binary. + // The variable must be a literal so that it will have the correct value + // before the initializer for package main runs. + // + // The runtime startup code refers to the variable, which keeps it live + // in all binaries. + // + // Note: we use an alternate recipe below for gccgo (based on an + // init function) due to the fact that gccgo does not support + // applying a "//go:linkname" directive to a variable. This has + // drawbacks in that other packages may want to look at the module + // info in their init functions (see issue 29628), which won't + // work for gccgo. See also issue 30344. + + if !isgccgo { + return []byte(fmt.Sprintf(`package main +import _ "unsafe" +//go:linkname __debug_modinfo__ runtime.modinfo +var __debug_modinfo__ = %q +`, string(infoStart)+info+string(infoEnd))) + } else { + return []byte(fmt.Sprintf(`package main +import _ "unsafe" +//go:linkname __set_debug_modinfo__ runtime.setmodinfo +func __set_debug_modinfo__(string) +func init() { __set_debug_modinfo__(%q) } +`, string(infoStart)+info+string(infoEnd))) + } +} diff --git a/src/cmd/go/internal/modload/buildlist.go b/src/cmd/go/internal/modload/buildlist.go new file mode 100644 index 0000000..0ed9853 --- /dev/null +++ b/src/cmd/go/internal/modload/buildlist.go @@ -0,0 +1,308 @@ +// 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" + "cmd/go/internal/cfg" + "cmd/go/internal/imports" + "cmd/go/internal/mvs" + "context" + "fmt" + "go/build" + "os" + "strings" + + "golang.org/x/mod/modfile" + "golang.org/x/mod/module" + "golang.org/x/mod/semver" +) + +// buildList is the list of modules to use for building packages. +// It is initialized by calling LoadPackages or ImportFromFiles, +// 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 + +// additionalExplicitRequirements is a list of modules paths for which +// WriteGoMod should record explicit requirements, even if they would be +// selected without those requirements. Each path must also appear in buildList. +var additionalExplicitRequirements []string + +// capVersionSlice returns s with its cap reduced to its length. +func capVersionSlice(s []module.Version) []module.Version { + return s[:len(s):len(s)] +} + +// LoadAllModules loads and returns the list of modules matching the "all" +// module pattern, starting with the Target module and in a deterministic +// (stable) order, without loading any packages. +// +// Modules are loaded automatically (and lazily) in LoadPackages: +// LoadAllModules need only be called if LoadPackages is not, +// typically in commands that care about modules but no particular package. +// +// The caller must not modify the returned list, but may append to it. +func LoadAllModules(ctx context.Context) []module.Version { + LoadModFile(ctx) + ReloadBuildList() + WriteGoMod() + return capVersionSlice(buildList) +} + +// Selected returns the selected version of the module with the given path, or +// the empty string if the given module has no selected version +// (either because it is not required or because it is the Target module). +func Selected(path string) (version string) { + if path == Target.Path { + return "" + } + for _, m := range buildList { + if m.Path == path { + return m.Version + } + } + return "" +} + +// EditBuildList edits the global build list by first adding every module in add +// to the existing build list, then adjusting versions (and adding or removing +// requirements as needed) until every module in mustSelect is selected at the +// given version. +// +// (Note that the newly-added modules might not be selected in the resulting +// build list: they could be lower than existing requirements or conflict with +// versions in mustSelect.) +// +// If the versions listed in mustSelect are mutually incompatible (due to one of +// the listed modules requiring a higher version of another), EditBuildList +// returns a *ConstraintError and leaves the build list in its previous state. +func EditBuildList(ctx context.Context, add, mustSelect []module.Version) error { + var upgraded = capVersionSlice(buildList) + if len(add) > 0 { + // First, upgrade the build list with any additions. + // In theory we could just append the additions to the build list and let + // mvs.Downgrade take care of resolving the upgrades too, but the + // diagnostics from Upgrade are currently much better in case of errors. + var err error + upgraded, err = mvs.Upgrade(Target, &mvsReqs{buildList: upgraded}, add...) + if err != nil { + return err + } + } + + downgraded, err := mvs.Downgrade(Target, &mvsReqs{buildList: append(upgraded, mustSelect...)}, mustSelect...) + if err != nil { + return err + } + + final, err := mvs.Upgrade(Target, &mvsReqs{buildList: downgraded}, mustSelect...) + if err != nil { + return err + } + + selected := make(map[string]module.Version, len(final)) + for _, m := range final { + selected[m.Path] = m + } + inconsistent := false + for _, m := range mustSelect { + s, ok := selected[m.Path] + if !ok { + if m.Version != "none" { + panic(fmt.Sprintf("internal error: mvs.BuildList lost %v", m)) + } + continue + } + if s.Version != m.Version { + inconsistent = true + break + } + } + + if !inconsistent { + buildList = final + additionalExplicitRequirements = make([]string, 0, len(mustSelect)) + for _, m := range mustSelect { + if m.Version != "none" { + additionalExplicitRequirements = append(additionalExplicitRequirements, m.Path) + } + } + return nil + } + + // We overshot one or more of the modules in mustSelected, which means that + // Downgrade removed something in mustSelect because it conflicted with + // something else in mustSelect. + // + // Walk the requirement graph to find the conflict. + // + // TODO(bcmills): Ideally, mvs.Downgrade (or a replacement for it) would do + // this directly. + + reqs := &mvsReqs{buildList: final} + reason := map[module.Version]module.Version{} + for _, m := range mustSelect { + reason[m] = m + } + queue := mustSelect[:len(mustSelect):len(mustSelect)] + for len(queue) > 0 { + var m module.Version + m, queue = queue[0], queue[1:] + required, err := reqs.Required(m) + if err != nil { + return err + } + for _, r := range required { + if _, ok := reason[r]; !ok { + reason[r] = reason[m] + queue = append(queue, r) + } + } + } + + var conflicts []Conflict + for _, m := range mustSelect { + s, ok := selected[m.Path] + if !ok { + if m.Version != "none" { + panic(fmt.Sprintf("internal error: mvs.BuildList lost %v", m)) + } + continue + } + if s.Version != m.Version { + conflicts = append(conflicts, Conflict{ + Source: reason[s], + Dep: s, + Constraint: m, + }) + } + } + + return &ConstraintError{ + Conflicts: conflicts, + } +} + +// A ConstraintError describes inconsistent constraints in EditBuildList +type ConstraintError struct { + // Conflict lists the source of the conflict for each version in mustSelect + // that could not be selected due to the requirements of some other version in + // mustSelect. + Conflicts []Conflict +} + +func (e *ConstraintError) Error() string { + b := new(strings.Builder) + b.WriteString("version constraints conflict:") + for _, c := range e.Conflicts { + fmt.Fprintf(b, "\n\t%v requires %v, but %v is requested", c.Source, c.Dep, c.Constraint) + } + return b.String() +} + +// A Conflict documents that Source requires Dep, which conflicts with Constraint. +// (That is, Dep has the same module path as Constraint but a higher version.) +type Conflict struct { + Source module.Version + Dep module.Version + Constraint module.Version +} + +// ReloadBuildList resets the state of loaded packages, then loads and returns +// the build list set by EditBuildList. +func ReloadBuildList() []module.Version { + loaded = loadFromRoots(loaderParams{ + PackageOpts: PackageOpts{ + Tags: imports.Tags(), + }, + listRoots: func() []string { return nil }, + allClosesOverTests: index.allPatternClosesOverTests(), // but doesn't matter because the root list is empty. + }) + return capVersionSlice(buildList) +} + +// CheckTidyVersion reports an error to stderr if the Go version indicated by +// the go.mod file is not supported by this version of the 'go' command. +// +// If allowError is false, such an error terminates the program. +func CheckTidyVersion(ctx context.Context, allowError bool) { + LoadModFile(ctx) + if index.goVersionV == "" { + return + } + + tags := build.Default.ReleaseTags + maxGo := tags[len(tags)-1] + if !strings.HasPrefix(maxGo, "go") || !modfile.GoVersionRE.MatchString(maxGo[2:]) { + base.Fatalf("go: unrecognized go version %q", maxGo) + } + max := maxGo[2:] + + if semver.Compare(index.goVersionV, "v"+max) > 0 { + have := index.goVersionV[1:] + if allowError { + fmt.Fprintf(os.Stderr, "go mod tidy: go.mod file indicates go %s, but maximum supported version is %s\n", have, max) + } else { + base.Fatalf("go mod tidy: go.mod file indicates go %s, but maximum supported version is %s\n", have, max) + } + } +} + +// TidyBuildList trims the build list to the minimal requirements needed to +// retain the same versions of all packages from the preceding call to +// LoadPackages. +func TidyBuildList() { + used := map[module.Version]bool{Target: true} + for _, pkg := range loaded.pkgs { + used[pkg.mod] = true + } + + keep := []module.Version{Target} + var direct []string + for _, m := range buildList[1:] { + if used[m] { + keep = append(keep, m) + if loaded.direct[m.Path] { + direct = append(direct, m.Path) + } + } else if cfg.BuildV { + if _, ok := index.require[m]; ok { + fmt.Fprintf(os.Stderr, "unused %s\n", m.Path) + } + } + } + + min, err := mvs.Req(Target, direct, &mvsReqs{buildList: keep}) + if err != nil { + base.Fatalf("go: %v", err) + } + buildList = append([]module.Version{Target}, min...) +} + +// checkMultiplePaths verifies that a given module path is used as itself +// or as a replacement for another module, but not both at the same time. +// +// (See https://golang.org/issue/26607 and https://golang.org/issue/34650.) +func checkMultiplePaths() { + 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() +} diff --git a/src/cmd/go/internal/modload/help.go b/src/cmd/go/internal/modload/help.go new file mode 100644 index 0000000..fd39ddd --- /dev/null +++ b/src/cmd/go/internal/modload/help.go @@ -0,0 +1,64 @@ +// 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" + +var HelpModules = &base.Command{ + UsageLine: "modules", + Short: "modules, module versions, and more", + Long: ` +Modules are how Go manages dependencies. + +A module is a collection of packages that are released, versioned, and +distributed together. Modules may be downloaded directly from version control +repositories or from module proxy servers. + +For a series of tutorials on modules, see +https://golang.org/doc/tutorial/create-module. + +For a detailed reference on modules, see https://golang.org/ref/mod. + +By default, the go command may download modules from https://proxy.golang.org. +It may authenticate modules using the checksum database at +https://sum.golang.org. Both services are operated by the Go team at Google. +The privacy policies for these services are available at +https://proxy.golang.org/privacy and https://sum.golang.org/privacy, +respectively. + +The go command's download behavior may be configured using GOPROXY, GOSUMDB, +GOPRIVATE, and other environment variables. See 'go help environment' +and https://golang.org/ref/mod#private-module-privacy for more information. + `, +} + +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 format is described in detail at +https://golang.org/ref/mod#go-mod-file. + +To create a new go.mod file, use 'go help init'. For details see +'go help mod init' or https://golang.org/ref/mod#go-mod-init. + +To add missing module requirements or remove unneeded requirements, +use 'go mod tidy'. For details, see 'go help mod tidy' or +https://golang.org/ref/mod#go-mod-tidy. + +To add, upgrade, downgrade, or remove a specific module requirement, use +'go get'. For details, see 'go help module-get' or +https://golang.org/ref/mod#go-get. + +To make other changes or to parse go.mod as JSON for use by other tools, +use 'go mod edit'. See 'go help mod edit' or +https://golang.org/ref/mod#go-mod-edit. + `, +} diff --git a/src/cmd/go/internal/modload/import.go b/src/cmd/go/internal/modload/import.go new file mode 100644 index 0000000..eda0568 --- /dev/null +++ b/src/cmd/go/internal/modload/import.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 ( + "context" + "errors" + "fmt" + "go/build" + "internal/goroot" + "io/fs" + "os" + "path/filepath" + "sort" + "strings" + + "cmd/go/internal/cfg" + "cmd/go/internal/fsys" + "cmd/go/internal/modfetch" + "cmd/go/internal/par" + "cmd/go/internal/search" + + "golang.org/x/mod/module" + "golang.org/x/mod/semver" +) + +type ImportMissingError struct { + Path string + Module module.Version + QueryErr error + + // isStd indicates whether we would expect to find the package in the standard + // library. This is normally true for all dotless import paths, but replace + // directives can cause us to treat the replaced paths as also being in + // modules. + isStd bool + + // replaced the highest replaced version of the module where the replacement + // contains the package. replaced is only set if the replacement is unused. + replaced module.Version + + // newMissingVersion is set to a newer version of Module if one is present + // in the build list. When set, we can't automatically upgrade. + newMissingVersion string +} + +func (e *ImportMissingError) Error() string { + if e.Module.Path == "" { + if e.isStd { + return fmt.Sprintf("package %s is not in GOROOT (%s)", e.Path, filepath.Join(cfg.GOROOT, "src", e.Path)) + } + if e.QueryErr != nil && e.QueryErr != ErrNoModRoot { + return fmt.Sprintf("cannot find module providing package %s: %v", e.Path, e.QueryErr) + } + if cfg.BuildMod == "mod" || (cfg.BuildMod == "readonly" && allowMissingModuleImports) { + return "cannot find module providing package " + e.Path + } + + if e.replaced.Path != "" { + suggestArg := e.replaced.Path + if !modfetch.IsZeroPseudoVersion(e.replaced.Version) { + suggestArg = e.replaced.String() + } + return fmt.Sprintf("module %s provides package %s and is replaced but not required; to add it:\n\tgo get %s", e.replaced.Path, e.Path, suggestArg) + } + + message := fmt.Sprintf("no required module provides package %s", e.Path) + if e.QueryErr != nil { + return fmt.Sprintf("%s: %v", message, e.QueryErr) + } + return fmt.Sprintf("%s; to add it:\n\tgo get %s", message, e.Path) + } + + if e.newMissingVersion != "" { + return fmt.Sprintf("package %s provided by %s at latest version %s but not at required version %s", e.Path, e.Module.Path, e.Module.Version, e.newMissingVersion) + } + + return fmt.Sprintf("missing module for import: %s@%s provides %s", e.Module.Path, e.Module.Version, e.Path) +} + +func (e *ImportMissingError) Unwrap() error { + return e.QueryErr +} + +func (e *ImportMissingError) ImportPath() string { + return e.Path +} + +// An AmbiguousImportError indicates an import of a package found in multiple +// modules in the build list, or found in both the main module and its vendor +// directory. +type AmbiguousImportError struct { + importPath string + Dirs []string + Modules []module.Version // Either empty or 1:1 with Dirs. +} + +func (e *AmbiguousImportError) ImportPath() string { + return e.importPath +} + +func (e *AmbiguousImportError) Error() string { + locType := "modules" + if len(e.Modules) == 0 { + locType = "directories" + } + + var buf strings.Builder + fmt.Fprintf(&buf, "ambiguous import: found package %s in multiple %s:", e.importPath, locType) + + for i, dir := range e.Dirs { + buf.WriteString("\n\t") + if i < len(e.Modules) { + m := e.Modules[i] + buf.WriteString(m.Path) + if m.Version != "" { + fmt.Fprintf(&buf, " %s", m.Version) + } + fmt.Fprintf(&buf, " (%s)", dir) + } else { + buf.WriteString(dir) + } + } + + return buf.String() +} + +// ImportMissingSumError is reported in readonly mode when we need to check +// if a module contains a package, but we don't have a sum for its .zip file. +// We might need sums for multiple modules to verify the package is unique. +// +// TODO(#43653): consolidate multiple errors of this type into a single error +// that suggests a 'go get' command for root packages that transtively import +// packages from modules with missing sums. load.CheckPackageErrors would be +// a good place to consolidate errors, but we'll need to attach the import +// stack here. +type ImportMissingSumError struct { + importPath string + found bool + mods []module.Version + importer, importerVersion string // optional, but used for additional context + importerIsTest bool +} + +func (e *ImportMissingSumError) Error() string { + var importParen string + if e.importer != "" { + importParen = fmt.Sprintf(" (imported by %s)", e.importer) + } + var message string + if e.found { + message = fmt.Sprintf("missing go.sum entry needed to verify package %s%s is provided by exactly one module", e.importPath, importParen) + } else { + message = fmt.Sprintf("missing go.sum entry for module providing package %s%s", e.importPath, importParen) + } + var hint string + if e.importer == "" { + // Importing package is unknown, or the missing package was named on the + // command line. Recommend 'go mod download' for the modules that could + // provide the package, since that shouldn't change go.mod. + if len(e.mods) > 0 { + args := make([]string, len(e.mods)) + for i, mod := range e.mods { + args[i] = mod.Path + } + hint = fmt.Sprintf("; to add:\n\tgo mod download %s", strings.Join(args, " ")) + } + } else { + // Importing package is known (common case). Recommend 'go get' on the + // current version of the importing package. + tFlag := "" + if e.importerIsTest { + tFlag = " -t" + } + version := "" + if e.importerVersion != "" { + version = "@" + e.importerVersion + } + hint = fmt.Sprintf("; to add:\n\tgo get%s %s%s", tFlag, e.importer, version) + } + return message + hint +} + +func (e *ImportMissingSumError) ImportPath() string { + return e.importPath +} + +type invalidImportError struct { + importPath string + err error +} + +func (e *invalidImportError) ImportPath() string { + return e.importPath +} + +func (e *invalidImportError) Error() string { + return e.err.Error() +} + +func (e *invalidImportError) Unwrap() error { + return e.err +} + +// importFromBuildList finds the module and directory in the build list +// containing the package with the given import path. The answer must be unique: +// importFromBuildList returns an error if multiple modules attempt to provide +// the same package. +// +// importFromBuildList can return a module with an empty m.Path, for packages in +// the standard library. +// +// importFromBuildList can return an empty directory string, for fake packages +// like "C" and "unsafe". +// +// If the package cannot be found in buildList, +// importFromBuildList returns an *ImportMissingError. +func importFromBuildList(ctx context.Context, path string, buildList []module.Version) (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 + } + // Before any further lookup, check that the path is valid. + if err := module.CheckImportPath(path); err != nil { + return module.Version{}, "", &invalidImportError{importPath: path, err: err} + } + + // Is the package in the standard library? + pathIsStd := search.IsStandardImportPath(path) + if pathIsStd && goroot.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, path) { + if targetInGorootSrc { + if dir, ok, err := dirInModule(path, targetPrefix, ModRoot(), true); err != nil { + return module.Version{}, dir, err + } else if ok { + return Target, dir, nil + } + } + 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, mainErr := dirInModule(path, targetPrefix, ModRoot(), true) + vendorDir, vendorOK, _ := dirInModule(path, "", filepath.Join(ModRoot(), "vendor"), false) + if mainOK && vendorOK { + return module.Version{}, "", &AmbiguousImportError{importPath: path, Dirs: []string{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 + } + if mainErr != nil { + return module.Version{}, "", mainErr + } + readVendorList() + return vendorPkgModule[path], vendorDir, nil + } + + // Check each module on the build list. + var dirs []string + var mods []module.Version + var sumErrMods []module.Version + for _, m := range buildList { + if !maybeInModule(path, m.Path) { + // Avoid possibly downloading irrelevant modules. + continue + } + needSum := true + root, isLocal, err := fetch(ctx, m, needSum) + if err != nil { + if sumErr := (*sumMissingError)(nil); errors.As(err, &sumErr) { + // We are missing a sum needed to fetch a module in the build list. + // We can't verify that the package is unique, and we may not find + // the package at all. Keep checking other modules to decide which + // error to report. Multiple sums may be missing if we need to look in + // multiple nested modules to resolve the import. + sumErrMods = append(sumErrMods, m) + continue + } + // 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 + } + if dir, ok, err := dirInModule(path, m.Path, root, isLocal); err != nil { + return module.Version{}, "", err + } else if ok { + mods = append(mods, m) + dirs = append(dirs, dir) + } + } + if len(mods) > 1 { + return module.Version{}, "", &AmbiguousImportError{importPath: path, Dirs: dirs, Modules: mods} + } + if len(sumErrMods) > 0 { + return module.Version{}, "", &ImportMissingSumError{ + importPath: path, + mods: sumErrMods, + found: len(mods) > 0, + } + } + if len(mods) == 1 { + return mods[0], dirs[0], nil + } + + var queryErr error + if !HasModRoot() { + queryErr = ErrNoModRoot + } + return module.Version{}, "", &ImportMissingError{Path: path, QueryErr: queryErr, isStd: pathIsStd} +} + +// queryImport attempts to locate a module that can be added to the current +// build list to provide the package with the given import path. +// +// Unlike QueryPattern, queryImport prefers to add a replaced version of a +// module *before* checking the proxies for a version to add. +func queryImport(ctx context.Context, path string) (module.Version, error) { + // To avoid spurious remote fetches, try the latest replacement for each + // module (golang.org/issue/26241). + if index != nil { + var mods []module.Version + for mp, mv := range index.highestReplaced { + if !maybeInModule(path, mp) { + continue + } + if mv == "" { + // The only replacement is a wildcard that doesn't specify a version, so + // synthesize a pseudo-version with an appropriate major version and a + // timestamp below any real timestamp. That way, if the main module is + // used from within some other module, the user will be able to upgrade + // the requirement to any real version they choose. + if _, pathMajor, ok := module.SplitPathVersion(mp); ok && len(pathMajor) > 0 { + mv = modfetch.ZeroPseudoVersion(pathMajor[1:]) + } else { + mv = modfetch.ZeroPseudoVersion("v0") + } + } + mods = append(mods, module.Version{Path: mp, Version: mv}) + } + + // Every module path in mods is a prefix of the import path. + // As in QueryPattern, prefer the longest prefix that satisfies the import. + sort.Slice(mods, func(i, j int) bool { + return len(mods[i].Path) > len(mods[j].Path) + }) + for _, m := range mods { + needSum := true + root, isLocal, err := fetch(ctx, m, needSum) + if err != nil { + if sumErr := (*sumMissingError)(nil); errors.As(err, &sumErr) { + return module.Version{}, &ImportMissingSumError{importPath: path} + } + return module.Version{}, err + } + if _, ok, err := dirInModule(path, m.Path, root, isLocal); err != nil { + return m, err + } else if ok { + if cfg.BuildMod == "readonly" { + return module.Version{}, &ImportMissingError{Path: path, replaced: m} + } + return m, nil + } + } + if len(mods) > 0 && module.CheckPath(path) != nil { + // The package path is not valid to fetch remotely, + // so it can only exist in a replaced module, + // and we know from the above loop that it is not. + return module.Version{}, &PackageNotInModuleError{ + Mod: mods[0], + Query: "latest", + Pattern: path, + Replacement: Replacement(mods[0]), + } + } + } + + if search.IsStandardImportPath(path) { + // This package isn't in the standard library, isn't in any module already + // in the build list, and isn't in any other module that the user has + // shimmed in via a "replace" directive. + // Moreover, the import path is reserved for the standard library, so + // QueryPattern cannot possibly find a module containing this package. + // + // Instead of trying QueryPattern, report an ImportMissingError immediately. + return module.Version{}, &ImportMissingError{Path: path, isStd: true} + } + + if cfg.BuildMod == "readonly" && !allowMissingModuleImports { + // In readonly mode, we can't write go.mod, so we shouldn't try to look up + // the module. If readonly mode was enabled explicitly, include that in + // the error message. + var queryErr error + if cfg.BuildModExplicit { + queryErr = fmt.Errorf("import lookup disabled by -mod=%s", cfg.BuildMod) + } else if cfg.BuildModReason != "" { + queryErr = fmt.Errorf("import lookup disabled by -mod=%s\n\t(%s)", cfg.BuildMod, cfg.BuildModReason) + } + return module.Version{}, &ImportMissingError{Path: path, QueryErr: queryErr} + } + + // 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, ImpportMissingError. + fmt.Fprintf(os.Stderr, "go: finding module for package %s\n", path) + + candidates, err := QueryPackages(ctx, path, "latest", Selected, CheckAllowed) + if err != nil { + if errors.Is(err, fs.ErrNotExist) { + // Return "cannot find module providing package […]" instead of whatever + // low-level error QueryPattern produced. + return module.Version{}, &ImportMissingError{Path: path, QueryErr: err} + } else { + return module.Version{}, err + } + } + + candidate0MissingVersion := "" + for i, c := range candidates { + cm := c.Mod + canAdd := true + for _, bm := range buildList { + if bm.Path == cm.Path && semver.Compare(bm.Version, cm.Version) > 0 { + // QueryPattern proposed that we add module cm to provide the package, + // but we already depend on a newer version of that module (and we don't + // have the package). + // + // This typically happens when a package is present at the "@latest" + // version (e.g., v1.0.0) of a module, but we have a newer version + // of the same module in the build list (e.g., v1.0.1-beta), and + // the package is not present there. + canAdd = false + if i == 0 { + candidate0MissingVersion = bm.Version + } + break + } + } + if canAdd { + return cm, nil + } + } + return module.Version{}, &ImportMissingError{ + Path: path, + Module: candidates[0].Mod, + newMissingVersion: candidate0MissingVersion, + } +} + +// 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 par.Cache // dir → bool + haveGoFilesCache par.Cache // dir → goFilesEntry +) + +type goFilesEntry struct { + haveGoFiles bool + err error +} + +// 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, nil. +// +// 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. +// A non-nil error indicates that the existence of the directory and/or +// source files could not be determined, for example due to a permission error. +func dirInModule(path, mpath, mdir string, isLocal bool) (dir string, haveGoFiles bool, err error) { + // 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, nil + } + + // 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{} { + fi, err := fsys.Stat(filepath.Join(d, "go.mod")) + return err == nil && !fi.IsDir() + }).(bool) + + if haveGoMod { + return "", false, nil + } + 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. + res := haveGoFilesCache.Do(dir, func() interface{} { + ok, err := fsys.IsDirWithGoFiles(dir) + return goFilesEntry{haveGoFiles: ok, err: err} + }).(goFilesEntry) + + return dir, res.haveGoFiles, res.err +} + +// fetch downloads the given module (or its replacement) +// and returns its location. +// +// needSum indicates whether the module may be downloaded in readonly mode +// without a go.sum entry. It should only be false for modules fetched +// speculatively (for example, for incompatible version filtering). The sum +// will still be verified normally. +// +// The isLocal return value reports whether the replacement, +// if any, is local to the filesystem. +func fetch(ctx context.Context, mod module.Version, needSum bool) (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) + } + // Ensure that the replacement directory actually exists: + // dirInModule does not report errors for missing modules, + // so if we don't report the error now, later failures will be + // very mysterious. + if _, err := fsys.Stat(dir); err != nil { + if os.IsNotExist(err) { + // Semantically the module version itself “exists” — we just don't + // have its source code. Remove the equivalence to os.ErrNotExist, + // and make the message more concise while we're at it. + err = fmt.Errorf("replacement directory %s does not exist", r.Path) + } else { + err = fmt.Errorf("replacement directory %s: %w", r.Path, err) + } + return dir, true, module.VersionError(mod, err) + } + return dir, true, nil + } + mod = r + } + + if HasModRoot() && cfg.BuildMod == "readonly" && needSum && !modfetch.HaveSum(mod) { + return "", false, module.VersionError(mod, &sumMissingError{}) + } + + dir, err = modfetch.Download(ctx, mod) + return dir, false, err +} + +type sumMissingError struct { + suggestion string +} + +func (e *sumMissingError) Error() string { + return "missing go.sum entry" + e.suggestion +} diff --git a/src/cmd/go/internal/modload/import_test.go b/src/cmd/go/internal/modload/import_test.go new file mode 100644 index 0000000..9420dc5 --- /dev/null +++ b/src/cmd/go/internal/modload/import_test.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 modload + +import ( + "context" + "internal/testenv" + "regexp" + "strings" + "testing" + + "golang.org/x/mod/module" +) + +var importTests = []struct { + path string + m module.Version + err string +}{ + { + path: "golang.org/x/net/context", + m: module.Version{ + Path: "golang.org/x/net", + }, + }, + { + path: "golang.org/x/net", + err: `module golang.org/x/net@.* found \(v0.0.0-.*\), but does not contain package golang.org/x/net`, + }, + { + path: "golang.org/x/text", + m: module.Version{ + Path: "golang.org/x/text", + }, + }, + { + path: "github.com/rsc/quote/buggy", + m: module.Version{ + Path: "github.com/rsc/quote", + Version: "v1.5.2", + }, + }, + { + path: "github.com/rsc/quote", + m: module.Version{ + Path: "github.com/rsc/quote", + Version: "v1.5.2", + }, + }, + { + path: "golang.org/x/foo/bar", + err: "cannot find module providing package golang.org/x/foo/bar", + }, +} + +func TestQueryImport(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + testenv.MustHaveExecPath(t, "git") + + oldAllowMissingModuleImports := allowMissingModuleImports + oldRootMode := RootMode + defer func() { + allowMissingModuleImports = oldAllowMissingModuleImports + RootMode = oldRootMode + }() + allowMissingModuleImports = true + RootMode = NoRoot + + ctx := context.Background() + + for _, tt := range importTests { + t.Run(strings.ReplaceAll(tt.path, "/", "_"), func(t *testing.T) { + // Note that there is no build list, so Import should always fail. + m, err := queryImport(ctx, tt.path) + + if tt.err == "" { + if err != nil { + t.Fatalf("queryImport(_, %q): %v", tt.path, err) + } + } else { + if err == nil { + t.Fatalf("queryImport(_, %q) = %v, nil; expected error", tt.path, m) + } + if !regexp.MustCompile(tt.err).MatchString(err.Error()) { + t.Fatalf("queryImport(_, %q): error %q, want error matching %#q", tt.path, err, tt.err) + } + } + + if m.Path != tt.m.Path || (tt.m.Version != "" && m.Version != tt.m.Version) { + t.Errorf("queryImport(_, %q) = %v, _; want %v", tt.path, m, tt.m) + } + }) + } +} diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go new file mode 100644 index 0000000..8ec1c86 --- /dev/null +++ b/src/cmd/go/internal/modload/init.go @@ -0,0 +1,1072 @@ +// 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" + "context" + "encoding/json" + "errors" + "fmt" + "go/build" + "internal/lazyregexp" + "os" + "path" + "path/filepath" + "sort" + "strconv" + "strings" + "sync" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/fsys" + "cmd/go/internal/lockedfile" + "cmd/go/internal/modconv" + "cmd/go/internal/modfetch" + "cmd/go/internal/mvs" + "cmd/go/internal/search" + "cmd/go/internal/str" + + "golang.org/x/mod/modfile" + "golang.org/x/mod/module" + "golang.org/x/mod/semver" +) + +var ( + initialized bool + + modRoot string + Target module.Version + + // targetPrefix is the path prefix for packages in Target, without a trailing + // slash. For most modules, targetPrefix is just Target.Path, but the + // standard-library module "std" has an empty prefix. + targetPrefix string + + // targetInGorootSrc caches whether modRoot is within GOROOT/src. + // The "std" module is special within GOROOT/src, but not otherwise. + targetInGorootSrc bool + + gopath string + + // RootMode determines whether a module root is needed. + RootMode Root + + // ForceUseModules may be set to force modules to be enabled when + // GO111MODULE=auto or to report an error when GO111MODULE=off. + ForceUseModules bool + + allowMissingModuleImports bool +) + +type Root int + +const ( + // AutoRoot is the default for most commands. modload.Init will look for + // a go.mod file in the current directory or any parent. If none is found, + // modules may be disabled (GO111MODULE=on) or commands may run in a + // limited module mode. + AutoRoot Root = iota + + // NoRoot is used for commands that run in module mode and ignore any go.mod + // file the current directory or in parent directories. + NoRoot + + // NeedRoot is used for commands that must run in module mode and don't + // make sense without a main module. + NeedRoot +) + +// ModFile returns the parsed go.mod file. +// +// Note that after calling LoadPackages or LoadAllModules, +// 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 loading. +func ModFile() *modfile.File { + Init() + if modFile == nil { + die() + } + return modFile +} + +func BinDir() string { + Init() + return filepath.Join(gopath, "bin") +} + +// Init determines whether module mode is enabled, locates the root of the +// current module (if any), sets environment variables for Git subprocesses, and +// configures the cfg, codehost, load, modfetch, and search packages for use +// with modules. +func Init() { + if initialized { + return + } + initialized = true + + // Keep in sync with WillBeEnabled. We perform extra validation here, and + // there are lots of diagnostics and side effects, so we can't use + // WillBeEnabled directly. + var mustUseModules bool + env := cfg.Getenv("GO111MODULE") + switch env { + default: + base.Fatalf("go: unknown environment setting GO111MODULE=%s", env) + case "auto": + mustUseModules = ForceUseModules + case "on", "": + mustUseModules = true + case "off": + if ForceUseModules { + base.Fatalf("go: modules disabled by GO111MODULE=off; see 'go help modules'") + } + mustUseModules = false + return + } + + if err := fsys.Init(base.Cwd); err != nil { + base.Fatalf("go: %v", err) + } + + // 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") + } + + if modRoot != "" { + // modRoot set before Init was called ("go mod init" does this). + // No need to search for go.mod. + } else if RootMode == NoRoot { + if cfg.ModFile != "" && !base.InGOFLAGS("-modfile") { + base.Fatalf("go: -modfile cannot be used with commands that ignore the current module") + } + modRoot = "" + } else { + modRoot = findModuleRoot(base.Cwd) + if modRoot == "" { + if cfg.ModFile != "" { + base.Fatalf("go: cannot find main module, but -modfile was set.\n\t-modfile cannot be used to set the module root directory.") + } + if RootMode == NeedRoot { + base.Fatalf("go: %v", ErrNoModRoot) + } + if !mustUseModules { + // GO111MODULE is 'auto', and we can't find a module root. + // Stay in GOPATH mode. + return + } + } else 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()) + if !mustUseModules { + return + } + } + } + if cfg.ModFile != "" && !strings.HasSuffix(cfg.ModFile, ".mod") { + base.Fatalf("go: -modfile=%s: file does not have .mod extension", cfg.ModFile) + } + + // We're in module mode. Set any global variables that need to be set. + cfg.ModulesEnabled = true + setDefaultBuildMod() + list := filepath.SplitList(cfg.BuildContext.GOPATH) + if len(list) == 0 || list[0] == "" { + base.Fatalf("missing $GOPATH") + } + gopath = list[0] + if _, err := fsys.Stat(filepath.Join(gopath, "go.mod")); err == nil { + base.Fatalf("$GOPATH/go.mod exists but should not") + } + + if modRoot == "" { + // We're in module mode, but not inside a module. + // + // Commands like 'go build', 'go run', 'go list' have no go.mod file to + // read or write. They would need to find and download the latest versions + // of a potentially large number of modules with no way to save version + // information. We can succeed slowly (but not reproducibly), but that's + // not usually a good experience. + // + // Instead, we forbid resolving import paths to modules other than std and + // cmd. Users may still build packages specified with .go files on the + // command line, but they'll see an error if those files import anything + // outside std. + // + // This can be overridden by calling AllowMissingModuleImports. + // For example, 'go get' does this, since it is expected to resolve paths. + // + // See golang.org/issue/32027. + } else { + modfetch.GoSumFile = strings.TrimSuffix(ModFilePath(), ".mod") + ".sum" + search.SetModRoot(modRoot) + } +} + +// WillBeEnabled checks whether modules should be enabled but does not +// initialize modules by installing hooks. If Init has already been called, +// WillBeEnabled returns the same result as Enabled. +// +// This function is needed to break a cycle. The main package needs to know +// whether modules are enabled in order to install the module or GOPATH version +// of 'go get', but Init reads the -modfile flag in 'go get', so it shouldn't +// be called until the command is installed and flags are parsed. Instead of +// calling Init and Enabled, the main package can call this function. +func WillBeEnabled() bool { + if modRoot != "" || cfg.ModulesEnabled { + // Already enabled. + return true + } + if initialized { + // Initialized, not enabled. + return false + } + + // Keep in sync with Init. Init does extra validation and prints warnings or + // exits, so it can't call this function directly. + env := cfg.Getenv("GO111MODULE") + switch env { + case "on", "": + return true + case "auto": + break + default: + return false + } + + if modRoot := findModuleRoot(base.Cwd); modRoot == "" { + // GO111MODULE is 'auto', and we can't find a module root. + // Stay in GOPATH mode. + return false + } else 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. + return false + } + return true +} + +// Enabled reports whether modules are (or must be) enabled. +// If modules are enabled but there is no main module, Enabled returns true +// and then the first use of module information will call die +// (usually through MustModRoot). +func Enabled() bool { + Init() + return modRoot != "" || cfg.ModulesEnabled +} + +// ModRoot returns the root of the main module. +// It calls base.Fatalf if there is no main module. +func ModRoot() string { + if !HasModRoot() { + die() + } + return modRoot +} + +// HasModRoot reports whether a main module is present. +// HasModRoot may return false even if Enabled returns true: for example, 'get' +// does not require a main module. +func HasModRoot() bool { + Init() + return modRoot != "" +} + +// ModFilePath returns the effective path of the go.mod file. Normally, this +// "go.mod" in the directory returned by ModRoot, but the -modfile flag may +// change its location. ModFilePath calls base.Fatalf if there is no main +// module, even if -modfile is set. +func ModFilePath() string { + if !HasModRoot() { + die() + } + if cfg.ModFile != "" { + return cfg.ModFile + } + return filepath.Join(modRoot, "go.mod") +} + +func die() { + if cfg.Getenv("GO111MODULE") == "off" { + base.Fatalf("go: modules disabled by GO111MODULE=off; see 'go help modules'") + } + if dir, name := findAltConfig(base.Cwd); dir != "" { + rel, err := filepath.Rel(base.Cwd, dir) + if err != nil { + rel = dir + } + cdCmd := "" + if rel != "." { + cdCmd = fmt.Sprintf("cd %s && ", rel) + } + base.Fatalf("go: cannot find main module, but found %s in %s\n\tto create a module there, run:\n\t%sgo mod init", name, dir, cdCmd) + } + base.Fatalf("go: %v", ErrNoModRoot) +} + +var ErrNoModRoot = errors.New("go.mod file not found in current directory or any parent directory; see 'go help modules'") + +// LoadModFile sets Target and, if there is a main module, parses the initial +// build list from its go.mod file. +// +// LoadModFile may make changes in memory, like adding a go directive and +// ensuring requirements are consistent. WriteGoMod should be called later to +// write changes out to disk or report errors in readonly mode. +// +// As a side-effect, LoadModFile may change cfg.BuildMod to "vendor" if +// -mod wasn't set explicitly and automatic vendoring should be enabled. +func LoadModFile(ctx context.Context) { + if len(buildList) > 0 { + return + } + + Init() + if modRoot == "" { + Target = module.Version{Path: "command-line-arguments"} + targetPrefix = "command-line-arguments" + buildList = []module.Version{Target} + return + } + + gomod := ModFilePath() + data, err := lockedfile.Read(gomod) + if err != nil { + base.Fatalf("go: %v", err) + } + + var fixed bool + f, err := modfile.Parse(gomod, data, fixVersion(ctx, &fixed)) + 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 + index = indexModFile(data, f, fixed) + + if f.Module == nil { + // No module declaration. Must add module path. + base.Fatalf("go: no module declaration in go.mod. To specify the module path:\n\tgo mod edit -module=example.com/mod") + } + + if err := checkModulePathLax(f.Module.Mod.Path); err != nil { + base.Fatalf("go: %v", err) + } + + setDefaultBuildMod() // possibly enable automatic vendoring + modFileToBuildList() + if cfg.BuildMod == "vendor" { + readVendorList() + checkVendorConsistency() + } +} + +// CreateModFile initializes a new module by creating a go.mod file. +// +// If modPath is empty, CreateModFile will attempt to infer the path from the +// directory location within GOPATH. +// +// If a vendoring configuration file is present, CreateModFile will attempt to +// translate it to go.mod directives. The resulting build list may not be +// exactly the same as in the legacy configuration (for example, we can't get +// packages at multiple versions from the same module). +func CreateModFile(ctx context.Context, modPath string) { + modRoot = base.Cwd + Init() + modFilePath := ModFilePath() + if _, err := fsys.Stat(modFilePath); err == nil { + base.Fatalf("go: %s already exists", modFilePath) + } + + if modPath == "" { + var err error + modPath, err = findModulePath(modRoot) + if err != nil { + base.Fatalf("go: %v", err) + } + } else if err := checkModulePathLax(modPath); err != nil { + base.Fatalf("go: %v", err) + } + + fmt.Fprintf(os.Stderr, "go: creating new go.mod: module %s\n", modPath) + modFile = new(modfile.File) + modFile.AddModuleStmt(modPath) + addGoStmt() // Add the go directive before converted module requirements. + + convertedFrom, err := convertLegacyConfig(modPath) + if convertedFrom != "" { + fmt.Fprintf(os.Stderr, "go: copying requirements from %s\n", base.ShortPath(convertedFrom)) + } + if err != nil { + base.Fatalf("go: %v", err) + } + + modFileToBuildList() + WriteGoMod() + + // Suggest running 'go mod tidy' unless the project is empty. Even if we + // imported all the correct requirements above, we're probably missing + // some sums, so the next build command in -mod=readonly will likely fail. + // + // We look for non-hidden .go files or subdirectories to determine whether + // this is an existing project. Walking the tree for packages would be more + // accurate, but could take much longer. + empty := true + files, _ := os.ReadDir(modRoot) + for _, f := range files { + name := f.Name() + if strings.HasPrefix(name, ".") || strings.HasPrefix(name, "_") { + continue + } + if strings.HasSuffix(name, ".go") || f.IsDir() { + empty = false + break + } + } + if !empty { + fmt.Fprintf(os.Stderr, "go: to add module requirements and sums:\n\tgo mod tidy\n") + } +} + +// checkModulePathLax checks that the path meets some minimum requirements +// to avoid confusing users or the module cache. The requirements are weaker +// than those of module.CheckPath to allow room for weakening module path +// requirements in the future, but strong enough to help users avoid significant +// problems. +func checkModulePathLax(p string) error { + // TODO(matloob): Replace calls of this function in this CL with calls + // to module.CheckImportPath once it's been laxened, if it becomes laxened. + // See golang.org/issue/29101 for a discussion about whether to make CheckImportPath + // more lax or more strict. + + errorf := func(format string, args ...interface{}) error { + return fmt.Errorf("invalid module path %q: %s", p, fmt.Sprintf(format, args...)) + } + + // Disallow shell characters " ' * < > ? ` | to avoid triggering bugs + // with file systems and subcommands. Disallow file path separators : and \ + // because path separators other than / will confuse the module cache. + // See fileNameOK in golang.org/x/mod/module/module.go. + shellChars := "`" + `\"'*<>?|` + fsChars := `\:` + if i := strings.IndexAny(p, shellChars); i >= 0 { + return errorf("contains disallowed shell character %q", p[i]) + } + if i := strings.IndexAny(p, fsChars); i >= 0 { + return errorf("contains disallowed path separator character %q", p[i]) + } + + // Ensure path.IsAbs and build.IsLocalImport are false, and that the path is + // invariant under path.Clean, also to avoid confusing the module cache. + if path.IsAbs(p) { + return errorf("is an absolute path") + } + if build.IsLocalImport(p) { + return errorf("is a local import path") + } + if path.Clean(p) != p { + return errorf("is not clean") + } + + return nil +} + +// fixVersion returns a modfile.VersionFixer implemented using the Query function. +// +// It resolves commit hashes and branch names to versions, +// canonicalizes versions that appeared in early vgo drafts, +// and does nothing for versions that already appear to be canonical. +// +// The VersionFixer sets 'fixed' if it ever returns a non-canonical version. +func fixVersion(ctx context.Context, fixed *bool) modfile.VersionFixer { + return func(path, vers string) (resolved string, err error) { + defer func() { + if err == nil && resolved != vers { + *fixed = true + } + }() + + // 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 "", &module.ModuleError{ + Path: path, + Err: &module.InvalidVersionError{ + Version: vers, + Err: fmt.Errorf("malformed module path %q", path), + }, + } + } + if vers != "" && module.CanonicalVersion(vers) == vers { + if err := module.CheckPathMajor(vers, pathMajor); err != nil { + return "", module.VersionError(module.Version{Path: path, Version: vers}, err) + } + return vers, nil + } + + info, err := Query(ctx, path, vers, "", nil) + if err != nil { + return "", err + } + return info.Version, nil + } +} + +// AllowMissingModuleImports allows import paths to be resolved to modules +// when there is no module root. Normally, this is forbidden because it's slow +// and there's no way to make the result reproducible, but some commands +// like 'go get' are expected to do this. +func AllowMissingModuleImports() { + allowMissingModuleImports = true +} + +// modFileToBuildList initializes buildList from the modFile. +func modFileToBuildList() { + Target = modFile.Module.Mod + targetPrefix = Target.Path + if rel := search.InDir(base.Cwd, cfg.GOROOTsrc); rel != "" { + targetInGorootSrc = true + if Target.Path == "std" { + targetPrefix = "" + } + } + + list := []module.Version{Target} + for _, r := range modFile.Require { + if index != nil && index.exclude[r.Mod] { + if cfg.BuildMod == "mod" { + fmt.Fprintf(os.Stderr, "go: dropping requirement on excluded version %s %s\n", r.Mod.Path, r.Mod.Version) + } else { + fmt.Fprintf(os.Stderr, "go: ignoring requirement on excluded version %s %s\n", r.Mod.Path, r.Mod.Version) + } + } else { + list = append(list, r.Mod) + } + } + buildList = list +} + +// setDefaultBuildMod sets a default value for cfg.BuildMod if the -mod flag +// wasn't provided. setDefaultBuildMod may be called multiple times. +func setDefaultBuildMod() { + if cfg.BuildModExplicit { + // Don't override an explicit '-mod=' argument. + return + } + + if cfg.CmdName == "get" || strings.HasPrefix(cfg.CmdName, "mod ") { + // 'get' and 'go mod' commands may update go.mod automatically. + // TODO(jayconrod): should this narrower? Should 'go mod download' or + // 'go mod graph' update go.mod by default? + cfg.BuildMod = "mod" + return + } + if modRoot == "" { + cfg.BuildMod = "readonly" + return + } + + if fi, err := fsys.Stat(filepath.Join(modRoot, "vendor")); err == nil && fi.IsDir() { + modGo := "unspecified" + if index != nil && index.goVersionV != "" { + if semver.Compare(index.goVersionV, "v1.14") >= 0 { + // The Go version is at least 1.14, and a vendor directory exists. + // Set -mod=vendor by default. + cfg.BuildMod = "vendor" + cfg.BuildModReason = "Go version in go.mod is at least 1.14 and vendor directory exists." + return + } else { + modGo = index.goVersionV[1:] + } + } + + // Since a vendor directory exists, we should record why we didn't use it. + // This message won't normally be shown, but it may appear with import errors. + cfg.BuildModReason = fmt.Sprintf("Go version in go.mod is %s, so vendor directory was not used.", modGo) + } + + cfg.BuildMod = "readonly" +} + +// convertLegacyConfig imports module requirements from a legacy vendoring +// configuration file, if one is present. +func convertLegacyConfig(modPath string) (from string, err error) { + for _, name := range altConfigs { + cfg := filepath.Join(modRoot, name) + data, err := os.ReadFile(cfg) + if err == nil { + convert := modconv.Converters[name] + if convert == nil { + return "", nil + } + cfg = filepath.ToSlash(cfg) + err := modconv.ConvertLegacyConfig(modFile, cfg, data) + return name, err + } + } + return "", nil +} + +// addGoStmt adds a go directive to the go.mod file if it does not already include one. +// The 'go' version added, if any, is the latest version supported by this toolchain. +func addGoStmt() { + if modFile.Go != nil && modFile.Go.Version != "" { + return + } + tags := build.Default.ReleaseTags + version := tags[len(tags)-1] + if !strings.HasPrefix(version, "go") || !modfile.GoVersionRE.MatchString(version[2:]) { + base.Fatalf("go: unrecognized default version %q", version) + } + if err := modFile.AddGoStmt(version[2:]); err != nil { + base.Fatalf("go: internal error: %v", err) + } +} + +var altConfigs = []string{ + "Gopkg.lock", + + "GLOCKFILE", + "Godeps/Godeps.json", + "dependencies.tsv", + "glide.lock", + "vendor.conf", + "vendor.yml", + "vendor/manifest", + "vendor/vendor.json", + + ".git/config", +} + +func findModuleRoot(dir string) (root string) { + if dir == "" { + panic("dir not set") + } + dir = filepath.Clean(dir) + + // Look for enclosing go.mod. + for { + if fi, err := fsys.Stat(filepath.Join(dir, "go.mod")); err == nil && !fi.IsDir() { + return dir + } + d := filepath.Dir(dir) + if d == dir { + break + } + dir = d + } + return "" +} + +func findAltConfig(dir string) (root, name string) { + if dir == "" { + panic("dir not set") + } + dir = filepath.Clean(dir) + if rel := search.InDir(dir, cfg.BuildContext.GOROOT); rel != "" { + // Don't suggest creating a module from $GOROOT/.git/config + // or a config file found in any parent of $GOROOT (see #34191). + return "", "" + } + for { + for _, name := range altConfigs { + if fi, err := fsys.Stat(filepath.Join(dir, name)); err == nil && !fi.IsDir() { + return dir, name + } + } + d := filepath.Dir(dir) + if d == dir { + break + } + dir = d + } + return "", "" +} + +func findModulePath(dir string) (string, error) { + // TODO(bcmills): once we have located a plausible module path, we should + // query version control (if available) to verify that it matches the major + // version of the most recent tag. + // See https://golang.org/issue/29433, https://golang.org/issue/27009, and + // https://golang.org/issue/31549. + + // Cast about for import comments, + // first in top-level directory, then in subdirectories. + list, _ := os.ReadDir(dir) + for _, info := range list { + if info.Type().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, _ := os.ReadDir(filepath.Join(dir, info1.Name())) + for _, info2 := range files { + if info2.Type().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, _ := os.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, _ = os.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. + var badPathErr error + for _, gpdir := range filepath.SplitList(cfg.BuildContext.GOPATH) { + if gpdir == "" { + continue + } + if rel := search.InDir(dir, filepath.Join(gpdir, "src")); rel != "" && rel != "." { + path := filepath.ToSlash(rel) + // TODO(matloob): replace this with module.CheckImportPath + // once it's been laxened. + // Only checkModulePathLax here. There are some unpublishable + // module names that are compatible with checkModulePathLax + // but they already work in GOPATH so don't break users + // trying to do a build with modules. gorelease will alert users + // publishing their modules to fix their paths. + if err := checkModulePathLax(path); err != nil { + badPathErr = err + break + } + return path, nil + } + } + + reason := "outside GOPATH, module path must be specified" + if badPathErr != nil { + // return a different error message if the module was in GOPATH, but + // the module path determined above would be an invalid path. + reason = fmt.Sprintf("bad module path inferred from directory in GOPATH: %v", badPathErr) + } + msg := `cannot determine module path for source directory %s (%s) + +Example usage: + 'go mod init example.com/m' to initialize a v0 or v1 module + 'go mod init example.com/m/v2' to initialize a v2 module + +Run 'go help mod init' for more information. +` + return "", fmt.Errorf(msg, dir, reason) +} + +var ( + importCommentRE = lazyregexp.New(`(?m)^package[ \t]+[^ \t\r\n/]+[ \t]+//[ \t]+import[ \t]+(\"[^"]+\")[ \t]*\r?\n`) +) + +func findImportComment(file string) string { + data, err := os.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 additional dependencies of Target, +// as will be written to go.mod. +func MinReqs() mvs.Reqs { + retain := append([]string{}, additionalExplicitRequirements...) + for _, m := range buildList[1:] { + _, explicit := index.require[m] + if explicit || loaded.direct[m.Path] { + retain = append(retain, m.Path) + } + } + sort.Strings(retain) + str.Uniq(&retain) + min, err := mvs.Req(Target, retain, &mvsReqs{buildList: buildList}) + 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 we aren't in a module, we don't have anywhere to write a go.mod file. + if modRoot == "" { + return + } + + if cfg.BuildMod != "readonly" { + addGoStmt() + } + + 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) + } + modFile.Cleanup() + + dirty := index.modFileIsDirty(modFile) + if dirty && cfg.BuildMod == "readonly" { + // If we're about to fail due to -mod=readonly, + // prefer to report a dirty go.mod over a dirty go.sum + if cfg.BuildModExplicit { + base.Fatalf("go: updates to go.mod needed, disabled by -mod=readonly") + } else if cfg.BuildModReason != "" { + base.Fatalf("go: updates to go.mod needed, disabled by -mod=readonly\n\t(%s)", cfg.BuildModReason) + } else { + base.Fatalf("go: updates to go.mod needed; to update it:\n\tgo mod tidy") + } + } + + if !dirty && cfg.CmdName != "mod tidy" { + // The go.mod file has the same semantic content that it had before + // (but not necessarily the same exact bytes). + // Don't write go.mod, but write go.sum in case we added or trimmed sums. + // 'go mod init' shouldn't write go.sum, since it will be incomplete. + if cfg.CmdName != "mod init" { + modfetch.WriteGoSum(keepSums(true)) + } + return + } + + new, err := modFile.Format() + if err != nil { + base.Fatalf("go: %v", err) + } + defer func() { + // At this point we have determined to make the go.mod file on disk equal to new. + index = indexModFile(new, modFile, false) + + // Update go.sum after releasing the side lock and refreshing the index. + // 'go mod init' shouldn't write go.sum, since it will be incomplete. + if cfg.CmdName != "mod init" { + modfetch.WriteGoSum(keepSums(true)) + } + }() + + // Make a best-effort attempt to acquire the side lock, only to exclude + // previous versions of the 'go' command from making simultaneous edits. + if unlock, err := modfetch.SideLock(); err == nil { + defer unlock() + } + + errNoChange := errors.New("no update needed") + + err = lockedfile.Transform(ModFilePath(), func(old []byte) ([]byte, error) { + if bytes.Equal(old, new) { + // The go.mod file is already equal to new, possibly as the result of some + // other process. + return nil, errNoChange + } + + if index != nil && !bytes.Equal(old, index.data) { + // The contents of the go.mod file have changed. In theory we could add all + // of the new modules to the build list, recompute, and check whether any + // module in *our* build list got bumped to a different version, but that's + // a lot of work for marginal benefit. Instead, fail the command: if users + // want to run concurrent commands, they need to start with a complete, + // consistent module definition. + return nil, fmt.Errorf("existing contents have changed since last read") + } + + return new, nil + }) + + if err != nil && err != errNoChange { + base.Fatalf("go: updating go.mod: %v", err) + } +} + +// keepSums returns a set of module sums to preserve in go.sum. The set +// includes entries for all modules used to load packages (according to +// the last load function such as LoadPackages or ImportFromFiles). +// It also contains entries for go.mod files needed for MVS (the version +// of these entries ends with "/go.mod"). +// +// If keepBuildListZips is true, the set also includes sums for zip files for +// all modules in the build list with replacements applied. 'go get' and +// 'go mod download' may add sums to this set when adding a requirement on a +// module without a root package or when downloading a direct or indirect +// dependency. +func keepSums(keepBuildListZips bool) map[module.Version]bool { + // Re-derive the build list using the current list of direct requirements. + // Keep the sum for the go.mod of each visited module version (or its + // replacement). + modkey := func(m module.Version) module.Version { + return module.Version{Path: m.Path, Version: m.Version + "/go.mod"} + } + keep := make(map[module.Version]bool) + var mu sync.Mutex + reqs := &keepSumReqs{ + Reqs: &mvsReqs{buildList: buildList}, + visit: func(m module.Version) { + // If we build using a replacement module, keep the sum for the replacement, + // since that's the code we'll actually use during a build. + mu.Lock() + r := Replacement(m) + if r.Path == "" { + keep[modkey(m)] = true + } else { + keep[modkey(r)] = true + } + mu.Unlock() + }, + } + buildList, err := mvs.BuildList(Target, reqs) + if err != nil { + panic(fmt.Sprintf("unexpected error reloading build list: %v", err)) + } + + actualMods := make(map[string]module.Version) + for _, m := range buildList[1:] { + if r := Replacement(m); r.Path != "" { + actualMods[m.Path] = r + } else { + actualMods[m.Path] = m + } + } + + // Add entries for modules in the build list with paths that are prefixes of + // paths of loaded packages. We need to retain sums for modules needed to + // report ambiguous import errors. We use our re-derived build list, + // since the global build list may have been tidied. + if loaded != nil { + for _, pkg := range loaded.pkgs { + if pkg.testOf != nil || pkg.inStd || module.CheckImportPath(pkg.path) != nil { + continue + } + for prefix := pkg.path; prefix != "."; prefix = path.Dir(prefix) { + if m, ok := actualMods[prefix]; ok { + keep[m] = true + } + } + } + } + + // Add entries for the zip of each module in the build list. + // We might not need all of these (tidy does not add them), but they may be + // added by a specific 'go get' or 'go mod download' command to resolve + // missing import sum errors. + if keepBuildListZips { + for _, m := range actualMods { + keep[m] = true + } + } + + return keep +} + +// keepSumReqs embeds another Reqs implementation. The Required method +// calls visit for each version in the module graph. +type keepSumReqs struct { + mvs.Reqs + visit func(module.Version) +} + +func (r *keepSumReqs) Required(m module.Version) ([]module.Version, error) { + r.visit(m) + return r.Reqs.Required(m) +} + +func TrimGoSum() { + // Don't retain sums for the zip file of every module in the build list. + // We may not need them all to build the main module's packages. + keepBuildListZips := false + modfetch.TrimGoSum(keepSums(keepBuildListZips)) +} diff --git a/src/cmd/go/internal/modload/list.go b/src/cmd/go/internal/modload/list.go new file mode 100644 index 0000000..7b1aa7f --- /dev/null +++ b/src/cmd/go/internal/modload/list.go @@ -0,0 +1,191 @@ +// 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 ( + "context" + "errors" + "fmt" + "os" + "runtime" + "strings" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/modinfo" + "cmd/go/internal/search" + + "golang.org/x/mod/module" +) + +func ListModules(ctx context.Context, args []string, listU, listVersions, listRetracted bool) []*modinfo.ModulePublic { + mods := listModules(ctx, args, listVersions, listRetracted) + + type token struct{} + sem := make(chan token, runtime.GOMAXPROCS(0)) + if listU || listVersions || listRetracted { + for _, m := range mods { + add := func(m *modinfo.ModulePublic) { + sem <- token{} + go func() { + if listU { + addUpdate(ctx, m) + } + if listVersions { + addVersions(ctx, m, listRetracted) + } + if listRetracted || listU { + addRetraction(ctx, m) + } + <-sem + }() + } + + add(m) + if m.Replace != nil { + add(m.Replace) + } + } + } + // Fill semaphore channel to wait for all tasks to finish. + for n := cap(sem); n > 0; n-- { + sem <- token{} + } + + return mods +} + +func listModules(ctx context.Context, args []string, listVersions, listRetracted bool) []*modinfo.ModulePublic { + LoadAllModules(ctx) + if len(args) == 0 { + return []*modinfo.ModulePublic{moduleInfo(ctx, buildList[0], true, listRetracted)} + } + + 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 !HasModRoot() && (arg == "all" || strings.Contains(arg, "...")) { + base.Fatalf("go: cannot match %q: %v", arg, ErrNoModRoot) + } + if i := strings.Index(arg, "@"); i >= 0 { + path := arg[:i] + vers := arg[i+1:] + var current string + for _, m := range buildList { + if m.Path == path { + current = m.Version + break + } + } + + allowed := CheckAllowed + if IsRevisionQuery(vers) || listRetracted { + // Allow excluded and retracted versions if the user asked for a + // specific revision or used 'go list -retracted'. + allowed = nil + } + info, err := Query(ctx, path, vers, current, allowed) + if err != nil { + mods = append(mods, &modinfo.ModulePublic{ + Path: path, + Version: vers, + Error: modinfoError(path, vers, err), + }) + continue + } + mod := moduleInfo(ctx, module.Version{Path: path, Version: info.Version}, false, listRetracted) + mods = append(mods, mod) + 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 i == 0 && !HasModRoot() { + // The root module doesn't actually exist: omit it. + continue + } + if match(m.Path) { + matched = true + if !matchedBuildList[i] { + matchedBuildList[i] = true + mods = append(mods, moduleInfo(ctx, m, true, listRetracted)) + } + } + } + if !matched { + if literal { + if listVersions { + // Don't make the user provide an explicit '@latest' when they're + // explicitly asking what the available versions are. + // Instead, resolve the module, even if it isn't an existing dependency. + info, err := Query(ctx, arg, "latest", "", nil) + if err == nil { + mod := moduleInfo(ctx, module.Version{Path: arg, Version: info.Version}, false, listRetracted) + mods = append(mods, mod) + } else { + mods = append(mods, &modinfo.ModulePublic{ + Path: arg, + Error: modinfoError(arg, "", err), + }) + } + continue + } + if cfg.BuildMod == "vendor" { + // In vendor mode, we can't determine whether a missing module is “a + // known dependency” because the module graph is incomplete. + // Give a more explicit error message. + mods = append(mods, &modinfo.ModulePublic{ + Path: arg, + Error: modinfoError(arg, "", errors.New("can't resolve module using the vendor directory\n\t(Use -mod=mod or -mod=readonly to bypass.)")), + }) + } else { + mods = append(mods, &modinfo.ModulePublic{ + Path: arg, + Error: modinfoError(arg, "", errors.New("not a known dependency")), + }) + } + } else { + fmt.Fprintf(os.Stderr, "warning: pattern %q matched no module dependencies\n", arg) + } + } + } + + return mods +} + +// modinfoError wraps an error to create an error message in +// modinfo.ModuleError with minimal redundancy. +func modinfoError(path, vers string, err error) *modinfo.ModuleError { + var nerr *NoMatchingVersionError + var merr *module.ModuleError + if errors.As(err, &nerr) { + // NoMatchingVersionError contains the query, so we don't mention the + // query again in ModuleError. + err = &module.ModuleError{Path: path, Err: err} + } else if !errors.As(err, &merr) { + // If the error does not contain path and version, wrap it in a + // module.ModuleError. + err = &module.ModuleError{Path: path, Version: vers, Err: err} + } + + return &modinfo.ModuleError{Err: err.Error()} +} diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go new file mode 100644 index 0000000..154fc3c --- /dev/null +++ b/src/cmd/go/internal/modload/load.go @@ -0,0 +1,1364 @@ +// 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 + +// This file contains the module-mode package loader, as well as some accessory +// functions pertaining to the package import graph. +// +// There are two exported entry points into package loading — LoadPackages and +// ImportFromFiles — both implemented in terms of loadFromRoots, which itself +// manipulates an instance of the loader struct. +// +// 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(#40775): It might be nice to make the loader take and return +// a buildList rather than hard-coding use of the global. +// +// Loading is an iterative process. On each iteration, we try to load the +// requested packages and their transitive imports, then try to resolve modules +// for any imported packages that are still missing. +// +// The first step of each iteration identifies a set of “root” packages. +// Normally the root packages are exactly those matching the named pattern +// arguments. However, for the "all" meta-pattern, the final set of packages is +// computed from the package import graph, and therefore cannot be an initial +// input to loading that graph. Instead, the root packages for the "all" pattern +// are those contained in the main module, and allPatternIsRoot parameter to the +// loader instructs it to dynamically expand those roots to the full "all" +// pattern as loading progresses. +// +// The pkgInAll flag on each loadPkg instance tracks whether that +// package is known to match the "all" meta-pattern. +// A package matches the "all" pattern if: +// - it is in the main module, or +// - it is imported by any test in the main module, or +// - it is imported by another package in "all", or +// - the main module specifies a go version ≤ 1.15, and the package is imported +// by a *test of* another package in "all". +// +// When we implement lazy loading, we will record the modules providing packages +// in "all" even when we are only loading individual packages, so we set the +// pkgInAll flag regardless of the whether the "all" pattern is a root. +// (This is necessary to maintain the “import invariant” described in +// https://golang.org/design/36460-lazy-module-loading.) +// +// Because "go mod vendor" prunes out the tests of vendored packages, the +// behavior of the "all" pattern with -mod=vendor in Go 1.11–1.15 is the same +// as the "all" pattern (regardless of the -mod flag) in 1.16+. +// The allClosesOverTests parameter to the loader indicates whether the "all" +// pattern should close over tests (as in Go 1.11–1.15) or stop at only those +// packages transitively imported by the packages and tests in the main module +// ("all" in Go 1.16+ and "go mod vendor" in Go 1.11+). +// +// Note that it is possible for a loaded package NOT to be in "all" even when we +// are loading the "all" pattern. For example, packages that are transitive +// dependencies of other roots named on the command line must be loaded, but are +// not in "all". (The mod_notall test illustrates this behavior.) +// Similarly, if the LoadTests flag is set but the "all" pattern does not close +// over test dependencies, then when we load the test of a package that is in +// "all" but outside the main module, the dependencies of that test will not +// necessarily themselves be in "all". (That configuration does not arise in Go +// 1.11–1.15, but it will be possible in Go 1.16+.) +// +// Loading proceeds from the roots, using a parallel work-queue with a limit on +// the amount of active work (to avoid saturating disks, CPU cores, and/or +// network connections). Each package is added to the queue the first time it is +// imported by another package. When we have finished identifying the imports of +// a package, we add the test for that package if it is needed. A test may be +// needed if: +// - the package matches a root pattern and tests of the roots were requested, or +// - the package is in the main module and the "all" pattern is requested +// (because the "all" pattern includes the dependencies of tests in the main +// module), or +// - the package is in "all" and the definition of "all" we are using includes +// dependencies of tests (as is the case in Go ≤1.15). +// +// After all available packages have been loaded, we examine the results to +// identify any requested or imported packages that are still missing, and if +// so, which modules we could add to the module graph in order to make the +// missing packages available. We add those to the module graph and iterate, +// until either all packages resolve successfully or we cannot identify any +// module that would resolve any remaining missing package. +// +// If the main module is “tidy” (that is, if "go mod tidy" is a no-op for it) +// and all requested packages are in "all", then loading completes in a single +// iteration. +// TODO(bcmills): We should also be able to load in a single iteration if the +// requested packages all come from modules that are themselves tidy, regardless +// of whether those packages are in "all". Today, that requires two iterations +// if those packages are not found in existing dependencies of the main module. + +import ( + "bytes" + "context" + "errors" + "fmt" + "go/build" + "io/fs" + "os" + "path" + pathpkg "path" + "path/filepath" + "reflect" + "runtime" + "sort" + "strings" + "sync" + "sync/atomic" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/fsys" + "cmd/go/internal/imports" + "cmd/go/internal/modfetch" + "cmd/go/internal/mvs" + "cmd/go/internal/par" + "cmd/go/internal/search" + "cmd/go/internal/str" + + "golang.org/x/mod/module" +) + +// loaded is the most recently-used package loader. +// It holds details about individual packages. +var loaded *loader + +// PackageOpts control the behavior of the LoadPackages function. +type PackageOpts struct { + // Tags are the build tags in effect (as interpreted by the + // cmd/go/internal/imports package). + // If nil, treated as equivalent to imports.Tags(). + Tags map[string]bool + + // ResolveMissingImports indicates that we should attempt to add module + // dependencies as needed to resolve imports of packages that are not found. + // + // For commands that support the -mod flag, resolving imports may still fail + // if the flag is set to "readonly" (the default) or "vendor". + ResolveMissingImports bool + + // AllowPackage, if non-nil, is called after identifying the module providing + // each package. If AllowPackage returns a non-nil error, that error is set + // for the package, and the imports and test of that package will not be + // loaded. + // + // AllowPackage may be invoked concurrently by multiple goroutines, + // and may be invoked multiple times for a given package path. + AllowPackage func(ctx context.Context, path string, mod module.Version) error + + // LoadTests loads the test dependencies of each package matching a requested + // pattern. If ResolveMissingImports is also true, test dependencies will be + // resolved if missing. + LoadTests bool + + // UseVendorAll causes the "all" package pattern to be interpreted as if + // running "go mod vendor" (or building with "-mod=vendor"). + // + // This is a no-op for modules that declare 'go 1.16' or higher, for which this + // is the default (and only) interpretation of the "all" pattern in module mode. + UseVendorAll bool + + // AllowErrors indicates that LoadPackages should not terminate the process if + // an error occurs. + AllowErrors bool + + // SilenceErrors indicates that LoadPackages should not print errors + // that occur while loading packages. SilenceErrors implies AllowErrors. + SilenceErrors bool + + // SilenceMissingStdImports indicates that LoadPackages should not print + // errors or terminate the process if an imported package is missing, and the + // import path looks like it might be in the standard library (perhaps in a + // future version). + SilenceMissingStdImports bool + + // SilenceUnmatchedWarnings suppresses the warnings normally emitted for + // patterns that did not match any packages. + SilenceUnmatchedWarnings bool +} + +// LoadPackages identifies the set of packages matching the given patterns and +// loads the packages in the import graph rooted at that set. +func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (matches []*search.Match, loadedPackages []string) { + LoadModFile(ctx) + if opts.Tags == nil { + opts.Tags = imports.Tags() + } + + patterns = search.CleanPatterns(patterns) + matches = make([]*search.Match, 0, len(patterns)) + allPatternIsRoot := false + for _, pattern := range patterns { + matches = append(matches, search.NewMatch(pattern)) + if pattern == "all" { + allPatternIsRoot = true + } + } + + updateMatches := func(ld *loader) { + for _, m := range matches { + switch { + case m.IsLocal(): + // Evaluate list of file system directories on first iteration. + if m.Dirs == nil { + matchLocalDirs(m) + } + + // 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 = m.Pkgs[:0] + for _, dir := range m.Dirs { + pkg, err := resolveLocalPackage(dir) + if err != nil { + if !m.IsLiteral() && (err == errPkgIsBuiltin || err == errPkgIsGorootSrc) { + continue // Don't include "builtin" or GOROOT/src in wildcard patterns. + } + + // If we're outside of a module, ensure that the failure mode + // indicates that. + ModRoot() + + if ld != nil { + m.AddError(err) + } + continue + } + m.Pkgs = append(m.Pkgs, pkg) + } + + case m.IsLiteral(): + m.Pkgs = []string{m.Pattern()} + + case strings.Contains(m.Pattern(), "..."): + m.Errs = m.Errs[:0] + matchPackages(ctx, m, opts.Tags, includeStd, buildList) + + case m.Pattern() == "all": + if ld == nil { + // The initial roots are the packages in the main module. + // loadFromRoots will expand that to "all". + m.Errs = m.Errs[:0] + matchPackages(ctx, m, opts.Tags, omitStd, []module.Version{Target}) + } else { + // Starting with the packages in the main module, + // enumerate the full list of "all". + m.Pkgs = ld.computePatternAll() + } + + case m.Pattern() == "std" || m.Pattern() == "cmd": + if m.Pkgs == nil { + m.MatchPackages() // Locate the packages within GOROOT/src. + } + + default: + panic(fmt.Sprintf("internal error: modload missing case for pattern %s", m.Pattern())) + } + } + } + + loaded = loadFromRoots(loaderParams{ + PackageOpts: opts, + + allClosesOverTests: index.allPatternClosesOverTests() && !opts.UseVendorAll, + allPatternIsRoot: allPatternIsRoot, + + listRoots: func() (roots []string) { + updateMatches(nil) + for _, m := range matches { + roots = append(roots, m.Pkgs...) + } + return roots + }, + }) + + // One last pass to finalize wildcards. + updateMatches(loaded) + + // Report errors, if any. + checkMultiplePaths() + for _, pkg := range loaded.pkgs { + if pkg.err != nil { + if sumErr := (*ImportMissingSumError)(nil); errors.As(pkg.err, &sumErr) { + if importer := pkg.stack; importer != nil { + sumErr.importer = importer.path + sumErr.importerVersion = importer.mod.Version + sumErr.importerIsTest = importer.testOf != nil + } + } + silence := opts.SilenceErrors + if stdErr := (*ImportMissingError)(nil); errors.As(pkg.err, &stdErr) && + stdErr.isStd && opts.SilenceMissingStdImports { + silence = true + } + + if !silence { + if opts.AllowErrors { + fmt.Fprintf(os.Stderr, "%s: %v\n", pkg.stackText(), pkg.err) + } else { + base.Errorf("%s: %v", pkg.stackText(), pkg.err) + } + } + } + if !pkg.isTest() { + loadedPackages = append(loadedPackages, pkg.path) + } + } + if !opts.SilenceErrors { + // Also list errors in matching patterns (such as directory permission + // errors for wildcard patterns). + for _, match := range matches { + for _, err := range match.Errs { + if opts.AllowErrors { + fmt.Fprintf(os.Stderr, "%v\n", err) + } else { + base.Errorf("%v", err) + } + } + } + } + base.ExitIfErrors() + + if !opts.SilenceUnmatchedWarnings { + search.WarnUnmatched(matches) + } + + // Success! Update go.mod (if needed) and return the results. + WriteGoMod() + sort.Strings(loadedPackages) + return matches, loadedPackages +} + +// matchLocalDirs is like m.MatchDirs, but tries to avoid scanning directories +// outside of the standard library and active modules. +func matchLocalDirs(m *search.Match) { + if !m.IsLocal() { + panic(fmt.Sprintf("internal error: resolveLocalDirs on non-local pattern %s", m.Pattern())) + } + + if i := strings.Index(m.Pattern(), "..."); i >= 0 { + // The pattern is local, but it is a wildcard. Its packages will + // only resolve to paths if they are inside of the standard + // library, the main module, or some dependency of the main + // module. Verify that before we walk the filesystem: a filesystem + // walk in a directory like /var or /etc can be very expensive! + dir := filepath.Dir(filepath.Clean(m.Pattern()[:i+3])) + absDir := dir + if !filepath.IsAbs(dir) { + absDir = filepath.Join(base.Cwd, dir) + } + if search.InDir(absDir, cfg.GOROOTsrc) == "" && search.InDir(absDir, ModRoot()) == "" && pathInModuleCache(absDir) == "" { + m.Dirs = []string{} + m.AddError(fmt.Errorf("directory prefix %s outside available modules", base.ShortPath(absDir))) + return + } + } + + m.MatchDirs() +} + +// resolveLocalPackage resolves a filesystem path to a package path. +func resolveLocalPackage(dir string) (string, error) { + var absDir string + if filepath.IsAbs(dir) { + absDir = filepath.Clean(dir) + } else { + absDir = filepath.Join(base.Cwd, dir) + } + + bp, err := cfg.BuildContext.ImportDir(absDir, 0) + if err != nil && (bp == nil || len(bp.IgnoredGoFiles) == 0) { + // golang.org/issue/32917: We should resolve a relative path to a + // package path only if the relative path actually contains the code + // for that package. + // + // If the named directory does not exist or contains no Go files, + // the package does not exist. + // Other errors may affect package loading, but not resolution. + if _, err := fsys.Stat(absDir); err != nil { + if os.IsNotExist(err) { + // Canonicalize OS-specific errors to errDirectoryNotFound so that error + // messages will be easier for users to search for. + return "", &fs.PathError{Op: "stat", Path: absDir, Err: errDirectoryNotFound} + } + return "", err + } + if _, noGo := err.(*build.NoGoError); noGo { + // A directory that does not contain any Go source files — even ignored + // ones! — is not a Go package, and we can't resolve it to a package + // path because that path could plausibly be provided by some other + // module. + // + // Any other error indicates that the package “exists” (at least in the + // sense that it cannot exist in any other module), but has some other + // problem (such as a syntax error). + return "", err + } + } + + if modRoot != "" && absDir == modRoot { + if absDir == cfg.GOROOTsrc { + return "", errPkgIsGorootSrc + } + return targetPrefix, nil + } + + // 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 modRoot != "" && strings.HasPrefix(absDir, modRoot+string(filepath.Separator)) && !strings.Contains(absDir[len(modRoot):], "@") { + suffix := filepath.ToSlash(absDir[len(modRoot):]) + if strings.HasPrefix(suffix, "/vendor/") { + if cfg.BuildMod != "vendor" { + return "", fmt.Errorf("without -mod=vendor, directory %s has no package path", absDir) + } + + readVendorList() + pkg := strings.TrimPrefix(suffix, "/vendor/") + if _, ok := vendorPkgModule[pkg]; !ok { + return "", fmt.Errorf("directory %s is not a package listed in vendor/modules.txt", absDir) + } + return pkg, nil + } + + if targetPrefix == "" { + pkg := strings.TrimPrefix(suffix, "/") + if pkg == "builtin" { + // "builtin" is a pseudo-package with a real source file. + // It's not included in "std", so it shouldn't resolve from "." + // within module "std" either. + return "", errPkgIsBuiltin + } + return pkg, nil + } + + pkg := targetPrefix + suffix + if _, ok, err := dirInModule(pkg, targetPrefix, modRoot, true); err != nil { + return "", err + } else if !ok { + return "", &PackageNotInModuleError{Mod: Target, Pattern: pkg} + } + return pkg, nil + } + + if sub := search.InDir(absDir, cfg.GOROOTsrc); sub != "" && sub != "." && !strings.Contains(sub, "@") { + pkg := filepath.ToSlash(sub) + if pkg == "builtin" { + return "", errPkgIsBuiltin + } + return pkg, nil + } + + pkg := pathInModuleCache(absDir) + if pkg == "" { + return "", fmt.Errorf("directory %s outside available modules", base.ShortPath(absDir)) + } + return pkg, nil +} + +var ( + errDirectoryNotFound = errors.New("directory not found") + errPkgIsGorootSrc = errors.New("GOROOT/src is not an importable package") + errPkgIsBuiltin = errors.New(`"builtin" is a pseudo-package, not an importable package`) +) + +// 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 { + tryMod := func(m module.Version) (string, bool) { + var root string + var err error + if repl := Replacement(m); repl.Path != "" && repl.Version == "" { + root = repl.Path + if !filepath.IsAbs(root) { + root = filepath.Join(ModRoot(), root) + } + } else if repl.Path != "" { + root, err = modfetch.DownloadDir(repl) + } else { + root, err = modfetch.DownloadDir(m) + } + if err != nil { + return "", false + } + + sub := search.InDir(dir, root) + if sub == "" { + return "", false + } + sub = filepath.ToSlash(sub) + if strings.Contains(sub, "/vendor/") || strings.HasPrefix(sub, "vendor/") || strings.Contains(sub, "@") { + return "", false + } + + return path.Join(m.Path, filepath.ToSlash(sub)), true + } + + for _, m := range buildList[1:] { + if importPath, ok := tryMod(m); ok { + // checkMultiplePaths ensures that a module can be used for at most one + // requirement, so this must be it. + return importPath + } + } + return "" +} + +// ImportFromFiles adds modules to the build list as needed +// to satisfy the imports in the named Go source files. +func ImportFromFiles(ctx context.Context, gofiles []string) { + LoadModFile(ctx) + + tags := imports.Tags() + imports, testImports, err := imports.ScanFiles(gofiles, tags) + if err != nil { + base.Fatalf("go: %v", err) + } + + loaded = loadFromRoots(loaderParams{ + PackageOpts: PackageOpts{ + Tags: tags, + ResolveMissingImports: true, + }, + allClosesOverTests: index.allPatternClosesOverTests(), + listRoots: func() (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 !HasModRoot() { + return "." + } + LoadModFile(context.TODO()) + + if !filepath.IsAbs(dir) { + dir = filepath.Join(base.Cwd, dir) + } else { + dir = filepath.Clean(dir) + } + + if dir == modRoot { + return targetPrefix + } + 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 targetPrefix + suffix + } + return "." +} + +// TargetPackages returns the list of packages in the target (top-level) module +// matching pattern, which may be relative to the working directory, under all +// build tag settings. +func TargetPackages(ctx context.Context, pattern string) *search.Match { + // TargetPackages is relative to the main module, so ensure that the main + // module is a thing that can contain packages. + LoadModFile(ctx) + ModRoot() + + m := search.NewMatch(pattern) + matchPackages(ctx, m, imports.AnyTags(), omitStd, []module.Version{Target}) + return m +} + +// 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 +} + +// PackageImports returns the imports for the package named by the import path. +// Test imports will be returned as well if tests were loaded for the package +// (i.e., if "all" was loaded or if LoadTests was set and the path was matched +// by a command line argument). PackageImports will return nil for +// unknown package paths. +func PackageImports(path string) (imports, testImports []string) { + pkg, ok := loaded.pkgCache.Get(path).(*loadPkg) + if !ok { + return nil, nil + } + imports = make([]string, len(pkg.imports)) + for i, p := range pkg.imports { + imports[i] = p.path + } + if pkg.test != nil { + testImports = make([]string, len(pkg.test.imports)) + for i, p := range pkg.test.imports { + testImports[i] = p.path + } + } + return imports, testImports +} + +// Lookup returns the source directory, import path, and any loading error for +// the package at path as imported from the package in parentDir. +// Lookup requires that one of the Load functions in this package has already +// been called. +func Lookup(parentPath string, parentIsStd bool, path string) (dir, realPath string, err error) { + if path == "" { + panic("Lookup called with empty package path") + } + + if parentIsStd { + path = loaded.stdVendor(parentPath, path) + } + 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. +type loader struct { + loaderParams + + work *par.Queue + + // reset on each iteration + roots []*loadPkg + pkgCache *par.Cache // package path (string) → *loadPkg + pkgs []*loadPkg // transitive closure of loaded packages and tests; populated in buildStacks + + // computed at end of iterations + direct map[string]bool // imported directly by main module +} + +// loaderParams configure the packages loaded by, and the properties reported +// by, a loader instance. +type loaderParams struct { + PackageOpts + + allClosesOverTests bool // Does the "all" pattern include the transitive closure of tests of packages in "all"? + allPatternIsRoot bool // Is the "all" pattern an additional root? + + listRoots func() []string +} + +func (ld *loader) reset() { + select { + case <-ld.work.Idle(): + default: + panic("loader.reset when not idle") + } + + ld.roots = nil + ld.pkgCache = new(par.Cache) + ld.pkgs = nil +} + +// A loadPkg records information about a single loaded package. +type loadPkg struct { + // Populated at construction time: + path string // import path + testOf *loadPkg + + // Populated at construction time and updated by (*loader).applyPkgFlags: + flags atomicLoadPkgFlags + + // Populated by (*loader).load: + mod module.Version // module providing package + dir string // directory containing source code + err error // error loading package + imports []*loadPkg // packages imported by this one + testImports []string // test-only imports, saved for use by pkg.test. + inStd bool + + // Populated by (*loader).pkgTest: + testOnce sync.Once + test *loadPkg + + // Populated by postprocessing in (*loader).buildStacks: + stack *loadPkg // package importing this one in minimal import stack for this pkg +} + +// loadPkgFlags is a set of flags tracking metadata about a package. +type loadPkgFlags int8 + +const ( + // pkgInAll indicates that the package is in the "all" package pattern, + // regardless of whether we are loading the "all" package pattern. + // + // When the pkgInAll flag and pkgImportsLoaded flags are both set, the caller + // who set the last of those flags must propagate the pkgInAll marking to all + // of the imports of the marked package. + // + // A test is marked with pkgInAll if that test would promote the packages it + // imports to be in "all" (such as when the test is itself within the main + // module, or when ld.allClosesOverTests is true). + pkgInAll loadPkgFlags = 1 << iota + + // pkgIsRoot indicates that the package matches one of the root package + // patterns requested by the caller. + // + // If LoadTests is set, then when pkgIsRoot and pkgImportsLoaded are both set, + // the caller who set the last of those flags must populate a test for the + // package (in the pkg.test field). + // + // If the "all" pattern is included as a root, then non-test packages in "all" + // are also roots (and must be marked pkgIsRoot). + pkgIsRoot + + // pkgImportsLoaded indicates that the imports and testImports fields of a + // loadPkg have been populated. + pkgImportsLoaded +) + +// has reports whether all of the flags in cond are set in f. +func (f loadPkgFlags) has(cond loadPkgFlags) bool { + return f&cond == cond +} + +// An atomicLoadPkgFlags stores a loadPkgFlags for which individual flags can be +// added atomically. +type atomicLoadPkgFlags struct { + bits int32 +} + +// update sets the given flags in af (in addition to any flags already set). +// +// update returns the previous flag state so that the caller may determine which +// flags were newly-set. +func (af *atomicLoadPkgFlags) update(flags loadPkgFlags) (old loadPkgFlags) { + for { + old := atomic.LoadInt32(&af.bits) + new := old | int32(flags) + if new == old || atomic.CompareAndSwapInt32(&af.bits, old, new) { + return loadPkgFlags(old) + } + } +} + +// has reports whether all of the flags in cond are set in af. +func (af *atomicLoadPkgFlags) has(cond loadPkgFlags) bool { + return loadPkgFlags(atomic.LoadInt32(&af.bits))&cond == cond +} + +// isTest reports whether pkg is a test of another package. +func (pkg *loadPkg) isTest() bool { + return pkg.testOf != nil +} + +var errMissing = errors.New("cannot find package") + +// loadFromRoots attempts to load the build graph needed to process a set of +// root packages and their dependencies. +// +// The set of root packages is returned by the params.listRoots function, and +// expanded to the full set of packages by tracing imports (and possibly tests) +// as needed. +func loadFromRoots(params loaderParams) *loader { + ld := &loader{ + loaderParams: params, + work: par.NewQueue(runtime.GOMAXPROCS(0)), + } + + var err error + reqs := &mvsReqs{buildList: buildList} + buildList, err = mvs.BuildList(Target, reqs) + if err != nil { + base.Fatalf("go: %v", err) + } + + addedModuleFor := make(map[string]bool) + for { + ld.reset() + + // Load the root packages and their imports. + // Note: the returned roots can change on each iteration, + // since the expansion of package patterns depends on the + // build list we're using. + inRoots := map[*loadPkg]bool{} + for _, path := range ld.listRoots() { + root := ld.pkg(path, pkgIsRoot) + if !inRoots[root] { + ld.roots = append(ld.roots, root) + inRoots[root] = true + } + } + + // ld.pkg adds imported packages to the work queue and calls applyPkgFlags, + // which adds tests (and test dependencies) as needed. + // + // When all of the work in the queue has completed, we'll know that the + // transitive closure of dependencies has been loaded. + <-ld.work.Idle() + + ld.buildStacks() + + if !ld.ResolveMissingImports || (!HasModRoot() && !allowMissingModuleImports) { + // We've loaded as much as we can without resolving missing imports. + break + } + modAddedBy := ld.resolveMissingImports(addedModuleFor) + if len(modAddedBy) == 0 { + break + } + + // Recompute buildList with all our additions. + reqs = &mvsReqs{buildList: buildList} + buildList, err = mvs.BuildList(Target, reqs) + if err != nil { + // If an error was found in a newly added module, report the package + // import stack instead of the module requirement stack. Packages + // are more descriptive. + if err, ok := err.(*mvs.BuildListError); ok { + if pkg := modAddedBy[err.Module()]; pkg != nil { + base.Fatalf("go: %s: %v", pkg.stackText(), err.Err) + } + } + 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 != "" && dep.mod.Path != Target.Path && index != nil { + _, explicit := index.require[dep.mod] + if allowWriteGoMod && cfg.BuildMod == "readonly" && !explicit { + // TODO(#40775): attach error to package instead of using + // base.Errorf. Ideally, 'go list' should not fail because of this, + // but today, LoadPackages calls WriteGoMod unconditionally, which + // would fail with a less clear message. + base.Errorf("go: %[1]s: package %[2]s imported from implicitly required module; to add missing requirements, run:\n\tgo get %[2]s@%[3]s", pkg.path, dep.path, dep.mod.Version) + } + ld.direct[dep.mod.Path] = true + } + } + } + } + base.ExitIfErrors() + + // If we didn't scan all of the imports from the main module, or didn't use + // imports.AnyTags, then we didn't necessarily load every package that + // contributes “direct” imports — so we can't safely mark existing + // dependencies as indirect-only. + // Conservatively mark those dependencies as direct. + if modFile != nil && (!ld.allPatternIsRoot || !reflect.DeepEqual(ld.Tags, imports.AnyTags())) { + for _, r := range modFile.Require { + if !r.Indirect { + ld.direct[r.Mod.Path] = true + } + } + } + + return ld +} + +// resolveMissingImports adds module dependencies to the global build list +// in order to resolve missing packages from pkgs. +// +// The newly-resolved packages are added to the addedModuleFor map, and +// resolveMissingImports returns a map from each newly-added module version to +// the first package for which that module was added. +func (ld *loader) resolveMissingImports(addedModuleFor map[string]bool) (modAddedBy map[module.Version]*loadPkg) { + var needPkgs []*loadPkg + for _, pkg := range ld.pkgs { + if pkg.err == nil { + continue + } + if pkg.isTest() { + // If we are missing a test, we are also missing its non-test version, and + // we should only add the missing import once. + continue + } + if !errors.As(pkg.err, new(*ImportMissingError)) { + // Leave other errors for Import or load.Packages to report. + continue + } + + needPkgs = append(needPkgs, pkg) + + pkg := pkg + ld.work.Add(func() { + pkg.mod, pkg.err = queryImport(context.TODO(), pkg.path) + }) + } + <-ld.work.Idle() + + modAddedBy = map[module.Version]*loadPkg{} + for _, pkg := range needPkgs { + if pkg.err != nil { + continue + } + + fmt.Fprintf(os.Stderr, "go: found %s in %s %s\n", pkg.path, pkg.mod.Path, pkg.mod.Version) + if addedModuleFor[pkg.path] { + // TODO(bcmills): This should only be an error if pkg.mod is the same + // version we already tried to add previously. + base.Fatalf("go: %s: looping trying to add package", pkg.stackText()) + } + if modAddedBy[pkg.mod] == nil { + modAddedBy[pkg.mod] = pkg + buildList = append(buildList, pkg.mod) + } + } + + return modAddedBy +} + +// pkg locates the *loadPkg for path, creating and queuing it for loading if +// needed, and updates its state to reflect the given flags. +// +// The imports of the returned *loadPkg will be loaded asynchronously in the +// ld.work queue, and its test (if requested) will also be populated once +// imports have been resolved. When ld.work goes idle, all transitive imports of +// the requested package (and its test, if requested) will have been loaded. +func (ld *loader) pkg(path string, flags loadPkgFlags) *loadPkg { + if flags.has(pkgImportsLoaded) { + panic("internal error: (*loader).pkg called with pkgImportsLoaded flag set") + } + + pkg := ld.pkgCache.Do(path, func() interface{} { + pkg := &loadPkg{ + path: path, + } + ld.applyPkgFlags(pkg, flags) + + ld.work.Add(func() { ld.load(pkg) }) + return pkg + }).(*loadPkg) + + ld.applyPkgFlags(pkg, flags) + return pkg +} + +// applyPkgFlags updates pkg.flags to set the given flags and propagate the +// (transitive) effects of those flags, possibly loading or enqueueing further +// packages as a result. +func (ld *loader) applyPkgFlags(pkg *loadPkg, flags loadPkgFlags) { + if flags == 0 { + return + } + + if flags.has(pkgInAll) && ld.allPatternIsRoot && !pkg.isTest() { + // This package matches a root pattern by virtue of being in "all". + flags |= pkgIsRoot + } + + old := pkg.flags.update(flags) + new := old | flags + if new == old || !new.has(pkgImportsLoaded) { + // We either didn't change the state of pkg, or we don't know anything about + // its dependencies yet. Either way, we can't usefully load its test or + // update its dependencies. + return + } + + if !pkg.isTest() { + // Check whether we should add (or update the flags for) a test for pkg. + // ld.pkgTest is idempotent and extra invocations are inexpensive, + // so it's ok if we call it more than is strictly necessary. + wantTest := false + switch { + case ld.allPatternIsRoot && pkg.mod == Target: + // We are loading the "all" pattern, which includes packages imported by + // tests in the main module. This package is in the main module, so we + // need to identify the imports of its test even if LoadTests is not set. + // + // (We will filter out the extra tests explicitly in computePatternAll.) + wantTest = true + + case ld.allPatternIsRoot && ld.allClosesOverTests && new.has(pkgInAll): + // This variant of the "all" pattern includes imports of tests of every + // package that is itself in "all", and pkg is in "all", so its test is + // also in "all" (as above). + wantTest = true + + case ld.LoadTests && new.has(pkgIsRoot): + // LoadTest explicitly requests tests of “the root packages”. + wantTest = true + } + + if wantTest { + var testFlags loadPkgFlags + if pkg.mod == Target || (ld.allClosesOverTests && new.has(pkgInAll)) { + // Tests of packages in the main module are in "all", in the sense that + // they cause the packages they import to also be in "all". So are tests + // of packages in "all" if "all" closes over test dependencies. + testFlags |= pkgInAll + } + ld.pkgTest(pkg, testFlags) + } + } + + if new.has(pkgInAll) && !old.has(pkgInAll|pkgImportsLoaded) { + // We have just marked pkg with pkgInAll, or we have just loaded its + // imports, or both. Now is the time to propagate pkgInAll to the imports. + for _, dep := range pkg.imports { + ld.applyPkgFlags(dep, pkgInAll) + } + } +} + +// load loads an individual package. +func (ld *loader) load(pkg *loadPkg) { + if strings.Contains(pkg.path, "@") { + // Leave for error during load. + return + } + if build.IsLocalImport(pkg.path) || filepath.IsAbs(pkg.path) { + // Leave for error during load. + // (Module mode does not allow local imports.) + return + } + + if search.IsMetaPackage(pkg.path) { + pkg.err = &invalidImportError{ + importPath: pkg.path, + err: fmt.Errorf("%q is not an importable package; see 'go help packages'", pkg.path), + } + return + } + + pkg.mod, pkg.dir, pkg.err = importFromBuildList(context.TODO(), pkg.path, buildList) + if pkg.dir == "" { + return + } + if pkg.mod == Target { + // Go ahead and mark pkg as in "all". This provides the invariant that a + // package that is *only* imported by other packages in "all" is always + // marked as such before loading its imports. + // + // We don't actually rely on that invariant at the moment, but it may + // improve efficiency somewhat and makes the behavior a bit easier to reason + // about (by reducing churn on the flag bits of dependencies), and costs + // essentially nothing (these atomic flag ops are essentially free compared + // to scanning source code for imports). + ld.applyPkgFlags(pkg, pkgInAll) + } + if ld.AllowPackage != nil { + if err := ld.AllowPackage(context.TODO(), pkg.path, pkg.mod); err != nil { + pkg.err = err + } + } + + pkg.inStd = (search.IsStandardImportPath(pkg.path) && search.InDir(pkg.dir, cfg.GOROOTsrc) != "") + + var imports, testImports []string + + if cfg.BuildContext.Compiler == "gccgo" && pkg.inStd { + // We can't scan standard packages for gccgo. + } else { + var err error + imports, testImports, err = scanDir(pkg.dir, ld.Tags) + if err != nil { + pkg.err = err + return + } + } + + pkg.imports = make([]*loadPkg, 0, len(imports)) + var importFlags loadPkgFlags + if pkg.flags.has(pkgInAll) { + importFlags = pkgInAll + } + for _, path := range imports { + if pkg.inStd { + // Imports from packages in "std" and "cmd" should resolve using + // GOROOT/src/vendor even when "std" is not the main module. + path = ld.stdVendor(pkg.path, path) + } + pkg.imports = append(pkg.imports, ld.pkg(path, importFlags)) + } + pkg.testImports = testImports + + ld.applyPkgFlags(pkg, pkgImportsLoaded) +} + +// pkgTest locates the test of pkg, creating it if needed, and updates its state +// to reflect the given flags. +// +// pkgTest requires that the imports of pkg have already been loaded (flagged +// with pkgImportsLoaded). +func (ld *loader) pkgTest(pkg *loadPkg, testFlags loadPkgFlags) *loadPkg { + if pkg.isTest() { + panic("pkgTest called on a test package") + } + + createdTest := false + pkg.testOnce.Do(func() { + pkg.test = &loadPkg{ + path: pkg.path, + testOf: pkg, + mod: pkg.mod, + dir: pkg.dir, + err: pkg.err, + inStd: pkg.inStd, + } + ld.applyPkgFlags(pkg.test, testFlags) + createdTest = true + }) + + test := pkg.test + if createdTest { + test.imports = make([]*loadPkg, 0, len(pkg.testImports)) + var importFlags loadPkgFlags + if test.flags.has(pkgInAll) { + importFlags = pkgInAll + } + for _, path := range pkg.testImports { + if pkg.inStd { + path = ld.stdVendor(test.path, path) + } + test.imports = append(test.imports, ld.pkg(path, importFlags)) + } + pkg.testImports = nil + ld.applyPkgFlags(test, pkgImportsLoaded) + } else { + ld.applyPkgFlags(test, testFlags) + } + + return test +} + +// stdVendor returns the canonical import path for the package with the given +// path when imported from the standard-library package at parentPath. +func (ld *loader) stdVendor(parentPath, path string) string { + if search.IsStandardImportPath(path) { + return path + } + + if str.HasPathPrefix(parentPath, "cmd") { + if Target.Path != "cmd" { + vendorPath := pathpkg.Join("cmd", "vendor", path) + if _, err := os.Stat(filepath.Join(cfg.GOROOTsrc, filepath.FromSlash(vendorPath))); err == nil { + return vendorPath + } + } + } else if Target.Path != "std" || str.HasPathPrefix(parentPath, "vendor") { + // If we are outside of the 'std' module, resolve imports from within 'std' + // to the vendor directory. + // + // Do the same for importers beginning with the prefix 'vendor/' even if we + // are *inside* of the 'std' module: the 'vendor/' packages that resolve + // globally from GOROOT/src/vendor (and are listed as part of 'go list std') + // are distinct from the real module dependencies, and cannot import + // internal packages from the real module. + // + // (Note that although the 'vendor/' packages match the 'std' *package* + // pattern, they are not part of the std *module*, and do not affect + // 'go mod tidy' and similar module commands when working within std.) + vendorPath := pathpkg.Join("vendor", path) + if _, err := os.Stat(filepath.Join(cfg.GOROOTsrc, filepath.FromSlash(vendorPath))); err == nil { + return vendorPath + } + } + + // Not vendored: resolve from modules. + return path +} + +// 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() (all []string) { + for _, pkg := range ld.pkgs { + if pkg.flags.has(pkgInAll) && !pkg.isTest() { + all = append(all, pkg.path) + } + } + 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 +// +// root imports +// other imports +// other2 tested by +// other2.test imports +// pkg +// +func (pkg *loadPkg) stackText() string { + var stack []*loadPkg + for p := pkg; p != nil; p = p.stack { + stack = append(stack, p) + } + + var buf bytes.Buffer + for i := len(stack) - 1; i >= 0; i-- { + p := stack[i] + fmt.Fprint(&buf, p.path) + if p.testOf != nil { + fmt.Fprint(&buf, ".test") + } + if i > 0 { + if stack[i-1].testOf == p { + fmt.Fprint(&buf, " tested by\n\t") + } else { + fmt.Fprint(&buf, " imports\n\t") + } + } + } + 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 contains 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 LoadPackages. +// 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 +} diff --git a/src/cmd/go/internal/modload/modfile.go b/src/cmd/go/internal/modload/modfile.go new file mode 100644 index 0000000..c6667d0 --- /dev/null +++ b/src/cmd/go/internal/modload/modfile.go @@ -0,0 +1,591 @@ +// Copyright 2020 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 ( + "context" + "errors" + "fmt" + "path/filepath" + "strings" + "sync" + "unicode" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/lockedfile" + "cmd/go/internal/modfetch" + "cmd/go/internal/par" + "cmd/go/internal/trace" + + "golang.org/x/mod/modfile" + "golang.org/x/mod/module" + "golang.org/x/mod/semver" +) + +// narrowAllVersionV is the Go version (plus leading "v") at which the +// module-module "all" pattern no longer closes over the dependencies of +// tests outside of the main module. +const narrowAllVersionV = "v1.16" +const go116EnableNarrowAll = true + +var modFile *modfile.File + +// A modFileIndex is an index of data corresponding to a modFile +// at a specific point in time. +type modFileIndex struct { + data []byte + dataNeedsFix bool // true if fixVersion applied a change while parsing data + module module.Version + goVersionV string // GoVersion with "v" prefix + require map[module.Version]requireMeta + replace map[module.Version]module.Version + highestReplaced map[string]string // highest replaced version of each module path; empty string for wildcard-only replacements + exclude map[module.Version]bool +} + +// index is the index of the go.mod file as of when it was last read or written. +var index *modFileIndex + +type requireMeta struct { + indirect bool +} + +// CheckAllowed returns an error equivalent to ErrDisallowed if m is excluded by +// the main module's go.mod or retracted by its author. Most version queries use +// this to filter out versions that should not be used. +func CheckAllowed(ctx context.Context, m module.Version) error { + if err := CheckExclusions(ctx, m); err != nil { + return err + } + if err := CheckRetractions(ctx, m); err != nil { + return err + } + return nil +} + +// ErrDisallowed is returned by version predicates passed to Query and similar +// functions to indicate that a version should not be considered. +var ErrDisallowed = errors.New("disallowed module version") + +// CheckExclusions returns an error equivalent to ErrDisallowed if module m is +// excluded by the main module's go.mod file. +func CheckExclusions(ctx context.Context, m module.Version) error { + if index != nil && index.exclude[m] { + return module.VersionError(m, errExcluded) + } + return nil +} + +var errExcluded = &excludedError{} + +type excludedError struct{} + +func (e *excludedError) Error() string { return "excluded by go.mod" } +func (e *excludedError) Is(err error) bool { return err == ErrDisallowed } + +// CheckRetractions returns an error if module m has been retracted by +// its author. +func CheckRetractions(ctx context.Context, m module.Version) error { + if m.Version == "" { + // Main module, standard library, or file replacement module. + // Cannot be retracted. + return nil + } + + // Look up retraction information from the latest available version of + // the module. Cache retraction information so we don't parse the go.mod + // file repeatedly. + type entry struct { + retract []retraction + err error + } + path := m.Path + e := retractCache.Do(path, func() (v interface{}) { + ctx, span := trace.StartSpan(ctx, "checkRetractions "+path) + defer span.Done() + + if repl := Replacement(module.Version{Path: m.Path}); repl.Path != "" { + // All versions of the module were replaced with a local directory. + // Don't load retractions. + return &entry{nil, nil} + } + + // Find the latest version of the module. + // Ignore exclusions from the main module's go.mod. + const ignoreSelected = "" + var allowAll AllowedFunc + rev, err := Query(ctx, path, "latest", ignoreSelected, allowAll) + if err != nil { + return &entry{nil, err} + } + + // Load go.mod for that version. + // If the version is replaced, we'll load retractions from the replacement. + // + // If there's an error loading the go.mod, we'll return it here. + // These errors should generally be ignored by callers of checkRetractions, + // since they happen frequently when we're offline. These errors are not + // equivalent to ErrDisallowed, so they may be distinguished from + // retraction errors. + // + // We load the raw file here: the go.mod file may have a different module + // path that we expect if the module or its repository was renamed. + // We still want to apply retractions to other aliases of the module. + rm := module.Version{Path: path, Version: rev.Version} + if repl := Replacement(rm); repl.Path != "" { + rm = repl + } + summary, err := rawGoModSummary(rm) + if err != nil { + return &entry{nil, err} + } + return &entry{summary.retract, nil} + }).(*entry) + + if err := e.err; err != nil { + // Attribute the error to the version being checked, not the version from + // which the retractions were to be loaded. + var mErr *module.ModuleError + if errors.As(err, &mErr) { + err = mErr.Err + } + return &retractionLoadingError{m: m, err: err} + } + + var rationale []string + isRetracted := false + for _, r := range e.retract { + if semver.Compare(r.Low, m.Version) <= 0 && semver.Compare(m.Version, r.High) <= 0 { + isRetracted = true + if r.Rationale != "" { + rationale = append(rationale, r.Rationale) + } + } + } + if isRetracted { + return module.VersionError(m, &ModuleRetractedError{Rationale: rationale}) + } + return nil +} + +var retractCache par.Cache + +type ModuleRetractedError struct { + Rationale []string +} + +func (e *ModuleRetractedError) Error() string { + msg := "retracted by module author" + if len(e.Rationale) > 0 { + // This is meant to be a short error printed on a terminal, so just + // print the first rationale. + msg += ": " + ShortRetractionRationale(e.Rationale[0]) + } + return msg +} + +func (e *ModuleRetractedError) Is(err error) bool { + return err == ErrDisallowed +} + +type retractionLoadingError struct { + m module.Version + err error +} + +func (e *retractionLoadingError) Error() string { + return fmt.Sprintf("loading module retractions for %v: %v", e.m, e.err) +} + +func (e *retractionLoadingError) Unwrap() error { + return e.err +} + +// ShortRetractionRationale returns a retraction rationale string that is safe +// to print in a terminal. It returns hard-coded strings if the rationale +// is empty, too long, or contains non-printable characters. +func ShortRetractionRationale(rationale string) string { + const maxRationaleBytes = 500 + if i := strings.Index(rationale, "\n"); i >= 0 { + rationale = rationale[:i] + } + rationale = strings.TrimSpace(rationale) + if rationale == "" { + return "retracted by module author" + } + if len(rationale) > maxRationaleBytes { + return "(rationale omitted: too long)" + } + for _, r := range rationale { + if !unicode.IsGraphic(r) && !unicode.IsSpace(r) { + return "(rationale omitted: contains non-printable characters)" + } + } + // NOTE: the go.mod parser rejects invalid UTF-8, so we don't check that here. + return rationale +} + +// 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 index != nil { + if r, ok := index.replace[mod]; ok { + return r + } + if r, ok := index.replace[module.Version{Path: mod.Path}]; ok { + return r + } + } + return module.Version{} +} + +// indexModFile rebuilds the index of modFile. +// If modFile has been changed since it was first read, +// modFile.Cleanup must be called before indexModFile. +func indexModFile(data []byte, modFile *modfile.File, needsFix bool) *modFileIndex { + i := new(modFileIndex) + i.data = data + i.dataNeedsFix = needsFix + + i.module = module.Version{} + if modFile.Module != nil { + i.module = modFile.Module.Mod + } + + i.goVersionV = "" + if modFile.Go != nil { + // We're going to use the semver package to compare Go versions, so go ahead + // and add the "v" prefix it expects once instead of every time. + i.goVersionV = "v" + modFile.Go.Version + } + + i.require = make(map[module.Version]requireMeta, len(modFile.Require)) + for _, r := range modFile.Require { + i.require[r.Mod] = requireMeta{indirect: r.Indirect} + } + + i.replace = make(map[module.Version]module.Version, len(modFile.Replace)) + for _, r := range modFile.Replace { + if prev, dup := i.replace[r.Old]; dup && prev != r.New { + base.Fatalf("go: conflicting replacements for %v:\n\t%v\n\t%v", r.Old, prev, r.New) + } + i.replace[r.Old] = r.New + } + + i.highestReplaced = make(map[string]string) + for _, r := range modFile.Replace { + v, ok := i.highestReplaced[r.Old.Path] + if !ok || semver.Compare(r.Old.Version, v) > 0 { + i.highestReplaced[r.Old.Path] = r.Old.Version + } + } + + i.exclude = make(map[module.Version]bool, len(modFile.Exclude)) + for _, x := range modFile.Exclude { + i.exclude[x.Mod] = true + } + + return i +} + +// allPatternClosesOverTests reports whether the "all" pattern includes +// dependencies of tests outside the main module (as in Go 1.11–1.15). +// (Otherwise — as in Go 1.16+ — the "all" pattern includes only the packages +// transitively *imported by* the packages and tests in the main module.) +func (i *modFileIndex) allPatternClosesOverTests() bool { + if !go116EnableNarrowAll { + return true + } + if i != nil && semver.Compare(i.goVersionV, narrowAllVersionV) < 0 { + // The module explicitly predates the change in "all" for lazy loading, so + // continue to use the older interpretation. (If i == nil, we not in any + // module at all and should use the latest semantics.) + return true + } + return false +} + +// modFileIsDirty reports whether the go.mod file differs meaningfully +// from what was indexed. +// If modFile has been changed (even cosmetically) since it was first read, +// modFile.Cleanup must be called before modFileIsDirty. +func (i *modFileIndex) modFileIsDirty(modFile *modfile.File) bool { + if i == nil { + return modFile != nil + } + + if i.dataNeedsFix { + return true + } + + if modFile.Module == nil { + if i.module != (module.Version{}) { + return true + } + } else if modFile.Module.Mod != i.module { + return true + } + + if modFile.Go == nil { + if i.goVersionV != "" { + return true + } + } else if "v"+modFile.Go.Version != i.goVersionV { + if i.goVersionV == "" && cfg.BuildMod == "readonly" { + // go.mod files did not always require a 'go' version, so do not error out + // if one is missing — we may be inside an older module in the module + // cache, and should bias toward providing useful behavior. + } else { + return true + } + } + + if len(modFile.Require) != len(i.require) || + len(modFile.Replace) != len(i.replace) || + len(modFile.Exclude) != len(i.exclude) { + return true + } + + for _, r := range modFile.Require { + if meta, ok := i.require[r.Mod]; !ok { + return true + } else if r.Indirect != meta.indirect { + if cfg.BuildMod == "readonly" { + // The module's requirements are consistent; only the "// indirect" + // comments that are wrong. But those are only guaranteed to be accurate + // after a "go mod tidy" — it's a good idea to run those before + // committing a change, but it's certainly not mandatory. + } else { + return true + } + } + } + + for _, r := range modFile.Replace { + if r.New != i.replace[r.Old] { + return true + } + } + + for _, x := range modFile.Exclude { + if !i.exclude[x.Mod] { + return true + } + } + + return false +} + +// rawGoVersion records the Go version parsed from each module's go.mod file. +// +// If a module is replaced, the version of the replacement is keyed by the +// replacement module.Version, not the version being replaced. +var rawGoVersion sync.Map // map[module.Version]string + +// A modFileSummary is a summary of a go.mod file for which we do not need to +// retain complete information — for example, the go.mod file of a dependency +// module. +type modFileSummary struct { + module module.Version + goVersionV string // GoVersion with "v" prefix + require []module.Version + retract []retraction +} + +// A retraction consists of a retracted version interval and rationale. +// retraction is like modfile.Retract, but it doesn't point to the syntax tree. +type retraction struct { + modfile.VersionInterval + Rationale string +} + +// goModSummary returns a summary of the go.mod file for module m, +// taking into account any replacements for m, exclusions of its dependencies, +// and/or vendoring. +// +// m must be a version in the module graph, reachable from the Target module. +// In readonly mode, the go.sum file must contain an entry for m's go.mod file +// (or its replacement). goModSummary must not be called for the Target module +// itself, as its requirements may change. Use rawGoModSummary for other +// module versions. +// +// The caller must not modify the returned summary. +func goModSummary(m module.Version) (*modFileSummary, error) { + if m == Target { + panic("internal error: goModSummary called on the Target module") + } + + if cfg.BuildMod == "vendor" { + summary := &modFileSummary{ + module: module.Version{Path: m.Path}, + } + if vendorVersion[m.Path] != m.Version { + // This module is not vendored, so packages cannot be loaded from it and + // it cannot be relevant to the build. + return summary, nil + } + + // For every module other than the target, + // return the full list of modules from modules.txt. + readVendorList() + + // TODO(#36876): Load the "go" version from vendor/modules.txt and store it + // in rawGoVersion with the appropriate key. + + // We don't know what versions the vendored module actually relies on, + // so assume that it requires everything. + summary.require = vendorList + return summary, nil + } + + actual := Replacement(m) + if actual.Path == "" { + actual = m + } + if HasModRoot() && cfg.BuildMod == "readonly" && actual.Version != "" { + key := module.Version{Path: actual.Path, Version: actual.Version + "/go.mod"} + if !modfetch.HaveSum(key) { + suggestion := fmt.Sprintf("; to add it:\n\tgo mod download %s", m.Path) + return nil, module.VersionError(actual, &sumMissingError{suggestion: suggestion}) + } + } + summary, err := rawGoModSummary(actual) + if err != nil { + return nil, err + } + + if actual.Version == "" { + // The actual module is a filesystem-local replacement, for which we have + // unfortunately not enforced any sort of invariants about module lines or + // matching module paths. Anything goes. + // + // TODO(bcmills): Remove this special-case, update tests, and add a + // release note. + } else { + if summary.module.Path == "" { + return nil, module.VersionError(actual, errors.New("parsing go.mod: missing module line")) + } + + // In theory we should only allow mpath to be unequal to m.Path here if the + // version that we fetched lacks an explicit go.mod file: if the go.mod file + // is explicit, then it should match exactly (to ensure that imports of other + // packages within the module are interpreted correctly). Unfortunately, we + // can't determine that information from the module proxy protocol: we'll have + // to leave that validation for when we load actual packages from within the + // module. + if mpath := summary.module.Path; mpath != m.Path && mpath != actual.Path { + return nil, module.VersionError(actual, fmt.Errorf(`parsing go.mod: + module declares its path as: %s + but was required as: %s`, mpath, m.Path)) + } + } + + if index != nil && len(index.exclude) > 0 { + // Drop any requirements on excluded versions. + // Don't modify the cached summary though, since we might need the raw + // summary separately. + haveExcludedReqs := false + for _, r := range summary.require { + if index.exclude[r] { + haveExcludedReqs = true + break + } + } + if haveExcludedReqs { + s := new(modFileSummary) + *s = *summary + s.require = make([]module.Version, 0, len(summary.require)) + for _, r := range summary.require { + if !index.exclude[r] { + s.require = append(s.require, r) + } + } + summary = s + } + } + return summary, nil +} + +// rawGoModSummary returns a new summary of the go.mod file for module m, +// ignoring all replacements that may apply to m and excludes that may apply to +// its dependencies. +// +// rawGoModSummary cannot be used on the Target module. +func rawGoModSummary(m module.Version) (*modFileSummary, error) { + if m == Target { + panic("internal error: rawGoModSummary called on the Target module") + } + + type cached struct { + summary *modFileSummary + err error + } + c := rawGoModSummaryCache.Do(m, func() interface{} { + summary := new(modFileSummary) + var f *modfile.File + if m.Version == "" { + // m is a replacement module with only a file path. + dir := m.Path + if !filepath.IsAbs(dir) { + dir = filepath.Join(ModRoot(), dir) + } + gomod := filepath.Join(dir, "go.mod") + + data, err := lockedfile.Read(gomod) + if err != nil { + return cached{nil, module.VersionError(m, fmt.Errorf("reading %s: %v", base.ShortPath(gomod), err))} + } + f, err = modfile.ParseLax(gomod, data, nil) + if err != nil { + return cached{nil, module.VersionError(m, fmt.Errorf("parsing %s: %v", base.ShortPath(gomod), err))} + } + } else { + if !semver.IsValid(m.Version) { + // Disallow the broader queries supported by fetch.Lookup. + base.Fatalf("go: internal error: %s@%s: unexpected invalid semantic version", m.Path, m.Version) + } + + data, err := modfetch.GoMod(m.Path, m.Version) + if err != nil { + return cached{nil, err} + } + f, err = modfile.ParseLax("go.mod", data, nil) + if err != nil { + return cached{nil, module.VersionError(m, fmt.Errorf("parsing go.mod: %v", err))} + } + } + + if f.Module != nil { + summary.module = f.Module.Mod + } + if f.Go != nil && f.Go.Version != "" { + rawGoVersion.LoadOrStore(m, f.Go.Version) + summary.goVersionV = "v" + f.Go.Version + } + if len(f.Require) > 0 { + summary.require = make([]module.Version, 0, len(f.Require)) + for _, req := range f.Require { + summary.require = append(summary.require, req.Mod) + } + } + if len(f.Retract) > 0 { + summary.retract = make([]retraction, 0, len(f.Retract)) + for _, ret := range f.Retract { + summary.retract = append(summary.retract, retraction{ + VersionInterval: ret.VersionInterval, + Rationale: ret.Rationale, + }) + } + } + + return cached{summary, nil} + }).(cached) + + return c.summary, c.err +} + +var rawGoModSummaryCache par.Cache // module.Version → rawGoModSummary result diff --git a/src/cmd/go/internal/modload/mvs.go b/src/cmd/go/internal/modload/mvs.go new file mode 100644 index 0000000..3101519 --- /dev/null +++ b/src/cmd/go/internal/modload/mvs.go @@ -0,0 +1,113 @@ +// Copyright 2020 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 ( + "context" + "errors" + "os" + "sort" + + "cmd/go/internal/modfetch" + + "golang.org/x/mod/module" + "golang.org/x/mod/semver" +) + +// mvsReqs implements mvs.Reqs for module semantic versions, +// with any exclusions or replacements applied internally. +type mvsReqs struct { + buildList []module.Version +} + +func (r *mvsReqs) Required(mod module.Version) ([]module.Version, error) { + if mod == Target { + // Use the build list as it existed when r was constructed, not the current + // global build list. + return r.buildList[1:], nil + } + + if mod.Version == "none" { + return nil, nil + } + + summary, err := goModSummary(mod) + if err != nil { + return nil, err + } + return summary.require, nil +} + +// Max returns the maximum of v1 and v2 according to semver.Compare. +// +// As a special case, the version "" is considered higher than all other +// versions. The main module (also known as the target) has no version and must +// be chosen over other versions of the same module in the module dependency +// graph. +func (*mvsReqs) Max(v1, v2 string) string { + if v1 != "" && (v2 == "" || 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(ctx context.Context, path string, allowed AllowedFunc) ([]string, error) { + // Note: modfetch.Lookup and repo.Versions are cached, + // so there's no need for us to add extra caching here. + var versions []string + err := modfetch.TryProxies(func(proxy string) error { + repo, err := lookupRepo(proxy, path) + if err != nil { + return err + } + allVersions, err := repo.Versions("") + if err != nil { + return err + } + allowedVersions := make([]string, 0, len(allVersions)) + for _, v := range allVersions { + if err := allowed(ctx, module.Version{Path: path, Version: v}); err == nil { + allowedVersions = append(allowedVersions, v) + } else if !errors.Is(err, ErrDisallowed) { + return err + } + } + versions = allowedVersions + return nil + }) + return versions, err +} + +// Previous returns the tagged version of m.Path immediately prior to +// m.Version, or version "none" if no prior version is tagged. +// +// Since the version of Target is not found in the version list, +// it has no previous version. +func (*mvsReqs) Previous(m module.Version) (module.Version, error) { + // TODO(golang.org/issue/38714): thread tracing context through MVS. + + if m == Target { + return module.Version{Path: m.Path, Version: "none"}, nil + } + + list, err := versions(context.TODO(), m.Path, CheckAllowed) + if err != nil { + if errors.Is(err, os.ErrNotExist) { + return module.Version{Path: m.Path, Version: "none"}, 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 +} diff --git a/src/cmd/go/internal/modload/mvs_test.go b/src/cmd/go/internal/modload/mvs_test.go new file mode 100644 index 0000000..50e93c3 --- /dev/null +++ b/src/cmd/go/internal/modload/mvs_test.go @@ -0,0 +1,31 @@ +// Copyright 2020 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 ( + "testing" +) + +func TestReqsMax(t *testing.T) { + type testCase struct { + a, b, want string + } + reqs := new(mvsReqs) + for _, tc := range []testCase{ + {a: "v0.1.0", b: "v0.2.0", want: "v0.2.0"}, + {a: "v0.2.0", b: "v0.1.0", want: "v0.2.0"}, + {a: "", b: "v0.1.0", want: ""}, // "" is Target.Version + {a: "v0.1.0", b: "", want: ""}, + {a: "none", b: "v0.1.0", want: "v0.1.0"}, + {a: "v0.1.0", b: "none", want: "v0.1.0"}, + {a: "none", b: "", want: ""}, + {a: "", b: "none", want: ""}, + } { + max := reqs.Max(tc.a, tc.b) + if max != tc.want { + t.Errorf("(%T).Max(%q, %q) = %q; want %q", reqs, tc.a, tc.b, max, tc.want) + } + } +} diff --git a/src/cmd/go/internal/modload/query.go b/src/cmd/go/internal/modload/query.go new file mode 100644 index 0000000..8affd17 --- /dev/null +++ b/src/cmd/go/internal/modload/query.go @@ -0,0 +1,1111 @@ +// 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 ( + "context" + "errors" + "fmt" + "io/fs" + "os" + pathpkg "path" + "path/filepath" + "sort" + "strings" + "sync" + "time" + + "cmd/go/internal/cfg" + "cmd/go/internal/imports" + "cmd/go/internal/modfetch" + "cmd/go/internal/search" + "cmd/go/internal/str" + "cmd/go/internal/trace" + + "golang.org/x/mod/module" + "golang.org/x/mod/semver" +) + +// 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. +// - the literal string "upgrade", equivalent to "latest" except that if +// current is a newer version, current will be returned (see below). +// - the literal string "patch", denoting the latest available tagged version +// with the same major and minor number as current (see below). +// - 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, +// denoting the version closest to the target and satisfying the given operator, +// with non-prereleases preferred over prereleases. +// - a repository commit identifier or tag, denoting that commit. +// +// current denotes the currently-selected version of the module; it may be +// "none" if no version is currently selected, or "" if the currently-selected +// version is unknown or should not be considered. If query is +// "upgrade" or "patch", current will be returned if it is a newer +// semantic version or a chronologically later pseudo-version than the +// version that would otherwise be chosen. This prevents accidental downgrades +// from newer pre-release or development versions. +// +// The allowed function (which may be nil) is used to filter out unsuitable +// versions (see AllowedFunc documentation for details). If the query refers to +// a specific revision (for example, "master"; see IsRevisionQuery), and the +// revision is disallowed by allowed, Query returns the error. If the query +// does not refer to a specific revision (for example, "latest"), Query +// acts as if versions disallowed by allowed do not exist. +// +// If path is the path of the main module and the query is "latest", +// Query returns Target.Version as the version. +func Query(ctx context.Context, path, query, current string, allowed AllowedFunc) (*modfetch.RevInfo, error) { + var info *modfetch.RevInfo + err := modfetch.TryProxies(func(proxy string) (err error) { + info, err = queryProxy(ctx, proxy, path, query, current, allowed) + return err + }) + return info, err +} + +// AllowedFunc is used by Query and other functions to filter out unsuitable +// versions, for example, those listed in exclude directives in the main +// module's go.mod file. +// +// An AllowedFunc returns an error equivalent to ErrDisallowed for an unsuitable +// version. Any other error indicates the function was unable to determine +// whether the version should be allowed, for example, the function was unable +// to fetch or parse a go.mod file containing retractions. Typically, errors +// other than ErrDisallowd may be ignored. +type AllowedFunc func(context.Context, module.Version) error + +var errQueryDisabled error = queryDisabledError{} + +type queryDisabledError struct{} + +func (queryDisabledError) Error() string { + if cfg.BuildModReason == "" { + return fmt.Sprintf("cannot query module due to -mod=%s", cfg.BuildMod) + } + return fmt.Sprintf("cannot query module due to -mod=%s\n\t(%s)", cfg.BuildMod, cfg.BuildModReason) +} + +func queryProxy(ctx context.Context, proxy, path, query, current string, allowed AllowedFunc) (*modfetch.RevInfo, error) { + ctx, span := trace.StartSpan(ctx, "modload.queryProxy "+path+" "+query) + defer span.Done() + + if current != "" && current != "none" && !semver.IsValid(current) { + return nil, fmt.Errorf("invalid previous version %q", current) + } + if cfg.BuildMod == "vendor" { + return nil, errQueryDisabled + } + if allowed == nil { + allowed = func(context.Context, module.Version) error { return nil } + } + + if path == Target.Path && (query == "upgrade" || query == "patch") { + if err := allowed(ctx, Target); err != nil { + return nil, fmt.Errorf("internal error: main module version is not allowed: %w", err) + } + return &modfetch.RevInfo{Version: Target.Version}, nil + } + + if path == "std" || path == "cmd" { + return nil, fmt.Errorf("can't query specific version (%q) of standard-library module %q", query, path) + } + + repo, err := lookupRepo(proxy, path) + if err != nil { + return nil, err + } + + // Parse query to detect parse errors (and possibly handle query) + // before any network I/O. + qm, err := newQueryMatcher(path, query, current, allowed) + if (err == nil && qm.canStat) || err == errRevQuery { + // Direct lookup of a commit identifier or complete (non-prefix) semantic + // version. + + // If the identifier is not a canonical semver tag — including if it's a + // semver tag with a +metadata suffix — then modfetch.Stat will populate + // info.Version with a suitable pseudo-version. + info, err := repo.Stat(query) + if err != nil { + queryErr := err + // The full query doesn't correspond to a tag. If it is a semantic version + // with a +metadata suffix, see if there is a tag without that suffix: + // semantic versioning defines them to be equivalent. + canonicalQuery := module.CanonicalVersion(query) + if canonicalQuery != "" && query != canonicalQuery { + info, err = repo.Stat(canonicalQuery) + if err != nil && !errors.Is(err, fs.ErrNotExist) { + return info, err + } + } + if err != nil { + return nil, queryErr + } + } + if err := allowed(ctx, module.Version{Path: path, Version: info.Version}); errors.Is(err, ErrDisallowed) { + return nil, err + } + return info, nil + } else if err != nil { + return nil, err + } + + // Load versions and execute query. + versions, err := repo.Versions(qm.prefix) + if err != nil { + return nil, err + } + releases, prereleases, err := qm.filterVersions(ctx, versions) + if err != nil { + return nil, err + } + + lookup := func(v string) (*modfetch.RevInfo, error) { + rev, err := repo.Stat(v) + if err != nil { + return nil, err + } + + if (query == "upgrade" || query == "patch") && modfetch.IsPseudoVersion(current) && !rev.Time.IsZero() { + // Don't allow "upgrade" or "patch" to move from a pseudo-version + // to a chronologically older version or pseudo-version. + // + // If the current version is a pseudo-version from an untagged branch, it + // may be semantically lower than the "latest" release or the latest + // pseudo-version on the main branch. A user on such a version is unlikely + // to intend to “upgrade” to a version that already existed at that point + // in time. + // + // We do this only if the current version is a pseudo-version: if the + // version is tagged, the author of the dependency module has given us + // explicit information about their intended precedence of this version + // relative to other versions, and we shouldn't contradict that + // information. (For example, v1.0.1 might be a backport of a fix already + // incorporated into v1.1.0, in which case v1.0.1 would be chronologically + // newer but v1.1.0 is still an “upgrade”; or v1.0.2 might be a revert of + // an unsuccessful fix in v1.0.1, in which case the v1.0.2 commit may be + // older than the v1.0.1 commit despite the tag itself being newer.) + currentTime, err := modfetch.PseudoVersionTime(current) + if err == nil && rev.Time.Before(currentTime) { + if err := allowed(ctx, module.Version{Path: path, Version: current}); errors.Is(err, ErrDisallowed) { + return nil, err + } + return repo.Stat(current) + } + } + + return rev, nil + } + + if qm.preferLower { + if len(releases) > 0 { + return lookup(releases[0]) + } + if len(prereleases) > 0 { + return lookup(prereleases[0]) + } + } else { + if len(releases) > 0 { + return lookup(releases[len(releases)-1]) + } + if len(prereleases) > 0 { + return lookup(prereleases[len(prereleases)-1]) + } + } + + if qm.mayUseLatest { + latest, err := repo.Latest() + if err == nil { + if qm.allowsVersion(ctx, latest.Version) { + return lookup(latest.Version) + } + } else if !errors.Is(err, fs.ErrNotExist) { + return nil, err + } + } + + if (query == "upgrade" || query == "patch") && current != "" && current != "none" { + // "upgrade" and "patch" may stay on the current version if allowed. + if err := allowed(ctx, module.Version{Path: path, Version: current}); errors.Is(err, ErrDisallowed) { + return nil, err + } + return lookup(current) + } + + return nil, &NoMatchingVersionError{query: query, current: current} +} + +// IsRevisionQuery returns true if vers is a version query that may refer to +// a particular version or revision in a repository like "v1.0.0", "master", +// or "0123abcd". IsRevisionQuery returns false if vers is a query that +// chooses from among available versions like "latest" or ">v1.0.0". +func IsRevisionQuery(vers string) bool { + if vers == "latest" || + vers == "upgrade" || + vers == "patch" || + strings.HasPrefix(vers, "<") || + strings.HasPrefix(vers, ">") || + (semver.IsValid(vers) && isSemverPrefix(vers)) { + return false + } + return true +} + +// 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 +} + +type queryMatcher struct { + path string + prefix string + filter func(version string) bool + allowed AllowedFunc + canStat bool // if true, the query can be resolved by repo.Stat + preferLower bool // if true, choose the lowest matching version + mayUseLatest bool + preferIncompatible bool +} + +var errRevQuery = errors.New("query refers to a non-semver revision") + +// newQueryMatcher returns a new queryMatcher that matches the versions +// specified by the given query on the module with the given path. +// +// If the query can only be resolved by statting a non-SemVer revision, +// newQueryMatcher returns errRevQuery. +func newQueryMatcher(path string, query, current string, allowed AllowedFunc) (*queryMatcher, error) { + badVersion := func(v string) (*queryMatcher, error) { + return nil, fmt.Errorf("invalid semantic version %q in range %q", v, query) + } + + matchesMajor := func(v string) bool { + _, pathMajor, ok := module.SplitPathVersion(path) + if !ok { + return false + } + return module.CheckPathMajor(v, pathMajor) == nil + } + + qm := &queryMatcher{ + path: path, + allowed: allowed, + preferIncompatible: strings.HasSuffix(current, "+incompatible"), + } + + switch { + case query == "latest": + qm.mayUseLatest = true + + case query == "upgrade": + if current == "" || current == "none" { + qm.mayUseLatest = true + } else { + qm.mayUseLatest = modfetch.IsPseudoVersion(current) + qm.filter = func(mv string) bool { return semver.Compare(mv, current) >= 0 } + } + + case query == "patch": + if current == "none" { + return nil, &NoPatchBaseError{path} + } + if current == "" { + qm.mayUseLatest = true + } else { + qm.mayUseLatest = modfetch.IsPseudoVersion(current) + qm.prefix = semver.MajorMinor(current) + "." + qm.filter = func(mv string) bool { return semver.Compare(mv, current) >= 0 } + } + + 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) + } + qm.filter = func(mv string) bool { return semver.Compare(mv, v) <= 0 } + if !matchesMajor(v) { + qm.preferIncompatible = true + } + + case strings.HasPrefix(query, "<"): + v := query[len("<"):] + if !semver.IsValid(v) { + return badVersion(v) + } + qm.filter = func(mv string) bool { return semver.Compare(mv, v) < 0 } + if !matchesMajor(v) { + qm.preferIncompatible = true + } + + case strings.HasPrefix(query, ">="): + v := query[len(">="):] + if !semver.IsValid(v) { + return badVersion(v) + } + qm.filter = func(mv string) bool { return semver.Compare(mv, v) >= 0 } + qm.preferLower = true + if !matchesMajor(v) { + qm.preferIncompatible = 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) + } + qm.filter = func(mv string) bool { return semver.Compare(mv, v) > 0 } + qm.preferLower = true + if !matchesMajor(v) { + qm.preferIncompatible = true + } + + case semver.IsValid(query): + if isSemverPrefix(query) { + qm.prefix = query + "." + // Do not allow the query "v1.2" to match versions lower than "v1.2.0", + // such as prereleases for that version. (https://golang.org/issue/31972) + qm.filter = func(mv string) bool { return semver.Compare(mv, query) >= 0 } + } else { + qm.canStat = true + qm.filter = func(mv string) bool { return semver.Compare(mv, query) == 0 } + qm.prefix = semver.Canonical(query) + } + if !matchesMajor(query) { + qm.preferIncompatible = true + } + + default: + return nil, errRevQuery + } + + return qm, nil +} + +// allowsVersion reports whether version v is allowed by the prefix, filter, and +// AllowedFunc of qm. +func (qm *queryMatcher) allowsVersion(ctx context.Context, v string) bool { + if qm.prefix != "" && !strings.HasPrefix(v, qm.prefix) { + return false + } + if qm.filter != nil && !qm.filter(v) { + return false + } + if qm.allowed != nil { + if err := qm.allowed(ctx, module.Version{Path: qm.path, Version: v}); errors.Is(err, ErrDisallowed) { + return false + } + } + return true +} + +// filterVersions classifies versions into releases and pre-releases, filtering +// out: +// 1. versions that do not satisfy the 'allowed' predicate, and +// 2. "+incompatible" versions, if a compatible one satisfies the predicate +// and the incompatible version is not preferred. +// +// If the allowed predicate returns an error not equivalent to ErrDisallowed, +// filterVersions returns that error. +func (qm *queryMatcher) filterVersions(ctx context.Context, versions []string) (releases, prereleases []string, err error) { + needIncompatible := qm.preferIncompatible + + var lastCompatible string + for _, v := range versions { + if !qm.allowsVersion(ctx, v) { + continue + } + + if !needIncompatible { + // We're not yet sure whether we need to include +incomptaible versions. + // Keep track of the last compatible version we've seen, and use the + // presence (or absence) of a go.mod file in that version to decide: a + // go.mod file implies that the module author is supporting modules at a + // compatible version (and we should ignore +incompatible versions unless + // requested explicitly), while a lack of go.mod file implies the + // potential for legacy (pre-modules) versioning without semantic import + // paths (and thus *with* +incompatible versions). + // + // This isn't strictly accurate if the latest compatible version has been + // replaced by a local file path, because we do not allow file-path + // replacements without a go.mod file: the user would have needed to add + // one. However, replacing the last compatible version while + // simultaneously expecting to upgrade implicitly to a +incompatible + // version seems like an extreme enough corner case to ignore for now. + + if !strings.HasSuffix(v, "+incompatible") { + lastCompatible = v + } else if lastCompatible != "" { + // If the latest compatible version is allowed and has a go.mod file, + // ignore any version with a higher (+incompatible) major version. (See + // https://golang.org/issue/34165.) Note that we even prefer a + // compatible pre-release over an incompatible release. + ok, err := versionHasGoMod(ctx, module.Version{Path: qm.path, Version: lastCompatible}) + if err != nil { + return nil, nil, err + } + if ok { + // The last compatible version has a go.mod file, so that's the + // highest version we're willing to consider. Don't bother even + // looking at higher versions, because they're all +incompatible from + // here onward. + break + } + + // No acceptable compatible release has a go.mod file, so the versioning + // for the module might not be module-aware, and we should respect + // legacy major-version tags. + needIncompatible = true + } + } + + if semver.Prerelease(v) != "" { + prereleases = append(prereleases, v) + } else { + releases = append(releases, v) + } + } + + return releases, prereleases, nil +} + +type QueryResult struct { + Mod module.Version + Rev *modfetch.RevInfo + Packages []string +} + +// QueryPackages is like QueryPattern, but requires that the pattern match at +// least one package and omits the non-package result (if any). +func QueryPackages(ctx context.Context, pattern, query string, current func(string) string, allowed AllowedFunc) ([]QueryResult, error) { + pkgMods, modOnly, err := QueryPattern(ctx, pattern, query, current, allowed) + + if len(pkgMods) == 0 && err == nil { + return nil, &PackageNotInModuleError{ + Mod: modOnly.Mod, + Replacement: Replacement(modOnly.Mod), + Query: query, + Pattern: pattern, + } + } + + return pkgMods, err +} + +// QueryPattern looks up the module(s) containing at least one package matching +// the given pattern at the given version. The results are sorted by module path +// length in descending order. If any proxy provides a non-empty set of candidate +// modules, no further proxies are tried. +// +// For wildcard patterns, QueryPattern looks in modules with package paths up to +// the first "..." in the pattern. For the pattern "example.com/a/b.../c", +// QueryPattern would consider prefixes of "example.com/a". +// +// If any matching package is in the main module, QueryPattern considers only +// the main module and only the version "latest", without checking for other +// possible modules. +// +// QueryPattern always returns at least one QueryResult (which may be only +// modOnly) or a non-nil error. +func QueryPattern(ctx context.Context, pattern, query string, current func(string) string, allowed AllowedFunc) (pkgMods []QueryResult, modOnly *QueryResult, err error) { + ctx, span := trace.StartSpan(ctx, "modload.QueryPattern "+pattern+" "+query) + defer span.Done() + + base := pattern + + firstError := func(m *search.Match) error { + if len(m.Errs) == 0 { + return nil + } + return m.Errs[0] + } + + var match func(mod module.Version, root string, isLocal bool) *search.Match + matchPattern := search.MatchPattern(pattern) + + if i := strings.Index(pattern, "..."); i >= 0 { + base = pathpkg.Dir(pattern[:i+3]) + if base == "." { + return nil, nil, &WildcardInFirstElementError{Pattern: pattern, Query: query} + } + match = func(mod module.Version, root string, isLocal bool) *search.Match { + m := search.NewMatch(pattern) + matchPackages(ctx, m, imports.AnyTags(), omitStd, []module.Version{mod}) + return m + } + } else { + match = func(mod module.Version, root string, isLocal bool) *search.Match { + m := search.NewMatch(pattern) + prefix := mod.Path + if mod == Target { + prefix = targetPrefix + } + if _, ok, err := dirInModule(pattern, prefix, root, isLocal); err != nil { + m.AddError(err) + } else if ok { + m.Pkgs = []string{pattern} + } + return m + } + } + + var queryMatchesMainModule bool + if HasModRoot() { + m := match(Target, modRoot, true) + if len(m.Pkgs) > 0 { + if query != "upgrade" && query != "patch" { + return nil, nil, &QueryMatchesPackagesInMainModuleError{ + Pattern: pattern, + Query: query, + Packages: m.Pkgs, + } + } + if err := allowed(ctx, Target); err != nil { + return nil, nil, fmt.Errorf("internal error: package %s is in the main module (%s), but version is not allowed: %w", pattern, Target.Path, err) + } + return []QueryResult{{ + Mod: Target, + Rev: &modfetch.RevInfo{Version: Target.Version}, + Packages: m.Pkgs, + }}, nil, nil + } + if err := firstError(m); err != nil { + return nil, nil, err + } + + if matchPattern(Target.Path) { + queryMatchesMainModule = true + } + + if (query == "upgrade" || query == "patch") && queryMatchesMainModule { + if err := allowed(ctx, Target); err == nil { + modOnly = &QueryResult{ + Mod: Target, + Rev: &modfetch.RevInfo{Version: Target.Version}, + } + } + } + } + + var ( + results []QueryResult + candidateModules = modulePrefixesExcludingTarget(base) + ) + if len(candidateModules) == 0 { + if modOnly != nil { + return nil, modOnly, nil + } else if queryMatchesMainModule { + return nil, nil, &QueryMatchesMainModuleError{ + Pattern: pattern, + Query: query, + } + } else { + return nil, nil, &PackageNotInModuleError{ + Mod: Target, + Query: query, + Pattern: pattern, + } + } + } + + err = modfetch.TryProxies(func(proxy string) error { + queryModule := func(ctx context.Context, path string) (r QueryResult, err error) { + ctx, span := trace.StartSpan(ctx, "modload.QueryPattern.queryModule ["+proxy+"] "+path) + defer span.Done() + + pathCurrent := current(path) + r.Mod.Path = path + r.Rev, err = queryProxy(ctx, proxy, path, query, pathCurrent, allowed) + if err != nil { + return r, err + } + r.Mod.Version = r.Rev.Version + needSum := true + root, isLocal, err := fetch(ctx, r.Mod, needSum) + if err != nil { + return r, err + } + m := match(r.Mod, root, isLocal) + r.Packages = m.Pkgs + if len(r.Packages) == 0 && !matchPattern(path) { + if err := firstError(m); err != nil { + return r, err + } + return r, &PackageNotInModuleError{ + Mod: r.Mod, + Replacement: Replacement(r.Mod), + Query: query, + Pattern: pattern, + } + } + return r, nil + } + + allResults, err := queryPrefixModules(ctx, candidateModules, queryModule) + results = allResults[:0] + for _, r := range allResults { + if len(r.Packages) == 0 { + modOnly = &r + } else { + results = append(results, r) + } + } + return err + }) + + if queryMatchesMainModule && len(results) == 0 && modOnly == nil && errors.Is(err, fs.ErrNotExist) { + return nil, nil, &QueryMatchesMainModuleError{ + Pattern: pattern, + Query: query, + } + } + return results[:len(results):len(results)], modOnly, err +} + +// modulePrefixesExcludingTarget returns all prefixes of path that may plausibly +// exist as a module, excluding targetPrefix but otherwise including path +// itself, sorted by descending length. +func modulePrefixesExcludingTarget(path string) []string { + prefixes := make([]string, 0, strings.Count(path, "/")+1) + + for { + if path != targetPrefix { + if _, _, ok := module.SplitPathVersion(path); ok { + prefixes = append(prefixes, path) + } + } + + j := strings.LastIndexByte(path, '/') + if j < 0 { + break + } + path = path[:j] + } + + return prefixes +} + +func queryPrefixModules(ctx context.Context, candidateModules []string, queryModule func(ctx context.Context, path string) (QueryResult, error)) (found []QueryResult, err error) { + ctx, span := trace.StartSpan(ctx, "modload.queryPrefixModules") + defer span.Done() + + // If the path we're attempting is not in the module cache and we don't have a + // fetch result cached either, we'll end up making a (potentially slow) + // request to the proxy or (often even slower) the origin server. + // To minimize latency, execute all of those requests in parallel. + type result struct { + QueryResult + err error + } + results := make([]result, len(candidateModules)) + var wg sync.WaitGroup + wg.Add(len(candidateModules)) + for i, p := range candidateModules { + ctx := trace.StartGoroutine(ctx) + go func(p string, r *result) { + r.QueryResult, r.err = queryModule(ctx, p) + wg.Done() + }(p, &results[i]) + } + wg.Wait() + + // Classify the results. In case of failure, identify the error that the user + // is most likely to find helpful: the most useful class of error at the + // longest matching path. + var ( + noPackage *PackageNotInModuleError + noVersion *NoMatchingVersionError + noPatchBase *NoPatchBaseError + notExistErr error + ) + for _, r := range results { + switch rErr := r.err.(type) { + case nil: + found = append(found, r.QueryResult) + case *PackageNotInModuleError: + // Given the option, prefer to attribute “package not in module” + // to modules other than the main one. + if noPackage == nil || noPackage.Mod == Target { + noPackage = rErr + } + case *NoMatchingVersionError: + if noVersion == nil { + noVersion = rErr + } + case *NoPatchBaseError: + if noPatchBase == nil { + noPatchBase = rErr + } + default: + if errors.Is(rErr, fs.ErrNotExist) { + if notExistErr == nil { + notExistErr = rErr + } + } else if err == nil { + if len(found) > 0 || noPackage != nil { + // golang.org/issue/34094: If we have already found a module that + // could potentially contain the target package, ignore unclassified + // errors for modules with shorter paths. + + // golang.org/issue/34383 is a special case of this: if we have + // already found example.com/foo/v2@v2.0.0 with a matching go.mod + // file, ignore the error from example.com/foo@v2.0.0. + } else { + err = r.err + } + } + } + } + + // TODO(#26232): If len(found) == 0 and some of the errors are 4xx HTTP + // codes, have the auth package recheck the failed paths. + // If we obtain new credentials for any of them, re-run the above loop. + + if len(found) == 0 && err == nil { + switch { + case noPackage != nil: + err = noPackage + case noVersion != nil: + err = noVersion + case noPatchBase != nil: + err = noPatchBase + case notExistErr != nil: + err = notExistErr + default: + panic("queryPrefixModules: no modules found, but no error detected") + } + } + + return found, err +} + +// A NoMatchingVersionError indicates that Query found a module at the requested +// path, but not at any versions satisfying the query string and allow-function. +// +// NOTE: NoMatchingVersionError MUST NOT implement Is(fs.ErrNotExist). +// +// If the module came from a proxy, that proxy had to return a successful status +// code for the versions it knows about, and thus did not have the opportunity +// to return a non-400 status code to suppress fallback. +type NoMatchingVersionError struct { + query, current string +} + +func (e *NoMatchingVersionError) Error() string { + currentSuffix := "" + if (e.query == "upgrade" || e.query == "patch") && e.current != "" && e.current != "none" { + currentSuffix = fmt.Sprintf(" (current version is %s)", e.current) + } + return fmt.Sprintf("no matching versions for query %q", e.query) + currentSuffix +} + +// A NoPatchBaseError indicates that Query was called with the query "patch" +// but with a current version of "" or "none". +type NoPatchBaseError struct { + path string +} + +func (e *NoPatchBaseError) Error() string { + return fmt.Sprintf(`can't query version "patch" of module %s: no existing version is required`, e.path) +} + +// A WildcardInFirstElementError indicates that a pattern passed to QueryPattern +// had a wildcard in its first path element, and therefore had no pattern-prefix +// modules to search in. +type WildcardInFirstElementError struct { + Pattern string + Query string +} + +func (e *WildcardInFirstElementError) Error() string { + return fmt.Sprintf("no modules to query for %s@%s because first path element contains a wildcard", e.Pattern, e.Query) +} + +// A PackageNotInModuleError indicates that QueryPattern found a candidate +// module at the requested version, but that module did not contain any packages +// matching the requested pattern. +// +// NOTE: PackageNotInModuleError MUST NOT implement Is(fs.ErrNotExist). +// +// If the module came from a proxy, that proxy had to return a successful status +// code for the versions it knows about, and thus did not have the opportunity +// to return a non-400 status code to suppress fallback. +type PackageNotInModuleError struct { + Mod module.Version + Replacement module.Version + Query string + Pattern string +} + +func (e *PackageNotInModuleError) Error() string { + if e.Mod == Target { + if strings.Contains(e.Pattern, "...") { + return fmt.Sprintf("main module (%s) does not contain packages matching %s", Target.Path, e.Pattern) + } + return fmt.Sprintf("main module (%s) does not contain package %s", Target.Path, e.Pattern) + } + + found := "" + if r := e.Replacement; r.Path != "" { + replacement := r.Path + if r.Version != "" { + replacement = fmt.Sprintf("%s@%s", r.Path, r.Version) + } + if e.Query == e.Mod.Version { + found = fmt.Sprintf(" (replaced by %s)", replacement) + } else { + found = fmt.Sprintf(" (%s, replaced by %s)", e.Mod.Version, replacement) + } + } else if e.Query != e.Mod.Version { + found = fmt.Sprintf(" (%s)", e.Mod.Version) + } + + if strings.Contains(e.Pattern, "...") { + return fmt.Sprintf("module %s@%s found%s, but does not contain packages matching %s", e.Mod.Path, e.Query, found, e.Pattern) + } + return fmt.Sprintf("module %s@%s found%s, but does not contain package %s", e.Mod.Path, e.Query, found, e.Pattern) +} + +func (e *PackageNotInModuleError) ImportPath() string { + if !strings.Contains(e.Pattern, "...") { + return e.Pattern + } + return "" +} + +// ModuleHasRootPackage returns whether module m contains a package m.Path. +func ModuleHasRootPackage(ctx context.Context, m module.Version) (bool, error) { + needSum := false + root, isLocal, err := fetch(ctx, m, needSum) + if err != nil { + return false, err + } + _, ok, err := dirInModule(m.Path, m.Path, root, isLocal) + return ok, err +} + +func versionHasGoMod(ctx context.Context, m module.Version) (bool, error) { + needSum := false + root, _, err := fetch(ctx, m, needSum) + if err != nil { + return false, err + } + fi, err := os.Stat(filepath.Join(root, "go.mod")) + return err == nil && !fi.IsDir(), nil +} + +// A versionRepo is a subset of modfetch.Repo that can report information about +// available versions, but cannot fetch specific source files. +type versionRepo interface { + ModulePath() string + Versions(prefix string) ([]string, error) + Stat(rev string) (*modfetch.RevInfo, error) + Latest() (*modfetch.RevInfo, error) +} + +var _ versionRepo = modfetch.Repo(nil) + +func lookupRepo(proxy, path string) (repo versionRepo, err error) { + err = module.CheckPath(path) + if err == nil { + repo = modfetch.Lookup(proxy, path) + } else { + repo = emptyRepo{path: path, err: err} + } + + if index == nil { + return repo, err + } + if _, ok := index.highestReplaced[path]; !ok { + return repo, err + } + + return &replacementRepo{repo: repo}, nil +} + +// An emptyRepo is a versionRepo that contains no versions. +type emptyRepo struct { + path string + err error +} + +var _ versionRepo = emptyRepo{} + +func (er emptyRepo) ModulePath() string { return er.path } +func (er emptyRepo) Versions(prefix string) ([]string, error) { return nil, nil } +func (er emptyRepo) Stat(rev string) (*modfetch.RevInfo, error) { return nil, er.err } +func (er emptyRepo) Latest() (*modfetch.RevInfo, error) { return nil, er.err } + +// A replacementRepo augments a versionRepo to include the replacement versions +// (if any) found in the main module's go.mod file. +// +// A replacementRepo suppresses "not found" errors for otherwise-nonexistent +// modules, so a replacementRepo should only be constructed for a module that +// actually has one or more valid replacements. +type replacementRepo struct { + repo versionRepo +} + +var _ versionRepo = (*replacementRepo)(nil) + +func (rr *replacementRepo) ModulePath() string { return rr.repo.ModulePath() } + +// Versions returns the versions from rr.repo augmented with any matching +// replacement versions. +func (rr *replacementRepo) Versions(prefix string) ([]string, error) { + repoVersions, err := rr.repo.Versions(prefix) + if err != nil && !errors.Is(err, os.ErrNotExist) { + return nil, err + } + + versions := repoVersions + if index != nil && len(index.replace) > 0 { + path := rr.ModulePath() + for m, _ := range index.replace { + if m.Path == path && strings.HasPrefix(m.Version, prefix) && m.Version != "" && !modfetch.IsPseudoVersion(m.Version) { + versions = append(versions, m.Version) + } + } + } + + if len(versions) == len(repoVersions) { // No replacement versions added. + return versions, nil + } + + sort.Slice(versions, func(i, j int) bool { + return semver.Compare(versions[i], versions[j]) < 0 + }) + str.Uniq(&versions) + return versions, nil +} + +func (rr *replacementRepo) Stat(rev string) (*modfetch.RevInfo, error) { + info, err := rr.repo.Stat(rev) + if err == nil || index == nil || len(index.replace) == 0 { + return info, err + } + + v := module.CanonicalVersion(rev) + if v != rev { + // The replacements in the go.mod file list only canonical semantic versions, + // so a non-canonical version can't possibly have a replacement. + return info, err + } + + path := rr.ModulePath() + _, pathMajor, ok := module.SplitPathVersion(path) + if ok && pathMajor == "" { + if err := module.CheckPathMajor(v, pathMajor); err != nil && semver.Build(v) == "" { + v += "+incompatible" + } + } + + if r := Replacement(module.Version{Path: path, Version: v}); r.Path == "" { + return info, err + } + return rr.replacementStat(v) +} + +func (rr *replacementRepo) Latest() (*modfetch.RevInfo, error) { + info, err := rr.repo.Latest() + + if index != nil { + path := rr.ModulePath() + if v, ok := index.highestReplaced[path]; ok { + if v == "" { + // The only replacement is a wildcard that doesn't specify a version, so + // synthesize a pseudo-version with an appropriate major version and a + // timestamp below any real timestamp. That way, if the main module is + // used from within some other module, the user will be able to upgrade + // the requirement to any real version they choose. + if _, pathMajor, ok := module.SplitPathVersion(path); ok && len(pathMajor) > 0 { + v = modfetch.PseudoVersion(pathMajor[1:], "", time.Time{}, "000000000000") + } else { + v = modfetch.PseudoVersion("v0", "", time.Time{}, "000000000000") + } + } + + if err != nil || semver.Compare(v, info.Version) > 0 { + return rr.replacementStat(v) + } + } + } + + return info, err +} + +func (rr *replacementRepo) replacementStat(v string) (*modfetch.RevInfo, error) { + rev := &modfetch.RevInfo{Version: v} + if modfetch.IsPseudoVersion(v) { + rev.Time, _ = modfetch.PseudoVersionTime(v) + rev.Short, _ = modfetch.PseudoVersionRev(v) + } + return rev, nil +} + +// A QueryMatchesMainModuleError indicates that a query requests +// a version of the main module that cannot be satisfied. +// (The main module's version cannot be changed.) +type QueryMatchesMainModuleError struct { + Pattern string + Query string +} + +func (e *QueryMatchesMainModuleError) Error() string { + if e.Pattern == Target.Path { + return fmt.Sprintf("can't request version %q of the main module (%s)", e.Query, e.Pattern) + } + + return fmt.Sprintf("can't request version %q of pattern %q that includes the main module (%s)", e.Query, e.Pattern, Target.Path) +} + +// A QueryMatchesPackagesInMainModuleError indicates that a query cannot be +// satisfied because it matches one or more packages found in the main module. +type QueryMatchesPackagesInMainModuleError struct { + Pattern string + Query string + Packages []string +} + +func (e *QueryMatchesPackagesInMainModuleError) Error() string { + if len(e.Packages) > 1 { + return fmt.Sprintf("pattern %s matches %d packages in the main module, so can't request version %s", e.Pattern, len(e.Packages), e.Query) + } + + if search.IsMetaPackage(e.Pattern) || strings.Contains(e.Pattern, "...") { + return fmt.Sprintf("pattern %s matches package %s in the main module, so can't request version %s", e.Pattern, e.Packages[0], e.Query) + } + + return fmt.Sprintf("package %s is in the main module, so can't request version %s", e.Packages[0], e.Query) +} diff --git a/src/cmd/go/internal/modload/query_test.go b/src/cmd/go/internal/modload/query_test.go new file mode 100644 index 0000000..e225a0e --- /dev/null +++ b/src/cmd/go/internal/modload/query_test.go @@ -0,0 +1,216 @@ +// 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 ( + "context" + "internal/testenv" + "log" + "os" + "path" + "path/filepath" + "strings" + "testing" + + "cmd/go/internal/cfg" + + "golang.org/x/mod/module" +) + +func TestMain(m *testing.M) { + os.Exit(testMain(m)) +} + +func testMain(m *testing.M) int { + cfg.GOPROXY = "direct" + + dir, err := os.MkdirTemp("", "modload-test-") + if err != nil { + log.Fatal(err) + } + defer os.RemoveAll(dir) + + os.Setenv("GOPATH", dir) + cfg.BuildContext.GOPATH = dir + cfg.GOMODCACHE = filepath.Join(dir, "pkg/mod") + 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. + emptyRepoPath = "vcs-test.golang.org/git/emptytest.git" +) + +var queryTests = []struct { + path string + query string + current 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 v1.9.10-pre2+metadata unversioned; 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 v2.6.0-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 checkout v2.5.5 + 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.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: `vcs-test.golang.org/git/querytest.git@v0.0.99: invalid version: 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: "v1.9.10-pre2+metadata", vers: "v1.9.10-pre2.0.20190513201126-42abcb6df8ee"}, + {path: queryRepo, query: "ed5ffdaa", vers: "v1.9.10-pre2.0.20191220134614-ed5ffdaa1f5e"}, + + // golang.org/issue/29262: The major version for for a module without a suffix + // should be based on the most recent tag (v1 as appropriate, not v0 + // unconditionally). + {path: queryRepo, query: "42abcb6df8ee", vers: "v1.9.10-pre2.0.20190513201126-42abcb6df8ee"}, + + {path: queryRepo, query: "v1.9.10-pre2+wrongmetadata", err: `vcs-test.golang.org/git/querytest.git@v1.9.10-pre2+wrongmetadata: invalid version: unknown revision v1.9.10-pre2+wrongmetadata`}, + {path: queryRepo, query: "v1.9.10-pre2", err: `vcs-test.golang.org/git/querytest.git@v1.9.10-pre2: invalid version: unknown revision v1.9.10-pre2`}, + {path: queryRepo, query: "latest", vers: "v1.9.9"}, + {path: queryRepo, query: "latest", current: "v1.9.10-pre1", vers: "v1.9.9"}, + {path: queryRepo, query: "upgrade", vers: "v1.9.9"}, + {path: queryRepo, query: "upgrade", current: "v1.9.10-pre1", vers: "v1.9.10-pre1"}, + {path: queryRepo, query: "upgrade", current: "v1.9.10-pre2+metadata", vers: "v1.9.10-pre2.0.20190513201126-42abcb6df8ee"}, + {path: queryRepo, query: "upgrade", current: "v0.0.0-20190513201126-42abcb6df8ee", vers: "v0.0.0-20190513201126-42abcb6df8ee"}, + {path: queryRepo, query: "upgrade", allow: "NOMATCH", err: `no matching versions for query "upgrade"`}, + {path: queryRepo, query: "upgrade", current: "v1.9.9", allow: "NOMATCH", err: `vcs-test.golang.org/git/querytest.git@v1.9.9: disallowed module version`}, + {path: queryRepo, query: "upgrade", current: "v1.99.99", err: `vcs-test.golang.org/git/querytest.git@v1.99.99: invalid version: unknown revision v1.99.99`}, + {path: queryRepo, query: "patch", current: "", vers: "v1.9.9"}, + {path: queryRepo, query: "patch", current: "v0.1.0", vers: "v0.1.2"}, + {path: queryRepo, query: "patch", current: "v1.9.0", vers: "v1.9.9"}, + {path: queryRepo, query: "patch", current: "v1.9.10-pre1", vers: "v1.9.10-pre1"}, + {path: queryRepo, query: "patch", current: "v1.9.10-pre2+metadata", vers: "v1.9.10-pre2.0.20190513201126-42abcb6df8ee"}, + {path: queryRepo, query: "patch", current: "v1.99.99", err: `vcs-test.golang.org/git/querytest.git@v1.99.99: invalid version: unknown revision v1.99.99`}, + {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"}, + + // golang.org/issue/27173: A pseudo-version may be based on the highest tag on + // any parent commit, or any existing semantically-lower tag: a given commit + // could have been a pre-release for a backport tag at any point. + {path: queryRepo, query: "3ef0cec634e0", vers: "v0.1.2-0.20180704023347-3ef0cec634e0"}, + {path: queryRepo, query: "v0.1.2-0.20180704023347-3ef0cec634e0", vers: "v0.1.2-0.20180704023347-3ef0cec634e0"}, + {path: queryRepo, query: "v0.1.1-0.20180704023347-3ef0cec634e0", vers: "v0.1.1-0.20180704023347-3ef0cec634e0"}, + {path: queryRepo, query: "v0.0.4-0.20180704023347-3ef0cec634e0", vers: "v0.0.4-0.20180704023347-3ef0cec634e0"}, + + // Invalid tags are tested in cmd/go/testdata/script/mod_pseudo_invalid.txt. + + {path: queryRepo, query: "start", vers: "v0.0.0-20180704023101-5e9e31667ddf"}, + {path: queryRepo, query: "5e9e31667ddf", vers: "v0.0.0-20180704023101-5e9e31667ddf"}, + {path: queryRepo, query: "v0.0.0-20180704023101-5e9e31667ddf", vers: "v0.0.0-20180704023101-5e9e31667ddf"}, + + {path: queryRepo, query: "7a1b6bf", vers: "v0.1.0"}, + + {path: queryRepoV2, query: "v0.0.0", vers: "v2.0.0"}, + {path: queryRepoV2, query: ">=v0.0.0", vers: "v2.0.0"}, + + {path: queryRepoV2, query: "v2", vers: "v2.5.5"}, + {path: queryRepoV2, query: "v2.5", vers: "v2.5.5"}, + {path: queryRepoV2, query: "v2.6", err: `no matching versions for query "v2.6"`}, + {path: queryRepoV2, query: "v2.6.0-pre1", vers: "v2.6.0-pre1"}, + {path: queryRepoV2, query: "latest", vers: "v2.5.5"}, + + // Commit e0cf3de987e6 is actually v1.19.10-pre1, not anything resembling v3, + // and it has a go.mod file with a non-v3 module path. Attempting to query it + // as the v3 module should fail. + {path: queryRepoV3, query: "e0cf3de987e6", err: `vcs-test.golang.org/git/querytest.git/v3@v3.0.0-20180704024501-e0cf3de987e6: invalid version: go.mod has non-.../v3 module path "vcs-test.golang.org/git/querytest.git" (and .../v3/go.mod does not exist) at revision e0cf3de987e6`}, + + // The querytest repo does not have any commits tagged with major version 3, + // and the latest commit in the repo has a go.mod file specifying a non-v3 path. + // That should prevent us from resolving any version for the /v3 path. + {path: queryRepoV3, query: "latest", err: `no matching versions for query "latest"`}, + + {path: emptyRepoPath, query: "latest", vers: "v0.0.0-20180704023549-7bb914627242"}, + {path: emptyRepoPath, query: ">v0.0.0", err: `no matching versions for query ">v0.0.0"`}, + {path: emptyRepoPath, query: "" { + // A wildcard replacement found in the main module's go.mod file. + mod = module.Version{Path: f[1]} + f = f[2:] + } else { + // Not a version or a wildcard replacement. + // We don't know how to interpret this module line, so ignore it. + mod = module.Version{} + continue + } + + if len(f) >= 2 && f[0] == "=>" { + meta := vendorMeta[mod] + if len(f) == 2 { + // File replacement. + meta.Replacement = module.Version{Path: f[1]} + vendorReplaced = append(vendorReplaced, mod) + } else if len(f) == 3 && semver.IsValid(f[2]) { + // Path and version replacement. + meta.Replacement = module.Version{Path: f[1], Version: f[2]} + vendorReplaced = append(vendorReplaced, mod) + } else { + // We don't understand this replacement. Ignore it. + } + vendorMeta[mod] = meta + } + continue + } + + // Not a module line. Must be a package within a module or a metadata + // directive, either of which requires a preceding module line. + if mod.Path == "" { + continue + } + + if strings.HasPrefix(line, "## ") { + // Metadata. Take the union of annotations across multiple lines, if present. + meta := vendorMeta[mod] + for _, entry := range strings.Split(strings.TrimPrefix(line, "## "), ";") { + entry = strings.TrimSpace(entry) + if entry == "explicit" { + meta.Explicit = true + } + // All other tokens are reserved for future use. + } + vendorMeta[mod] = meta + continue + } + + if f := strings.Fields(line); len(f) == 1 && module.CheckImportPath(f[0]) == nil { + // A package within the current module. + vendorPkgModule[f[0]] = mod + + // Since this module provides a package for the build, we know that it + // is in the build list and is the selected version of its path. + // If this information is new, record it. + if v, ok := vendorVersion[mod.Path]; !ok || semver.Compare(v, mod.Version) < 0 { + vendorList = append(vendorList, mod) + vendorVersion[mod.Path] = mod.Version + } + } + } + }) +} + +// checkVendorConsistency verifies that the vendor/modules.txt file matches (if +// go 1.14) or at least does not contradict (go 1.13 or earlier) the +// requirements and replacements listed in the main module's go.mod file. +func checkVendorConsistency() { + readVendorList() + + pre114 := false + if semver.Compare(index.goVersionV, "v1.14") < 0 { + // Go versions before 1.14 did not include enough information in + // vendor/modules.txt to check for consistency. + // If we know that we're on an earlier version, relax the consistency check. + pre114 = true + } + + vendErrors := new(strings.Builder) + vendErrorf := func(mod module.Version, format string, args ...interface{}) { + detail := fmt.Sprintf(format, args...) + if mod.Version == "" { + fmt.Fprintf(vendErrors, "\n\t%s: %s", mod.Path, detail) + } else { + fmt.Fprintf(vendErrors, "\n\t%s@%s: %s", mod.Path, mod.Version, detail) + } + } + + // Iterate over the Require directives in their original (not indexed) order + // so that the errors match the original file. + for _, r := range modFile.Require { + if !vendorMeta[r.Mod].Explicit { + if pre114 { + // Before 1.14, modules.txt did not indicate whether modules were listed + // explicitly in the main module's go.mod file. + // However, we can at least detect a version mismatch if packages were + // vendored from a non-matching version. + if vv, ok := vendorVersion[r.Mod.Path]; ok && vv != r.Mod.Version { + vendErrorf(r.Mod, fmt.Sprintf("is explicitly required in go.mod, but vendor/modules.txt indicates %s@%s", r.Mod.Path, vv)) + } + } else { + vendErrorf(r.Mod, "is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt") + } + } + } + + describe := func(m module.Version) string { + if m.Version == "" { + return m.Path + } + return m.Path + "@" + m.Version + } + + // We need to verify *all* replacements that occur in modfile: even if they + // don't directly apply to any module in the vendor list, the replacement + // go.mod file can affect the selected versions of other (transitive) + // dependencies + for _, r := range modFile.Replace { + vr := vendorMeta[r.Old].Replacement + if vr == (module.Version{}) { + if pre114 && (r.Old.Version == "" || vendorVersion[r.Old.Path] != r.Old.Version) { + // Before 1.14, modules.txt omitted wildcard replacements and + // replacements for modules that did not have any packages to vendor. + } else { + vendErrorf(r.Old, "is replaced in go.mod, but not marked as replaced in vendor/modules.txt") + } + } else if vr != r.New { + vendErrorf(r.Old, "is replaced by %s in go.mod, but marked as replaced by %s in vendor/modules.txt", describe(r.New), describe(vr)) + } + } + + for _, mod := range vendorList { + meta := vendorMeta[mod] + if meta.Explicit { + if _, inGoMod := index.require[mod]; !inGoMod { + vendErrorf(mod, "is marked as explicit in vendor/modules.txt, but not explicitly required in go.mod") + } + } + } + + for _, mod := range vendorReplaced { + r := Replacement(mod) + if r == (module.Version{}) { + vendErrorf(mod, "is marked as replaced in vendor/modules.txt, but not replaced in go.mod") + continue + } + if meta := vendorMeta[mod]; r != meta.Replacement { + vendErrorf(mod, "is marked as replaced by %s in vendor/modules.txt, but replaced by %s in go.mod", describe(meta.Replacement), describe(r)) + } + } + + if vendErrors.Len() > 0 { + base.Fatalf("go: inconsistent vendoring in %s:%s\n\n\tTo ignore the vendor directory, use -mod=readonly or -mod=mod.\n\tTo sync the vendor directory, run:\n\t\tgo mod vendor", modRoot, vendErrors) + } +} diff --git a/src/cmd/go/internal/mvs/errors.go b/src/cmd/go/internal/mvs/errors.go new file mode 100644 index 0000000..5564965 --- /dev/null +++ b/src/cmd/go/internal/mvs/errors.go @@ -0,0 +1,101 @@ +// Copyright 2020 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 ( + "fmt" + "strings" + + "golang.org/x/mod/module" +) + +// BuildListError decorates an error that occurred gathering requirements +// while constructing a build list. BuildListError prints the chain +// of requirements to the module where the error occurred. +type BuildListError struct { + Err error + stack []buildListErrorElem +} + +type buildListErrorElem struct { + m module.Version + + // nextReason is the reason this module depends on the next module in the + // stack. Typically either "requires", or "updating to". + nextReason string +} + +// NewBuildListError returns a new BuildListError wrapping an error that +// occurred at a module found along the given path of requirements and/or +// upgrades, which must be non-empty. +// +// The isUpgrade function reports whether a path step is due to an upgrade. +// A nil isUpgrade function indicates that none of the path steps are due to upgrades. +func NewBuildListError(err error, path []module.Version, isUpgrade func(from, to module.Version) bool) *BuildListError { + stack := make([]buildListErrorElem, 0, len(path)) + for len(path) > 1 { + reason := "requires" + if isUpgrade != nil && isUpgrade(path[0], path[1]) { + reason = "updating to" + } + stack = append(stack, buildListErrorElem{ + m: path[0], + nextReason: reason, + }) + path = path[1:] + } + stack = append(stack, buildListErrorElem{m: path[0]}) + + return &BuildListError{ + Err: err, + stack: stack, + } +} + +// Module returns the module where the error occurred. If the module stack +// is empty, this returns a zero value. +func (e *BuildListError) Module() module.Version { + if len(e.stack) == 0 { + return module.Version{} + } + return e.stack[len(e.stack)-1].m +} + +func (e *BuildListError) Error() string { + b := &strings.Builder{} + stack := e.stack + + // Don't print modules at the beginning of the chain without a + // version. These always seem to be the main module or a + // synthetic module ("target@"). + for len(stack) > 0 && stack[0].m.Version == "" { + stack = stack[1:] + } + + if len(stack) == 0 { + b.WriteString(e.Err.Error()) + } else { + for _, elem := range stack[:len(stack)-1] { + fmt.Fprintf(b, "%s %s\n\t", elem.m, elem.nextReason) + } + // Ensure that the final module path and version are included as part of the + // error message. + m := stack[len(stack)-1].m + if mErr, ok := e.Err.(*module.ModuleError); ok { + actual := module.Version{Path: mErr.Path, Version: mErr.Version} + if v, ok := mErr.Err.(*module.InvalidVersionError); ok { + actual.Version = v.Version + } + if actual == m { + fmt.Fprintf(b, "%v", e.Err) + } else { + fmt.Fprintf(b, "%s (replaced by %s): %v", m, actual, mErr.Err) + } + } else { + fmt.Fprintf(b, "%v", module.VersionError(m, e.Err)) + } + } + return b.String() +} diff --git a/src/cmd/go/internal/mvs/mvs.go b/src/cmd/go/internal/mvs/mvs.go new file mode 100644 index 0000000..b630b61 --- /dev/null +++ b/src/cmd/go/internal/mvs/mvs.go @@ -0,0 +1,481 @@ +// 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" + "sync/atomic" + + "cmd/go/internal/par" + + "golang.org/x/mod/module" +) + +// 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 target 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) +} + +// BuildList returns the build list for the target module. +// +// target is the root vertex of a module requirement graph. For cmd/go, this is +// typically the main module, but note that this algorithm is not intended to +// be Go-specific: module paths and versions are treated as opaque values. +// +// reqs describes the module requirement graph and provides an opaque method +// for comparing versions. +// +// BuildList traverses the graph and returns a list containing the highest +// version for each visited module. The first element of the returned list is +// target itself; reqs.Max requires target.Version to compare higher than all +// other versions, so no other version can be selected. The remaining elements +// of the list are sorted by path. +// +// See https://research.swtch.com/vgo-mvs for details. +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, error)) ([]module.Version, error) { + // Explore work graph in parallel in case reqs.Required + // does high-latency network operations. + type modGraphNode struct { + m module.Version + required []module.Version + upgrade module.Version + err error + } + var ( + mu sync.Mutex + modGraph = map[module.Version]*modGraphNode{} + min = map[string]string{} // maps module path to minimum required version + haveErr int32 + ) + setErr := func(n *modGraphNode, err error) { + n.err = err + atomic.StoreInt32(&haveErr, 1) + } + + var work par.Work + work.Add(target) + work.Do(10, func(item interface{}) { + m := item.(module.Version) + + node := &modGraphNode{m: m} + mu.Lock() + modGraph[m] = node + if m.Version != "none" { + if v, ok := min[m.Path]; !ok || reqs.Max(v, m.Version) != v { + min[m.Path] = m.Version + } + } + mu.Unlock() + + if m.Version != "none" { + required, err := reqs.Required(m) + if err != nil { + setErr(node, err) + return + } + node.required = required + for _, r := range node.required { + work.Add(r) + } + } + + if upgrade != nil { + u, err := upgrade(m) + if err != nil { + setErr(node, err) + return + } + if u != m { + node.upgrade = u + work.Add(u) + } + } + }) + + // If there was an error, find the shortest path from the target to the + // node where the error occurred so we can report a useful error message. + if haveErr != 0 { + // neededBy[a] = b means a was added to the module graph by b. + neededBy := make(map[*modGraphNode]*modGraphNode) + q := make([]*modGraphNode, 0, len(modGraph)) + q = append(q, modGraph[target]) + for len(q) > 0 { + node := q[0] + q = q[1:] + + if node.err != nil { + pathUpgrade := map[module.Version]module.Version{} + + // Construct the error path reversed (from the error to the main module), + // then reverse it to obtain the usual order (from the main module to + // the error). + errPath := []module.Version{node.m} + for n, prev := neededBy[node], node; n != nil; n, prev = neededBy[n], n { + if n.upgrade == prev.m { + pathUpgrade[n.m] = prev.m + } + errPath = append(errPath, n.m) + } + i, j := 0, len(errPath)-1 + for i < j { + errPath[i], errPath[j] = errPath[j], errPath[i] + i++ + j-- + } + + isUpgrade := func(from, to module.Version) bool { + return pathUpgrade[from] == to + } + + return nil, NewBuildListError(node.err, errPath, isUpgrade) + } + + neighbors := node.required + if node.upgrade.Path != "" { + neighbors = append(neighbors, node.upgrade) + } + for _, neighbor := range neighbors { + nn := modGraph[neighbor] + if neededBy[nn] != nil { + continue + } + neededBy[nn] = node + q = append(q, nn) + } + } + } + + // The final list is the minimum version of each module found in the graph. + + if v := min[target.Path]; v != target.Version { + // target.Version will be "" for modload, the main client of MVS. + // "" denotes the main module, which has no version. However, MVS treats + // version strings as opaque, so "" is not a special value here. + // See golang.org/issue/31491, golang.org/issue/29773. + panic(fmt.Sprintf("mistake: chose version %q instead of target %+v", v, target)) // TODO: Don't panic. + } + + list := []module.Version{target} + for path, vers := range min { + if path != target.Path { + list = append(list, module.Version{Path: path, Version: vers}) + } + + n := modGraph[module.Version{Path: path, Version: vers}] + required := n.required + for _, r := range required { + if r.Version == "none" { + continue + } + 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. + } + } + } + + 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, +// with the constraint that all module paths listed in base must +// appear in the returned list. +func Req(target module.Version, base []string, reqs Reqs) ([]module.Version, error) { + list, err := BuildList(target, reqs) + if err != nil { + return nil, err + } + + // 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[module.Version]bool{} + walk = func(m module.Version) error { + if have[m] { + return nil + } + have[m] = true + 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] { + 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, error) { + if m.Path == target.Path { + return target, nil + } + + return reqs.Upgrade(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 { + return nil, err + } + + pathInList := make(map[string]bool, len(list)) + for _, m := range list { + pathInList[m.Path] = true + } + list = append([]module.Version(nil), list...) + + upgradeTo := make(map[string]string, len(upgrade)) + for _, u := range upgrade { + if !pathInList[u.Path] { + list = append(list, module.Version{Path: u.Path, Version: "none"}) + } + if prev, dup := upgradeTo[u.Path]; dup { + upgradeTo[u.Path] = reqs.Max(prev, u.Version) + } else { + upgradeTo[u.Path] = u.Version + } + } + + return buildList(target, &override{target, list, reqs}, func(m module.Version) (module.Version, error) { + if v, ok := upgradeTo[m.Path]; ok { + return module.Version{Path: m.Path, Version: v}, nil + } + return m, nil + }) +} + +// Downgrade returns a build list for the target module +// in which the given additional modules are downgraded, +// potentially overriding the requirements of the target. +// +// 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 { + return nil, err + } + 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 { + // If we can't load the requirements, we couldn't load the go.mod file. + // There are a number of reasons this can happen, but this usually + // means an older version of the module had a missing or invalid + // go.mod file. For example, if example.com/mod released v2.0.0 before + // migrating to modules (v2.0.0+incompatible), then added a valid go.mod + // in v2.0.1, downgrading from v2.0.1 would cause this error. + // + // TODO(golang.org/issue/31730, golang.org/issue/30134): if the error + // is transient (we couldn't download go.mod), return the error from + // Downgrade. Currently, we can't tell what kind of error it is. + exclude(m) + } + 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 { + // This is likely a transient error reaching the repository, + // rather than a permanent error with the retrieved version. + // + // TODO(golang.org/issue/31730, golang.org/issue/30134): + // decode what to do based on the actual error. + return nil, err + } + // 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/src/cmd/go/internal/mvs/mvs_test.go b/src/cmd/go/internal/mvs/mvs_test.go new file mode 100644 index 0000000..721cd96 --- /dev/null +++ b/src/cmd/go/internal/mvs/mvs_test.go @@ -0,0 +1,525 @@ +// 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 ( + "fmt" + "reflect" + "strings" + "testing" + + "golang.org/x/mod/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 F1 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 D3 + +# 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 + +# golang.org/issue/31248: +# Even though we select X2, the requirement on I1 +# via X1 should be preserved. +name: cross8 +M: A1 B1 +A1: X1 +B1: X2 +X1: I1 +X2: +build M: M A1 B1 I1 X2 + +# Upgrade from B1 to B2 should not 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 D2 + +name: simplify +A: B1 C1 +B1: C2 +C1: D1 +C2: +build A: A B1 C2 D1 + +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: downcycle +A: A B2 +B2: A +B1: +downgrade A B1: A B1 + +# 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 + +# golang.org/issue/29773: +# Requirements of older versions of the target +# must be carried over. +name: cycle2 +A: B1 +A1: C1 +A2: D1 +B1: A1 +B2: A2 +C1: A2 +C2: +D2: +build A: A B1 C1 D1 +upgrade* A: A B2 C2 D2 + +# Cycles with multiple possible solutions. +# (golang.org/issue/34086) +name: cycle3 +M: A1 C2 +A1: B1 +B1: C1 +B2: C2 +C1: +C2: B2 +build M: M A1 B2 C2 +req M: A1 B2 +req M A: A1 B2 +req M C: A1 C2 + +# 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 + +name: req3 +M: A1 B1 +A1: X1 +B1: X2 +X1: I1 +X2: +req M: A1 B1 + +name: reqnone +M: Anone B1 D1 E1 +B1: Cnone D1 +E1: Fnone +build M: M B1 D1 E1 +req M: B1 E1 +` + +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) + } + if len(fns) == 0 { + t.Errorf("no functions tested") + } + }) + } + } + 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 { + // Copy the reqs map, but substitute the upgraded requirements in + // place of the target's original requirements. + upReqs := make(reqsMap, len(reqs)) + for m, r := range reqs { + upReqs[m] = r + } + upReqs[m(kf[1])] = list + + list, err = Req(m(kf[1]), nil, upReqs) + } + 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 := Req(m(kf[1]), 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) { + u := module.Version{Version: "none"} + for k := range r { + if k.Path == m.Path && r.Max(u.Version, k.Version) == k.Version && !strings.HasSuffix(k.Version, ".hidden") { + u = k + } + } + if u.Path == "" { + return module.Version{}, fmt.Errorf("missing module: %v", module.Version{Path: m.Path}) + } + 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, fmt.Errorf("missing module: %v", m) + } + return rr, nil +} diff --git a/src/cmd/go/internal/par/queue.go b/src/cmd/go/internal/par/queue.go new file mode 100644 index 0000000..180bc75 --- /dev/null +++ b/src/cmd/go/internal/par/queue.go @@ -0,0 +1,88 @@ +// Copyright 2020 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 "fmt" + +// Queue manages a set of work items to be executed in parallel. The number of +// active work items is limited, and excess items are queued sequentially. +type Queue struct { + maxActive int + st chan queueState +} + +type queueState struct { + active int // number of goroutines processing work; always nonzero when len(backlog) > 0 + backlog []func() + idle chan struct{} // if non-nil, closed when active becomes 0 +} + +// NewQueue returns a Queue that executes up to maxActive items in parallel. +// +// maxActive must be positive. +func NewQueue(maxActive int) *Queue { + if maxActive < 1 { + panic(fmt.Sprintf("par.NewQueue called with nonpositive limit (%d)", maxActive)) + } + + q := &Queue{ + maxActive: maxActive, + st: make(chan queueState, 1), + } + q.st <- queueState{} + return q +} + +// Add adds f as a work item in the queue. +// +// Add returns immediately, but the queue will be marked as non-idle until after +// f (and any subsequently-added work) has completed. +func (q *Queue) Add(f func()) { + st := <-q.st + if st.active == q.maxActive { + st.backlog = append(st.backlog, f) + q.st <- st + return + } + if st.active == 0 { + // Mark q as non-idle. + st.idle = nil + } + st.active++ + q.st <- st + + go func() { + for { + f() + + st := <-q.st + if len(st.backlog) == 0 { + if st.active--; st.active == 0 && st.idle != nil { + close(st.idle) + } + q.st <- st + return + } + f, st.backlog = st.backlog[0], st.backlog[1:] + q.st <- st + } + }() +} + +// Idle returns a channel that will be closed when q has no (active or enqueued) +// work outstanding. +func (q *Queue) Idle() <-chan struct{} { + st := <-q.st + defer func() { q.st <- st }() + + if st.idle == nil { + st.idle = make(chan struct{}) + if st.active == 0 { + close(st.idle) + } + } + + return st.idle +} diff --git a/src/cmd/go/internal/par/queue_test.go b/src/cmd/go/internal/par/queue_test.go new file mode 100644 index 0000000..1331e65 --- /dev/null +++ b/src/cmd/go/internal/par/queue_test.go @@ -0,0 +1,79 @@ +// Copyright 2020 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" + "testing" +) + +func TestQueueIdle(t *testing.T) { + q := NewQueue(1) + select { + case <-q.Idle(): + default: + t.Errorf("NewQueue(1) is not initially idle.") + } + + started := make(chan struct{}) + unblock := make(chan struct{}) + q.Add(func() { + close(started) + <-unblock + }) + + <-started + idle := q.Idle() + select { + case <-idle: + t.Errorf("NewQueue(1) is marked idle while processing work.") + default: + } + + close(unblock) + <-idle // Should be closed as soon as the Add callback returns. +} + +func TestQueueBacklog(t *testing.T) { + const ( + maxActive = 2 + totalWork = 3 * maxActive + ) + + q := NewQueue(maxActive) + t.Logf("q = NewQueue(%d)", maxActive) + + var wg sync.WaitGroup + wg.Add(totalWork) + started := make([]chan struct{}, totalWork) + unblock := make(chan struct{}) + for i := range started { + started[i] = make(chan struct{}) + i := i + q.Add(func() { + close(started[i]) + <-unblock + wg.Done() + }) + } + + for i, c := range started { + if i < maxActive { + <-c // Work item i should be started immediately. + } else { + select { + case <-c: + t.Errorf("Work item %d started before previous items finished.", i) + default: + } + } + } + + close(unblock) + for _, c := range started[maxActive:] { + <-c + } + wg.Wait() +} diff --git a/src/cmd/go/internal/par/work.go b/src/cmd/go/internal/par/work.go new file mode 100644 index 0000000..960cec6 --- /dev/null +++ b/src/cmd/go/internal/par/work.go @@ -0,0 +1,190 @@ +// 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 +} + +// Clear removes all entries in the cache. +// +// Concurrent calls to Get may return old values. Concurrent calls to Do +// may return old values or store results in entries that have been deleted. +// +// TODO(jayconrod): Delete this after the package cache clearing functions +// in internal/load have been removed. +func (c *Cache) Clear() { + c.m.Range(func(key, value interface{}) bool { + c.m.Delete(key) + return true + }) +} + +// Delete removes an entry from the map. It is safe to call Delete for an +// entry that does not exist. Delete will return quickly, even if the result +// for a key is still being computed; the computation will finish, but the +// result won't be accessible through the cache. +// +// TODO(jayconrod): Delete this after the package cache clearing functions +// in internal/load have been removed. +func (c *Cache) Delete(key interface{}) { + c.m.Delete(key) +} + +// DeleteIf calls pred for each key in the map. If pred returns true for a key, +// DeleteIf removes the corresponding entry. If the result for a key is +// still being computed, DeleteIf will remove the entry without waiting for +// the computation to finish. The result won't be accessible through the cache. +// +// TODO(jayconrod): Delete this after the package cache clearing functions +// in internal/load have been removed. +func (c *Cache) DeleteIf(pred func(key interface{}) bool) { + c.m.Range(func(key, _ interface{}) bool { + if pred(key) { + c.Delete(key) + } + return true + }) +} diff --git a/src/cmd/go/internal/par/work_test.go b/src/cmd/go/internal/par/work_test.go new file mode 100644 index 0000000..f104bc4 --- /dev/null +++ b/src/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/src/cmd/go/internal/renameio/renameio.go b/src/cmd/go/internal/renameio/renameio.go new file mode 100644 index 0000000..9788171 --- /dev/null +++ b/src/cmd/go/internal/renameio/renameio.go @@ -0,0 +1,94 @@ +// 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 renameio writes files atomically by renaming temporary files. +package renameio + +import ( + "bytes" + "io" + "io/fs" + "math/rand" + "os" + "path/filepath" + "strconv" + + "cmd/go/internal/robustio" +) + +const patternSuffix = ".tmp" + +// Pattern returns a glob pattern that matches the unrenamed temporary files +// created when writing to filename. +func Pattern(filename string) string { + return filepath.Join(filepath.Dir(filename), filepath.Base(filename)+patternSuffix) +} + +// WriteFile is like os.WriteFile, but first writes data to an arbitrary +// file in the same directory as filename, then renames it atomically to the +// final name. +// +// That ensures that the final location, if it exists, is always a complete file. +func WriteFile(filename string, data []byte, perm fs.FileMode) (err error) { + return WriteToFile(filename, bytes.NewReader(data), perm) +} + +// WriteToFile is a variant of WriteFile that accepts the data as an io.Reader +// instead of a slice. +func WriteToFile(filename string, data io.Reader, perm fs.FileMode) (err error) { + f, err := tempFile(filepath.Dir(filename), filepath.Base(filename), perm) + if err != nil { + return err + } + defer func() { + // Only call os.Remove on f.Name() if we failed to rename it: otherwise, + // some other process may have created a new file with the same name after + // that. + if err != nil { + f.Close() + os.Remove(f.Name()) + } + }() + + if _, err := io.Copy(f, data); err != nil { + return err + } + // Sync the file before renaming it: otherwise, after a crash the reader may + // observe a 0-length file instead of the actual contents. + // See https://golang.org/issue/22397#issuecomment-380831736. + if err := f.Sync(); err != nil { + return err + } + if err := f.Close(); err != nil { + return err + } + + return robustio.Rename(f.Name(), filename) +} + +// ReadFile is like os.ReadFile, but on Windows retries spurious errors that +// may occur if the file is concurrently replaced. +// +// Errors are classified heuristically and retries are bounded, so even this +// function may occasionally return a spurious error on Windows. +// If so, the error will likely wrap one of: +// - syscall.ERROR_ACCESS_DENIED +// - syscall.ERROR_FILE_NOT_FOUND +// - internal/syscall/windows.ERROR_SHARING_VIOLATION +func ReadFile(filename string) ([]byte, error) { + return robustio.ReadFile(filename) +} + +// tempFile creates a new temporary file with given permission bits. +func tempFile(dir, prefix string, perm fs.FileMode) (f *os.File, err error) { + for i := 0; i < 10000; i++ { + name := filepath.Join(dir, prefix+strconv.Itoa(rand.Intn(1000000000))+patternSuffix) + f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, perm) + if os.IsExist(err) { + continue + } + break + } + return +} diff --git a/src/cmd/go/internal/renameio/renameio_test.go b/src/cmd/go/internal/renameio/renameio_test.go new file mode 100644 index 0000000..5b2ed83 --- /dev/null +++ b/src/cmd/go/internal/renameio/renameio_test.go @@ -0,0 +1,160 @@ +// Copyright 2019 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 !plan9 + +package renameio + +import ( + "encoding/binary" + "errors" + "internal/testenv" + "math/rand" + "os" + "path/filepath" + "runtime" + "strings" + "sync" + "sync/atomic" + "syscall" + "testing" + "time" + + "cmd/go/internal/robustio" +) + +func TestConcurrentReadsAndWrites(t *testing.T) { + if runtime.GOOS == "darwin" && strings.HasSuffix(testenv.Builder(), "-10_14") { + testenv.SkipFlaky(t, 33041) + } + + dir, err := os.MkdirTemp("", "renameio") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + path := filepath.Join(dir, "blob.bin") + + const chunkWords = 8 << 10 + buf := make([]byte, 2*chunkWords*8) + for i := uint64(0); i < 2*chunkWords; i++ { + binary.LittleEndian.PutUint64(buf[i*8:], i) + } + + var attempts int64 = 128 + if !testing.Short() { + attempts *= 16 + } + const parallel = 32 + + var sem = make(chan bool, parallel) + + var ( + writeSuccesses, readSuccesses int64 // atomic + writeErrnoSeen, readErrnoSeen sync.Map + ) + + for n := attempts; n > 0; n-- { + sem <- true + go func() { + defer func() { <-sem }() + + time.Sleep(time.Duration(rand.Intn(100)) * time.Microsecond) + offset := rand.Intn(chunkWords) + chunk := buf[offset*8 : (offset+chunkWords)*8] + if err := WriteFile(path, chunk, 0666); err == nil { + atomic.AddInt64(&writeSuccesses, 1) + } else if robustio.IsEphemeralError(err) { + var ( + errno syscall.Errno + dup bool + ) + if errors.As(err, &errno) { + _, dup = writeErrnoSeen.LoadOrStore(errno, true) + } + if !dup { + t.Logf("ephemeral error: %v", err) + } + } else { + t.Errorf("unexpected error: %v", err) + } + + time.Sleep(time.Duration(rand.Intn(100)) * time.Microsecond) + data, err := ReadFile(path) + if err == nil { + atomic.AddInt64(&readSuccesses, 1) + } else if robustio.IsEphemeralError(err) { + var ( + errno syscall.Errno + dup bool + ) + if errors.As(err, &errno) { + _, dup = readErrnoSeen.LoadOrStore(errno, true) + } + if !dup { + t.Logf("ephemeral error: %v", err) + } + return + } else { + t.Errorf("unexpected error: %v", err) + return + } + + if len(data) != 8*chunkWords { + t.Errorf("read %d bytes, but each write is a %d-byte file", len(data), 8*chunkWords) + return + } + + u := binary.LittleEndian.Uint64(data) + for i := 1; i < chunkWords; i++ { + next := binary.LittleEndian.Uint64(data[i*8:]) + if next != u+1 { + t.Errorf("wrote sequential integers, but read integer out of sequence at offset %d", i) + return + } + u = next + } + }() + } + + for n := parallel; n > 0; n-- { + sem <- true + } + + var minWriteSuccesses int64 = attempts + if runtime.GOOS == "windows" { + // Windows produces frequent "Access is denied" errors under heavy rename load. + // As long as those are the only errors and *some* of the writes succeed, we're happy. + minWriteSuccesses = attempts / 4 + } + + if writeSuccesses < minWriteSuccesses { + t.Errorf("%d (of %d) writes succeeded; want ≥ %d", writeSuccesses, attempts, minWriteSuccesses) + } else { + t.Logf("%d (of %d) writes succeeded (ok: ≥ %d)", writeSuccesses, attempts, minWriteSuccesses) + } + + var minReadSuccesses int64 = attempts + + switch runtime.GOOS { + case "windows": + // Windows produces frequent "Access is denied" errors under heavy rename load. + // As long as those are the only errors and *some* of the reads succeed, we're happy. + minReadSuccesses = attempts / 4 + + case "darwin", "ios": + // The filesystem on certain versions of macOS (10.14) and iOS (affected + // versions TBD) occasionally fail with "no such file or directory" errors. + // See https://golang.org/issue/33041 and https://golang.org/issue/42066. + // The flake rate is fairly low, so ensure that at least 75% of attempts + // succeed. + minReadSuccesses = attempts - (attempts / 4) + } + + if readSuccesses < minReadSuccesses { + t.Errorf("%d (of %d) reads succeeded; want ≥ %d", readSuccesses, attempts, minReadSuccesses) + } else { + t.Logf("%d (of %d) reads succeeded (ok: ≥ %d)", readSuccesses, attempts, minReadSuccesses) + } +} diff --git a/src/cmd/go/internal/renameio/umask_test.go b/src/cmd/go/internal/renameio/umask_test.go new file mode 100644 index 0000000..65e4fa5 --- /dev/null +++ b/src/cmd/go/internal/renameio/umask_test.go @@ -0,0 +1,42 @@ +// Copyright 2019 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 !plan9,!windows,!js + +package renameio + +import ( + "io/fs" + "os" + "path/filepath" + "syscall" + "testing" +) + +func TestWriteFileModeAppliesUmask(t *testing.T) { + dir, err := os.MkdirTemp("", "renameio") + if err != nil { + t.Fatalf("Failed to create temporary directory: %v", err) + } + defer os.RemoveAll(dir) + + const mode = 0644 + const umask = 0007 + defer syscall.Umask(syscall.Umask(umask)) + + file := filepath.Join(dir, "testWrite") + err = WriteFile(file, []byte("go-build"), mode) + if err != nil { + t.Fatalf("Failed to write file: %v", err) + } + + fi, err := os.Stat(file) + if err != nil { + t.Fatalf("Stat %q (looking for mode %#o): %s", file, mode, err) + } + + if fi.Mode()&fs.ModePerm != 0640 { + t.Errorf("Stat %q: mode %#o want %#o", file, fi.Mode()&fs.ModePerm, 0640) + } +} diff --git a/src/cmd/go/internal/robustio/robustio.go b/src/cmd/go/internal/robustio/robustio.go new file mode 100644 index 0000000..ce3dbbd --- /dev/null +++ b/src/cmd/go/internal/robustio/robustio.go @@ -0,0 +1,53 @@ +// Copyright 2019 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 robustio wraps I/O functions that are prone to failure on Windows, +// transparently retrying errors up to an arbitrary timeout. +// +// Errors are classified heuristically and retries are bounded, so the functions +// in this package do not completely eliminate spurious errors. However, they do +// significantly reduce the rate of failure in practice. +// +// If so, the error will likely wrap one of: +// The functions in this package do not completely eliminate spurious errors, +// but substantially reduce their rate of occurrence in practice. +package robustio + +// Rename is like os.Rename, but on Windows retries errors that may occur if the +// file is concurrently read or overwritten. +// +// (See golang.org/issue/31247 and golang.org/issue/32188.) +func Rename(oldpath, newpath string) error { + return rename(oldpath, newpath) +} + +// ReadFile is like os.ReadFile, but on Windows retries errors that may +// occur if the file is concurrently replaced. +// +// (See golang.org/issue/31247 and golang.org/issue/32188.) +func ReadFile(filename string) ([]byte, error) { + return readFile(filename) +} + +// RemoveAll is like os.RemoveAll, but on Windows retries errors that may occur +// if an executable file in the directory has recently been executed. +// +// (See golang.org/issue/19491.) +func RemoveAll(path string) error { + return removeAll(path) +} + +// IsEphemeralError reports whether err is one of the errors that the functions +// in this package attempt to mitigate. +// +// Errors considered ephemeral include: +// - syscall.ERROR_ACCESS_DENIED +// - syscall.ERROR_FILE_NOT_FOUND +// - internal/syscall/windows.ERROR_SHARING_VIOLATION +// +// This set may be expanded in the future; programs must not rely on the +// non-ephemerality of any given error. +func IsEphemeralError(err error) bool { + return isEphemeralError(err) +} diff --git a/src/cmd/go/internal/robustio/robustio_darwin.go b/src/cmd/go/internal/robustio/robustio_darwin.go new file mode 100644 index 0000000..99fd8eb --- /dev/null +++ b/src/cmd/go/internal/robustio/robustio_darwin.go @@ -0,0 +1,21 @@ +// Copyright 2019 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 robustio + +import ( + "errors" + "syscall" +) + +const errFileNotFound = syscall.ENOENT + +// isEphemeralError returns true if err may be resolved by waiting. +func isEphemeralError(err error) bool { + var errno syscall.Errno + if errors.As(err, &errno) { + return errno == errFileNotFound + } + return false +} diff --git a/src/cmd/go/internal/robustio/robustio_flaky.go b/src/cmd/go/internal/robustio/robustio_flaky.go new file mode 100644 index 0000000..5bd44bd --- /dev/null +++ b/src/cmd/go/internal/robustio/robustio_flaky.go @@ -0,0 +1,91 @@ +// Copyright 2019 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 + +package robustio + +import ( + "errors" + "math/rand" + "os" + "syscall" + "time" +) + +const arbitraryTimeout = 2000 * time.Millisecond + +// retry retries ephemeral errors from f up to an arbitrary timeout +// to work around filesystem flakiness on Windows and Darwin. +func retry(f func() (err error, mayRetry bool)) error { + var ( + bestErr error + lowestErrno syscall.Errno + start time.Time + nextSleep time.Duration = 1 * time.Millisecond + ) + for { + err, mayRetry := f() + if err == nil || !mayRetry { + return err + } + + var errno syscall.Errno + if errors.As(err, &errno) && (lowestErrno == 0 || errno < lowestErrno) { + bestErr = err + lowestErrno = errno + } else if bestErr == nil { + bestErr = err + } + + if start.IsZero() { + start = time.Now() + } else if d := time.Since(start) + nextSleep; d >= arbitraryTimeout { + break + } + time.Sleep(nextSleep) + nextSleep += time.Duration(rand.Int63n(int64(nextSleep))) + } + + return bestErr +} + +// rename is like os.Rename, but retries ephemeral errors. +// +// On Windows it wraps os.Rename, which (as of 2019-06-04) uses MoveFileEx with +// MOVEFILE_REPLACE_EXISTING. +// +// Windows also provides a different system call, ReplaceFile, +// that provides similar semantics, but perhaps preserves more metadata. (The +// documentation on the differences between the two is very sparse.) +// +// Empirical error rates with MoveFileEx are lower under modest concurrency, so +// for now we're sticking with what the os package already provides. +func rename(oldpath, newpath string) (err error) { + return retry(func() (err error, mayRetry bool) { + err = os.Rename(oldpath, newpath) + return err, isEphemeralError(err) + }) +} + +// readFile is like os.ReadFile, but retries ephemeral errors. +func readFile(filename string) ([]byte, error) { + var b []byte + err := retry(func() (err error, mayRetry bool) { + b, err = os.ReadFile(filename) + + // Unlike in rename, we do not retry errFileNotFound here: it can occur + // as a spurious error, but the file may also genuinely not exist, so the + // increase in robustness is probably not worth the extra latency. + return err, isEphemeralError(err) && !errors.Is(err, errFileNotFound) + }) + return b, err +} + +func removeAll(path string) error { + return retry(func() (err error, mayRetry bool) { + err = os.RemoveAll(path) + return err, isEphemeralError(err) + }) +} diff --git a/src/cmd/go/internal/robustio/robustio_other.go b/src/cmd/go/internal/robustio/robustio_other.go new file mode 100644 index 0000000..6fe7b7e --- /dev/null +++ b/src/cmd/go/internal/robustio/robustio_other.go @@ -0,0 +1,27 @@ +// Copyright 2019 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 + +package robustio + +import ( + "os" +) + +func rename(oldpath, newpath string) error { + return os.Rename(oldpath, newpath) +} + +func readFile(filename string) ([]byte, error) { + return os.ReadFile(filename) +} + +func removeAll(path string) error { + return os.RemoveAll(path) +} + +func isEphemeralError(err error) bool { + return false +} diff --git a/src/cmd/go/internal/robustio/robustio_windows.go b/src/cmd/go/internal/robustio/robustio_windows.go new file mode 100644 index 0000000..687dcb6 --- /dev/null +++ b/src/cmd/go/internal/robustio/robustio_windows.go @@ -0,0 +1,27 @@ +// Copyright 2019 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 robustio + +import ( + "errors" + "internal/syscall/windows" + "syscall" +) + +const errFileNotFound = syscall.ERROR_FILE_NOT_FOUND + +// isEphemeralError returns true if err may be resolved by waiting. +func isEphemeralError(err error) bool { + var errno syscall.Errno + if errors.As(err, &errno) { + switch errno { + case syscall.ERROR_ACCESS_DENIED, + syscall.ERROR_FILE_NOT_FOUND, + windows.ERROR_SHARING_VIOLATION: + return true + } + } + return false +} diff --git a/src/cmd/go/internal/run/run.go b/src/cmd/go/internal/run/run.go new file mode 100644 index 0000000..666b1a0 --- /dev/null +++ b/src/cmd/go/internal/run/run.go @@ -0,0 +1,144 @@ +// Copyright 2011 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 run implements the ``go run'' command. +package run + +import ( + "context" + "fmt" + "os" + "path" + "strings" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/load" + "cmd/go/internal/str" + "cmd/go/internal/work" +) + +var CmdRun = &base.Command{ + UsageLine: "go run [build flags] [-exec xprog] package [arguments...]", + Short: "compile and run Go program", + Long: ` +Run compiles and runs the named main Go package. +Typically the package is specified as a list of .go source files from a single directory, +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: + 'xprog a.out arguments...'. +If the -exec flag is not given, GOOS or GOARCH is different from the system +default, and a program named go_$GOOS_$GOARCH_exec can be found +on the current search path, 'go run' invokes the binary using that program, +for example 'go_js_wasm_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. + `, +} + +func init() { + CmdRun.Run = runRun // break init loop + + work.AddBuildFlags(CmdRun, work.DefaultBuildFlags) + CmdRun.Flag.Var((*base.StringsFlag)(&work.ExecCmd), "exec", "") +} + +func printStderr(args ...interface{}) (int, error) { + return fmt.Fprint(os.Stderr, args...) +} + +func runRun(ctx context.Context, cmd *base.Command, args []string) { + work.BuildInit() + var b work.Builder + b.Init() + b.Print = printStderr + i := 0 + for i < len(args) && strings.HasSuffix(args[i], ".go") { + i++ + } + 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(ctx, files) + } else if len(args) > 0 && !strings.HasPrefix(args[0], "-") { + pkgs := load.PackagesAndErrors(ctx, args[:1]) + if len(pkgs) == 0 { + base.Fatalf("go run: no packages loaded from %s", args[0]) + } + 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") + } + cmdArgs := args[i:] + load.CheckPackageErrors([]*load.Package{p}) + + if p.Name != "main" { + base.Fatalf("go run: cannot run non-main package") + } + p.Internal.OmitDebug = true + p.Target = "" // must build - not up to date + if p.Internal.CmdlineFiles { + //set executable name if go file is given as cmd-argument + var src string + if len(p.GoFiles) > 0 { + src = p.GoFiles[0] + } else if len(p.CgoFiles) > 0 { + src = p.CgoFiles[0] + } else { + // this case could only happen if the provided source uses cgo + // while cgo is disabled. + hint := "" + if !cfg.BuildContext.CgoEnabled { + hint = " (cgo is disabled)" + } + base.Fatalf("go run: no suitable source files%s", hint) + } + p.Internal.ExeName = src[:len(src)-len(".go")] + } else { + p.Internal.ExeName = path.Base(p.ImportPath) + } + a1 := b.LinkAction(work.ModeBuild, work.ModeBuild, p) + a := &work.Action{Mode: "go run", Func: buildRunProgram, Args: cmdArgs, Deps: []*work.Action{a1}} + b.Do(ctx, a) +} + +// buildRunProgram is the action for running a binary that has already +// been compiled. We ignore exit status. +func buildRunProgram(b *work.Builder, ctx context.Context, a *work.Action) error { + cmdline := str.StringList(work.FindExecCmd(), a.Deps[0].Target, a.Args) + if cfg.BuildN || cfg.BuildX { + b.Showcmd("", "%s", strings.Join(cmdline, " ")) + if cfg.BuildN { + return nil + } + } + + base.RunStdin(cmdline) + return nil +} diff --git a/src/cmd/go/internal/search/search.go b/src/cmd/go/internal/search/search.go new file mode 100644 index 0000000..18738cf --- /dev/null +++ b/src/cmd/go/internal/search/search.go @@ -0,0 +1,639 @@ +// 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" + "cmd/go/internal/fsys" + "fmt" + "go/build" + "io/fs" + "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 + Dirs []string // if the pattern is local, directories that potentially contain matching packages + Pkgs []string // matching packages (import paths) + Errs []error // errors matching the patterns to packages, NOT errors loading those packages + + // Errs may be non-empty even if len(Pkgs) > 0, indicating that some matching + // packages could be located but results may be incomplete. + // If len(Pkgs) == 0 && len(Errs) == 0, the pattern is well-formed but did not + // match any packages. +} + +// NewMatch returns a Match describing the given pattern, +// without resolving its packages or errors. +func NewMatch(pattern string) *Match { + return &Match{pattern: pattern} +} + +// Pattern returns the pattern to be matched. +func (m *Match) Pattern() string { return m.pattern } + +// AddError appends a MatchError wrapping err to m.Errs. +func (m *Match) AddError(err error) { + m.Errs = append(m.Errs, &MatchError{Match: m, Err: err}) +} + +// Literal reports whether the pattern is free of wildcards and meta-patterns. +// +// A literal pattern must match at most one package. +func (m *Match) IsLiteral() bool { + return !strings.Contains(m.pattern, "...") && !m.IsMeta() +} + +// Local reports whether the pattern must be resolved from a specific root or +// directory, such as a filesystem path or a single module. +func (m *Match) IsLocal() bool { + return build.IsLocalImport(m.pattern) || filepath.IsAbs(m.pattern) +} + +// Meta reports whether the pattern is a “meta-package” keyword that represents +// multiple packages, such as "std", "cmd", or "all". +func (m *Match) IsMeta() bool { + return IsMetaPackage(m.pattern) +} + +// 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" +} + +// A MatchError indicates an error that occurred while attempting to match a +// pattern. +type MatchError struct { + Match *Match + Err error +} + +func (e *MatchError) Error() string { + if e.Match.IsLiteral() { + return fmt.Sprintf("%s: %v", e.Match.Pattern(), e.Err) + } + return fmt.Sprintf("pattern %s: %v", e.Match.Pattern(), e.Err) +} + +func (e *MatchError) Unwrap() error { + return e.Err +} + +// MatchPackages sets m.Pkgs to a non-nil slice containing all the packages that +// can be found under the $GOPATH directories and $GOROOT that match the +// pattern. The pattern must be either "all" (all packages), "std" (standard +// packages), "cmd" (standard commands), or a path including "...". +// +// If any errors may have caused the set of packages to be incomplete, +// MatchPackages appends those errors to m.Errs. +func (m *Match) MatchPackages() { + m.Pkgs = []string{} + if m.IsLocal() { + m.AddError(fmt.Errorf("internal error: MatchPackages: %s is not a valid package pattern", m.pattern)) + return + } + + if m.IsLiteral() { + m.Pkgs = []string{m.pattern} + return + } + + match := func(string) bool { return true } + treeCanMatch := func(string) bool { return true } + if !m.IsMeta() { + match = MatchPattern(m.pattern) + treeCanMatch = TreeCanMatchPattern(m.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 (m.pattern == "std" || m.pattern == "cmd") && src != cfg.GOROOTsrc { + continue + } + src = filepath.Clean(src) + string(filepath.Separator) + root := src + if m.pattern == "cmd" { + root += "cmd" + string(filepath.Separator) + } + err := fsys.Walk(root, func(path string, fi fs.FileInfo, err error) error { + if err != nil { + return err // Likely a permission error, which could interfere with matching. + } + if path == src { + return nil // GOROOT/src and GOPATH/src cannot contain packages. + } + + 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 m.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()&fs.ModeSymlink != 0 && want { + if target, err := fsys.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 { + // The package does not actually exist, so record neither the package + // nor the error. + return nil + } + // There was an error importing path, but not matching it, + // which is all that Match promises to do. + // Ignore the import error. + } + + // 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 m.pattern == "cmd" && pkg != nil && strings.HasPrefix(pkg.ImportPath, "cmd/vendor") && pkg.Name == "main" { + return nil + } + + m.Pkgs = append(m.Pkgs, name) + return nil + }) + if err != nil { + m.AddError(err) + } + } +} + +var modRoot string + +func SetModRoot(dir string) { + modRoot = dir +} + +// MatchDirs sets m.Dirs to a non-nil slice containing all directories that +// potentially match a local pattern. The pattern must begin with an absolute +// path, or "./", or "../". On Windows, the pattern may use slash or backslash +// separators or a mix of both. +// +// If any errors may have caused the set of directories to be incomplete, +// MatchDirs appends those errors to m.Errs. +func (m *Match) MatchDirs() { + m.Dirs = []string{} + if !m.IsLocal() { + m.AddError(fmt.Errorf("internal error: MatchDirs: %s is not a valid filesystem pattern", m.pattern)) + return + } + + if m.IsLiteral() { + m.Dirs = []string{m.pattern} + return + } + + // Clean the path and create a matching predicate. + // filepath.Clean removes "./" prefixes (and ".\" on Windows). We need to + // preserve these, since they are meaningful in MatchPattern and in + // returned import paths. + cleanPattern := filepath.Clean(m.pattern) + isLocal := strings.HasPrefix(m.pattern, "./") || (os.PathSeparator == '\\' && strings.HasPrefix(m.pattern, `.\`)) + prefix := "" + if cleanPattern != "." && isLocal { + prefix = "./" + cleanPattern = "." + string(os.PathSeparator) + cleanPattern + } + slashPattern := filepath.ToSlash(cleanPattern) + match := MatchPattern(slashPattern) + + // 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(cleanPattern, "...") + dir, _ := filepath.Split(cleanPattern[: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. + + if modRoot != "" { + abs, err := filepath.Abs(dir) + if err != nil { + m.AddError(err) + return + } + if !hasFilepathPrefix(abs, modRoot) { + m.AddError(fmt.Errorf("directory %s is outside module root (%s)", abs, modRoot)) + return + } + } + + err := fsys.Walk(dir, func(path string, fi fs.FileInfo, err error) error { + if err != nil { + return err // Likely a permission error, which could interfere with matching. + } + if !fi.IsDir() { + return nil + } + top := false + if path == dir { + // 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 fi, err := fsys.Stat(filepath.Join(path, "go.mod")); err == nil && !fi.IsDir() { + 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 { + // The package does not actually exist, so record neither the package + // nor the error. + return nil + } + // There was an error importing path, but not matching it, + // which is all that Match promises to do. + // Ignore the import error. + } + m.Dirs = append(m.Dirs, name) + return nil + }) + if err != nil { + m.AddError(err) + } +} + +// 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-separated 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.ReplaceAll(re, `\.\.\.`, `[^`+vendorChar+`]*`) + + 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 && len(m.Errs) == 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) { + m := NewMatch(a) + if m.IsLocal() { + m.MatchDirs() + + // Change the file import path to a regular import path if the package + // is in GOPATH or GOROOT. We don't report errors here; LoadImport + // (or something similar) will report them later. + m.Pkgs = make([]string, len(m.Dirs)) + for i, dir := range m.Dirs { + absDir := dir + if !filepath.IsAbs(dir) { + absDir = filepath.Join(base.Cwd, dir) + } + if bp, _ := cfg.BuildContext.ImportDir(absDir, build.FindOnly); bp.ImportPath != "" && bp.ImportPath != "." { + m.Pkgs[i] = bp.ImportPath + } else { + m.Pkgs[i] = dir + } + } + } else { + m.MatchPackages() + } + + out = append(out, m) + } + return out +} + +// CleanPatterns returns the patterns to use for the given command line. It +// canonicalizes the patterns but does not evaluate any matches. For patterns +// that are not local or absolute paths, it preserves text after '@' to avoid +// modifying version queries. +func CleanPatterns(patterns []string) []string { + if len(patterns) == 0 { + return []string{"."} + } + var out []string + for _, a := range patterns { + var p, v string + if build.IsLocalImport(a) || filepath.IsAbs(a) { + p = a + } else if i := strings.IndexByte(a, '@'); i < 0 { + p = a + } else { + p = a[:i] + v = a[i:] + } + + // Arguments may be either file paths or import paths. + // As a courtesy to Windows developers, rewrite \ to / + // in arguments that look like import paths. + // Don't replace slashes in absolute paths. + if filepath.IsAbs(p) { + p = filepath.Clean(p) + } else { + if filepath.Separator == '\\' { + p = strings.ReplaceAll(p, `\`, `/`) + } + + // Put argument in canonical form, but preserve leading ./. + if strings.HasPrefix(p, "./") { + p = "./" + path.Clean(p) + if p == "./." { + p = "." + } + } else { + p = path.Clean(p) + } + } + + out = append(out, p+v) + } + return out +} + +// 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/src/cmd/go/internal/search/search_test.go b/src/cmd/go/internal/search/search_test.go new file mode 100644 index 0000000..5f27daf --- /dev/null +++ b/src/cmd/go/internal/search/search_test.go @@ -0,0 +1,165 @@ +// 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. + +package search + +import ( + "strings" + "testing" +) + +var matchPatternTests = ` + pattern ... + match foo + + pattern net + match net + not net/http + + pattern net/http + match net/http + not net + + pattern net... + match net net/http netchan + not not/http not/net/http + + # Special cases. Quoting docs: + + # 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. + pattern net/... + match net net/http + not not/http not/net/http netchan + + # Second, any slash-separated 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. + pattern ./... + match ./vendor ./mycode/vendor + not ./vendor/foo ./mycode/vendor/foo + + pattern ./vendor/... + match ./vendor/foo ./vendor/foo/vendor + not ./vendor/foo/vendor/bar + + pattern mycode/vendor/... + match mycode/vendor mycode/vendor/foo mycode/vendor/foo/vendor + not mycode/vendor/foo/vendor/bar + + pattern x/vendor/y + match x/vendor/y + not x/vendor + + pattern x/vendor/y/... + match x/vendor/y x/vendor/y/z x/vendor/y/vendor x/vendor/y/z/vendor + not x/vendor/y/vendor/z + + pattern .../vendor/... + match x/vendor/y x/vendor/y/z x/vendor/y/vendor x/vendor/y/z/vendor +` + +func TestMatchPattern(t *testing.T) { + testPatterns(t, "MatchPattern", matchPatternTests, func(pattern, name string) bool { + return MatchPattern(pattern)(name) + }) +} + +var treeCanMatchPatternTests = ` + pattern ... + match foo + + pattern net + match net + not net/http + + pattern net/http + match net net/http + + pattern net... + match net netchan net/http + not not/http not/net/http + + pattern net/... + match net net/http + not not/http netchan + + pattern abc.../def + match abcxyz + not xyzabc + + pattern x/y/z/... + match x x/y x/y/z x/y/z/w + + pattern x/y/z + match x x/y x/y/z + not x/y/z/w + + pattern x/.../y/z + match x/a/b/c + not y/x/a/b/c +` + +func TestTreeCanMatchPattern(t *testing.T) { + testPatterns(t, "TreeCanMatchPattern", treeCanMatchPatternTests, func(pattern, name string) bool { + return TreeCanMatchPattern(pattern)(name) + }) +} + +var hasPathPrefixTests = []stringPairTest{ + {"abc", "a", false}, + {"a/bc", "a", true}, + {"a", "a", true}, + {"a/bc", "a/", true}, +} + +func TestHasPathPrefix(t *testing.T) { + testStringPairs(t, "hasPathPrefix", hasPathPrefixTests, hasPathPrefix) +} + +type stringPairTest struct { + in1 string + in2 string + out bool +} + +func testStringPairs(t *testing.T, name string, tests []stringPairTest, f func(string, string) bool) { + for _, tt := range tests { + if out := f(tt.in1, tt.in2); out != tt.out { + t.Errorf("%s(%q, %q) = %v, want %v", name, tt.in1, tt.in2, out, tt.out) + } + } +} + +func testPatterns(t *testing.T, name, tests string, fn func(string, string) bool) { + var patterns []string + for _, line := range strings.Split(tests, "\n") { + if i := strings.Index(line, "#"); i >= 0 { + line = line[:i] + } + f := strings.Fields(line) + if len(f) == 0 { + continue + } + switch f[0] { + default: + t.Fatalf("unknown directive %q", f[0]) + case "pattern": + patterns = f[1:] + case "match", "not": + want := f[0] == "match" + for _, pattern := range patterns { + for _, in := range f[1:] { + if fn(pattern, in) != want { + t.Errorf("%s(%q, %q) = %v, want %v", name, pattern, in, !want, want) + } + } + } + } + } +} diff --git a/src/cmd/go/internal/str/path.go b/src/cmd/go/internal/str/path.go new file mode 100644 index 0000000..51ab2af --- /dev/null +++ b/src/cmd/go/internal/str/path.go @@ -0,0 +1,51 @@ +// 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 str + +import ( + "path/filepath" + "strings" +) + +// HasPathPrefix 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)) + s = s[len(sv):] + prefix = prefix[len(pv):] + switch { + default: + return false + case sv != pv: + return false + case len(s) == len(prefix): + return s == prefix + case prefix == "": + return true + case len(s) > len(prefix): + 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/src/cmd/go/internal/str/str.go b/src/cmd/go/internal/str/str.go new file mode 100644 index 0000000..9106ebf --- /dev/null +++ b/src/cmd/go/internal/str/str.go @@ -0,0 +1,155 @@ +// 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 str provides string manipulation utilities. +package str + +import ( + "bytes" + "fmt" + "unicode" + "unicode/utf8" +) + +// StringList flattens its arguments into a single []string. +// Each argument in args must have type string or []string. +func StringList(args ...interface{}) []string { + var x []string + for _, arg := range args { + switch arg := arg.(type) { + case []string: + x = append(x, arg...) + case string: + x = append(x, arg) + default: + panic("stringList: invalid argument of type " + fmt.Sprintf("%T", arg)) + } + } + return x +} + +// ToFold returns a string with the property that +// strings.EqualFold(s, t) iff ToFold(s) == ToFold(t) +// This lets us test a large set of strings for fold-equivalent +// duplicates without making a quadratic number of calls +// to EqualFold. Note that strings.ToUpper and strings.ToLower +// do not have the desired property in some corner cases. +func ToFold(s string) string { + // Fast path: all ASCII, no upper case. + // Most paths look like this already. + for i := 0; i < len(s); i++ { + c := s[i] + if c >= utf8.RuneSelf || 'A' <= c && c <= 'Z' { + goto Slow + } + } + return s + +Slow: + var buf bytes.Buffer + for _, r := range s { + // SimpleFold(x) cycles to the next equivalent rune > x + // or wraps around to smaller values. Iterate until it wraps, + // and we've found the minimum value. + for { + r0 := r + r = unicode.SimpleFold(r0) + if r <= r0 { + break + } + } + // Exception to allow fast path above: A-Z => a-z + if 'A' <= r && r <= 'Z' { + r += 'a' - 'A' + } + buf.WriteRune(r) + } + return buf.String() +} + +// FoldDup reports a pair of strings from the list that are +// equal according to strings.EqualFold. +// It returns "", "" if there are no such strings. +func FoldDup(list []string) (string, string) { + clash := map[string]string{} + for _, s := range list { + fold := ToFold(s) + if t := clash[fold]; t != "" { + if s > t { + s, t = t, s + } + return s, t + } + clash[fold] = s + } + return "", "" +} + +// Contains reports whether x contains s. +func Contains(x []string, s string) bool { + for _, t := range x { + if t == s { + return true + } + } + return false +} + +// Uniq removes consecutive duplicate strings from ss. +func Uniq(ss *[]string) { + if len(*ss) <= 1 { + return + } + uniq := (*ss)[:1] + for _, s := range *ss { + if s != uniq[len(uniq)-1] { + uniq = append(uniq, s) + } + } + *ss = uniq +} + +func isSpaceByte(c byte) bool { + return c == ' ' || c == '\t' || c == '\n' || c == '\r' +} + +// SplitQuotedFields splits s into a list of fields, +// allowing single or double quotes around elements. +// There is no unescaping or other processing within +// quoted fields. +func SplitQuotedFields(s string) ([]string, error) { + // Split fields allowing '' or "" around elements. + // Quotes further inside the string do not count. + var f []string + for len(s) > 0 { + for len(s) > 0 && isSpaceByte(s[0]) { + s = s[1:] + } + if len(s) == 0 { + break + } + // Accepted quoted string. No unescaping inside. + if s[0] == '"' || s[0] == '\'' { + quote := s[0] + s = s[1:] + i := 0 + for i < len(s) && s[i] != quote { + i++ + } + if i >= len(s) { + return nil, fmt.Errorf("unterminated %c string", quote) + } + f = append(f, s[:i]) + s = s[i+1:] + continue + } + i := 0 + for i < len(s) && !isSpaceByte(s[i]) { + i++ + } + f = append(f, s[:i]) + s = s[i:] + } + return f, nil +} diff --git a/src/cmd/go/internal/str/str_test.go b/src/cmd/go/internal/str/str_test.go new file mode 100644 index 0000000..147ce1a --- /dev/null +++ b/src/cmd/go/internal/str/str_test.go @@ -0,0 +1,27 @@ +// Copyright 2020 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 str + +import "testing" + +var foldDupTests = []struct { + list []string + f1, f2 string +}{ + {StringList("math/rand", "math/big"), "", ""}, + {StringList("math", "strings"), "", ""}, + {StringList("strings"), "", ""}, + {StringList("strings", "strings"), "strings", "strings"}, + {StringList("Rand", "rand", "math", "math/rand", "math/Rand"), "Rand", "rand"}, +} + +func TestFoldDup(t *testing.T) { + for _, tt := range foldDupTests { + f1, f2 := FoldDup(tt.list) + if f1 != tt.f1 || f2 != tt.f2 { + t.Errorf("foldDup(%q) = %q, %q, want %q, %q", tt.list, f1, f2, tt.f1, tt.f2) + } + } +} diff --git a/src/cmd/go/internal/test/cover.go b/src/cmd/go/internal/test/cover.go new file mode 100644 index 0000000..9841791 --- /dev/null +++ b/src/cmd/go/internal/test/cover.go @@ -0,0 +1,84 @@ +// 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 test + +import ( + "cmd/go/internal/base" + "fmt" + "io" + "os" + "path/filepath" + "sync" +) + +var coverMerge struct { + f *os.File + sync.Mutex // for f.Write +} + +// initCoverProfile initializes the test coverage profile. +// It must be run before any calls to mergeCoverProfile or closeCoverProfile. +// 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 == "" || testC { + return + } + if !filepath.IsAbs(testCoverProfile) && testOutputDir != "" { + testCoverProfile = filepath.Join(testOutputDir, testCoverProfile) + } + + // No mutex - caller's responsibility to call with no racing goroutines. + f, err := os.Create(testCoverProfile) + if err != nil { + base.Fatalf("%v", err) + } + _, err = fmt.Fprintf(f, "mode: %s\n", testCoverMode) + if err != nil { + base.Fatalf("%v", err) + } + coverMerge.f = f +} + +// mergeCoverProfile merges file into the profile stored in testCoverProfile. +// It prints any errors it encounters to ew. +func mergeCoverProfile(ew io.Writer, file string) { + if coverMerge.f == nil { + return + } + coverMerge.Lock() + defer coverMerge.Unlock() + + expect := fmt.Sprintf("mode: %s\n", testCoverMode) + buf := make([]byte, len(expect)) + r, err := os.Open(file) + if err != nil { + // Test did not create profile, which is OK. + return + } + defer r.Close() + + n, err := io.ReadFull(r, buf) + if n == 0 { + return + } + if err != nil || string(buf) != expect { + fmt.Fprintf(ew, "error: test wrote malformed coverage profile.\n") + return + } + _, err = io.Copy(coverMerge.f, r) + if err != nil { + fmt.Fprintf(ew, "error: saving coverage profile: %v\n", err) + } +} + +func closeCoverProfile() { + if coverMerge.f == nil { + return + } + if err := coverMerge.f.Close(); err != nil { + base.Errorf("closing coverage profile: %v", err) + } +} diff --git a/src/cmd/go/internal/test/flagdefs.go b/src/cmd/go/internal/test/flagdefs.go new file mode 100644 index 0000000..8a0a076 --- /dev/null +++ b/src/cmd/go/internal/test/flagdefs.go @@ -0,0 +1,34 @@ +// Copyright 2019 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. + +// Code generated by genflags.go — DO NOT EDIT. + +package test + +// passFlagToTest contains the flags that should be forwarded to +// the test binary with the prefix "test.". +var passFlagToTest = map[string]bool{ + "bench": true, + "benchmem": true, + "benchtime": true, + "blockprofile": true, + "blockprofilerate": true, + "count": true, + "coverprofile": true, + "cpu": true, + "cpuprofile": true, + "failfast": true, + "list": true, + "memprofile": true, + "memprofilerate": true, + "mutexprofile": true, + "mutexprofilefraction": true, + "outputdir": true, + "parallel": true, + "run": true, + "short": true, + "timeout": true, + "trace": true, + "v": true, +} diff --git a/src/cmd/go/internal/test/flagdefs_test.go b/src/cmd/go/internal/test/flagdefs_test.go new file mode 100644 index 0000000..ab5440b --- /dev/null +++ b/src/cmd/go/internal/test/flagdefs_test.go @@ -0,0 +1,39 @@ +// Copyright 2019 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 test + +import ( + "flag" + "strings" + "testing" +) + +func TestPassFlagToTestIncludesAllTestFlags(t *testing.T) { + flag.VisitAll(func(f *flag.Flag) { + if !strings.HasPrefix(f.Name, "test.") { + return + } + name := strings.TrimPrefix(f.Name, "test.") + switch name { + case "testlogfile", "paniconexit0": + // These are internal flags. + default: + if !passFlagToTest[name] { + t.Errorf("passFlagToTest missing entry for %q (flag test.%s)", name, name) + t.Logf("(Run 'go generate cmd/go/internal/test' if it should be added.)") + } + } + }) + + for name := range passFlagToTest { + if flag.Lookup("test."+name) == nil { + t.Errorf("passFlagToTest contains %q, but flag -test.%s does not exist in test binary", name, name) + } + + if CmdTest.Flag.Lookup(name) == nil { + t.Errorf("passFlagToTest contains %q, but flag -%s does not exist in 'go test' subcommand", name, name) + } + } +} diff --git a/src/cmd/go/internal/test/genflags.go b/src/cmd/go/internal/test/genflags.go new file mode 100644 index 0000000..30334b0 --- /dev/null +++ b/src/cmd/go/internal/test/genflags.go @@ -0,0 +1,91 @@ +// Copyright 2019 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 + +package main + +import ( + "bytes" + "flag" + exec "internal/execabs" + "log" + "os" + "strings" + "testing" + "text/template" +) + +func main() { + if err := regenerate(); err != nil { + log.Fatal(err) + } +} + +func regenerate() error { + t := template.Must(template.New("fileTemplate").Parse(fileTemplate)) + buf := bytes.NewBuffer(nil) + if err := t.Execute(buf, testFlags()); err != nil { + return err + } + + f, err := os.Create("flagdefs.go") + if err != nil { + return err + } + + cmd := exec.Command("gofmt") + cmd.Stdin = buf + cmd.Stdout = f + cmd.Stderr = os.Stderr + cmdErr := cmd.Run() + + if err := f.Close(); err != nil { + return err + } + if cmdErr != nil { + os.Remove(f.Name()) + return cmdErr + } + + return nil +} + +func testFlags() []string { + testing.Init() + + var names []string + flag.VisitAll(func(f *flag.Flag) { + if !strings.HasPrefix(f.Name, "test.") { + return + } + name := strings.TrimPrefix(f.Name, "test.") + + switch name { + case "testlogfile", "paniconexit0": + // These flags are only for use by cmd/go. + default: + names = append(names, name) + } + }) + + return names +} + +const fileTemplate = `// Copyright 2019 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. + +// Code generated by genflags.go — DO NOT EDIT. + +package test + +// passFlagToTest contains the flags that should be forwarded to +// the test binary with the prefix "test.". +var passFlagToTest = map[string]bool { +{{- range .}} + "{{.}}": true, +{{- end }} +} +` diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go new file mode 100644 index 0000000..7fc9e8f --- /dev/null +++ b/src/cmd/go/internal/test/test.go @@ -0,0 +1,1720 @@ +// Copyright 2011 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 test + +import ( + "bytes" + "context" + "crypto/sha256" + "errors" + "fmt" + "go/build" + exec "internal/execabs" + "io" + "io/fs" + "os" + "path" + "path/filepath" + "regexp" + "sort" + "strconv" + "strings" + "sync" + "time" + + "cmd/go/internal/base" + "cmd/go/internal/cache" + "cmd/go/internal/cfg" + "cmd/go/internal/load" + "cmd/go/internal/lockedfile" + "cmd/go/internal/str" + "cmd/go/internal/trace" + "cmd/go/internal/work" + "cmd/internal/test2json" +) + +// Break init loop. +func init() { + CmdTest.Run = runTest +} + +const testUsage = "go test [build/test flags] [packages] [build/test flags & test binary flags]" + +var CmdTest = &base.Command{ + CustomFlags: true, + UsageLine: testUsage, + Short: "test packages", + Long: ` +'Go test' automates testing the packages named by the import paths. +It prints a summary of the test results in the format: + + ok archive/tar 0.011s + FAIL archive/zip 0.022s + ok compress/gzip 0.033s + ... + +followed by detailed output for each failed package. + +'Go test' recompiles each package along with any files with names matching +the file pattern "*_test.go". +These additional files can contain test functions, benchmark functions, and +example functions. See 'go help testfunc' for more. +Each listed package causes the execution of a separate test binary. +Files whose names begin with "_" (including "_test.go") or "." are ignored. + +Test files that declare a package with the suffix "_test" will be compiled as a +separate package, and then linked and run with the main test binary. + +The go tool will ignore a directory named "testdata", making it available +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. That subset is: 'atomic', 'bool', 'buildtags', 'errorsas', +'ifaceassert', 'nilfunc', 'printf', and 'stringintconv'. 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 +error. (The go command's standard error is reserved for printing +errors building the tests.) + +Go test runs in two different modes: + +The first, called local directory mode, occurs when go test is +invoked with no package arguments (for example, 'go test' or 'go +test -v'). In this mode, go test compiles the package sources and +tests found in the current directory and then runs the resulting +test binary. In this mode, caching (discussed below) is disabled. +After the package test finishes, go test prints a summary line +showing the test status ('ok' or 'FAIL'), package name, and elapsed +time. + +The second, called package list mode, occurs when go test is invoked +with explicit package arguments (for example 'go test math', 'go +test ./...', and even 'go test .'). In this mode, go test compiles +and tests each of the packages listed on the command line. If a +package test passes, go test prints only the final 'ok' summary +line. If a package test fails, go test prints the full test output. +If invoked with the -bench or -v flag, go test prints the full +output even for passing package tests, in order to display the +requested benchmark results or verbose logging. After the package +tests for all of the listed packages finish, and their output is +printed, go test prints a final 'FAIL' status if any package test +has failed. + +In package list mode only, go test caches successful package test +results to avoid unnecessary repeated running of tests. When the +result of a test can be recovered from the cache, go test will +redisplay the previous output instead of running the test binary +again. When this happens, go test prints '(cached)' in place of the +elapsed time in the summary line. + +The rule for a match in the cache is that the run involves the same +test binary and the flags on the command line come entirely from a +restricted set of 'cacheable' test flags, defined as -cpu, -list, +-parallel, -run, -short, and -v. If a run of go test has any test +or non-test flags outside this set, the result is not cached. 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. Tests that open files within the package's source +root (usually $GOPATH) or that consult environment variables only +match future runs in which the files and environment variables are unchanged. +A cached test result is treated as executing in no time at all, +so a successful package test result will be cached and reused +regardless of -timeout setting. + +In addition to the build flags, the flags handled by 'go test' itself are: + + -args + Pass the remainder of the command line (everything after -args) + to the test binary, uninterpreted and unchanged. + Because this flag consumes the remainder of the command line, + the package list (if present) must appear before this flag. + + -c + Compile the test binary to pkg.test but do not run it + (where pkg is the last element of the package's import path). + The file name can be changed with the -o flag. + + -exec xprog + Run the test binary using xprog. The behavior is the same as + in 'go run'. See 'go help run' for details. + + -i + Install packages that are dependencies of the test. + Do not run the test. + The -i flag is deprecated. Compiled packages are cached automatically. + + -json + Convert test output to JSON suitable for automated processing. + See 'go doc test2json' for the encoding details. + + -o file + Compile the test binary to the named file. + The test still runs (unless -c or -i is specified). + +The test binary also accepts flags that control execution of the test; these +flags are also accessible by 'go test'. See 'go help testflag' for details. + +For more about build flags, see 'go help build'. +For more about specifying packages, see 'go help packages'. + +See also: go build, go vet. +`, +} + +var HelpTestflag = &base.Command{ + UsageLine: "testflag", + Short: "testing flags", + Long: ` +The 'go test' command takes both flags that apply to 'go test' itself +and flags that apply to the resulting test binary. + +Several of the flags control profiling and write an execution profile +suitable for "go tool pprof"; run "go tool pprof -h" for more +information. The --alloc_space, --alloc_objects, and --show_bytes +options of pprof control how the information is presented. + +The following flags are recognized by the 'go test' command and +control the execution of any test: + + -bench regexp + Run only those benchmarks matching a regular expression. + By default, no benchmarks are run. + To run all benchmarks, use '-bench .' or '-bench=.'. + The regular expression is split by unbracketed slash (/) + characters into a sequence of regular expressions, and each + part of a benchmark's identifier must match the corresponding + element in the sequence, if any. Possible parents of matches + are run with b.N=1 to identify sub-benchmarks. For example, + given -bench=X/Y, top-level benchmarks matching X are run + with b.N=1 to find any sub-benchmarks matching Y, which are + then run in full. + + -benchtime t + Run enough iterations of each benchmark to take t, specified + as a time.Duration (for example, -benchtime 1h30s). + The default is 1 second (1s). + The special syntax Nx means to run the benchmark N times + (for example, -benchtime 100x). + + -count n + Run each test and benchmark n times (default 1). + If -cpu is set, run n times for each GOMAXPROCS value. + Examples are always run once. + + -cover + Enable coverage analysis. + Note that because coverage works by annotating the source + code before compilation, compilation and test failures with + coverage enabled may report line numbers that don't correspond + to the original sources. + + -covermode set,count,atomic + Set the mode for coverage analysis for the package[s] + being tested. The default is "set" unless -race is enabled, + in which case it is "atomic". + The values: + set: bool: does this statement run? + count: int: how many times does this statement run? + atomic: int: count, but correct in multithreaded tests; + significantly more expensive. + Sets -cover. + + -coverpkg pattern1,pattern2,pattern3 + Apply coverage analysis in each test to packages matching the patterns. + The default is for each test to analyze only the package being tested. + See 'go help packages' for a description of package patterns. + Sets -cover. + + -cpu 1,2,4 + Specify a list of GOMAXPROCS values for which the tests or + benchmarks should be executed. The default is the current value + of GOMAXPROCS. + + -failfast + Do not start new tests after the first test failure. + + -list regexp + List tests, benchmarks, or examples matching the regular expression. + No tests, benchmarks or examples will be run. This will only + list top-level tests. No subtest or subbenchmarks will be shown. + + -parallel n + Allow parallel execution of test functions that call t.Parallel. + The value of this flag is the maximum number of tests to run + simultaneously; by default, it is set to the value of GOMAXPROCS. + Note that -parallel only applies within a single test binary. + The 'go test' command may run tests for different packages + in parallel as well, according to the setting of the -p flag + (see 'go help build'). + + -run regexp + Run only those tests and examples matching the regular expression. + For tests, the regular expression is split by unbracketed slash (/) + characters into a sequence of regular expressions, and each part + of a test's identifier must match the corresponding element in + the sequence, if any. Note that possible parents of matches are + run too, so that -run=X/Y matches and runs and reports the result + of all tests matching X, even those without sub-tests matching Y, + because it must run them to look for those sub-tests. + + -short + Tell long-running tests to shorten their run time. + It is off by default but set during all.bash so that installing + the Go tree can run a sanity check but not spend time running + exhaustive tests. + + -timeout d + If a test binary runs longer than duration d, panic. + If d is 0, the timeout is disabled. + The default is 10 minutes (10m). + + -v + Verbose output: log all tests as they are run. Also print all + text from Log and Logf calls even if the test succeeds. + + -vet list + Configure the invocation of "go vet" during "go test" + to use the comma-separated list of vet checks. + If list is empty, "go test" runs "go vet" with a curated list of + checks believed to be always worth addressing. + If list is "off", "go test" does not run "go vet" at all. + +The following flags are also recognized by 'go test' and can be used to +profile the tests during execution: + + -benchmem + Print memory allocation statistics for benchmarks. + + -blockprofile block.out + Write a goroutine blocking profile to the specified file + when all tests are complete. + Writes test binary as -c would. + + -blockprofilerate n + Control the detail provided in goroutine blocking profiles by + calling runtime.SetBlockProfileRate with n. + See 'go doc runtime.SetBlockProfileRate'. + The profiler aims to sample, on average, one blocking event every + n nanoseconds the program spends blocked. By default, + if -test.blockprofile is set without this flag, all blocking events + are recorded, equivalent to -test.blockprofilerate=1. + + -coverprofile cover.out + Write a coverage profile to the file after all tests have passed. + Sets -cover. + + -cpuprofile cpu.out + Write a CPU profile to the specified file before exiting. + Writes test binary as -c would. + + -memprofile mem.out + 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 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 + when all tests are complete. + Writes test binary as -c would. + + -mutexprofilefraction n + Sample 1 in n stack traces of goroutines holding a + contended mutex. + + -outputdir directory + Place output files from profiling in the specified directory, + by default the directory in which "go test" is running. + + -trace trace.out + Write an execution trace to the specified file before exiting. + +Each of these flags is also recognized with an optional 'test.' prefix, +as in -test.v. When invoking the generated test binary (the result of +'go test -c') directly, however, the prefix is mandatory. + +The 'go test' command rewrites or removes recognized flags, +as appropriate, both before and after the optional package list, +before invoking the test binary. + +For instance, the command + + go test -v -myflag testdata -cpuprofile=prof.out -x + +will compile the test binary and then run it as + + pkg.test -test.v -myflag testdata -test.cpuprofile=prof.out + +(The -x flag is removed because it applies only to the go command's +execution, not to the test itself.) + +The test flags that generate profiles (other than for coverage) also +leave the test binary in pkg.test for use when analyzing the profiles. + +When 'go test' runs a test binary, it does so from within the +corresponding package's source code directory. Depending on the test, +it may be necessary to do the same when invoking a generated test +binary directly. + +The command-line package list, if present, must appear before any +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 +uninterpreted and unaltered. + +For instance, the command + + go test -v -args -x -v + +will compile the test binary and then run it as + + pkg.test -test.v -x -v + +Similarly, + + go test -args math + +will compile the test binary and then run it as + + pkg.test math + +In the first example, the -x and the second -v are passed through to the +test binary unchanged and with no effect on the go command itself. +In the second example, the argument math is passed through to the test +binary, instead of being interpreted as the package list. +`, +} + +var HelpTestfunc = &base.Command{ + UsageLine: "testfunc", + Short: "testing functions", + Long: ` +The 'go test' command expects to find test, benchmark, and example functions +in the "*_test.go" files corresponding to the package under test. + +A test function is one named TestXxx (where Xxx does not start with a +lower case letter) and should have the signature, + + func TestXxx(t *testing.T) { ... } + +A benchmark function is one named BenchmarkXxx and should have the signature, + + func BenchmarkXxx(b *testing.B) { ... } + +An example function is similar to a test function but, instead of using +*testing.T to report success or failure, prints output to os.Stdout. +If the last comment in the function starts with "Output:" then the output +is compared exactly against the comment (see examples below). If the last +comment begins with "Unordered output:" then the output is compared to the +comment, however the order of the lines is ignored. An example with no such +comment is compiled but not executed. An example with no text after +"Output:" is compiled, executed, and expected to produce no output. + +Godoc displays the body of ExampleXxx to demonstrate the use +of the function, constant, or variable Xxx. An example of a method M with +receiver type T or *T is named ExampleT_M. There may be multiple examples +for a given function, constant, or variable, distinguished by a trailing _xxx, +where xxx is a suffix not beginning with an upper case letter. + +Here is an example of an example: + + func ExamplePrintln() { + Println("The output of\nthis example.") + // Output: The output of + // this example. + } + +Here is another example where the ordering of the output is ignored: + + func ExamplePerm() { + for _, value := range Perm(4) { + fmt.Println(value) + } + + // Unordered output: 4 + // 2 + // 1 + // 3 + // 0 + } + +The entire test file is presented as the example when it contains a single +example function, at least one other function, type, variable, or constant +declaration, and no test or benchmark functions. + +See the documentation of the testing package for more information. +`, +} + +var ( + testBench string // -bench flag + testC bool // -c flag + testCover bool // -cover flag + testCoverMode string // -covermode flag + testCoverPaths []string // -coverpkg flag + testCoverPkgs []*load.Package // -coverpkg flag + testCoverProfile string // -coverprofile flag + testJSON bool // -json flag + testList string // -list flag + testO string // -o flag + testOutputDir = base.Cwd // -outputdir flag + testTimeout time.Duration // -timeout flag + testV bool // -v flag + testVet = vetFlag{flags: defaultVetFlags} // -vet flag +) + +var ( + testArgs []string + pkgArgs []string + pkgs []*load.Package + + testHelp bool // -help option passed to test via -args + + testKillTimeout = 100 * 365 * 24 * time.Hour // backup alarm; defaults to about a century if no timeout is set + testCacheExpire time.Time // ignore cached test results before this time + + testBlockProfile, testCPUProfile, testMemProfile, testMutexProfile, testTrace string // profiling flag that limits test to one package +) + +// testProfile returns the name of an arbitrary single-package profiling flag +// that is set, if any. +func testProfile() string { + switch { + case testBlockProfile != "": + return "-blockprofile" + case testCPUProfile != "": + return "-cpuprofile" + case testMemProfile != "": + return "-memprofile" + case testMutexProfile != "": + return "-mutexprofile" + case testTrace != "": + return "-trace" + default: + return "" + } +} + +// testNeedBinary reports whether the test needs to keep the binary around. +func testNeedBinary() bool { + switch { + case testBlockProfile != "": + return true + case testCPUProfile != "": + return true + case testMemProfile != "": + return true + case testMutexProfile != "": + return true + case testO != "": + return true + default: + return false + } +} + +// testShowPass reports whether the output for a passing test should be shown. +func testShowPass() bool { + return testV || (testList != "") || testHelp +} + +var defaultVetFlags = []string{ + // TODO(rsc): Decide which tests are enabled by default. + // See golang.org/issue/18085. + // "-asmdecl", + // "-assign", + "-atomic", + "-bool", + "-buildtags", + // "-cgocall", + // "-composites", + // "-copylocks", + "-errorsas", + // "-httpresponse", + "-ifaceassert", + // "-lostcancel", + // "-methods", + "-nilfunc", + "-printf", + // "-rangeloops", + // "-shift", + "-stringintconv", + // "-structtags", + // "-tests", + // "-unreachable", + // "-unsafeptr", + // "-unusedresult", +} + +func runTest(ctx context.Context, cmd *base.Command, args []string) { + load.ModResolveTests = true + + pkgArgs, testArgs = testFlags(args) + + if cfg.DebugTrace != "" { + var close func() error + var err error + ctx, close, err = trace.Start(ctx, cfg.DebugTrace) + if err != nil { + base.Fatalf("failed to start trace: %v", err) + } + defer func() { + if err := close(); err != nil { + base.Fatalf("failed to stop trace: %v", err) + } + }() + } + + ctx, span := trace.StartSpan(ctx, fmt.Sprint("Running ", cmd.Name(), " command")) + defer span.Done() + + work.FindExecCmd() // initialize cached result + + work.BuildInit() + work.VetFlags = testVet.flags + work.VetExplicit = testVet.explicit + + pkgs = load.PackagesAndErrors(ctx, pkgArgs) + load.CheckPackageErrors(pkgs) + if len(pkgs) == 0 { + base.Fatalf("no packages to test") + } + + if testC && len(pkgs) != 1 { + base.Fatalf("cannot use -c flag with multiple packages") + } + if testO != "" && len(pkgs) != 1 { + base.Fatalf("cannot use -o flag with multiple packages") + } + if testProfile() != "" && len(pkgs) != 1 { + base.Fatalf("cannot use %s flag with multiple packages", testProfile()) + } + initCoverProfile() + defer closeCoverProfile() + + // If a test timeout is finite, set our kill timeout + // to that timeout plus one minute. This is a backup alarm in case + // the test wedges with a goroutine spinning and its background + // timer does not get a chance to fire. + if testTimeout > 0 { + testKillTimeout = testTimeout + 1*time.Minute + } + + // For 'go test -i -o x.test', we want to build x.test. Imply -c to make the logic easier. + if cfg.BuildI && testO != "" { + testC = true + } + + // Read testcache expiration time, if present. + // (We implement go clean -testcache by writing an expiration date + // instead of searching out and deleting test result cache entries.) + if dir := cache.DefaultDir(); dir != "off" { + if data, _ := lockedfile.Read(filepath.Join(dir, "testexpire.txt")); len(data) > 0 && data[len(data)-1] == '\n' { + if t, err := strconv.ParseInt(string(data[:len(data)-1]), 10, 64); err == nil { + testCacheExpire = time.Unix(0, t) + } + } + } + + var b work.Builder + b.Init() + + if cfg.BuildI { + fmt.Fprint(os.Stderr, "go test: -i flag is deprecated\n") + cfg.BuildV = testV + + deps := make(map[string]bool) + for _, dep := range load.TestMainDeps { + deps[dep] = true + } + + for _, p := range pkgs { + // Dependencies for each test. + for _, path := range p.Imports { + deps[path] = true + } + for _, path := range p.Resolve(p.TestImports) { + deps[path] = true + } + for _, path := range p.Resolve(p.XTestImports) { + deps[path] = true + } + } + + // translate C to runtime/cgo + if deps["C"] { + delete(deps, "C") + deps["runtime/cgo"] = true + } + // Ignore pseudo-packages. + delete(deps, "unsafe") + + all := []string{} + for path := range deps { + if !build.IsLocalImport(path) { + all = append(all, path) + } + } + sort.Strings(all) + + a := &work.Action{Mode: "go test -i"} + pkgs := load.PackagesAndErrors(ctx, all) + load.CheckPackageErrors(pkgs) + for _, p := range pkgs { + if cfg.BuildToolchainName == "gccgo" && p.Standard { + // gccgo's standard library packages + // can not be reinstalled. + continue + } + a.Deps = append(a.Deps, b.CompileAction(work.ModeInstall, work.ModeInstall, p)) + } + b.Do(ctx, a) + if !testC || a.Failed { + return + } + b.Init() + } + + var builds, runs, prints []*work.Action + + if testCoverPaths != nil { + match := make([]func(*load.Package) bool, len(testCoverPaths)) + matched := make([]bool, len(testCoverPaths)) + for i := range testCoverPaths { + match[i] = load.MatchPackage(testCoverPaths[i], base.Cwd) + } + + // Select for coverage all dependencies matching the testCoverPaths patterns. + for _, p := range load.TestPackageList(ctx, pkgs) { + haveMatch := false + for i := range testCoverPaths { + if match[i](p) { + matched[i] = true + haveMatch = true + } + } + + // Silently ignore attempts to run coverage on + // sync/atomic when using atomic coverage mode. + // Atomic coverage mode uses sync/atomic, so + // we can't also do coverage on it. + if testCoverMode == "atomic" && p.Standard && p.ImportPath == "sync/atomic" { + continue + } + + // If using the race detector, silently ignore + // attempts to run coverage on the runtime + // packages. It will cause the race detector + // to be invoked before it has been initialized. + if cfg.BuildRace && p.Standard && (p.ImportPath == "runtime" || strings.HasPrefix(p.ImportPath, "runtime/internal")) { + continue + } + + if haveMatch { + testCoverPkgs = append(testCoverPkgs, p) + } + } + + // Warn about -coverpkg arguments that are not actually used. + for i := range testCoverPaths { + if !matched[i] { + fmt.Fprintf(os.Stderr, "warning: no packages being tested depend on matches for pattern %s\n", testCoverPaths[i]) + } + } + + // Mark all the coverage packages for rebuilding with coverage. + for _, p := range testCoverPkgs { + // There is nothing to cover in package unsafe; it comes from the compiler. + if p.ImportPath == "unsafe" { + continue + } + p.Internal.CoverMode = testCoverMode + var coverFiles []string + coverFiles = append(coverFiles, p.GoFiles...) + coverFiles = append(coverFiles, p.CgoFiles...) + coverFiles = append(coverFiles, p.TestGoFiles...) + p.Internal.CoverVars = declareCoverVars(p, coverFiles...) + if testCover && testCoverMode == "atomic" { + ensureImport(p, "sync/atomic") + } + } + } + + // Prepare build + run + print actions for all packages being tested. + for _, p := range pkgs { + // sync/atomic import is inserted by the cover tool. See #18486 + if testCover && testCoverMode == "atomic" { + ensureImport(p, "sync/atomic") + } + + buildTest, runTest, printTest, err := builderTest(&b, ctx, p) + if err != nil { + str := err.Error() + str = strings.TrimPrefix(str, "\n") + if p.ImportPath != "" { + base.Errorf("# %s\n%s", p.ImportPath, str) + } else { + base.Errorf("%s", str) + } + fmt.Printf("FAIL\t%s [setup failed]\n", p.ImportPath) + continue + } + builds = append(builds, buildTest) + runs = append(runs, runTest) + prints = append(prints, printTest) + } + + // Ultimately the goal is to print the output. + root := &work.Action{Mode: "go test", Func: printExitStatus, Deps: prints} + + // Force the printing of results to happen in order, + // one at a time. + for i, a := range prints { + if i > 0 { + a.Deps = append(a.Deps, prints[i-1]) + } + } + + // Force benchmarks to run in serial. + if !testC && (testBench != "") { + // The first run must wait for all builds. + // Later runs must wait for the previous run's print. + for i, run := range runs { + if i == 0 { + run.Deps = append(run.Deps, builds...) + } else { + run.Deps = append(run.Deps, prints[i-1]) + } + } + } + + b.Do(ctx, root) +} + +// ensures that package p imports the named package +func ensureImport(p *load.Package, pkg string) { + for _, d := range p.Internal.Imports { + if d.Name == pkg { + return + } + } + + p1 := load.LoadImportWithFlags(pkg, p.Dir, p, &load.ImportStack{}, nil, 0) + if p1.Error != nil { + base.Fatalf("load %s: %v", pkg, p1.Error) + } + + p.Internal.Imports = append(p.Internal.Imports, p1) +} + +var windowsBadWords = []string{ + "install", + "patch", + "setup", + "update", +} + +func builderTest(b *work.Builder, ctx context.Context, p *load.Package) (buildAction, runAction, printAction *work.Action, err error) { + if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 { + build := b.CompileAction(work.ModeBuild, work.ModeBuild, p) + run := &work.Action{Mode: "test run", Package: p, Deps: []*work.Action{build}} + addTestVet(b, p, run, nil) + print := &work.Action{Mode: "test print", Func: builderNoTest, Package: p, Deps: []*work.Action{run}} + return build, run, print, nil + } + + // Build Package structs describing: + // pmain - pkg.test binary + // ptest - package + test files + // pxtest - package of external test files + 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.TestPackagesFor(ctx, p, cover) + if err != nil { + return nil, nil, nil, err + } + + // Use last element of import path, not package name. + // They differ when package name is "main". + // But if the import path is "command-line-arguments", + // like it is during 'go run', use the package name. + var elem string + if p.ImportPath == "command-line-arguments" { + elem = p.Name + } else { + elem = p.DefaultExecName() + } + testBinary := elem + ".test" + + testDir := b.NewObjdir() + if err := b.Mkdir(testDir); err != nil { + return nil, nil, nil, err + } + + pmain.Dir = testDir + pmain.Internal.OmitDebug = !testC && !testNeedBinary() + + if !cfg.BuildN { + // writeTestmain writes _testmain.go, + // using the test description gathered in t. + if err := os.WriteFile(testDir+"_testmain.go", *pmain.Internal.TestmainGo, 0666); err != nil { + return nil, nil, nil, err + } + } + + // Set compile objdir to testDir we've already created, + // so that the default file path stripping applies to _testmain.go. + b.CompileAction(work.ModeBuild, work.ModeBuild, pmain).Objdir = testDir + + a := b.LinkAction(work.ModeBuild, work.ModeBuild, pmain) + a.Target = testDir + testBinary + cfg.ExeSuffix + if cfg.Goos == "windows" { + // There are many reserved words on Windows that, + // if used in the name of an executable, cause Windows + // to try to ask for extra permissions. + // The word list includes setup, install, update, and patch, + // but it does not appear to be defined anywhere. + // We have run into this trying to run the + // go.codereview/patch tests. + // For package names containing those words, use test.test.exe + // instead of pkgname.test.exe. + // Note that this file name is only used in the Go command's + // temporary directory. If the -c or other flags are + // given, the code below will still use pkgname.test.exe. + // There are two user-visible effects of this change. + // First, you can actually run 'go test' in directories that + // have names that Windows thinks are installer-like, + // without getting a dialog box asking for more permissions. + // Second, in the Windows process listing during go test, + // the test shows up as test.test.exe, not pkgname.test.exe. + // That second one is a drawback, but it seems a small + // price to pay for the test running at all. + // If maintaining the list of bad words is too onerous, + // we could just do this always on Windows. + for _, bad := range windowsBadWords { + if strings.Contains(testBinary, bad) { + a.Target = testDir + "test.test" + cfg.ExeSuffix + break + } + } + } + buildAction = a + var installAction, cleanAction *work.Action + if testC || testNeedBinary() { + // -c or profiling flag: create action to copy binary to ./test.out. + target := filepath.Join(base.Cwd, testBinary+cfg.ExeSuffix) + if testO != "" { + target = testO + if !filepath.IsAbs(target) { + target = filepath.Join(base.Cwd, target) + } + } + if target == os.DevNull { + runAction = buildAction + } else { + pmain.Target = target + installAction = &work.Action{ + Mode: "test build", + Func: work.BuildInstallFunc, + Deps: []*work.Action{buildAction}, + Package: pmain, + Target: target, + } + 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) + runAction = &work.Action{ + Mode: "test run", + Func: c.builderRunTest, + Deps: []*work.Action{buildAction}, + Package: p, + IgnoreFail: true, // run (prepare output) even if build failed + TryCache: c.tryCache, + Objdir: testDir, + } + vetRunAction = runAction + cleanAction = &work.Action{ + Mode: "test clean", + Func: builderCleanTest, + Deps: []*work.Action{runAction}, + Package: p, + IgnoreFail: true, // clean even if test failed + Objdir: testDir, + } + printAction = &work.Action{ + Mode: "test print", + Func: builderPrintTest, + Deps: []*work.Action{cleanAction}, + Package: p, + 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) + } + if cleanAction != nil { + cleanAction.Deps = append(cleanAction.Deps, installAction) + } + } + + return buildAction, runAction, printAction, nil +} + +func addTestVet(b *work.Builder, p *load.Package, runAction, installAction *work.Action) { + if testVet.off { + return + } + + vet := b.VetAction(work.ModeBuild, work.ModeBuild, p) + runAction.Deps = append(runAction.Deps, vet) + // Install will clean the build directory. + // Make sure vet runs first. + // The install ordering in b.VetAction does not apply here + // because we are using a custom installAction (created above). + if installAction != nil { + installAction.Deps = append(installAction.Deps, vet) + } +} + +// isTestFile reports whether the source file is a set of tests and should therefore +// be excluded from coverage analysis. +func isTestFile(file string) bool { + // We don't cover tests, only the code they test. + return strings.HasSuffix(file, "_test.go") +} + +// declareCoverVars attaches the required cover variables names +// to the files, to be used when annotating the files. +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. + // We need to avoid collisions with user variables (GoCover_0 is unlikely but still) + // and more importantly with dot imports of other covered packages, + // 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(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: longFile, + Var: fmt.Sprintf("GoCover_%d_%x", coverIndex, h), + } + coverIndex++ + } + return coverVars +} + +var noTestsToRun = []byte("\ntesting: warning: no tests to run\n") + +type runCache struct { + disableCache bool // cache should be disabled for this run + + buf *bytes.Buffer + id1 cache.ActionID + id2 cache.ActionID +} + +// stdoutMu and lockedStdout provide a locked standard output +// that guarantees never to interlace writes from multiple +// goroutines, so that we can have multiple JSON streams writing +// to a lockedStdout simultaneously and know that events will +// still be intelligible. +var stdoutMu sync.Mutex + +type lockedStdout struct{} + +func (lockedStdout) Write(b []byte) (int, error) { + stdoutMu.Lock() + defer stdoutMu.Unlock() + return os.Stdout.Write(b) +} + +// builderRunTest is the action for running a test binary. +func (c *runCache) builderRunTest(b *work.Builder, ctx context.Context, a *work.Action) error { + if a.Failed { + // We were unable to build the binary. + a.Failed = false + a.TestOutput = new(bytes.Buffer) + fmt.Fprintf(a.TestOutput, "FAIL\t%s [build failed]\n", a.Package.ImportPath) + base.SetExitStatus(1) + return nil + } + + var stdout io.Writer = os.Stdout + var err error + if testJSON { + json := test2json.NewConverter(lockedStdout{}, a.Package.ImportPath, test2json.Timestamp) + defer func() { + json.Exited(err) + json.Close() + }() + stdout = json + } + + var buf bytes.Buffer + if len(pkgArgs) == 0 || (testBench != "") { + // Stream test output (no buffering) when no package has + // been given on the command line (implicit current directory) + // or when benchmarking. + // No change to stdout. + } else { + // If we're only running a single package under test or if parallelism is + // set to 1, and if we're displaying all output (testShowPass), we can + // hurry the output along, echoing it as soon as it comes in. + // We still have to copy to &buf for caching the result. This special + // case was introduced in Go 1.5 and is intentionally undocumented: + // the exact details of output buffering are up to the go command and + // subject to change. It would be nice to remove this special case + // entirely, but it is surely very helpful to see progress being made + // when tests are run on slow single-CPU ARM systems. + // + // If we're showing JSON output, then display output as soon as + // possible even when multiple tests are being run: the JSON output + // events are attributed to specific package tests, so interlacing them + // is OK. + if testShowPass() && (len(pkgs) == 1 || cfg.BuildP == 1) || testJSON { + // Write both to stdout and buf, for possible saving + // to cache, and for looking for the "no tests to run" message. + stdout = io.MultiWriter(stdout, &buf) + } else { + stdout = &buf + } + } + + if c.buf == nil { + // We did not find a cached result using the link step action ID, + // so we ran the link step. Try again now with the link output + // content ID. The attempt using the action ID makes sure that + // if the link inputs don't change, we reuse the cached test + // result without even rerunning the linker. The attempt using + // the link output (test binary) content ID makes sure that if + // we have different link inputs but the same final binary, + // we still reuse the cached test result. + // c.saveOutput will store the result under both IDs. + c.tryCacheWithID(b, a, a.Deps[0].BuildContentID()) + } + if c.buf != nil { + if stdout != &buf { + stdout.Write(c.buf.Bytes()) + c.buf.Reset() + } + a.TestOutput = c.buf + return nil + } + + execCmd := work.FindExecCmd() + testlogArg := []string{} + if !c.disableCache && len(execCmd) == 0 { + testlogArg = []string{"-test.testlogfile=" + a.Objdir + "testlog.txt"} + } + panicArg := "-test.paniconexit0" + args := str.StringList(execCmd, a.Deps[0].BuiltTarget(), testlogArg, panicArg, testArgs) + + if testCoverProfile != "" { + // Write coverage to temporary profile, for merging later. + for i, arg := range args { + if strings.HasPrefix(arg, "-test.coverprofile=") { + args[i] = "-test.coverprofile=" + a.Objdir + "_cover_.out" + } + } + } + + if cfg.BuildN || cfg.BuildX { + b.Showcmd("", "%s", strings.Join(args, " ")) + if cfg.BuildN { + return nil + } + } + + cmd := exec.Command(args[0], args[1:]...) + cmd.Dir = a.Package.Dir + cmd.Env = base.AppendPWD(cfg.OrigEnv[:len(cfg.OrigEnv):len(cfg.OrigEnv)], cmd.Dir) + cmd.Stdout = stdout + cmd.Stderr = stdout + + // If there are any local SWIG dependencies, we want to load + // the shared library from the build directory. + if a.Package.UsesSwig() { + env := cmd.Env + found := false + prefix := "LD_LIBRARY_PATH=" + for i, v := range env { + if strings.HasPrefix(v, prefix) { + env[i] = v + ":." + found = true + break + } + } + if !found { + env = append(env, "LD_LIBRARY_PATH=.") + } + cmd.Env = env + } + + t0 := time.Now() + err = cmd.Start() + + // This is a last-ditch deadline to detect and + // stop wedged test binaries, to keep the builders + // running. + if err == nil { + tick := time.NewTimer(testKillTimeout) + base.StartSigHandlers() + done := make(chan error) + go func() { + done <- cmd.Wait() + }() + Outer: + select { + case err = <-done: + // ok + case <-tick.C: + if base.SignalTrace != nil { + // Send a quit signal in the hope that the program will print + // a stack trace and exit. Give it five seconds before resorting + // to Kill. + cmd.Process.Signal(base.SignalTrace) + select { + case err = <-done: + fmt.Fprintf(cmd.Stdout, "*** Test killed with %v: ran too long (%v).\n", base.SignalTrace, testKillTimeout) + break Outer + case <-time.After(5 * time.Second): + } + } + cmd.Process.Kill() + err = <-done + fmt.Fprintf(cmd.Stdout, "*** Test killed: ran too long (%v).\n", testKillTimeout) + } + tick.Stop() + } + out := buf.Bytes() + a.TestOutput = &buf + t := fmt.Sprintf("%.3fs", time.Since(t0).Seconds()) + + mergeCoverProfile(cmd.Stdout, a.Objdir+"_cover_.out") + + if err == nil { + norun := "" + if !testShowPass() && !testJSON { + buf.Reset() + } + if bytes.HasPrefix(out, noTestsToRun[1:]) || bytes.Contains(out, noTestsToRun) { + norun = " [no tests to run]" + } + fmt.Fprintf(cmd.Stdout, "ok \t%s\t%s%s%s\n", a.Package.ImportPath, t, coveragePercentage(out), norun) + c.saveOutput(a) + } else { + base.SetExitStatus(1) + // If there was test output, assume we don't need to print the exit status. + // Buf there's no test output, do print the exit status. + if len(out) == 0 { + fmt.Fprintf(cmd.Stdout, "%s\n", err) + } + // NOTE(golang.org/issue/37555): test2json reports that a test passes + // unless "FAIL" is printed at the beginning of a line. The test may not + // actually print that if it panics, exits, or terminates abnormally, + // so we print it here. We can't always check whether it was printed + // because some tests need stdout to be a terminal (golang.org/issue/34791), + // not a pipe. + // TODO(golang.org/issue/29062): tests that exit with status 0 without + // printing a final result should fail. + fmt.Fprintf(cmd.Stdout, "FAIL\t%s\t%s\n", a.Package.ImportPath, t) + } + + if cmd.Stdout != &buf { + buf.Reset() // cmd.Stdout was going to os.Stdout already + } + return nil +} + +// tryCache is called just before the link attempt, +// to see if the test result is cached and therefore the link is unneeded. +// It reports whether the result can be satisfied from cache. +func (c *runCache) tryCache(b *work.Builder, a *work.Action) bool { + return c.tryCacheWithID(b, a, a.Deps[0].BuildActionID()) +} + +func (c *runCache) tryCacheWithID(b *work.Builder, a *work.Action, id string) bool { + if len(pkgArgs) == 0 { + // Caching does not apply to "go test", + // only to "go test foo" (including "go test ."). + if cache.DebugTest { + fmt.Fprintf(os.Stderr, "testcache: caching disabled in local directory mode\n") + } + c.disableCache = true + return false + } + + if a.Package.Root == "" { + // Caching does not apply to tests outside of any module, GOPATH, or GOROOT. + if cache.DebugTest { + fmt.Fprintf(os.Stderr, "testcache: caching disabled for package outside of module root, GOPATH, or GOROOT: %s\n", a.Package.ImportPath) + } + c.disableCache = true + return false + } + + var cacheArgs []string + for _, arg := range testArgs { + i := strings.Index(arg, "=") + if i < 0 || !strings.HasPrefix(arg, "-test.") { + if cache.DebugTest { + fmt.Fprintf(os.Stderr, "testcache: caching disabled for test argument: %s\n", arg) + } + c.disableCache = true + return false + } + switch arg[:i] { + case "-test.cpu", + "-test.list", + "-test.parallel", + "-test.run", + "-test.short", + "-test.timeout", + "-test.v": + // These are cacheable. + // Note that this list is documented above, + // so if you add to this list, update the docs too. + cacheArgs = append(cacheArgs, arg) + + default: + // nothing else is cacheable + if cache.DebugTest { + fmt.Fprintf(os.Stderr, "testcache: caching disabled for test argument: %s\n", arg) + } + c.disableCache = true + return false + } + } + + if cache.Default() == nil { + if cache.DebugTest { + fmt.Fprintf(os.Stderr, "testcache: GOCACHE=off\n") + } + c.disableCache = true + return false + } + + // The test cache result fetch is a two-level lookup. + // + // First, we use the content hash of the test binary + // and its command-line arguments to find the + // list of environment variables and files consulted + // the last time the test was run with those arguments. + // (To avoid unnecessary links, we store this entry + // under two hashes: id1 uses the linker inputs as a + // proxy for the test binary, and id2 uses the actual + // test binary. If the linker inputs are unchanged, + // this way we avoid the link step, even though we + // do not cache link outputs.) + // + // Second, we compute a hash of the values of the + // environment variables and the content of the files + // listed in the log from the previous run. + // Then we look up test output using a combination of + // the hash from the first part (testID) and the hash of the + // test inputs (testInputsID). + // + // In order to store a new test result, we must redo the + // testInputsID computation using the log from the run + // we want to cache, and then we store that new log and + // the new outputs. + + h := cache.NewHash("testResult") + fmt.Fprintf(h, "test binary %s args %q execcmd %q", id, cacheArgs, work.ExecCmd) + testID := h.Sum() + if c.id1 == (cache.ActionID{}) { + c.id1 = testID + } else { + c.id2 = testID + } + if cache.DebugTest { + fmt.Fprintf(os.Stderr, "testcache: %s: test ID %x => %x\n", a.Package.ImportPath, id, testID) + } + + // Load list of referenced environment variables and files + // from last run of testID, and compute hash of that content. + data, entry, err := cache.Default().GetBytes(testID) + if !bytes.HasPrefix(data, testlogMagic) || data[len(data)-1] != '\n' { + if cache.DebugTest { + if err != nil { + fmt.Fprintf(os.Stderr, "testcache: %s: input list not found: %v\n", a.Package.ImportPath, err) + } else { + fmt.Fprintf(os.Stderr, "testcache: %s: input list malformed\n", a.Package.ImportPath) + } + } + return false + } + testInputsID, err := computeTestInputsID(a, data) + if err != nil { + return false + } + if cache.DebugTest { + fmt.Fprintf(os.Stderr, "testcache: %s: test ID %x => input ID %x => %x\n", a.Package.ImportPath, testID, testInputsID, testAndInputKey(testID, testInputsID)) + } + + // Parse cached result in preparation for changing run time to "(cached)". + // If we can't parse the cached result, don't use it. + data, entry, err = cache.Default().GetBytes(testAndInputKey(testID, testInputsID)) + if len(data) == 0 || data[len(data)-1] != '\n' { + if cache.DebugTest { + if err != nil { + fmt.Fprintf(os.Stderr, "testcache: %s: test output not found: %v\n", a.Package.ImportPath, err) + } else { + fmt.Fprintf(os.Stderr, "testcache: %s: test output malformed\n", a.Package.ImportPath) + } + } + return false + } + if entry.Time.Before(testCacheExpire) { + if cache.DebugTest { + fmt.Fprintf(os.Stderr, "testcache: %s: test output expired due to go clean -testcache\n", a.Package.ImportPath) + } + return false + } + i := bytes.LastIndexByte(data[:len(data)-1], '\n') + 1 + if !bytes.HasPrefix(data[i:], []byte("ok \t")) { + if cache.DebugTest { + fmt.Fprintf(os.Stderr, "testcache: %s: test output malformed\n", a.Package.ImportPath) + } + return false + } + j := bytes.IndexByte(data[i+len("ok \t"):], '\t') + if j < 0 { + if cache.DebugTest { + fmt.Fprintf(os.Stderr, "testcache: %s: test output malformed\n", a.Package.ImportPath) + } + return false + } + j += i + len("ok \t") + 1 + + // Committed to printing. + c.buf = new(bytes.Buffer) + c.buf.Write(data[:j]) + c.buf.WriteString("(cached)") + for j < len(data) && ('0' <= data[j] && data[j] <= '9' || data[j] == '.' || data[j] == 's') { + j++ + } + c.buf.Write(data[j:]) + return true +} + +var errBadTestInputs = errors.New("error parsing test inputs") +var testlogMagic = []byte("# test log\n") // known to testing/internal/testdeps/deps.go + +// computeTestInputsID computes the "test inputs ID" +// (see comment in tryCacheWithID above) for the +// test log. +func computeTestInputsID(a *work.Action, testlog []byte) (cache.ActionID, error) { + testlog = bytes.TrimPrefix(testlog, testlogMagic) + h := cache.NewHash("testInputs") + pwd := a.Package.Dir + for _, line := range bytes.Split(testlog, []byte("\n")) { + if len(line) == 0 { + continue + } + s := string(line) + i := strings.Index(s, " ") + if i < 0 { + if cache.DebugTest { + fmt.Fprintf(os.Stderr, "testcache: %s: input list malformed (%q)\n", a.Package.ImportPath, line) + } + return cache.ActionID{}, errBadTestInputs + } + op := s[:i] + name := s[i+1:] + switch op { + default: + if cache.DebugTest { + fmt.Fprintf(os.Stderr, "testcache: %s: input list malformed (%q)\n", a.Package.ImportPath, line) + } + return cache.ActionID{}, errBadTestInputs + case "getenv": + fmt.Fprintf(h, "env %s %x\n", name, hashGetenv(name)) + case "chdir": + pwd = name // always absolute + fmt.Fprintf(h, "chdir %s %x\n", name, hashStat(name)) + case "stat": + if !filepath.IsAbs(name) { + name = filepath.Join(pwd, name) + } + if a.Package.Root == "" || !inDir(name, a.Package.Root) { + // Do not recheck files outside the module, GOPATH, or GOROOT root. + break + } + fmt.Fprintf(h, "stat %s %x\n", name, hashStat(name)) + case "open": + if !filepath.IsAbs(name) { + name = filepath.Join(pwd, name) + } + if a.Package.Root == "" || !inDir(name, a.Package.Root) { + // Do not recheck files outside the module, GOPATH, or GOROOT root. + break + } + fh, err := hashOpen(name) + if err != nil { + if cache.DebugTest { + fmt.Fprintf(os.Stderr, "testcache: %s: input file %s: %s\n", a.Package.ImportPath, name, err) + } + return cache.ActionID{}, err + } + fmt.Fprintf(h, "open %s %x\n", name, fh) + } + } + sum := h.Sum() + return sum, nil +} + +func inDir(path, dir string) bool { + if str.HasFilePathPrefix(path, dir) { + return true + } + xpath, err1 := filepath.EvalSymlinks(path) + xdir, err2 := filepath.EvalSymlinks(dir) + if err1 == nil && err2 == nil && str.HasFilePathPrefix(xpath, xdir) { + return true + } + return false +} + +func hashGetenv(name string) cache.ActionID { + h := cache.NewHash("getenv") + v, ok := os.LookupEnv(name) + if !ok { + h.Write([]byte{0}) + } else { + h.Write([]byte{1}) + h.Write([]byte(v)) + } + return h.Sum() +} + +const modTimeCutoff = 2 * time.Second + +var errFileTooNew = errors.New("file used as input is too new") + +func hashOpen(name string) (cache.ActionID, error) { + h := cache.NewHash("open") + info, err := os.Stat(name) + if err != nil { + fmt.Fprintf(h, "err %v\n", err) + return h.Sum(), nil + } + hashWriteStat(h, info) + if info.IsDir() { + files, err := os.ReadDir(name) + if err != nil { + fmt.Fprintf(h, "err %v\n", err) + } + for _, f := range files { + fmt.Fprintf(h, "file %s ", f.Name()) + finfo, err := f.Info() + if err != nil { + fmt.Fprintf(h, "err %v\n", err) + } else { + hashWriteStat(h, finfo) + } + } + } else if info.Mode().IsRegular() { + // Because files might be very large, do not attempt + // to hash the entirety of their content. Instead assume + // the mtime and size recorded in hashWriteStat above + // are good enough. + // + // To avoid problems for very recent files where a new + // write might not change the mtime due to file system + // mtime precision, reject caching if a file was read that + // is less than modTimeCutoff old. + if time.Since(info.ModTime()) < modTimeCutoff { + return cache.ActionID{}, errFileTooNew + } + } + return h.Sum(), nil +} + +func hashStat(name string) cache.ActionID { + h := cache.NewHash("stat") + if info, err := os.Stat(name); err != nil { + fmt.Fprintf(h, "err %v\n", err) + } else { + hashWriteStat(h, info) + } + if info, err := os.Lstat(name); err != nil { + fmt.Fprintf(h, "err %v\n", err) + } else { + hashWriteStat(h, info) + } + return h.Sum() +} + +func hashWriteStat(h io.Writer, info fs.FileInfo) { + fmt.Fprintf(h, "stat %d %x %v %v\n", info.Size(), uint64(info.Mode()), info.ModTime(), info.IsDir()) +} + +// testAndInputKey returns the actual cache key for the pair (testID, testInputsID). +func testAndInputKey(testID, testInputsID cache.ActionID) cache.ActionID { + return cache.Subkey(testID, fmt.Sprintf("inputs:%x", testInputsID)) +} + +func (c *runCache) saveOutput(a *work.Action) { + if c.id1 == (cache.ActionID{}) && c.id2 == (cache.ActionID{}) { + return + } + + // See comment about two-level lookup in tryCacheWithID above. + testlog, err := os.ReadFile(a.Objdir + "testlog.txt") + if err != nil || !bytes.HasPrefix(testlog, testlogMagic) || testlog[len(testlog)-1] != '\n' { + if cache.DebugTest { + if err != nil { + fmt.Fprintf(os.Stderr, "testcache: %s: reading testlog: %v\n", a.Package.ImportPath, err) + } else { + fmt.Fprintf(os.Stderr, "testcache: %s: reading testlog: malformed\n", a.Package.ImportPath) + } + } + return + } + testInputsID, err := computeTestInputsID(a, testlog) + if err != nil { + return + } + if c.id1 != (cache.ActionID{}) { + if cache.DebugTest { + fmt.Fprintf(os.Stderr, "testcache: %s: save test ID %x => input ID %x => %x\n", a.Package.ImportPath, c.id1, testInputsID, testAndInputKey(c.id1, testInputsID)) + } + cache.Default().PutNoVerify(c.id1, bytes.NewReader(testlog)) + cache.Default().PutNoVerify(testAndInputKey(c.id1, testInputsID), bytes.NewReader(a.TestOutput.Bytes())) + } + if c.id2 != (cache.ActionID{}) { + if cache.DebugTest { + fmt.Fprintf(os.Stderr, "testcache: %s: save test ID %x => input ID %x => %x\n", a.Package.ImportPath, c.id2, testInputsID, testAndInputKey(c.id2, testInputsID)) + } + cache.Default().PutNoVerify(c.id2, bytes.NewReader(testlog)) + cache.Default().PutNoVerify(testAndInputKey(c.id2, testInputsID), bytes.NewReader(a.TestOutput.Bytes())) + } +} + +// coveragePercentage returns the coverage results (if enabled) for the +// test. It uncovers the data by scanning the output from the test run. +func coveragePercentage(out []byte) string { + if !testCover { + return "" + } + // The string looks like + // test coverage for encoding/binary: 79.9% of statements + // Extract the piece from the percentage to the end of the line. + re := regexp.MustCompile(`coverage: (.*)\n`) + matches := re.FindSubmatch(out) + if matches == nil { + // Probably running "go test -cover" not "go test -cover fmt". + // The coverage output will appear in the output directly. + return "" + } + return fmt.Sprintf("\tcoverage: %s", matches[1]) +} + +// builderCleanTest is the action for cleaning up after a test. +func builderCleanTest(b *work.Builder, ctx context.Context, a *work.Action) error { + if cfg.BuildWork { + return nil + } + if cfg.BuildX { + b.Showcmd("", "rm -r %s", a.Objdir) + } + os.RemoveAll(a.Objdir) + return nil +} + +// builderPrintTest is the action for printing a test result. +func builderPrintTest(b *work.Builder, ctx context.Context, a *work.Action) error { + clean := a.Deps[0] + run := clean.Deps[0] + if run.TestOutput != nil { + os.Stdout.Write(run.TestOutput.Bytes()) + run.TestOutput = nil + } + return nil +} + +// builderNoTest is the action for testing a package with no test files. +func builderNoTest(b *work.Builder, ctx context.Context, a *work.Action) error { + var stdout io.Writer = os.Stdout + if testJSON { + json := test2json.NewConverter(lockedStdout{}, a.Package.ImportPath, test2json.Timestamp) + defer json.Close() + stdout = json + } + fmt.Fprintf(stdout, "? \t%s\t[no test files]\n", a.Package.ImportPath) + return nil +} + +// printExitStatus is the action for printing the exit status +func printExitStatus(b *work.Builder, ctx context.Context, a *work.Action) error { + if !testJSON && len(pkgArgs) != 0 { + if base.GetExitStatus() != 0 { + fmt.Println("FAIL") + return nil + } + } + return nil +} diff --git a/src/cmd/go/internal/test/testflag.go b/src/cmd/go/internal/test/testflag.go new file mode 100644 index 0000000..10e6604 --- /dev/null +++ b/src/cmd/go/internal/test/testflag.go @@ -0,0 +1,412 @@ +// Copyright 2011 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 test + +import ( + "errors" + "flag" + "fmt" + "os" + "path/filepath" + "strings" + "time" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/cmdflag" + "cmd/go/internal/work" +) + +//go:generate go run ./genflags.go + +// The flag handling part of go test is large and distracting. +// We can't use (*flag.FlagSet).Parse because some of the flags from +// our command line are for us, and some are for the test binary, and +// some are for both. + +func init() { + work.AddBuildFlags(CmdTest, work.OmitVFlag) + + cf := CmdTest.Flag + cf.BoolVar(&testC, "c", false, "") + cf.BoolVar(&cfg.BuildI, "i", false, "") + cf.StringVar(&testO, "o", "", "") + + cf.BoolVar(&testCover, "cover", false, "") + cf.Var(coverFlag{(*coverModeFlag)(&testCoverMode)}, "covermode", "") + cf.Var(coverFlag{commaListFlag{&testCoverPaths}}, "coverpkg", "") + + cf.Var((*base.StringsFlag)(&work.ExecCmd), "exec", "") + cf.BoolVar(&testJSON, "json", false, "") + cf.Var(&testVet, "vet", "") + + // Register flags to be forwarded to the test binary. We retain variables for + // some of them so that cmd/go knows what to do with the test output, or knows + // to build the test in a way that supports the use of the flag. + + cf.StringVar(&testBench, "bench", "", "") + cf.Bool("benchmem", false, "") + cf.String("benchtime", "", "") + cf.StringVar(&testBlockProfile, "blockprofile", "", "") + cf.String("blockprofilerate", "", "") + cf.Int("count", 0, "") + cf.Var(coverFlag{stringFlag{&testCoverProfile}}, "coverprofile", "") + cf.String("cpu", "", "") + cf.StringVar(&testCPUProfile, "cpuprofile", "", "") + cf.Bool("failfast", false, "") + cf.StringVar(&testList, "list", "", "") + cf.StringVar(&testMemProfile, "memprofile", "", "") + cf.String("memprofilerate", "", "") + cf.StringVar(&testMutexProfile, "mutexprofile", "", "") + cf.String("mutexprofilefraction", "", "") + cf.Var(outputdirFlag{&testOutputDir}, "outputdir", "") + cf.Int("parallel", 0, "") + cf.String("run", "", "") + cf.Bool("short", false, "") + cf.DurationVar(&testTimeout, "timeout", 10*time.Minute, "") + cf.StringVar(&testTrace, "trace", "", "") + cf.BoolVar(&testV, "v", false, "") + + for name, _ := range passFlagToTest { + cf.Var(cf.Lookup(name).Value, "test."+name, "") + } +} + +// A coverFlag is a flag.Value that also implies -cover. +type coverFlag struct{ v flag.Value } + +func (f coverFlag) String() string { return f.v.String() } + +func (f coverFlag) Set(value string) error { + if err := f.v.Set(value); err != nil { + return err + } + testCover = true + return nil +} + +type coverModeFlag string + +func (f *coverModeFlag) String() string { return string(*f) } +func (f *coverModeFlag) Set(value string) error { + switch value { + case "", "set", "count", "atomic": + *f = coverModeFlag(value) + return nil + default: + return errors.New(`valid modes are "set", "count", or "atomic"`) + } +} + +// A commaListFlag is a flag.Value representing a comma-separated list. +type commaListFlag struct{ vals *[]string } + +func (f commaListFlag) String() string { return strings.Join(*f.vals, ",") } + +func (f commaListFlag) Set(value string) error { + if value == "" { + *f.vals = nil + } else { + *f.vals = strings.Split(value, ",") + } + return nil +} + +// A stringFlag is a flag.Value representing a single string. +type stringFlag struct{ val *string } + +func (f stringFlag) String() string { return *f.val } +func (f stringFlag) Set(value string) error { + *f.val = value + return nil +} + +// outputdirFlag implements the -outputdir flag. +// It interprets an empty value as the working directory of the 'go' command. +type outputdirFlag struct { + resolved *string +} + +func (f outputdirFlag) String() string { return *f.resolved } +func (f outputdirFlag) Set(value string) (err error) { + if value == "" { + // The empty string implies the working directory of the 'go' command. + *f.resolved = base.Cwd + } else { + *f.resolved, err = filepath.Abs(value) + } + return err +} + +// vetFlag implements the special parsing logic for the -vet flag: +// a comma-separated list, with a distinguished value "off" and +// a boolean tracking whether it was set explicitly. +type vetFlag struct { + explicit bool + off bool + flags []string // passed to vet when invoked automatically during 'go test' +} + +func (f *vetFlag) String() string { + if f.off { + return "off" + } + + var buf strings.Builder + for i, f := range f.flags { + if i > 0 { + buf.WriteByte(',') + } + buf.WriteString(f) + } + return buf.String() +} + +func (f *vetFlag) Set(value string) error { + if value == "" { + *f = vetFlag{flags: defaultVetFlags} + return nil + } + + if value == "off" { + *f = vetFlag{ + explicit: true, + off: true, + } + return nil + } + + if strings.Contains(value, "=") { + return fmt.Errorf("-vet argument cannot contain equal signs") + } + if strings.Contains(value, " ") { + return fmt.Errorf("-vet argument is comma-separated list, cannot contain spaces") + } + *f = vetFlag{explicit: true} + for _, arg := range strings.Split(value, ",") { + if arg == "" { + return fmt.Errorf("-vet argument contains empty list element") + } + f.flags = append(f.flags, "-"+arg) + } + return nil +} + +// testFlags processes the command line, grabbing -x and -c, rewriting known flags +// to have "test" before them, and reading the command line for the test binary. +// Unfortunately for us, we need to do our own flag processing because go test +// grabs some flags but otherwise its command line is just a holding place for +// pkg.test's arguments. +// We allow known flags both before and after the package name list, +// to allow both +// go test fmt -custom-flag-for-fmt-test +// go test -x math +func testFlags(args []string) (packageNames, passToTest []string) { + base.SetFromGOFLAGS(&CmdTest.Flag) + addFromGOFLAGS := map[string]bool{} + CmdTest.Flag.Visit(func(f *flag.Flag) { + if short := strings.TrimPrefix(f.Name, "test."); passFlagToTest[short] { + addFromGOFLAGS[f.Name] = true + } + }) + + // firstUnknownFlag helps us report an error when flags not known to 'go + // test' are used along with -i or -c. + firstUnknownFlag := "" + + explicitArgs := make([]string, 0, len(args)) + inPkgList := false + afterFlagWithoutValue := false + for len(args) > 0 { + f, remainingArgs, err := cmdflag.ParseOne(&CmdTest.Flag, args) + + wasAfterFlagWithoutValue := afterFlagWithoutValue + afterFlagWithoutValue = false // provisionally + + if errors.Is(err, flag.ErrHelp) { + exitWithUsage() + } + + if errors.Is(err, cmdflag.ErrFlagTerminator) { + // 'go list' allows package arguments to be named either before or after + // the terminator, but 'go test' has historically allowed them only + // before. Preserve that behavior and treat all remaining arguments — + // including the terminator itself! — as arguments to the test. + explicitArgs = append(explicitArgs, args...) + break + } + + if nf := (cmdflag.NonFlagError{}); errors.As(err, &nf) { + if !inPkgList && packageNames != nil { + // We already saw the package list previously, and this argument is not + // a flag, so it — and everything after it — must be either a value for + // a preceding flag or a literal argument to the test binary. + if wasAfterFlagWithoutValue { + // This argument could syntactically be a flag value, so + // optimistically assume that it is and keep looking for go command + // flags after it. + // + // (If we're wrong, we'll at least be consistent with historical + // behavior; see https://golang.org/issue/40763.) + explicitArgs = append(explicitArgs, nf.RawArg) + args = remainingArgs + continue + } else { + // This argument syntactically cannot be a flag value, so it must be a + // positional argument, and so must everything after it. + explicitArgs = append(explicitArgs, args...) + break + } + } + + inPkgList = true + packageNames = append(packageNames, nf.RawArg) + args = remainingArgs // Consume the package name. + continue + } + + if inPkgList { + // This argument is syntactically a flag, so if we were in the package + // list we're not anymore. + inPkgList = false + } + + if nd := (cmdflag.FlagNotDefinedError{}); errors.As(err, &nd) { + // This is a flag we do not know. We must assume that any args we see + // after this might be flag arguments, not package names, so make + // packageNames non-nil to indicate that the package list is complete. + // + // (Actually, we only strictly need to assume that if the flag is not of + // the form -x=value, but making this more precise would be a breaking + // change in the command line API.) + if packageNames == nil { + packageNames = []string{} + } + + if nd.RawArg == "-args" || nd.RawArg == "--args" { + // -args or --args signals that everything that follows + // should be passed to the test. + explicitArgs = append(explicitArgs, remainingArgs...) + break + } + + if firstUnknownFlag == "" { + firstUnknownFlag = nd.RawArg + } + + explicitArgs = append(explicitArgs, nd.RawArg) + args = remainingArgs + if !nd.HasValue { + afterFlagWithoutValue = true + } + continue + } + + if err != nil { + fmt.Fprintln(os.Stderr, err) + exitWithUsage() + } + + if short := strings.TrimPrefix(f.Name, "test."); passFlagToTest[short] { + explicitArgs = append(explicitArgs, fmt.Sprintf("-test.%s=%v", short, f.Value)) + + // This flag has been overridden explicitly, so don't forward its implicit + // value from GOFLAGS. + delete(addFromGOFLAGS, short) + delete(addFromGOFLAGS, "test."+short) + } + + args = remainingArgs + } + if firstUnknownFlag != "" && (testC || cfg.BuildI) { + buildFlag := "-c" + if !testC { + buildFlag = "-i" + } + fmt.Fprintf(os.Stderr, "go test: unknown flag %s cannot be used with %s\n", firstUnknownFlag, buildFlag) + exitWithUsage() + } + + var injectedFlags []string + if testJSON { + // If converting to JSON, we need the full output in order to pipe it to + // test2json. + injectedFlags = append(injectedFlags, "-test.v=true") + delete(addFromGOFLAGS, "v") + delete(addFromGOFLAGS, "test.v") + } + + // Inject flags from GOFLAGS before the explicit command-line arguments. + // (They must appear before the flag terminator or first non-flag argument.) + // Also determine whether flags with awkward defaults have already been set. + var timeoutSet, outputDirSet bool + CmdTest.Flag.Visit(func(f *flag.Flag) { + short := strings.TrimPrefix(f.Name, "test.") + if addFromGOFLAGS[f.Name] { + injectedFlags = append(injectedFlags, fmt.Sprintf("-test.%s=%v", short, f.Value)) + } + switch short { + case "timeout": + timeoutSet = true + case "outputdir": + outputDirSet = true + } + }) + + // 'go test' has a default timeout, but the test binary itself does not. + // If the timeout wasn't set (and forwarded) explicitly, add the default + // timeout to the command line. + if testTimeout > 0 && !timeoutSet { + injectedFlags = append(injectedFlags, fmt.Sprintf("-test.timeout=%v", testTimeout)) + } + + // Similarly, the test binary defaults -test.outputdir to its own working + // directory, but 'go test' defaults it to the working directory of the 'go' + // command. Set it explicitly if it is needed due to some other flag that + // requests output. + if testProfile() != "" && !outputDirSet { + injectedFlags = append(injectedFlags, "-test.outputdir="+testOutputDir) + } + + // If the user is explicitly passing -help or -h, show output + // of the test binary so that the help output is displayed + // even though the test will exit with success. + // This loop is imperfect: it will do the wrong thing for a case + // like -args -test.outputdir -help. Such cases are probably rare, + // and getting this wrong doesn't do too much harm. +helpLoop: + for _, arg := range explicitArgs { + switch arg { + case "--": + break helpLoop + case "-h", "-help", "--help": + testHelp = true + break helpLoop + } + } + + // Ensure that -race and -covermode are compatible. + if testCoverMode == "" { + testCoverMode = "set" + if cfg.BuildRace { + // Default coverage mode is atomic when -race is set. + testCoverMode = "atomic" + } + } + if cfg.BuildRace && testCoverMode != "atomic" { + base.Fatalf(`-covermode must be "atomic", not %q, when -race is enabled`, testCoverMode) + } + + // Forward any unparsed arguments (following --args) to the test binary. + return packageNames, append(injectedFlags, explicitArgs...) +} + +func exitWithUsage() { + fmt.Fprintf(os.Stderr, "usage: %s\n", CmdTest.UsageLine) + fmt.Fprintf(os.Stderr, "Run 'go help %s' and 'go help %s' for details.\n", CmdTest.LongName(), HelpTestflag.LongName()) + + base.SetExitStatus(2) + base.Exit() +} diff --git a/src/cmd/go/internal/tool/tool.go b/src/cmd/go/internal/tool/tool.go new file mode 100644 index 0000000..95c90ea --- /dev/null +++ b/src/cmd/go/internal/tool/tool.go @@ -0,0 +1,147 @@ +// Copyright 2011 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 tool implements the ``go tool'' command. +package tool + +import ( + "context" + "fmt" + exec "internal/execabs" + "os" + "os/signal" + "sort" + "strings" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" +) + +var CmdTool = &base.Command{ + Run: runTool, + UsageLine: "go tool [-n] command [args...]", + Short: "run specified go tool", + Long: ` +Tool runs the go tool command identified by the arguments. +With no arguments it prints the list of known tools. + +The -n flag causes tool to print the command that would be +executed but not execute it. + +For more about each tool command, see 'go doc cmd/'. +`, +} + +var toolN bool + +// Return whether tool can be expected in the gccgo tool directory. +// Other binaries could be in the same directory so don't +// show those with the 'go tool' command. +func isGccgoTool(tool string) bool { + switch tool { + case "cgo", "fix", "cover", "godoc", "vet": + return true + } + return false +} + +func init() { + CmdTool.Flag.BoolVar(&toolN, "n", false, "") +} + +func runTool(ctx context.Context, cmd *base.Command, args []string) { + if len(args) == 0 { + listTools() + return + } + toolName := args[0] + // The tool name must be lower-case letters, numbers or underscores. + for _, c := range toolName { + switch { + case 'a' <= c && c <= 'z', '0' <= c && c <= '9', c == '_': + default: + fmt.Fprintf(os.Stderr, "go tool: bad tool name %q\n", toolName) + base.SetExitStatus(2) + return + } + } + toolPath := base.Tool(toolName) + if toolPath == "" { + return + } + if toolN { + cmd := toolPath + if len(args) > 1 { + cmd += " " + strings.Join(args[1:], " ") + } + fmt.Printf("%s\n", cmd) + return + } + args[0] = toolPath // in case the tool wants to re-exec itself, e.g. cmd/dist + toolCmd := &exec.Cmd{ + Path: toolPath, + Args: args, + Stdin: os.Stdin, + Stdout: os.Stdout, + Stderr: os.Stderr, + } + err := toolCmd.Start() + if err == nil { + c := make(chan os.Signal, 100) + signal.Notify(c) + go func() { + for sig := range c { + toolCmd.Process.Signal(sig) + } + }() + err = toolCmd.Wait() + signal.Stop(c) + close(c) + } + if err != nil { + // Only print about the exit status if the command + // didn't even run (not an ExitError) or it didn't exit cleanly + // or we're printing command lines too (-x mode). + // Assume if command exited cleanly (even with non-zero status) + // it printed any messages it wanted to print. + if e, ok := err.(*exec.ExitError); !ok || !e.Exited() || cfg.BuildX { + fmt.Fprintf(os.Stderr, "go tool %s: %s\n", toolName, err) + } + base.SetExitStatus(1) + return + } +} + +// listTools prints a list of the available tools in the tools directory. +func listTools() { + f, err := os.Open(base.ToolDir) + if err != nil { + fmt.Fprintf(os.Stderr, "go tool: no tool directory: %s\n", err) + base.SetExitStatus(2) + return + } + defer f.Close() + names, err := f.Readdirnames(-1) + if err != nil { + fmt.Fprintf(os.Stderr, "go tool: can't read directory: %s\n", err) + base.SetExitStatus(2) + return + } + + sort.Strings(names) + for _, name := range names { + // Unify presentation by going to lower case. + name = strings.ToLower(name) + // If it's windows, don't show the .exe suffix. + if base.ToolIsWindows && strings.HasSuffix(name, base.ToolWindowsExtension) { + name = name[:len(name)-len(base.ToolWindowsExtension)] + } + // The tool directory used by gccgo will have other binaries + // in addition to go tools. Only display go tools here. + if cfg.BuildToolchainName == "gccgo" && !isGccgoTool(name) { + continue + } + fmt.Println(name) + } +} diff --git a/src/cmd/go/internal/trace/trace.go b/src/cmd/go/internal/trace/trace.go new file mode 100644 index 0000000..f108a2b --- /dev/null +++ b/src/cmd/go/internal/trace/trace.go @@ -0,0 +1,206 @@ +// Copyright 2020 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 trace + +import ( + "cmd/internal/traceviewer" + "context" + "encoding/json" + "errors" + "os" + "strings" + "sync/atomic" + "time" +) + +// Constants used in event fields. +// See https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU +// for more details. +const ( + phaseDurationBegin = "B" + phaseDurationEnd = "E" + phaseFlowStart = "s" + phaseFlowEnd = "f" + + bindEnclosingSlice = "e" +) + +var traceStarted int32 + +func getTraceContext(ctx context.Context) (traceContext, bool) { + if atomic.LoadInt32(&traceStarted) == 0 { + return traceContext{}, false + } + v := ctx.Value(traceKey{}) + if v == nil { + return traceContext{}, false + } + return v.(traceContext), true +} + +// StartSpan starts a trace event with the given name. The Span ends when its Done method is called. +func StartSpan(ctx context.Context, name string) (context.Context, *Span) { + tc, ok := getTraceContext(ctx) + if !ok { + return ctx, nil + } + childSpan := &Span{t: tc.t, name: name, tid: tc.tid, start: time.Now()} + tc.t.writeEvent(&traceviewer.Event{ + Name: childSpan.name, + Time: float64(childSpan.start.UnixNano()) / float64(time.Microsecond), + TID: childSpan.tid, + Phase: phaseDurationBegin, + }) + ctx = context.WithValue(ctx, traceKey{}, traceContext{tc.t, tc.tid}) + return ctx, childSpan +} + +// StartGoroutine associates the context with a new Thread ID. The Chrome trace viewer associates each +// trace event with a thread, and doesn't expect events with the same thread id to happen at the +// same time. +func StartGoroutine(ctx context.Context) context.Context { + tc, ok := getTraceContext(ctx) + if !ok { + return ctx + } + return context.WithValue(ctx, traceKey{}, traceContext{tc.t, tc.t.getNextTID()}) +} + +// Flow marks a flow indicating that the 'to' span depends on the 'from' span. +// Flow should be called while the 'to' span is in progress. +func Flow(ctx context.Context, from *Span, to *Span) { + tc, ok := getTraceContext(ctx) + if !ok || from == nil || to == nil { + return + } + + id := tc.t.getNextFlowID() + tc.t.writeEvent(&traceviewer.Event{ + Name: from.name + " -> " + to.name, + Category: "flow", + ID: id, + Time: float64(from.end.UnixNano()) / float64(time.Microsecond), + Phase: phaseFlowStart, + TID: from.tid, + }) + tc.t.writeEvent(&traceviewer.Event{ + Name: from.name + " -> " + to.name, + Category: "flow", // TODO(matloob): Add Category to Flow? + ID: id, + Time: float64(to.start.UnixNano()) / float64(time.Microsecond), + Phase: phaseFlowEnd, + TID: to.tid, + BindPoint: bindEnclosingSlice, + }) +} + +type Span struct { + t *tracer + + name string + tid uint64 + start time.Time + end time.Time +} + +func (s *Span) Done() { + if s == nil { + return + } + s.end = time.Now() + s.t.writeEvent(&traceviewer.Event{ + Name: s.name, + Time: float64(s.end.UnixNano()) / float64(time.Microsecond), + TID: s.tid, + Phase: phaseDurationEnd, + }) +} + +type tracer struct { + file chan traceFile // 1-buffered + + nextTID uint64 + nextFlowID uint64 +} + +func (t *tracer) writeEvent(ev *traceviewer.Event) error { + f := <-t.file + defer func() { t.file <- f }() + var err error + if f.entries == 0 { + _, err = f.sb.WriteString("[\n") + } else { + _, err = f.sb.WriteString(",") + } + f.entries++ + if err != nil { + return nil + } + + if err := f.enc.Encode(ev); err != nil { + return err + } + + // Write event string to output file. + _, err = f.f.WriteString(f.sb.String()) + f.sb.Reset() + return err +} + +func (t *tracer) Close() error { + f := <-t.file + defer func() { t.file <- f }() + + _, firstErr := f.f.WriteString("]") + if err := f.f.Close(); firstErr == nil { + firstErr = err + } + return firstErr +} + +func (t *tracer) getNextTID() uint64 { + return atomic.AddUint64(&t.nextTID, 1) +} + +func (t *tracer) getNextFlowID() uint64 { + return atomic.AddUint64(&t.nextFlowID, 1) +} + +// traceKey is the context key for tracing information. It is unexported to prevent collisions with context keys defined in +// other packages. +type traceKey struct{} + +type traceContext struct { + t *tracer + tid uint64 +} + +// Start starts a trace which writes to the given file. +func Start(ctx context.Context, file string) (context.Context, func() error, error) { + atomic.StoreInt32(&traceStarted, 1) + if file == "" { + return nil, nil, errors.New("no trace file supplied") + } + f, err := os.Create(file) + if err != nil { + return nil, nil, err + } + t := &tracer{file: make(chan traceFile, 1)} + sb := new(strings.Builder) + t.file <- traceFile{ + f: f, + sb: sb, + enc: json.NewEncoder(sb), + } + ctx = context.WithValue(ctx, traceKey{}, traceContext{t: t}) + return ctx, t.Close, nil +} + +type traceFile struct { + f *os.File + sb *strings.Builder + enc *json.Encoder + entries int64 +} diff --git a/src/cmd/go/internal/txtar/archive.go b/src/cmd/go/internal/txtar/archive.go new file mode 100644 index 0000000..1796684 --- /dev/null +++ b/src/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" + "os" + "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 := os.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/src/cmd/go/internal/txtar/archive_test.go b/src/cmd/go/internal/txtar/archive_test.go new file mode 100644 index 0000000..3f734f6 --- /dev/null +++ b/src/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/src/cmd/go/internal/vcs/discovery.go b/src/cmd/go/internal/vcs/discovery.go new file mode 100644 index 0000000..327b44c --- /dev/null +++ b/src/cmd/go/internal/vcs/discovery.go @@ -0,0 +1,97 @@ +// 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. + +package vcs + +import ( + "encoding/xml" + "fmt" + "io" + "strings" +) + +// charsetReader returns a reader that converts from the given charset to UTF-8. +// Currently it only supports UTF-8 and ASCII. Otherwise, it returns a meaningful +// error which is printed by go get, so the user can find why the package +// wasn't downloaded if the encoding is not supported. Note that, in +// order to reduce potential errors, ASCII is treated as UTF-8 (i.e. characters +// greater than 0x7f are not rejected). +func charsetReader(charset string, input io.Reader) (io.Reader, error) { + switch strings.ToLower(charset) { + case "utf-8", "ascii": + return input, nil + default: + return nil, fmt.Errorf("can't decode XML document using charset %q", charset) + } +} + +// parseMetaGoImports returns meta imports from the HTML in r. +// Parsing ends at the end of the section or the beginning of the . +func parseMetaGoImports(r io.Reader, mod ModuleMode) ([]metaImport, error) { + d := xml.NewDecoder(r) + d.CharsetReader = charsetReader + d.Strict = false + var imports []metaImport + for { + t, err := d.RawToken() + if err != nil { + if err != io.EOF && len(imports) == 0 { + return nil, err + } + break + } + if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") { + break + } + if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") { + break + } + e, ok := t.(xml.StartElement) + if !ok || !strings.EqualFold(e.Name.Local, "meta") { + continue + } + if attrValue(e.Attr, "name") != "go-import" { + continue + } + if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 { + imports = append(imports, metaImport{ + Prefix: f[0], + VCS: f[1], + RepoRoot: f[2], + }) + } + } + + // 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 +// `name', or the empty string if nothing is found. +func attrValue(attrs []xml.Attr, name string) string { + for _, a := range attrs { + if strings.EqualFold(a.Name.Local, name) { + return a.Value + } + } + return "" +} diff --git a/src/cmd/go/internal/vcs/discovery_test.go b/src/cmd/go/internal/vcs/discovery_test.go new file mode 100644 index 0000000..eb99fdf --- /dev/null +++ b/src/cmd/go/internal/vcs/discovery_test.go @@ -0,0 +1,110 @@ +// Copyright 2014 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 vcs + +import ( + "reflect" + "strings" + "testing" +) + +var parseMetaGoImportsTests = []struct { + in string + mod ModuleMode + out []metaImport +}{ + { + ``, + IgnoreMod, + []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}}, + }, + { + ` + `, + IgnoreMod, + []metaImport{ + {"foo/bar", "git", "https://github.com/rsc/foo/bar"}, + {"baz/quux", "git", "http://github.com/rsc/baz/quux"}, + }, + }, + { + ` + `, + IgnoreMod, + []metaImport{ + {"foo/bar", "git", "https://github.com/rsc/foo/bar"}, + }, + }, + { + ` + `, + IgnoreMod, + []metaImport{ + {"foo/bar", "git", "https://github.com/rsc/foo/bar"}, + }, + }, + { + ` + `, + PreferMod, + []metaImport{ + {"foo/bar", "mod", "http://github.com/rsc/baz/quux"}, + }, + }, + { + ` + + `, + IgnoreMod, + []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}}, + }, + { + ` + `, + IgnoreMod, + []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}}, + }, + { + ``, + IgnoreMod, + []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}}, + }, + { + // XML doesn't like
. + `Page Not Found
DRAFT
`, + IgnoreMod, + []metaImport{{"chitin.io/chitin", "git", "https://github.com/chitin-io/chitin"}}, + }, + { + ` + + `, + IgnoreMod, + []metaImport{{"myitcv.io", "git", "https://github.com/myitcv/x"}}, + }, + { + ` + + `, + 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), tt.mod) + if err != nil { + t.Errorf("test#%d: %v", i, err) + continue + } + if !reflect.DeepEqual(out, tt.out) { + t.Errorf("test#%d:\n\thave %q\n\twant %q", i, out, tt.out) + } + } +} diff --git a/src/cmd/go/internal/vcs/vcs.go b/src/cmd/go/internal/vcs/vcs.go new file mode 100644 index 0000000..9feffe0 --- /dev/null +++ b/src/cmd/go/internal/vcs/vcs.go @@ -0,0 +1,1363 @@ +// 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. + +package vcs + +import ( + "encoding/json" + "errors" + "fmt" + exec "internal/execabs" + "internal/lazyregexp" + "internal/singleflight" + "io/fs" + "log" + urlpkg "net/url" + "os" + "path/filepath" + "regexp" + "strings" + "sync" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/search" + "cmd/go/internal/str" + "cmd/go/internal/web" + + "golang.org/x/mod/module" +) + +// A vcsCmd describes how to use a version control system +// like Mercurial, Git, or Subversion. +type Cmd struct { + Name string + Cmd string // name of binary to invoke command + + CreateCmd []string // commands to download a fresh copy of a repository + DownloadCmd []string // commands to download updates into an existing repository + + TagCmd []tagCmd // commands to list tags + TagLookupCmd []tagCmd // commands to lookup tags before running tagSyncCmd + TagSyncCmd []string // commands to sync to specific tag + TagSyncDefault []string // commands to sync to default tag + + Scheme []string + PingCmd string + + RemoteRepo func(v *Cmd, rootDir string) (remoteRepo string, err error) + ResolveRepo func(v *Cmd, rootDir, remoteRepo string) (realRepo string, err error) +} + +var defaultSecureScheme = map[string]bool{ + "https": true, + "git+ssh": true, + "bzr+ssh": true, + "svn+ssh": true, + "ssh": true, +} + +func (v *Cmd) IsSecure(repo string) bool { + u, err := urlpkg.Parse(repo) + if err != nil { + // If repo is not a URL, it's not secure. + return false + } + return v.isSecureScheme(u.Scheme) +} + +func (v *Cmd) isSecureScheme(scheme string) bool { + switch v.Cmd { + case "git": + // GIT_ALLOW_PROTOCOL is an environment variable defined by Git. It is a + // colon-separated list of schemes that are allowed to be used with git + // fetch/clone. Any scheme not mentioned will be considered insecure. + if allow := os.Getenv("GIT_ALLOW_PROTOCOL"); allow != "" { + for _, s := range strings.Split(allow, ":") { + if s == scheme { + return true + } + } + return false + } + } + return defaultSecureScheme[scheme] +} + +// A tagCmd describes a command to list available tags +// that can be passed to tagSyncCmd. +type tagCmd struct { + cmd string // command to list tags + pattern string // regexp to extract tags from list +} + +// vcsList lists the known version control systems +var vcsList = []*Cmd{ + vcsHg, + vcsGit, + vcsSvn, + vcsBzr, + vcsFossil, +} + +// vcsMod is a stub for the "mod" scheme. It's returned by +// repoRootForImportPathDynamic, but is otherwise not treated as a VCS command. +var vcsMod = &Cmd{Name: "mod"} + +// vcsByCmd returns the version control system for the given +// command name (hg, git, svn, bzr). +func vcsByCmd(cmd string) *Cmd { + for _, vcs := range vcsList { + if vcs.Cmd == cmd { + return vcs + } + } + return nil +} + +// vcsHg describes how to use Mercurial. +var vcsHg = &Cmd{ + Name: "Mercurial", + Cmd: "hg", + + CreateCmd: []string{"clone -U -- {repo} {dir}"}, + DownloadCmd: []string{"pull"}, + + // We allow both tag and branch names as 'tags' + // for selecting a version. This lets people have + // a go.release.r60 branch and a go1 branch + // and make changes in both, without constantly + // editing .hgtags. + TagCmd: []tagCmd{ + {"tags", `^(\S+)`}, + {"branches", `^(\S+)`}, + }, + TagSyncCmd: []string{"update -r {tag}"}, + TagSyncDefault: []string{"update default"}, + + Scheme: []string{"https", "http", "ssh"}, + PingCmd: "identify -- {scheme}://{repo}", + RemoteRepo: hgRemoteRepo, +} + +func hgRemoteRepo(vcsHg *Cmd, rootDir string) (remoteRepo string, err error) { + out, err := vcsHg.runOutput(rootDir, "paths default") + if err != nil { + return "", err + } + return strings.TrimSpace(string(out)), nil +} + +// vcsGit describes how to use Git. +var vcsGit = &Cmd{ + Name: "Git", + Cmd: "git", + + CreateCmd: []string{"clone -- {repo} {dir}", "-go-internal-cd {dir} submodule update --init --recursive"}, + DownloadCmd: []string{"pull --ff-only", "submodule update --init --recursive"}, + + TagCmd: []tagCmd{ + // tags/xxx matches a git tag named xxx + // origin/xxx matches a git branch named xxx on the default remote repository + {"show-ref", `(?:tags|origin)/(\S+)$`}, + }, + TagLookupCmd: []tagCmd{ + {"show-ref tags/{tag} origin/{tag}", `((?:tags|origin)/\S+)$`}, + }, + TagSyncCmd: []string{"checkout {tag}", "submodule update --init --recursive"}, + // both createCmd and downloadCmd update the working dir. + // No need to do more here. We used to 'checkout master' + // but that doesn't work if the default branch is not named master. + // DO NOT add 'checkout master' here. + // See golang.org/issue/9032. + TagSyncDefault: []string{"submodule update --init --recursive"}, + + Scheme: []string{"git", "https", "http", "git+ssh", "ssh"}, + + // Leave out the '--' separator in the ls-remote command: git 2.7.4 does not + // support such a separator for that command, and this use should be safe + // without it because the {scheme} value comes from the predefined list above. + // See golang.org/issue/33836. + PingCmd: "ls-remote {scheme}://{repo}", + + RemoteRepo: gitRemoteRepo, +} + +// scpSyntaxRe matches the SCP-like addresses used by Git to access +// repositories by SSH. +var scpSyntaxRe = lazyregexp.New(`^([a-zA-Z0-9_]+)@([a-zA-Z0-9._-]+):(.*)$`) + +func gitRemoteRepo(vcsGit *Cmd, rootDir string) (remoteRepo string, err error) { + cmd := "config remote.origin.url" + errParse := errors.New("unable to parse output of git " + cmd) + errRemoteOriginNotFound := errors.New("remote origin not found") + outb, err := vcsGit.run1(rootDir, cmd, nil, false) + if err != nil { + // if it doesn't output any message, it means the config argument is correct, + // but the config value itself doesn't exist + if outb != nil && len(outb) == 0 { + return "", errRemoteOriginNotFound + } + return "", err + } + out := strings.TrimSpace(string(outb)) + + var repoURL *urlpkg.URL + if m := scpSyntaxRe.FindStringSubmatch(out); m != nil { + // Match SCP-like syntax and convert it to a URL. + // Eg, "git@github.com:user/repo" becomes + // "ssh://git@github.com/user/repo". + repoURL = &urlpkg.URL{ + Scheme: "ssh", + User: urlpkg.User(m[1]), + Host: m[2], + Path: m[3], + } + } else { + repoURL, err = urlpkg.Parse(out) + if err != nil { + return "", err + } + } + + // Iterate over insecure schemes too, because this function simply + // reports the state of the repo. If we can't see insecure schemes then + // we can't report the actual repo URL. + for _, s := range vcsGit.Scheme { + if repoURL.Scheme == s { + return repoURL.String(), nil + } + } + return "", errParse +} + +// vcsBzr describes how to use Bazaar. +var vcsBzr = &Cmd{ + Name: "Bazaar", + Cmd: "bzr", + + CreateCmd: []string{"branch -- {repo} {dir}"}, + + // Without --overwrite bzr will not pull tags that changed. + // Replace by --overwrite-tags after http://pad.lv/681792 goes in. + DownloadCmd: []string{"pull --overwrite"}, + + TagCmd: []tagCmd{{"tags", `^(\S+)`}}, + TagSyncCmd: []string{"update -r {tag}"}, + TagSyncDefault: []string{"update -r revno:-1"}, + + Scheme: []string{"https", "http", "bzr", "bzr+ssh"}, + PingCmd: "info -- {scheme}://{repo}", + RemoteRepo: bzrRemoteRepo, + ResolveRepo: bzrResolveRepo, +} + +func bzrRemoteRepo(vcsBzr *Cmd, rootDir string) (remoteRepo string, err error) { + outb, err := vcsBzr.runOutput(rootDir, "config parent_location") + if err != nil { + return "", err + } + return strings.TrimSpace(string(outb)), nil +} + +func bzrResolveRepo(vcsBzr *Cmd, rootDir, remoteRepo string) (realRepo string, err error) { + outb, err := vcsBzr.runOutput(rootDir, "info "+remoteRepo) + if err != nil { + return "", err + } + out := string(outb) + + // Expect: + // ... + // (branch root|repository branch): + // ... + + found := false + for _, prefix := range []string{"\n branch root: ", "\n repository branch: "} { + i := strings.Index(out, prefix) + if i >= 0 { + out = out[i+len(prefix):] + found = true + break + } + } + if !found { + return "", fmt.Errorf("unable to parse output of bzr info") + } + + i := strings.Index(out, "\n") + if i < 0 { + return "", fmt.Errorf("unable to parse output of bzr info") + } + out = out[:i] + return strings.TrimSpace(out), nil +} + +// vcsSvn describes how to use Subversion. +var vcsSvn = &Cmd{ + Name: "Subversion", + Cmd: "svn", + + CreateCmd: []string{"checkout -- {repo} {dir}"}, + DownloadCmd: []string{"update"}, + + // There is no tag command in subversion. + // The branch information is all in the path names. + + Scheme: []string{"https", "http", "svn", "svn+ssh"}, + PingCmd: "info -- {scheme}://{repo}", + RemoteRepo: svnRemoteRepo, +} + +func svnRemoteRepo(vcsSvn *Cmd, rootDir string) (remoteRepo string, err error) { + outb, err := vcsSvn.runOutput(rootDir, "info") + if err != nil { + return "", err + } + out := string(outb) + + // Expect: + // + // ... + // URL: + // ... + // + // Note that we're not using the Repository Root line, + // because svn allows checking out subtrees. + // The URL will be the URL of the subtree (what we used with 'svn co') + // while the Repository Root may be a much higher parent. + i := strings.Index(out, "\nURL: ") + if i < 0 { + return "", fmt.Errorf("unable to parse output of svn info") + } + out = out[i+len("\nURL: "):] + i = strings.Index(out, "\n") + if i < 0 { + return "", fmt.Errorf("unable to parse output of svn info") + } + out = out[:i] + return strings.TrimSpace(out), nil +} + +// fossilRepoName is the name go get associates with a fossil repository. In the +// real world the file can be named anything. +const fossilRepoName = ".fossil" + +// vcsFossil describes how to use Fossil (fossil-scm.org) +var vcsFossil = &Cmd{ + Name: "Fossil", + Cmd: "fossil", + + CreateCmd: []string{"-go-internal-mkdir {dir} clone -- {repo} " + filepath.Join("{dir}", fossilRepoName), "-go-internal-cd {dir} open .fossil"}, + DownloadCmd: []string{"up"}, + + TagCmd: []tagCmd{{"tag ls", `(.*)`}}, + TagSyncCmd: []string{"up tag:{tag}"}, + TagSyncDefault: []string{"up trunk"}, + + Scheme: []string{"https", "http"}, + RemoteRepo: fossilRemoteRepo, +} + +func fossilRemoteRepo(vcsFossil *Cmd, rootDir string) (remoteRepo string, err error) { + out, err := vcsFossil.runOutput(rootDir, "remote-url") + if err != nil { + return "", err + } + return strings.TrimSpace(string(out)), nil +} + +func (v *Cmd) String() string { + return v.Name +} + +// run runs the command line cmd in the given directory. +// keyval is a list of key, value pairs. run expands +// instances of {key} in cmd into value, but only after +// splitting cmd into individual arguments. +// If an error occurs, run prints the command line and the +// command's combined stdout+stderr to standard error. +// Otherwise run discards the command's output. +func (v *Cmd) run(dir string, cmd string, keyval ...string) error { + _, err := v.run1(dir, cmd, keyval, true) + return err +} + +// runVerboseOnly is like run but only generates error output to standard error in verbose mode. +func (v *Cmd) runVerboseOnly(dir string, cmd string, keyval ...string) error { + _, err := v.run1(dir, cmd, keyval, false) + return err +} + +// runOutput is like run but returns the output of the command. +func (v *Cmd) runOutput(dir string, cmd string, keyval ...string) ([]byte, error) { + return v.run1(dir, cmd, keyval, true) +} + +// run1 is the generalized implementation of run and runOutput. +func (v *Cmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([]byte, error) { + m := make(map[string]string) + for i := 0; i < len(keyval); i += 2 { + m[keyval[i]] = keyval[i+1] + } + args := strings.Fields(cmdline) + for i, arg := range args { + args[i] = expand(m, arg) + } + + if len(args) >= 2 && args[0] == "-go-internal-mkdir" { + var err error + if filepath.IsAbs(args[1]) { + err = os.Mkdir(args[1], fs.ModePerm) + } else { + err = os.Mkdir(filepath.Join(dir, args[1]), fs.ModePerm) + } + if err != nil { + return nil, err + } + args = args[2:] + } + + if len(args) >= 2 && args[0] == "-go-internal-cd" { + if filepath.IsAbs(args[1]) { + dir = args[1] + } else { + dir = filepath.Join(dir, args[1]) + } + args = args[2:] + } + + _, err := exec.LookPath(v.Cmd) + if err != nil { + fmt.Fprintf(os.Stderr, + "go: missing %s command. See https://golang.org/s/gogetcmd\n", + v.Name) + return nil, err + } + + cmd := exec.Command(v.Cmd, args...) + cmd.Dir = dir + cmd.Env = base.AppendPWD(os.Environ(), cmd.Dir) + if cfg.BuildX { + fmt.Fprintf(os.Stderr, "cd %s\n", dir) + fmt.Fprintf(os.Stderr, "%s %s\n", v.Cmd, strings.Join(args, " ")) + } + 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, " ")) + 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 +} + +// Ping pings to determine scheme to use. +func (v *Cmd) Ping(scheme, repo string) error { + return v.runVerboseOnly(".", v.PingCmd, "scheme", scheme, "repo", repo) +} + +// Create creates a new copy of repo in dir. +// The parent of dir must exist; dir must not. +func (v *Cmd) Create(dir, repo string) error { + for _, cmd := range v.CreateCmd { + if err := v.run(".", cmd, "dir", dir, "repo", repo); err != nil { + return err + } + } + return nil +} + +// Download downloads any new changes for the repo in dir. +func (v *Cmd) Download(dir string) error { + for _, cmd := range v.DownloadCmd { + if err := v.run(dir, cmd); err != nil { + return err + } + } + return nil +} + +// Tags returns the list of available tags for the repo in dir. +func (v *Cmd) Tags(dir string) ([]string, error) { + var tags []string + for _, tc := range v.TagCmd { + out, err := v.runOutput(dir, tc.cmd) + if err != nil { + return nil, err + } + re := regexp.MustCompile(`(?m-s)` + tc.pattern) + for _, m := range re.FindAllStringSubmatch(string(out), -1) { + tags = append(tags, m[1]) + } + } + return tags, nil +} + +// tagSync syncs the repo in dir to the named tag, +// which either is a tag returned by tags or is v.tagDefault. +func (v *Cmd) TagSync(dir, tag string) error { + if v.TagSyncCmd == nil { + return nil + } + if tag != "" { + for _, tc := range v.TagLookupCmd { + out, err := v.runOutput(dir, tc.cmd, "tag", tag) + if err != nil { + return err + } + re := regexp.MustCompile(`(?m-s)` + tc.pattern) + m := re.FindStringSubmatch(string(out)) + if len(m) > 1 { + tag = m[1] + break + } + } + } + + if tag == "" && v.TagSyncDefault != nil { + for _, cmd := range v.TagSyncDefault { + if err := v.run(dir, cmd); err != nil { + return err + } + } + return nil + } + + for _, cmd := range v.TagSyncCmd { + if err := v.run(dir, cmd, "tag", tag); err != nil { + return err + } + } + return nil +} + +// A vcsPath describes how to convert an import path into a +// version control system and repository name. +type vcsPath struct { + pathPrefix string // prefix this description applies to + regexp *lazyregexp.Regexp // compiled pattern for import path + repo string // repository to use (expand with match of re) + vcs string // version control system to use (expand with match of re) + check func(match map[string]string) error // additional checks + schemelessRepo bool // if true, the repo pattern lacks a scheme +} + +// FromDir inspects dir and its parents to determine the +// version control system and code repository to use. +// On return, root is the import path +// corresponding to the root of the repository. +func FromDir(dir, srcRoot string) (vcs *Cmd, root string, err error) { + // Clean and double-check that dir is in (a subdirectory of) srcRoot. + dir = filepath.Clean(dir) + srcRoot = filepath.Clean(srcRoot) + if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator { + return nil, "", fmt.Errorf("directory %q is outside source root %q", dir, srcRoot) + } + + var vcsRet *Cmd + var rootRet string + + origDir := dir + for len(dir) > len(srcRoot) { + for _, vcs := range vcsList { + if _, err := os.Stat(filepath.Join(dir, "."+vcs.Cmd)); err == nil { + root := filepath.ToSlash(dir[len(srcRoot)+1:]) + // Record first VCS we find, but keep looking, + // to detect mistakes like one kind of VCS inside another. + if vcsRet == nil { + vcsRet = vcs + rootRet = root + continue + } + // Allow .git inside .git, which can arise due to submodules. + if vcsRet == vcs && vcs.Cmd == "git" { + continue + } + // Otherwise, we have one VCS inside a different VCS. + return nil, "", fmt.Errorf("directory %q uses %s, but parent %q uses %s", + filepath.Join(srcRoot, rootRet), vcsRet.Cmd, filepath.Join(srcRoot, root), vcs.Cmd) + } + } + + // Move to parent. + ndir := filepath.Dir(dir) + if len(ndir) >= len(dir) { + // Shouldn't happen, but just in case, stop. + break + } + dir = ndir + } + + if vcsRet != nil { + if err := checkGOVCS(vcsRet, rootRet); err != nil { + return nil, "", err + } + return vcsRet, rootRet, nil + } + + return nil, "", fmt.Errorf("directory %q is not using a known version control system", origDir) +} + +// A govcsRule is a single GOVCS rule like private:hg|svn. +type govcsRule struct { + pattern string + allowed []string +} + +// A govcsConfig is a full GOVCS configuration. +type govcsConfig []govcsRule + +func parseGOVCS(s string) (govcsConfig, error) { + s = strings.TrimSpace(s) + if s == "" { + return nil, nil + } + var cfg govcsConfig + have := make(map[string]string) + for _, item := range strings.Split(s, ",") { + item = strings.TrimSpace(item) + if item == "" { + return nil, fmt.Errorf("empty entry in GOVCS") + } + i := strings.Index(item, ":") + if i < 0 { + return nil, fmt.Errorf("malformed entry in GOVCS (missing colon): %q", item) + } + pattern, list := strings.TrimSpace(item[:i]), strings.TrimSpace(item[i+1:]) + if pattern == "" { + return nil, fmt.Errorf("empty pattern in GOVCS: %q", item) + } + if list == "" { + return nil, fmt.Errorf("empty VCS list in GOVCS: %q", item) + } + if search.IsRelativePath(pattern) { + return nil, fmt.Errorf("relative pattern not allowed in GOVCS: %q", pattern) + } + if old := have[pattern]; old != "" { + return nil, fmt.Errorf("unreachable pattern in GOVCS: %q after %q", item, old) + } + have[pattern] = item + allowed := strings.Split(list, "|") + for i, a := range allowed { + a = strings.TrimSpace(a) + if a == "" { + return nil, fmt.Errorf("empty VCS name in GOVCS: %q", item) + } + allowed[i] = a + } + cfg = append(cfg, govcsRule{pattern, allowed}) + } + return cfg, nil +} + +func (c *govcsConfig) allow(path string, private bool, vcs string) bool { + for _, rule := range *c { + match := false + switch rule.pattern { + case "private": + match = private + case "public": + match = !private + default: + // Note: rule.pattern is known to be comma-free, + // so MatchPrefixPatterns is only matching a single pattern for us. + match = module.MatchPrefixPatterns(rule.pattern, path) + } + if !match { + continue + } + for _, allow := range rule.allowed { + if allow == vcs || allow == "all" { + return true + } + } + return false + } + + // By default, nothing is allowed. + return false +} + +var ( + govcs govcsConfig + govcsErr error + govcsOnce sync.Once +) + +// defaultGOVCS is the default setting for GOVCS. +// Setting GOVCS adds entries ahead of these but does not remove them. +// (They are appended to the parsed GOVCS setting.) +// +// The rationale behind allowing only Git and Mercurial is that +// these two systems have had the most attention to issues +// of being run as clients of untrusted servers. In contrast, +// Bazaar, Fossil, and Subversion have primarily been used +// in trusted, authenticated environments and are not as well +// scrutinized as attack surfaces. +// +// See golang.org/issue/41730 for details. +var defaultGOVCS = govcsConfig{ + {"private", []string{"all"}}, + {"public", []string{"git", "hg"}}, +} + +func checkGOVCS(vcs *Cmd, root string) error { + if vcs == vcsMod { + // Direct module (proxy protocol) fetches don't + // involve an external version control system + // and are always allowed. + return nil + } + + govcsOnce.Do(func() { + govcs, govcsErr = parseGOVCS(os.Getenv("GOVCS")) + govcs = append(govcs, defaultGOVCS...) + }) + if govcsErr != nil { + return govcsErr + } + + private := module.MatchPrefixPatterns(cfg.GOPRIVATE, root) + if !govcs.allow(root, private, vcs.Cmd) { + what := "public" + if private { + what = "private" + } + return fmt.Errorf("GOVCS disallows using %s for %s %s; see 'go help vcs'", vcs.Cmd, what, root) + } + + return nil +} + +// CheckNested checks for an incorrectly-nested VCS-inside-VCS +// situation for dir, checking parents up until srcRoot. +func CheckNested(vcs *Cmd, dir, srcRoot string) error { + if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator { + return fmt.Errorf("directory %q is outside source root %q", dir, srcRoot) + } + + otherDir := dir + for len(otherDir) > len(srcRoot) { + for _, otherVCS := range vcsList { + if _, err := os.Stat(filepath.Join(otherDir, "."+otherVCS.Cmd)); err == nil { + // Allow expected vcs in original dir. + if otherDir == dir && otherVCS == vcs { + continue + } + // Allow .git inside .git, which can arise due to submodules. + if otherVCS == vcs && vcs.Cmd == "git" { + continue + } + // Otherwise, we have one VCS inside a different VCS. + return fmt.Errorf("directory %q uses %s, but parent %q uses %s", dir, vcs.Cmd, otherDir, otherVCS.Cmd) + } + } + // Move to parent. + newDir := filepath.Dir(otherDir) + if len(newDir) >= len(otherDir) { + // Shouldn't happen, but just in case, stop. + break + } + otherDir = newDir + } + + return nil +} + +// 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 tags (as opposed to hard-coded pattern) + VCS *Cmd +} + +func httpPrefix(s string) string { + for _, prefix := range [...]string{"http:", "https:"} { + if strings.HasPrefix(s, prefix) { + return prefix + } + } + return "" +} + +// 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, mod ModuleMode, security web.SecurityMode) (*RepoRoot, error) { + rr, err := repoRootFromVCSPaths(importPath, security, vcsPaths) + if err == errUnknownSite { + rr, err = repoRootForImportDynamic(importPath, mod, security) + if err != nil { + err = importErrorf(importPath, "unrecognized import path %q: %v", importPath, err) + } + } + if err != nil { + rr1, err1 := repoRootFromVCSPaths(importPath, security, vcsPathsAfterDynamic) + if err1 == nil { + rr = rr1 + err = nil + } + } + + // Should have been taken care of above, but make sure. + if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.Root, "...") { + // Do not allow wildcards in the repo root. + rr = nil + err = importErrorf(importPath, "cannot expand ... in %q", importPath) + } + return rr, err +} + +var errUnknownSite = errors.New("dynamic lookup required to find mapping") + +// repoRootFromVCSPaths attempts to map importPath to a repoRoot +// using the mappings defined in vcsPaths. +func repoRootFromVCSPaths(importPath string, security web.SecurityMode, vcsPaths []*vcsPath) (*RepoRoot, error) { + if str.HasPathPrefix(importPath, "example.net") { + // TODO(rsc): This should not be necessary, but it's required to keep + // tests like ../../testdata/script/mod_get_extra.txt from using the network. + // That script has everything it needs in the replacement set, but it is still + // doing network calls. + return nil, fmt.Errorf("no modules on example.net") + } + if importPath == "rsc.io" { + // This special case allows tests like ../../testdata/script/govcs.txt + // to avoid making any network calls. The module lookup for a path + // like rsc.io/nonexist.svn/foo needs to not make a network call for + // a lookup on rsc.io. + return nil, fmt.Errorf("rsc.io is not a module") + } + // A common error is to use https://packagepath because that's what + // hg and git require. Diagnose this helpfully. + if prefix := httpPrefix(importPath); prefix != "" { + // The importPath has been cleaned, so has only one slash. The pattern + // ignores the slashes; the error message puts them back on the RHS at least. + return nil, fmt.Errorf("%q not allowed in import path", prefix+"//") + } + for _, srv := range vcsPaths { + if !str.HasPathPrefix(importPath, srv.pathPrefix) { + continue + } + m := srv.regexp.FindStringSubmatch(importPath) + if m == nil { + if srv.pathPrefix != "" { + return nil, importErrorf(importPath, "invalid %s import path %q", srv.pathPrefix, importPath) + } + continue + } + + // Build map of named subexpression matches for expand. + match := map[string]string{ + "prefix": srv.pathPrefix + "/", + "import": importPath, + } + for i, name := range srv.regexp.SubexpNames() { + if name != "" && match[name] == "" { + match[name] = m[i] + } + } + if srv.vcs != "" { + match["vcs"] = expand(match, srv.vcs) + } + if srv.repo != "" { + match["repo"] = expand(match, srv.repo) + } + if srv.check != nil { + if err := srv.check(match); err != nil { + return nil, err + } + } + vcs := vcsByCmd(match["vcs"]) + if vcs == nil { + return nil, fmt.Errorf("unknown version control system %q", match["vcs"]) + } + if err := checkGOVCS(vcs, match["root"]); err != nil { + return nil, err + } + var repoURL string + if !srv.schemelessRepo { + repoURL = match["repo"] + } else { + scheme := vcs.Scheme[0] // default to first scheme + repo := match["repo"] + if vcs.PingCmd != "" { + // If we know how to test schemes, scan to find one. + for _, s := range vcs.Scheme { + if security == web.SecureOnly && !vcs.isSecureScheme(s) { + continue + } + if vcs.Ping(s, repo) == nil { + scheme = s + break + } + } + } + repoURL = scheme + "://" + repo + } + rr := &RepoRoot{ + Repo: repoURL, + Root: match["root"], + VCS: vcs, + } + return rr, nil + } + return nil, errUnknownSite +} + +// urlForImportPath returns a partially-populated URL for the given Go import path. +// +// The URL leaves the Scheme field blank so that web.Get will try any scheme +// allowed by the selected security mode. +func urlForImportPath(importPath string) (*urlpkg.URL, error) { + slash := strings.Index(importPath, "/") + if slash < 0 { + slash = len(importPath) + } + host, path := importPath[:slash], importPath[slash:] + if !strings.Contains(host, ".") { + return nil, errors.New("import path does not begin with hostname") + } + if len(path) == 0 { + path = "/" + } + return &urlpkg.URL{Host: host, Path: path, RawQuery: "go-get=1"}, nil +} + +// 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, mod ModuleMode, security web.SecurityMode) (*RepoRoot, error) { + url, err := urlForImportPath(importPath) + if err != nil { + return nil, err + } + resp, err := web.Get(security, url) + if err != nil { + msg := "https fetch: %v" + if security == web.Insecure { + msg = "http/" + msg + } + return nil, fmt.Errorf(msg, err) + } + body := resp.Body + defer body.Close() + imports, err := parseMetaGoImports(body, mod) + if len(imports) == 0 { + if respErr := resp.Err(); respErr != nil { + // If the server's status was not OK, prefer to report that instead of + // an XML parse error. + return nil, respErr + } + } + if err != nil { + return nil, fmt.Errorf("parsing %s: %v", importPath, err) + } + // Find the matched meta import. + mmi, err := matchGoImport(imports, importPath) + if err != nil { + if _, ok := err.(ImportMismatchError); !ok { + return nil, fmt.Errorf("parse %s: %v", url, err) + } + return nil, fmt.Errorf("parse %s: no go-import meta tags (%s)", resp.URL, err) + } + if cfg.BuildV { + log.Printf("get %q: found meta tag %#v at %s", importPath, mmi, url) + } + // If the import was "uni.edu/bob/project", which said the + // prefix was "uni.edu" and the RepoRoot was "evilroot.com", + // make sure we don't trust Bob and check out evilroot.com to + // "uni.edu" yet (possibly overwriting/preempting another + // non-evil student). Instead, first verify the root and see + // if it matches Bob's claim. + if mmi.Prefix != importPath { + if cfg.BuildV { + log.Printf("get %q: verifying non-authoritative meta tag", importPath) + } + var imports []metaImport + url, imports, err = metaImportsForPrefix(mmi.Prefix, mod, security) + if err != nil { + return nil, err + } + metaImport2, err := matchGoImport(imports, importPath) + if err != nil || mmi != metaImport2 { + return nil, fmt.Errorf("%s and %s disagree about go-import for %s", resp.URL, url, mmi.Prefix) + } + } + + if err := validateRepoRoot(mmi.RepoRoot); err != nil { + return nil, fmt.Errorf("%s: invalid repo root %q: %v", resp.URL, mmi.RepoRoot, err) + } + var vcs *Cmd + if mmi.VCS == "mod" { + vcs = vcsMod + } else { + vcs = vcsByCmd(mmi.VCS) + if vcs == nil { + return nil, fmt.Errorf("%s: unknown vcs %q", resp.URL, mmi.VCS) + } + } + + if err := checkGOVCS(vcs, mmi.Prefix); err != nil { + return nil, err + } + + rr := &RepoRoot{ + Repo: mmi.RepoRoot, + Root: mmi.Prefix, + IsCustom: true, + VCS: vcs, + } + return rr, nil +} + +// validateRepoRoot returns an error if repoRoot does not seem to be +// a valid URL with scheme. +func validateRepoRoot(repoRoot string) error { + url, err := urlpkg.Parse(repoRoot) + if err != nil { + return err + } + if url.Scheme == "" { + return errors.New("no scheme") + } + if url.Scheme == "file" { + return errors.New("file scheme disallowed") + } + return nil +} + +var fetchGroup singleflight.Group +var ( + fetchCacheMu sync.Mutex + fetchCache = map[string]fetchResult{} // key is metaImportsForPrefix's importPrefix +) + +// metaImportsForPrefix takes a package's root import path as declared in a tag +// and returns its HTML discovery URL and the parsed metaImport lines +// found on the page. +// +// The importPath is of the form "golang.org/x/tools". +// It is an error if no imports are found. +// url will still be valid if err != nil. +// The returned url will be of the form "https://golang.org/x/tools?go-get=1" +func metaImportsForPrefix(importPrefix string, mod ModuleMode, security web.SecurityMode) (*urlpkg.URL, []metaImport, error) { + setCache := func(res fetchResult) (fetchResult, error) { + fetchCacheMu.Lock() + defer fetchCacheMu.Unlock() + fetchCache[importPrefix] = res + return res, nil + } + + resi, _, _ := fetchGroup.Do(importPrefix, func() (resi interface{}, err error) { + fetchCacheMu.Lock() + if res, ok := fetchCache[importPrefix]; ok { + fetchCacheMu.Unlock() + return res, nil + } + fetchCacheMu.Unlock() + + url, err := urlForImportPath(importPrefix) + if err != nil { + return setCache(fetchResult{err: err}) + } + resp, err := web.Get(security, url) + if err != nil { + return setCache(fetchResult{url: url, err: fmt.Errorf("fetching %s: %v", importPrefix, err)}) + } + body := resp.Body + defer body.Close() + imports, err := parseMetaGoImports(body, mod) + if len(imports) == 0 { + if respErr := resp.Err(); respErr != nil { + // If the server's status was not OK, prefer to report that instead of + // an XML parse error. + return setCache(fetchResult{url: url, err: respErr}) + } + } + if err != nil { + return setCache(fetchResult{url: url, err: fmt.Errorf("parsing %s: %v", resp.URL, err)}) + } + if len(imports) == 0 { + err = fmt.Errorf("fetching %s: no go-import meta tag found in %s", importPrefix, resp.URL) + } + return setCache(fetchResult{url: url, imports: imports, err: err}) + }) + res := resi.(fetchResult) + return res.url, res.imports, res.err +} + +type fetchResult struct { + url *urlpkg.URL + imports []metaImport + err error +} + +// metaImport represents the parsed tags from HTML files. +type metaImport struct { + Prefix, VCS, RepoRoot string +} + +// A ImportMismatchError is returned where metaImport/s are present +// but none match our import path. +type ImportMismatchError struct { + importPath string + mismatches []string // the meta imports that were discarded for not matching our importPath +} + +func (m ImportMismatchError) Error() string { + formattedStrings := make([]string, len(m.mismatches)) + for i, pre := range m.mismatches { + formattedStrings[i] = fmt.Sprintf("meta tag %s did not match import path %s", pre, m.importPath) + } + return strings.Join(formattedStrings, ", ") +} + +// matchGoImport returns the metaImport from imports matching importPath. +// An error is returned if there are multiple matches. +// An ImportMismatchError is returned if none match. +func matchGoImport(imports []metaImport, importPath string) (metaImport, error) { + match := -1 + + errImportMismatch := ImportMismatchError{importPath: importPath} + for i, im := range imports { + if !str.HasPathPrefix(importPath, im.Prefix) { + errImportMismatch.mismatches = append(errImportMismatch.mismatches, im.Prefix) + continue + } + + 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 + } + + if match == -1 { + return metaImport{}, errImportMismatch + } + return imports[match], nil +} + +// expand rewrites s to replace {k} with match[k] for each key k in match. +func expand(match map[string]string, s string) string { + // We want to replace each match exactly once, and the result of expansion + // must not depend on the iteration order through the map. + // A strings.Replacer has exactly the properties we're looking for. + oldNew := make([]string, 0, 2*len(match)) + for k, v := range match { + oldNew = append(oldNew, "{"+k+"}", v) + } + return strings.NewReplacer(oldNew...).Replace(s) +} + +// vcsPaths defines the meaning of import paths referring to +// commonly-used VCS hosting sites (github.com/user/dir) +// and import paths referring to a fully-qualified importPath +// containing a VCS type (foo.com/repo.git/dir) +var vcsPaths = []*vcsPath{ + // Github + { + pathPrefix: "github.com", + regexp: lazyregexp.New(`^(?Pgithub\.com/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`), + vcs: "git", + repo: "https://{root}", + check: noVCSSuffix, + }, + + // Bitbucket + { + pathPrefix: "bitbucket.org", + regexp: lazyregexp.New(`^(?Pbitbucket\.org/(?P[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`), + repo: "https://{root}", + check: bitbucketVCS, + }, + + // IBM DevOps Services (JazzHub) + { + pathPrefix: "hub.jazz.net/git", + regexp: lazyregexp.New(`^(?Phub\.jazz\.net/git/[a-z0-9]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`), + vcs: "git", + repo: "https://{root}", + check: noVCSSuffix, + }, + + // Git at Apache + { + pathPrefix: "git.apache.org", + regexp: lazyregexp.New(`^(?Pgit\.apache\.org/[a-z0-9_.\-]+\.git)(/[A-Za-z0-9_.\-]+)*$`), + vcs: "git", + repo: "https://{root}", + }, + + // Git at OpenStack + { + pathPrefix: "git.openstack.org", + regexp: lazyregexp.New(`^(?Pgit\.openstack\.org/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(\.git)?(/[A-Za-z0-9_.\-]+)*$`), + vcs: "git", + repo: "https://{root}", + }, + + // chiselapp.com for fossil + { + pathPrefix: "chiselapp.com", + regexp: lazyregexp.New(`^(?Pchiselapp\.com/user/[A-Za-z0-9]+/repository/[A-Za-z0-9_.\-]+)$`), + vcs: "fossil", + repo: "https://{root}", + }, + + // General syntax for any server. + // Must be last. + { + regexp: lazyregexp.New(`(?P(?P([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?(/~?[A-Za-z0-9_.\-]+)+?)\.(?Pbzr|fossil|git|hg|svn))(/~?[A-Za-z0-9_.\-]+)*$`), + schemelessRepo: true, + }, +} + +// vcsPathsAfterDynamic gives additional vcsPaths entries +// to try after the dynamic HTML check. +// This gives those sites a chance to introduce tags +// as part of a graceful transition away from the hard-coded logic. +var vcsPathsAfterDynamic = []*vcsPath{ + // Launchpad. See golang.org/issue/11436. + { + pathPrefix: "launchpad.net", + regexp: lazyregexp.New(`^(?Plaunchpad\.net/((?P[A-Za-z0-9_.\-]+)(?P/[A-Za-z0-9_.\-]+)?|~[A-Za-z0-9_.\-]+/(\+junk|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`), + vcs: "bzr", + repo: "https://{root}", + check: launchpadVCS, + }, +} + +// noVCSSuffix checks that the repository name does not +// end in .foo for any version control system foo. +// The usual culprit is ".git". +func noVCSSuffix(match map[string]string) error { + repo := match["repo"] + for _, vcs := range vcsList { + if strings.HasSuffix(repo, "."+vcs.Cmd) { + return fmt.Errorf("invalid version control suffix in %s path", match["prefix"]) + } + } + return nil +} + +// bitbucketVCS determines the version control system for a +// Bitbucket repository, by using the Bitbucket API. +func bitbucketVCS(match map[string]string) error { + if err := noVCSSuffix(match); err != nil { + return err + } + + var resp struct { + SCM string `json:"scm"` + } + url := &urlpkg.URL{ + Scheme: "https", + Host: "api.bitbucket.org", + Path: expand(match, "/2.0/repositories/{bitname}"), + RawQuery: "fields=scm", + } + data, err := web.GetBytes(url) + if err != nil { + if httpErr, ok := err.(*web.HTTPError); ok && httpErr.StatusCode == 403 { + // this may be a private repository. If so, attempt to determine which + // VCS it uses. See issue 5375. + root := match["root"] + for _, vcs := range []string{"git", "hg"} { + if vcsByCmd(vcs).Ping("https", root) == nil { + resp.SCM = vcs + break + } + } + } + + if resp.SCM == "" { + return err + } + } else { + if err := json.Unmarshal(data, &resp); err != nil { + return fmt.Errorf("decoding %s: %v", url, err) + } + } + + if vcsByCmd(resp.SCM) != nil { + match["vcs"] = resp.SCM + if resp.SCM == "git" { + match["repo"] += ".git" + } + return nil + } + + return fmt.Errorf("unable to detect version control system for bitbucket.org/ path") +} + +// launchpadVCS solves the ambiguity for "lp.net/project/foo". In this case, +// "foo" could be a series name registered in Launchpad with its own branch, +// and it could also be the name of a directory within the main project +// branch one level up. +func launchpadVCS(match map[string]string) error { + if match["project"] == "" || match["series"] == "" { + return nil + } + url := &urlpkg.URL{ + Scheme: "https", + Host: "code.launchpad.net", + Path: expand(match, "/{project}{series}/.bzr/branch-format"), + } + _, err := web.GetBytes(url) + if err != nil { + match["root"] = expand(match, "launchpad.net/{project}") + match["repo"] = expand(match, "https://{root}") + } + return nil +} + +// importError is a copy of load.importError, made to avoid a dependency cycle +// on cmd/go/internal/load. It just needs to satisfy load.ImportPathError. +type importError struct { + importPath string + err error +} + +func importErrorf(path, format string, args ...interface{}) error { + err := &importError{importPath: path, err: fmt.Errorf(format, args...)} + if errStr := err.Error(); !strings.Contains(errStr, path) { + panic(fmt.Sprintf("path %q not in error %q", path, errStr)) + } + return err +} + +func (e *importError) Error() string { + return e.err.Error() +} + +func (e *importError) Unwrap() error { + // Don't return e.err directly, since we're only wrapping an error if %w + // was passed to ImportErrorf. + return errors.Unwrap(e.err) +} + +func (e *importError) ImportPath() string { + return e.importPath +} diff --git a/src/cmd/go/internal/vcs/vcs_test.go b/src/cmd/go/internal/vcs/vcs_test.go new file mode 100644 index 0000000..c5c7a32 --- /dev/null +++ b/src/cmd/go/internal/vcs/vcs_test.go @@ -0,0 +1,578 @@ +// Copyright 2014 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 vcs + +import ( + "errors" + "internal/testenv" + "os" + "path" + "path/filepath" + "strings" + "testing" + + "cmd/go/internal/web" +) + +func init() { + // GOVCS defaults to public:git|hg,private:all, + // which breaks many tests here - they can't use non-git, non-hg VCS at all! + // Change to fully permissive. + // The tests of the GOVCS setting itself are in ../../testdata/script/govcs.txt. + os.Setenv("GOVCS", "*:all") +} + +// 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 + }{ + { + "github.com/golang/groupcache", + &RepoRoot{ + VCS: vcsGit, + Repo: "https://github.com/golang/groupcache", + }, + }, + // Unicode letters in directories are not valid. + { + "github.com/user/unicode/испытание", + nil, + }, + // IBM DevOps Services tests + { + "hub.jazz.net/git/user1/pkgname", + &RepoRoot{ + VCS: vcsGit, + Repo: "https://hub.jazz.net/git/user1/pkgname", + }, + }, + { + "hub.jazz.net/git/user1/pkgname/submodule/submodule/submodule", + &RepoRoot{ + VCS: vcsGit, + Repo: "https://hub.jazz.net/git/user1/pkgname", + }, + }, + { + "hub.jazz.net", + nil, + }, + { + "hubajazz.net", + nil, + }, + { + "hub2.jazz.net", + nil, + }, + { + "hub.jazz.net/someotherprefix", + nil, + }, + { + "hub.jazz.net/someotherprefix/user1/pkgname", + nil, + }, + // Spaces are not valid in user names or package names + { + "hub.jazz.net/git/User 1/pkgname", + nil, + }, + { + "hub.jazz.net/git/user1/pkg name", + nil, + }, + // Dots are not valid in user names + { + "hub.jazz.net/git/user.1/pkgname", + nil, + }, + { + "hub.jazz.net/git/user/pkg.name", + &RepoRoot{ + VCS: vcsGit, + Repo: "https://hub.jazz.net/git/user/pkg.name", + }, + }, + // User names cannot have uppercase letters + { + "hub.jazz.net/git/USER/pkgname", + nil, + }, + // OpenStack tests + { + "git.openstack.org/openstack/swift", + &RepoRoot{ + VCS: vcsGit, + Repo: "https://git.openstack.org/openstack/swift", + }, + }, + // Trailing .git is less preferred but included for + // compatibility purposes while the same source needs to + // be compilable on both old and new go + { + "git.openstack.org/openstack/swift.git", + &RepoRoot{ + VCS: vcsGit, + Repo: "https://git.openstack.org/openstack/swift.git", + }, + }, + { + "git.openstack.org/openstack/swift/go/hummingbird", + &RepoRoot{ + VCS: vcsGit, + Repo: "https://git.openstack.org/openstack/swift", + }, + }, + { + "git.openstack.org", + nil, + }, + { + "git.openstack.org/openstack", + nil, + }, + // Spaces are not valid in package name + { + "git.apache.org/package name/path/to/lib", + nil, + }, + // Should have ".git" suffix + { + "git.apache.org/package-name/path/to/lib", + nil, + }, + { + "gitbapache.org", + nil, + }, + { + "git.apache.org/package-name.git", + &RepoRoot{ + VCS: vcsGit, + Repo: "https://git.apache.org/package-name.git", + }, + }, + { + "git.apache.org/package-name_2.x.git/path/to/lib", + &RepoRoot{ + VCS: vcsGit, + Repo: "https://git.apache.org/package-name_2.x.git", + }, + }, + { + "chiselapp.com/user/kyle/repository/fossilgg", + &RepoRoot{ + VCS: vcsFossil, + Repo: "https://chiselapp.com/user/kyle/repository/fossilgg", + }, + }, + { + // must have a user/$name/repository/$repo path + "chiselapp.com/kyle/repository/fossilgg", + nil, + }, + { + "chiselapp.com/user/kyle/fossilgg", + nil, + }, + } + + for _, test := range tests { + got, err := RepoRootForImportPath(test.path, IgnoreMod, web.SecureOnly) + want := test.want + + if want == nil { + if err == nil { + t.Errorf("RepoRootForImportPath(%q): Error expected but not received", test.path) + } + continue + } + if err != nil { + 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) + } + } +} + +// Test that vcsFromDir correctly inspects a given directory and returns the right VCS and root. +func TestFromDir(t *testing.T) { + tempDir, err := os.MkdirTemp("", "vcstest") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tempDir) + + for j, vcs := range vcsList { + dir := filepath.Join(tempDir, "example.com", vcs.Name, "."+vcs.Cmd) + if j&1 == 0 { + err := os.MkdirAll(dir, 0755) + if err != nil { + t.Fatal(err) + } + } else { + err := os.MkdirAll(filepath.Dir(dir), 0755) + if err != nil { + t.Fatal(err) + } + f, err := os.Create(dir) + if err != nil { + t.Fatal(err) + } + f.Close() + } + + want := RepoRoot{ + VCS: vcs, + Root: path.Join("example.com", vcs.Name), + } + var got RepoRoot + got.VCS, got.Root, err = FromDir(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) + } + } +} + +func TestIsSecure(t *testing.T) { + tests := []struct { + vcs *Cmd + url string + secure bool + }{ + {vcsGit, "http://example.com/foo.git", false}, + {vcsGit, "https://example.com/foo.git", true}, + {vcsBzr, "http://example.com/foo.bzr", false}, + {vcsBzr, "https://example.com/foo.bzr", true}, + {vcsSvn, "http://example.com/svn", false}, + {vcsSvn, "https://example.com/svn", true}, + {vcsHg, "http://example.com/foo.hg", false}, + {vcsHg, "https://example.com/foo.hg", true}, + {vcsGit, "ssh://user@example.com/foo.git", true}, + {vcsGit, "user@server:path/to/repo.git", false}, + {vcsGit, "user@server:", false}, + {vcsGit, "server:repo.git", false}, + {vcsGit, "server:path/to/repo.git", false}, + {vcsGit, "example.com:path/to/repo.git", false}, + {vcsGit, "path/that/contains/a:colon/repo.git", false}, + {vcsHg, "ssh://user@example.com/path/to/repo.hg", true}, + {vcsFossil, "http://example.com/foo", false}, + {vcsFossil, "https://example.com/foo", true}, + } + + for _, test := range tests { + secure := test.vcs.IsSecure(test.url) + if secure != test.secure { + t.Errorf("%s isSecure(%q) = %t; want %t", test.vcs, test.url, secure, test.secure) + } + } +} + +func TestIsSecureGitAllowProtocol(t *testing.T) { + tests := []struct { + vcs *Cmd + url string + secure bool + }{ + // Same as TestIsSecure to verify same behavior. + {vcsGit, "http://example.com/foo.git", false}, + {vcsGit, "https://example.com/foo.git", true}, + {vcsBzr, "http://example.com/foo.bzr", false}, + {vcsBzr, "https://example.com/foo.bzr", true}, + {vcsSvn, "http://example.com/svn", false}, + {vcsSvn, "https://example.com/svn", true}, + {vcsHg, "http://example.com/foo.hg", false}, + {vcsHg, "https://example.com/foo.hg", true}, + {vcsGit, "user@server:path/to/repo.git", false}, + {vcsGit, "user@server:", false}, + {vcsGit, "server:repo.git", false}, + {vcsGit, "server:path/to/repo.git", false}, + {vcsGit, "example.com:path/to/repo.git", false}, + {vcsGit, "path/that/contains/a:colon/repo.git", false}, + {vcsHg, "ssh://user@example.com/path/to/repo.hg", true}, + // New behavior. + {vcsGit, "ssh://user@example.com/foo.git", false}, + {vcsGit, "foo://example.com/bar.git", true}, + {vcsHg, "foo://example.com/bar.hg", false}, + {vcsSvn, "foo://example.com/svn", false}, + {vcsBzr, "foo://example.com/bar.bzr", false}, + } + + defer os.Unsetenv("GIT_ALLOW_PROTOCOL") + os.Setenv("GIT_ALLOW_PROTOCOL", "https:foo") + for _, test := range tests { + secure := test.vcs.IsSecure(test.url) + if secure != test.secure { + t.Errorf("%s isSecure(%q) = %t; want %t", test.vcs, test.url, secure, test.secure) + } + } +} + +func TestMatchGoImport(t *testing.T) { + tests := []struct { + imports []metaImport + path string + mi metaImport + err error + }{ + { + imports: []metaImport{ + {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + path: "example.com/user/foo", + mi: metaImport{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + { + imports: []metaImport{ + {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + path: "example.com/user/foo/", + mi: metaImport{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + { + imports: []metaImport{ + {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + {Prefix: "example.com/user/fooa", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + path: "example.com/user/foo", + mi: metaImport{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + { + imports: []metaImport{ + {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + {Prefix: "example.com/user/fooa", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + path: "example.com/user/fooa", + mi: metaImport{Prefix: "example.com/user/fooa", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + { + imports: []metaImport{ + {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + {Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + path: "example.com/user/foo/bar", + err: errors.New("should not be allowed to create nested repo"), + }, + { + imports: []metaImport{ + {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + {Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + path: "example.com/user/foo/bar/baz", + err: errors.New("should not be allowed to create nested repo"), + }, + { + imports: []metaImport{ + {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + {Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + path: "example.com/user/foo/bar/baz/qux", + err: errors.New("should not be allowed to create nested repo"), + }, + { + imports: []metaImport{ + {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + {Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + path: "example.com/user/foo/bar/baz/", + err: errors.New("should not be allowed to create nested repo"), + }, + { + imports: []metaImport{ + {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + {Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + path: "example.com", + err: errors.New("pathologically short path"), + }, + { + imports: []metaImport{ + {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"}, + }, + 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 { + mi, err := matchGoImport(test.imports, test.path) + if mi != test.mi { + t.Errorf("unexpected metaImport; got %v, want %v", mi, test.mi) + } + + got := err + want := test.err + if (got == nil) != (want == nil) { + t.Errorf("unexpected error; got %v, want %v", got, want) + } + } +} + +func TestValidateRepoRoot(t *testing.T) { + tests := []struct { + root string + ok bool + }{ + { + root: "", + ok: false, + }, + { + root: "http://", + ok: true, + }, + { + root: "git+ssh://", + ok: true, + }, + { + root: "http#://", + ok: false, + }, + { + root: "-config", + ok: false, + }, + { + root: "-config://", + ok: false, + }, + } + + for _, test := range tests { + err := validateRepoRoot(test.root) + ok := err == nil + if ok != test.ok { + want := "error" + if test.ok { + want = "nil" + } + t.Errorf("validateRepoRoot(%q) = %q, want %s", test.root, err, want) + } + } +} + +var govcsTests = []struct { + govcs string + path string + vcs string + ok bool +}{ + {"private:all", "is-public.com/foo", "zzz", false}, + {"private:all", "is-private.com/foo", "zzz", true}, + {"public:all", "is-public.com/foo", "zzz", true}, + {"public:all", "is-private.com/foo", "zzz", false}, + {"public:all,private:none", "is-public.com/foo", "zzz", true}, + {"public:all,private:none", "is-private.com/foo", "zzz", false}, + {"*:all", "is-public.com/foo", "zzz", true}, + {"golang.org:git", "golang.org/x/text", "zzz", false}, + {"golang.org:git", "golang.org/x/text", "git", true}, + {"golang.org:zzz", "golang.org/x/text", "zzz", true}, + {"golang.org:zzz", "golang.org/x/text", "git", false}, + {"golang.org:zzz", "golang.org/x/text", "zzz", true}, + {"golang.org:zzz", "golang.org/x/text", "git", false}, + {"golang.org:git|hg", "golang.org/x/text", "hg", true}, + {"golang.org:git|hg", "golang.org/x/text", "git", true}, + {"golang.org:git|hg", "golang.org/x/text", "zzz", false}, + {"golang.org:all", "golang.org/x/text", "hg", true}, + {"golang.org:all", "golang.org/x/text", "git", true}, + {"golang.org:all", "golang.org/x/text", "zzz", true}, + {"other.xyz/p:none,golang.org/x:git", "other.xyz/p/x", "git", false}, + {"other.xyz/p:none,golang.org/x:git", "unexpected.com", "git", false}, + {"other.xyz/p:none,golang.org/x:git", "golang.org/x/text", "zzz", false}, + {"other.xyz/p:none,golang.org/x:git", "golang.org/x/text", "git", true}, + {"other.xyz/p:none,golang.org/x:zzz", "golang.org/x/text", "zzz", true}, + {"other.xyz/p:none,golang.org/x:zzz", "golang.org/x/text", "git", false}, + {"other.xyz/p:none,golang.org/x:git|hg", "golang.org/x/text", "hg", true}, + {"other.xyz/p:none,golang.org/x:git|hg", "golang.org/x/text", "git", true}, + {"other.xyz/p:none,golang.org/x:git|hg", "golang.org/x/text", "zzz", false}, + {"other.xyz/p:none,golang.org/x:all", "golang.org/x/text", "hg", true}, + {"other.xyz/p:none,golang.org/x:all", "golang.org/x/text", "git", true}, + {"other.xyz/p:none,golang.org/x:all", "golang.org/x/text", "zzz", true}, + {"other.xyz/p:none,golang.org/x:git", "golang.org/y/text", "zzz", false}, + {"other.xyz/p:none,golang.org/x:git", "golang.org/y/text", "git", false}, + {"other.xyz/p:none,golang.org/x:zzz", "golang.org/y/text", "zzz", false}, + {"other.xyz/p:none,golang.org/x:zzz", "golang.org/y/text", "git", false}, + {"other.xyz/p:none,golang.org/x:git|hg", "golang.org/y/text", "hg", false}, + {"other.xyz/p:none,golang.org/x:git|hg", "golang.org/y/text", "git", false}, + {"other.xyz/p:none,golang.org/x:git|hg", "golang.org/y/text", "zzz", false}, + {"other.xyz/p:none,golang.org/x:all", "golang.org/y/text", "hg", false}, + {"other.xyz/p:none,golang.org/x:all", "golang.org/y/text", "git", false}, + {"other.xyz/p:none,golang.org/x:all", "golang.org/y/text", "zzz", false}, +} + +func TestGOVCS(t *testing.T) { + for _, tt := range govcsTests { + cfg, err := parseGOVCS(tt.govcs) + if err != nil { + t.Errorf("parseGOVCS(%q): %v", tt.govcs, err) + continue + } + private := strings.HasPrefix(tt.path, "is-private") + ok := cfg.allow(tt.path, private, tt.vcs) + if ok != tt.ok { + t.Errorf("parseGOVCS(%q).allow(%q, %v, %q) = %v, want %v", + tt.govcs, tt.path, private, tt.vcs, ok, tt.ok) + } + } +} + +var govcsErrors = []struct { + s string + err string +}{ + {`,`, `empty entry in GOVCS`}, + {`,x`, `empty entry in GOVCS`}, + {`x,`, `malformed entry in GOVCS (missing colon): "x"`}, + {`x:y,`, `empty entry in GOVCS`}, + {`x`, `malformed entry in GOVCS (missing colon): "x"`}, + {`x:`, `empty VCS list in GOVCS: "x:"`}, + {`x:|`, `empty VCS name in GOVCS: "x:|"`}, + {`x:y|`, `empty VCS name in GOVCS: "x:y|"`}, + {`x:|y`, `empty VCS name in GOVCS: "x:|y"`}, + {`x:y,z:`, `empty VCS list in GOVCS: "z:"`}, + {`x:y,z:|`, `empty VCS name in GOVCS: "z:|"`}, + {`x:y,z:|w`, `empty VCS name in GOVCS: "z:|w"`}, + {`x:y,z:w|`, `empty VCS name in GOVCS: "z:w|"`}, + {`x:y,z:w||v`, `empty VCS name in GOVCS: "z:w||v"`}, + {`x:y,x:z`, `unreachable pattern in GOVCS: "x:z" after "x:y"`}, +} + +func TestGOVCSErrors(t *testing.T) { + for _, tt := range govcsErrors { + _, err := parseGOVCS(tt.s) + if err == nil || !strings.Contains(err.Error(), tt.err) { + t.Errorf("parseGOVCS(%s): err=%v, want %v", tt.s, err, tt.err) + } + } +} diff --git a/src/cmd/go/internal/version/exe.go b/src/cmd/go/internal/version/exe.go new file mode 100644 index 0000000..0e7deef --- /dev/null +++ b/src/cmd/go/internal/version/exe.go @@ -0,0 +1,263 @@ +// Copyright 2019 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 version + +import ( + "bytes" + "debug/elf" + "debug/macho" + "debug/pe" + "fmt" + "internal/xcoff" + "io" + "os" +) + +// An exe is a generic interface to an OS executable (ELF, Mach-O, PE, XCOFF). +type exe interface { + // Close closes the underlying file. + Close() error + + // ReadData reads and returns up to size byte starting at virtual address addr. + ReadData(addr, size uint64) ([]byte, error) + + // DataStart returns the writable data segment start address. + DataStart() uint64 +} + +// openExe opens file and returns it as an exe. +func openExe(file string) (exe, error) { + f, err := os.Open(file) + if err != nil { + return nil, err + } + data := make([]byte, 16) + if _, err := io.ReadFull(f, data); err != nil { + return nil, err + } + f.Seek(0, 0) + if bytes.HasPrefix(data, []byte("\x7FELF")) { + e, err := elf.NewFile(f) + if err != nil { + f.Close() + return nil, err + } + return &elfExe{f, e}, nil + } + if bytes.HasPrefix(data, []byte("MZ")) { + e, err := pe.NewFile(f) + if err != nil { + f.Close() + return nil, err + } + return &peExe{f, e}, nil + } + if bytes.HasPrefix(data, []byte("\xFE\xED\xFA")) || bytes.HasPrefix(data[1:], []byte("\xFA\xED\xFE")) { + e, err := macho.NewFile(f) + if err != nil { + f.Close() + return nil, err + } + return &machoExe{f, e}, nil + } + if bytes.HasPrefix(data, []byte{0x01, 0xDF}) || bytes.HasPrefix(data, []byte{0x01, 0xF7}) { + e, err := xcoff.NewFile(f) + if err != nil { + f.Close() + return nil, err + } + return &xcoffExe{f, e}, nil + + } + return nil, fmt.Errorf("unrecognized executable format") +} + +// elfExe is the ELF implementation of the exe interface. +type elfExe struct { + os *os.File + f *elf.File +} + +func (x *elfExe) Close() error { + return x.os.Close() +} + +func (x *elfExe) ReadData(addr, size uint64) ([]byte, error) { + for _, prog := range x.f.Progs { + if prog.Vaddr <= addr && addr <= prog.Vaddr+prog.Filesz-1 { + n := prog.Vaddr + prog.Filesz - addr + if n > size { + n = size + } + data := make([]byte, n) + _, err := prog.ReadAt(data, int64(addr-prog.Vaddr)) + if err != nil { + return nil, err + } + return data, nil + } + } + return nil, fmt.Errorf("address not mapped") +} + +func (x *elfExe) DataStart() uint64 { + for _, s := range x.f.Sections { + if s.Name == ".go.buildinfo" { + return s.Addr + } + } + for _, p := range x.f.Progs { + if p.Type == elf.PT_LOAD && p.Flags&(elf.PF_X|elf.PF_W) == elf.PF_W { + return p.Vaddr + } + } + return 0 +} + +// peExe is the PE (Windows Portable Executable) implementation of the exe interface. +type peExe struct { + os *os.File + f *pe.File +} + +func (x *peExe) Close() error { + return x.os.Close() +} + +func (x *peExe) imageBase() uint64 { + switch oh := x.f.OptionalHeader.(type) { + case *pe.OptionalHeader32: + return uint64(oh.ImageBase) + case *pe.OptionalHeader64: + return oh.ImageBase + } + return 0 +} + +func (x *peExe) ReadData(addr, size uint64) ([]byte, error) { + addr -= x.imageBase() + for _, sect := range x.f.Sections { + if uint64(sect.VirtualAddress) <= addr && addr <= uint64(sect.VirtualAddress+sect.Size-1) { + n := uint64(sect.VirtualAddress+sect.Size) - addr + if n > size { + n = size + } + data := make([]byte, n) + _, err := sect.ReadAt(data, int64(addr-uint64(sect.VirtualAddress))) + if err != nil { + return nil, err + } + return data, nil + } + } + return nil, fmt.Errorf("address not mapped") +} + +func (x *peExe) DataStart() uint64 { + // Assume data is first writable section. + const ( + IMAGE_SCN_CNT_CODE = 0x00000020 + IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040 + IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080 + IMAGE_SCN_MEM_EXECUTE = 0x20000000 + IMAGE_SCN_MEM_READ = 0x40000000 + IMAGE_SCN_MEM_WRITE = 0x80000000 + IMAGE_SCN_MEM_DISCARDABLE = 0x2000000 + IMAGE_SCN_LNK_NRELOC_OVFL = 0x1000000 + IMAGE_SCN_ALIGN_32BYTES = 0x600000 + ) + for _, sect := range x.f.Sections { + if sect.VirtualAddress != 0 && sect.Size != 0 && + sect.Characteristics&^IMAGE_SCN_ALIGN_32BYTES == IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE { + return uint64(sect.VirtualAddress) + x.imageBase() + } + } + return 0 +} + +// machoExe is the Mach-O (Apple macOS/iOS) implementation of the exe interface. +type machoExe struct { + os *os.File + f *macho.File +} + +func (x *machoExe) Close() error { + return x.os.Close() +} + +func (x *machoExe) ReadData(addr, size uint64) ([]byte, error) { + for _, load := range x.f.Loads { + seg, ok := load.(*macho.Segment) + if !ok { + continue + } + if seg.Addr <= addr && addr <= seg.Addr+seg.Filesz-1 { + if seg.Name == "__PAGEZERO" { + continue + } + n := seg.Addr + seg.Filesz - addr + if n > size { + n = size + } + data := make([]byte, n) + _, err := seg.ReadAt(data, int64(addr-seg.Addr)) + if err != nil { + return nil, err + } + return data, nil + } + } + return nil, fmt.Errorf("address not mapped") +} + +func (x *machoExe) DataStart() uint64 { + // Look for section named "__go_buildinfo". + for _, sec := range x.f.Sections { + if sec.Name == "__go_buildinfo" { + return sec.Addr + } + } + // Try the first non-empty writable segment. + const RW = 3 + for _, load := range x.f.Loads { + seg, ok := load.(*macho.Segment) + if ok && seg.Addr != 0 && seg.Filesz != 0 && seg.Prot == RW && seg.Maxprot == RW { + return seg.Addr + } + } + return 0 +} + +// xcoffExe is the XCOFF (AIX eXtended COFF) implementation of the exe interface. +type xcoffExe struct { + os *os.File + f *xcoff.File +} + +func (x *xcoffExe) Close() error { + return x.os.Close() +} + +func (x *xcoffExe) ReadData(addr, size uint64) ([]byte, error) { + for _, sect := range x.f.Sections { + if uint64(sect.VirtualAddress) <= addr && addr <= uint64(sect.VirtualAddress+sect.Size-1) { + n := uint64(sect.VirtualAddress+sect.Size) - addr + if n > size { + n = size + } + data := make([]byte, n) + _, err := sect.ReadAt(data, int64(addr-uint64(sect.VirtualAddress))) + if err != nil { + return nil, err + } + return data, nil + } + } + return nil, fmt.Errorf("address not mapped") +} + +func (x *xcoffExe) DataStart() uint64 { + return x.f.SectionByType(xcoff.STYP_DATA).VirtualAddress +} diff --git a/src/cmd/go/internal/version/version.go b/src/cmd/go/internal/version/version.go new file mode 100644 index 0000000..58cbd32 --- /dev/null +++ b/src/cmd/go/internal/version/version.go @@ -0,0 +1,224 @@ +// Copyright 2011 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 version implements the ``go version'' command. +package version + +import ( + "bytes" + "context" + "encoding/binary" + "fmt" + "io/fs" + "os" + "path/filepath" + "runtime" + "strings" + + "cmd/go/internal/base" +) + +var CmdVersion = &base.Command{ + UsageLine: "go version [-m] [-v] [file ...]", + Short: "print Go version", + Long: `Version prints the build information for Go executables. + +Go version reports the Go version used to build each of the named +executable files. + +If no files are named on the command line, go version prints its own +version information. + +If a directory is named, go version walks that directory, recursively, +looking for recognized Go binaries and reporting their versions. +By default, go version does not report unrecognized files found +during a directory scan. The -v flag causes it to report unrecognized files. + +The -m flag causes go version to print each executable's embedded +module version information, when available. In the output, the module +information consists of multiple lines following the version line, each +indented by a leading tab character. + +See also: go doc runtime/debug.BuildInfo. +`, +} + +func init() { + CmdVersion.Run = runVersion // break init cycle +} + +var ( + versionM = CmdVersion.Flag.Bool("m", false, "") + versionV = CmdVersion.Flag.Bool("v", false, "") +) + +func runVersion(ctx context.Context, cmd *base.Command, args []string) { + if len(args) == 0 { + // If any of this command's flags were passed explicitly, error + // out, because they only make sense with arguments. + // + // Don't error if the flags came from GOFLAGS, since that can be + // a reasonable use case. For example, imagine GOFLAGS=-v to + // turn "verbose mode" on for all Go commands, which should not + // break "go version". + if (!base.InGOFLAGS("-m") && *versionM) || (!base.InGOFLAGS("-v") && *versionV) { + fmt.Fprintf(os.Stderr, "go version: flags can only be used with arguments\n") + base.SetExitStatus(2) + return + } + fmt.Printf("go version %s %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH) + return + } + + for _, arg := range args { + info, err := os.Stat(arg) + if err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) + base.SetExitStatus(1) + continue + } + if info.IsDir() { + scanDir(arg) + } else { + scanFile(arg, info, true) + } + } +} + +// scanDir scans a directory for executables to run scanFile on. +func scanDir(dir string) { + filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error { + if d.Type().IsRegular() || d.Type()&fs.ModeSymlink != 0 { + info, err := d.Info() + if err != nil { + if *versionV { + fmt.Fprintf(os.Stderr, "%s: %v\n", path, err) + } + return nil + } + scanFile(path, info, *versionV) + } + return nil + }) +} + +// isExe reports whether the file should be considered executable. +func isExe(file string, info fs.FileInfo) bool { + if runtime.GOOS == "windows" { + return strings.HasSuffix(strings.ToLower(file), ".exe") + } + return info.Mode().IsRegular() && info.Mode()&0111 != 0 +} + +// scanFile scans file to try to report the Go and module versions. +// If mustPrint is true, scanFile will report any error reading file. +// Otherwise (mustPrint is false, because scanFile is being called +// by scanDir) scanFile prints nothing for non-Go executables. +func scanFile(file string, info fs.FileInfo, mustPrint bool) { + if info.Mode()&fs.ModeSymlink != 0 { + // Accept file symlinks only. + i, err := os.Stat(file) + if err != nil || !i.Mode().IsRegular() { + if mustPrint { + fmt.Fprintf(os.Stderr, "%s: symlink\n", file) + } + return + } + info = i + } + + if !isExe(file, info) { + if mustPrint { + fmt.Fprintf(os.Stderr, "%s: not executable file\n", file) + } + return + } + + x, err := openExe(file) + if err != nil { + if mustPrint { + fmt.Fprintf(os.Stderr, "%s: %v\n", file, err) + } + return + } + defer x.Close() + + vers, mod := findVers(x) + if vers == "" { + if mustPrint { + fmt.Fprintf(os.Stderr, "%s: go version not found\n", file) + } + return + } + + fmt.Printf("%s: %s\n", file, vers) + if *versionM && mod != "" { + fmt.Printf("\t%s\n", strings.ReplaceAll(mod[:len(mod)-1], "\n", "\n\t")) + } +} + +// The build info blob left by the linker is identified by +// a 16-byte header, consisting of buildInfoMagic (14 bytes), +// the binary's pointer size (1 byte), +// and whether the binary is big endian (1 byte). +var buildInfoMagic = []byte("\xff Go buildinf:") + +// findVers finds and returns the Go version and module version information +// in the executable x. +func findVers(x exe) (vers, mod string) { + // Read the first 64kB of text to find the build info blob. + text := x.DataStart() + data, err := x.ReadData(text, 64*1024) + if err != nil { + return + } + for ; !bytes.HasPrefix(data, buildInfoMagic); data = data[32:] { + if len(data) < 32 { + return + } + } + + // Decode the blob. + ptrSize := int(data[14]) + bigEndian := data[15] != 0 + var bo binary.ByteOrder + if bigEndian { + bo = binary.BigEndian + } else { + bo = binary.LittleEndian + } + var readPtr func([]byte) uint64 + if ptrSize == 4 { + readPtr = func(b []byte) uint64 { return uint64(bo.Uint32(b)) } + } else { + readPtr = bo.Uint64 + } + vers = readString(x, ptrSize, readPtr, readPtr(data[16:])) + if vers == "" { + return + } + mod = readString(x, ptrSize, readPtr, readPtr(data[16+ptrSize:])) + if len(mod) >= 33 && mod[len(mod)-17] == '\n' { + // Strip module framing. + mod = mod[16 : len(mod)-16] + } else { + mod = "" + } + return +} + +// readString returns the string at address addr in the executable x. +func readString(x exe, ptrSize int, readPtr func([]byte) uint64, addr uint64) string { + hdr, err := x.ReadData(addr, uint64(2*ptrSize)) + if err != nil || len(hdr) < 2*ptrSize { + return "" + } + dataAddr := readPtr(hdr) + dataLen := readPtr(hdr[ptrSize:]) + data, err := x.ReadData(dataAddr, dataLen) + if err != nil || uint64(len(data)) < dataLen { + return "" + } + return string(data) +} diff --git a/src/cmd/go/internal/vet/vet.go b/src/cmd/go/internal/vet/vet.go new file mode 100644 index 0000000..4257c90 --- /dev/null +++ b/src/cmd/go/internal/vet/vet.go @@ -0,0 +1,118 @@ +// Copyright 2011 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 vet implements the ``go vet'' command. +package vet + +import ( + "context" + "fmt" + "path/filepath" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/load" + "cmd/go/internal/trace" + "cmd/go/internal/work" +) + +// Break init loop. +func init() { + CmdVet.Run = runVet +} + +var CmdVet = &base.Command{ + CustomFlags: true, + UsageLine: "go vet [-n] [-x] [-vettool prog] [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. + +For more about vet and its flags, see 'go doc cmd/vet'. +For more about specifying packages, see 'go help packages'. +For a list of checkers and their flags, see 'go tool vet help'. +For details of a specific checker such as 'printf', see 'go tool vet help printf'. + +The -n flag prints commands that would be executed. +The -x flag prints commands as they are executed. + +The -vettool=prog flag selects a different analysis tool with alternative +or additional checks. +For example, the 'shadow' analyzer can be built and run using these commands: + + go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow + go vet -vettool=$(which shadow) + +The build flags supported by go vet are those that control package resolution +and execution, such as -n, -x, -v, -tags, and -toolexec. +For more about these flags, see 'go help build'. + +See also: go fmt, go fix. + `, +} + +func runVet(ctx context.Context, cmd *base.Command, args []string) { + load.ModResolveTests = true + + vetFlags, pkgArgs := vetFlags(args) + + if cfg.DebugTrace != "" { + var close func() error + var err error + ctx, close, err = trace.Start(ctx, cfg.DebugTrace) + if err != nil { + base.Fatalf("failed to start trace: %v", err) + } + defer func() { + if err := close(); err != nil { + base.Fatalf("failed to stop trace: %v", err) + } + }() + } + + ctx, span := trace.StartSpan(ctx, fmt.Sprint("Running ", cmd.Name(), " command")) + defer span.Done() + + work.BuildInit() + work.VetFlags = vetFlags + if len(vetFlags) > 0 { + work.VetExplicit = true + } + if vetTool != "" { + var err error + work.VetTool, err = filepath.Abs(vetTool) + if err != nil { + base.Fatalf("%v", err) + } + } + + pkgs := load.PackagesAndErrors(ctx, pkgArgs) + load.CheckPackageErrors(pkgs) + if len(pkgs) == 0 { + base.Fatalf("no packages to vet") + } + + var b work.Builder + b.Init() + + root := &work.Action{Mode: "go vet"} + for _, p := range pkgs { + _, ptest, pxtest, err := load.TestPackagesFor(ctx, p, nil) + if err != nil { + base.Errorf("%v", err) + continue + } + if len(ptest.GoFiles) == 0 && len(ptest.CgoFiles) == 0 && pxtest == nil { + base.Errorf("go vet %s: no Go files in %s", p.ImportPath, p.Dir) + continue + } + if len(ptest.GoFiles) > 0 || len(ptest.CgoFiles) > 0 { + root.Deps = append(root.Deps, b.VetAction(work.ModeBuild, work.ModeBuild, ptest)) + } + if pxtest != nil { + root.Deps = append(root.Deps, b.VetAction(work.ModeBuild, work.ModeBuild, pxtest)) + } + } + b.Do(ctx, root) +} diff --git a/src/cmd/go/internal/vet/vetflag.go b/src/cmd/go/internal/vet/vetflag.go new file mode 100644 index 0000000..b5b3c46 --- /dev/null +++ b/src/cmd/go/internal/vet/vetflag.go @@ -0,0 +1,192 @@ +// 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 vet + +import ( + "bytes" + "encoding/json" + "errors" + "flag" + "fmt" + exec "internal/execabs" + "log" + "os" + "path/filepath" + "strings" + + "cmd/go/internal/base" + "cmd/go/internal/cmdflag" + "cmd/go/internal/work" +) + +// go vet flag processing +// +// We query the flags of the tool specified by -vettool and accept any +// of those flags plus any flag valid for 'go build'. The tool must +// support -flags, which prints a description of its flags in JSON to +// stdout. + +// vetTool specifies the vet command to run. +// Any tool that supports the (still unpublished) vet +// command-line protocol may be supplied; see +// golang.org/x/tools/go/analysis/unitchecker for one +// implementation. It is also used by tests. +// +// The default behavior (vetTool=="") runs 'go tool vet'. +// +var vetTool string // -vettool + +func init() { + work.AddBuildFlags(CmdVet, work.DefaultBuildFlags) + CmdVet.Flag.StringVar(&vetTool, "vettool", "", "") +} + +func parseVettoolFlag(args []string) { + // Extract -vettool by ad hoc flag processing: + // its value is needed even before we can declare + // the flags available during main flag processing. + for i, arg := range args { + if arg == "-vettool" || arg == "--vettool" { + if i+1 >= len(args) { + log.Fatalf("%s requires a filename", arg) + } + vetTool = args[i+1] + return + } else if strings.HasPrefix(arg, "-vettool=") || + strings.HasPrefix(arg, "--vettool=") { + vetTool = arg[strings.IndexByte(arg, '=')+1:] + return + } + } +} + +// 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) { + parseVettoolFlag(args) + + // Query the vet command for its flags. + var tool string + if vetTool == "" { + tool = base.Tool("vet") + } else { + var err error + tool, err = filepath.Abs(vetTool) + if err != nil { + log.Fatal(err) + } + } + out := new(bytes.Buffer) + vetcmd := exec.Command(tool, "-flags") + vetcmd.Stdout = out + if err := vetcmd.Run(); err != nil { + fmt.Fprintf(os.Stderr, "go vet: can't execute %s -flags: %v\n", tool, err) + base.SetExitStatus(2) + base.Exit() + } + var analysisFlags []struct { + Name string + Bool bool + Usage string + } + if err := json.Unmarshal(out.Bytes(), &analysisFlags); err != nil { + fmt.Fprintf(os.Stderr, "go vet: can't unmarshal JSON from %s -flags: %v", tool, err) + base.SetExitStatus(2) + base.Exit() + } + + // Add vet's flags to CmdVet.Flag. + // + // Some flags, in particular -tags and -v, are known to vet but + // also defined as build flags. This works fine, so we omit duplicates here. + // However some, like -x, are known to the build but not to vet. + isVetFlag := make(map[string]bool, len(analysisFlags)) + cf := CmdVet.Flag + for _, f := range analysisFlags { + isVetFlag[f.Name] = true + if cf.Lookup(f.Name) == nil { + if f.Bool { + cf.Bool(f.Name, false, "") + } else { + cf.String(f.Name, "", "") + } + } + } + + // Record the set of vet tool flags set by GOFLAGS. We want to pass them to + // the vet tool, but only if they aren't overridden by an explicit argument. + base.SetFromGOFLAGS(&CmdVet.Flag) + addFromGOFLAGS := map[string]bool{} + CmdVet.Flag.Visit(func(f *flag.Flag) { + if isVetFlag[f.Name] { + addFromGOFLAGS[f.Name] = true + } + }) + + explicitFlags := make([]string, 0, len(args)) + for len(args) > 0 { + f, remainingArgs, err := cmdflag.ParseOne(&CmdVet.Flag, args) + + if errors.Is(err, flag.ErrHelp) { + exitWithUsage() + } + + if errors.Is(err, cmdflag.ErrFlagTerminator) { + // All remaining args must be package names, but the flag terminator is + // not included. + packageNames = remainingArgs + break + } + + if nf := (cmdflag.NonFlagError{}); errors.As(err, &nf) { + // Everything from here on out — including the argument we just consumed — + // must be a package name. + packageNames = args + break + } + + if err != nil { + fmt.Fprintln(os.Stderr, err) + exitWithUsage() + } + + if isVetFlag[f.Name] { + // Forward the raw arguments rather than cleaned equivalents, just in + // case the vet tool parses them idiosyncratically. + explicitFlags = append(explicitFlags, args[:len(args)-len(remainingArgs)]...) + + // This flag has been overridden explicitly, so don't forward its implicit + // value from GOFLAGS. + delete(addFromGOFLAGS, f.Name) + } + + args = remainingArgs + } + + // Prepend arguments from GOFLAGS before other arguments. + CmdVet.Flag.Visit(func(f *flag.Flag) { + if addFromGOFLAGS[f.Name] { + passToVet = append(passToVet, fmt.Sprintf("-%s=%s", f.Name, f.Value)) + } + }) + passToVet = append(passToVet, explicitFlags...) + return passToVet, packageNames +} + +func exitWithUsage() { + fmt.Fprintf(os.Stderr, "usage: %s\n", CmdVet.UsageLine) + fmt.Fprintf(os.Stderr, "Run 'go help %s' for details.\n", CmdVet.LongName()) + + // This part is additional to what (*Command).Usage does: + cmd := "go tool vet" + if vetTool != "" { + cmd = vetTool + } + fmt.Fprintf(os.Stderr, "Run '%s help' for a full list of flags and analyzers.\n", cmd) + fmt.Fprintf(os.Stderr, "Run '%s -help' for an overview.\n", cmd) + + base.SetExitStatus(2) + base.Exit() +} diff --git a/src/cmd/go/internal/web/api.go b/src/cmd/go/internal/web/api.go new file mode 100644 index 0000000..9053b16 --- /dev/null +++ b/src/cmd/go/internal/web/api.go @@ -0,0 +1,236 @@ +// 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 web defines minimal helper routines for accessing HTTP/HTTPS +// resources without requiring external dependencies on the net package. +// +// If the cmd_go_bootstrap build tag is present, web avoids the use of the net +// package and returns errors for all network operations. +package web + +import ( + "bytes" + "fmt" + "io" + "io/fs" + "net/url" + "strings" + "unicode" + "unicode/utf8" +) + +// SecurityMode specifies whether a function should make network +// calls using insecure transports (eg, plain text HTTP). +// The zero value is "secure". +type SecurityMode int + +const ( + SecureOnly SecurityMode = iota // Reject plain HTTP; validate HTTPS. + DefaultSecurity // Allow plain HTTP if explicit; validate HTTPS. + Insecure // Allow plain HTTP if not explicitly HTTPS; skip HTTPS validation. +) + +// An HTTPError describes an HTTP error response (non-200 result). +type HTTPError struct { + URL string // redacted + Status string + StatusCode int + Err error // underlying error, if known + Detail string // limited to maxErrorDetailLines and maxErrorDetailBytes +} + +const ( + maxErrorDetailLines = 8 + maxErrorDetailBytes = maxErrorDetailLines * 81 +) + +func (e *HTTPError) Error() string { + if e.Detail != "" { + detailSep := " " + if strings.ContainsRune(e.Detail, '\n') { + detailSep = "\n\t" + } + return fmt.Sprintf("reading %s: %v\n\tserver response:%s%s", e.URL, e.Status, detailSep, e.Detail) + } + + if err := e.Err; err != nil { + if pErr, ok := e.Err.(*fs.PathError); ok && strings.HasSuffix(e.URL, pErr.Path) { + // Remove the redundant copy of the path. + err = pErr.Err + } + return fmt.Sprintf("reading %s: %v", e.URL, err) + } + + return fmt.Sprintf("reading %s: %v", e.URL, e.Status) +} + +func (e *HTTPError) Is(target error) bool { + return target == fs.ErrNotExist && (e.StatusCode == 404 || e.StatusCode == 410) +} + +func (e *HTTPError) Unwrap() error { + return e.Err +} + +// GetBytes returns the body of the requested resource, or an error if the +// response status was not http.StatusOK. +// +// GetBytes is a convenience wrapper around Get and Response.Err. +func GetBytes(u *url.URL) ([]byte, error) { + resp, err := Get(DefaultSecurity, u) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if err := resp.Err(); err != nil { + return nil, err + } + b, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("reading %s: %v", u.Redacted(), err) + } + return b, nil +} + +type Response struct { + URL string // redacted + Status string + StatusCode int + Header map[string][]string + Body io.ReadCloser // Either the original body or &errorDetail. + + fileErr error + errorDetail errorDetailBuffer +} + +// Err returns an *HTTPError corresponding to the response r. +// If the response r has StatusCode 200 or 0 (unset), Err returns nil. +// Otherwise, Err may read from r.Body in order to extract relevant error detail. +func (r *Response) Err() error { + if r.StatusCode == 200 || r.StatusCode == 0 { + return nil + } + + return &HTTPError{ + URL: r.URL, + Status: r.Status, + StatusCode: r.StatusCode, + Err: r.fileErr, + Detail: r.formatErrorDetail(), + } +} + +// formatErrorDetail converts r.errorDetail (a prefix of the output of r.Body) +// into a short, tab-indented summary. +func (r *Response) formatErrorDetail() string { + if r.Body != &r.errorDetail { + return "" // Error detail collection not enabled. + } + + // Ensure that r.errorDetail has been populated. + _, _ = io.Copy(io.Discard, r.Body) + + s := r.errorDetail.buf.String() + if !utf8.ValidString(s) { + return "" // Don't try to recover non-UTF-8 error messages. + } + for _, r := range s { + if !unicode.IsGraphic(r) && !unicode.IsSpace(r) { + return "" // Don't let the server do any funny business with the user's terminal. + } + } + + var detail strings.Builder + for i, line := range strings.Split(s, "\n") { + if strings.TrimSpace(line) == "" { + break // Stop at the first blank line. + } + if i > 0 { + detail.WriteString("\n\t") + } + if i >= maxErrorDetailLines { + detail.WriteString("[Truncated: too many lines.]") + break + } + if detail.Len()+len(line) > maxErrorDetailBytes { + detail.WriteString("[Truncated: too long.]") + break + } + detail.WriteString(line) + } + + return detail.String() +} + +// Get returns the body of the HTTP or HTTPS resource specified at the given URL. +// +// If the URL does not include an explicit scheme, Get first tries "https". +// If the server does not respond under that scheme and the security mode is +// Insecure, Get then tries "http". +// The URL included in the response indicates which scheme was actually used, +// and it is a redacted URL suitable for use in error messages. +// +// For the "https" scheme only, credentials are attached using the +// cmd/go/internal/auth package. If the URL itself includes a username and +// password, it will not be attempted under the "http" scheme unless the +// security mode is Insecure. +// +// Get returns a non-nil error only if the request did not receive a response +// under any applicable scheme. (A non-2xx response does not cause an error.) +func Get(security SecurityMode, u *url.URL) (*Response, error) { + return get(security, u) +} + +// OpenBrowser attempts to open the requested URL in a web browser. +func OpenBrowser(url string) (opened bool) { + return openBrowser(url) +} + +// Join returns the result of adding the slash-separated +// path elements to the end of u's path. +func Join(u *url.URL, path string) *url.URL { + j := *u + if path == "" { + return &j + } + j.Path = strings.TrimSuffix(u.Path, "/") + "/" + strings.TrimPrefix(path, "/") + j.RawPath = strings.TrimSuffix(u.RawPath, "/") + "/" + strings.TrimPrefix(path, "/") + return &j +} + +// An errorDetailBuffer is an io.ReadCloser that copies up to +// maxErrorDetailLines into a buffer for later inspection. +type errorDetailBuffer struct { + r io.ReadCloser + buf strings.Builder + bufLines int +} + +func (b *errorDetailBuffer) Close() error { + return b.r.Close() +} + +func (b *errorDetailBuffer) Read(p []byte) (n int, err error) { + n, err = b.r.Read(p) + + // Copy the first maxErrorDetailLines+1 lines into b.buf, + // discarding any further lines. + // + // Note that the read may begin or end in the middle of a UTF-8 character, + // so don't try to do anything fancy with characters that encode to larger + // than one byte. + if b.bufLines <= maxErrorDetailLines { + for _, line := range bytes.SplitAfterN(p[:n], []byte("\n"), maxErrorDetailLines-b.bufLines) { + b.buf.Write(line) + if len(line) > 0 && line[len(line)-1] == '\n' { + b.bufLines++ + if b.bufLines > maxErrorDetailLines { + break + } + } + } + } + + return n, err +} diff --git a/src/cmd/go/internal/web/bootstrap.go b/src/cmd/go/internal/web/bootstrap.go new file mode 100644 index 0000000..7817021 --- /dev/null +++ b/src/cmd/go/internal/web/bootstrap.go @@ -0,0 +1,23 @@ +// 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. + +// +build cmd_go_bootstrap + +// This code is compiled only into the bootstrap 'go' binary. +// These stubs avoid importing packages with large dependency +// trees that potentially require C linking, +// like the use of "net/http" in vcs.go. + +package web + +import ( + "errors" + urlpkg "net/url" +) + +func get(security SecurityMode, url *urlpkg.URL) (*Response, error) { + return nil, errors.New("no http in bootstrap go command") +} + +func openBrowser(url string) bool { return false } diff --git a/src/cmd/go/internal/web/file_test.go b/src/cmd/go/internal/web/file_test.go new file mode 100644 index 0000000..3734df5 --- /dev/null +++ b/src/cmd/go/internal/web/file_test.go @@ -0,0 +1,60 @@ +// Copyright 2019 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 web + +import ( + "errors" + "io/fs" + "os" + "path/filepath" + "testing" +) + +func TestGetFileURL(t *testing.T) { + const content = "Hello, file!\n" + + f, err := os.CreateTemp("", "web-TestGetFileURL") + if err != nil { + t.Fatal(err) + } + defer os.Remove(f.Name()) + + if _, err := f.WriteString(content); err != nil { + t.Error(err) + } + if err := f.Close(); err != nil { + t.Fatal(err) + } + + u, err := urlFromFilePath(f.Name()) + if err != nil { + t.Fatal(err) + } + + b, err := GetBytes(u) + if err != nil { + t.Fatalf("GetBytes(%v) = _, %v", u, err) + } + if string(b) != content { + t.Fatalf("after writing %q to %s, GetBytes(%v) read %q", content, f.Name(), u, b) + } +} + +func TestGetNonexistentFile(t *testing.T) { + path, err := filepath.Abs("nonexistent") + if err != nil { + t.Fatal(err) + } + + u, err := urlFromFilePath(path) + if err != nil { + t.Fatal(err) + } + + b, err := GetBytes(u) + if !errors.Is(err, fs.ErrNotExist) { + t.Fatalf("GetBytes(%v) = %q, %v; want _, fs.ErrNotExist", u, b, err) + } +} diff --git a/src/cmd/go/internal/web/http.go b/src/cmd/go/internal/web/http.go new file mode 100644 index 0000000..72fa2b2 --- /dev/null +++ b/src/cmd/go/internal/web/http.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. + +// +build !cmd_go_bootstrap + +// This code is compiled into the real 'go' binary, but it is not +// compiled into the binary that is built during all.bash, so as +// to avoid needing to build net (and thus use cgo) during the +// bootstrap process. + +package web + +import ( + "crypto/tls" + "errors" + "fmt" + "mime" + "net/http" + urlpkg "net/url" + "os" + "strings" + "time" + + "cmd/go/internal/auth" + "cmd/go/internal/cfg" + "cmd/internal/browser" +) + +// impatientInsecureHTTPClient is used in -insecure mode, +// when we're connecting to https servers that might not be there +// or might be using self-signed certificates. +var impatientInsecureHTTPClient = &http.Client{ + Timeout: 5 * time.Second, + Transport: &http.Transport{ + Proxy: http.ProxyFromEnvironment, + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + }, +} + +// securityPreservingHTTPClient is like the default HTTP client, but rejects +// redirects to plain-HTTP URLs if the original URL was secure. +var securityPreservingHTTPClient = &http.Client{ + CheckRedirect: func(req *http.Request, via []*http.Request) error { + if len(via) > 0 && via[0].URL.Scheme == "https" && req.URL.Scheme != "https" { + lastHop := via[len(via)-1].URL + return fmt.Errorf("redirected from secure URL %s to insecure URL %s", lastHop, req.URL) + } + + // Go's http.DefaultClient allows 10 redirects before returning an error. + // The securityPreservingHTTPClient also uses this default policy to avoid + // Go command hangs. + if len(via) >= 10 { + return errors.New("stopped after 10 redirects") + } + return nil + }, +} + +func get(security SecurityMode, url *urlpkg.URL) (*Response, error) { + start := time.Now() + + if url.Scheme == "file" { + return getFile(url) + } + + if os.Getenv("TESTGOPROXY404") == "1" && url.Host == "proxy.golang.org" { + res := &Response{ + URL: url.Redacted(), + Status: "404 testing", + StatusCode: 404, + Header: make(map[string][]string), + Body: http.NoBody, + } + if cfg.BuildX { + fmt.Fprintf(os.Stderr, "# get %s: %v (%.3fs)\n", url.Redacted(), res.Status, time.Since(start).Seconds()) + } + return res, nil + } + + if url.Host == "localhost.localdev" { + return nil, fmt.Errorf("no such host localhost.localdev") + } + if os.Getenv("TESTGONETWORK") == "panic" && !strings.HasPrefix(url.Host, "127.0.0.1") && !strings.HasPrefix(url.Host, "0.0.0.0") { + panic("use of network: " + url.String()) + } + + fetch := func(url *urlpkg.URL) (*urlpkg.URL, *http.Response, error) { + // Note: The -v build flag does not mean "print logging information", + // despite its historical misuse for this in GOPATH-based go get. + // We print extra logging in -x mode instead, which traces what + // commands are executed. + if cfg.BuildX { + fmt.Fprintf(os.Stderr, "# get %s\n", url.Redacted()) + } + + req, err := http.NewRequest("GET", url.String(), nil) + if err != nil { + return nil, nil, err + } + if url.Scheme == "https" { + auth.AddCredentials(req) + } + + var res *http.Response + if security == Insecure && url.Scheme == "https" { // fail earlier + res, err = impatientInsecureHTTPClient.Do(req) + } else { + res, err = securityPreservingHTTPClient.Do(req) + } + return url, res, err + } + + var ( + fetched *urlpkg.URL + res *http.Response + err error + ) + if url.Scheme == "" || url.Scheme == "https" { + secure := new(urlpkg.URL) + *secure = *url + secure.Scheme = "https" + + fetched, res, err = fetch(secure) + if err != nil { + if cfg.BuildX { + fmt.Fprintf(os.Stderr, "# get %s: %v\n", secure.Redacted(), err) + } + if security != Insecure || url.Scheme == "https" { + // HTTPS failed, and we can't fall back to plain HTTP. + // Report the error from the HTTPS attempt. + return nil, err + } + } + } + + if res == nil { + switch url.Scheme { + case "http": + if security == SecureOnly { + if cfg.BuildX { + fmt.Fprintf(os.Stderr, "# get %s: insecure\n", url.Redacted()) + } + return nil, fmt.Errorf("insecure URL: %s", url.Redacted()) + } + case "": + if security != Insecure { + panic("should have returned after HTTPS failure") + } + default: + if cfg.BuildX { + fmt.Fprintf(os.Stderr, "# get %s: unsupported\n", url.Redacted()) + } + return nil, fmt.Errorf("unsupported scheme: %s", url.Redacted()) + } + + insecure := new(urlpkg.URL) + *insecure = *url + insecure.Scheme = "http" + if insecure.User != nil && security != Insecure { + if cfg.BuildX { + fmt.Fprintf(os.Stderr, "# get %s: insecure credentials\n", insecure.Redacted()) + } + return nil, fmt.Errorf("refusing to pass credentials to insecure URL: %s", insecure.Redacted()) + } + + fetched, res, err = fetch(insecure) + if err != nil { + if cfg.BuildX { + fmt.Fprintf(os.Stderr, "# get %s: %v\n", insecure.Redacted(), err) + } + // HTTP failed, and we already tried HTTPS if applicable. + // Report the error from the HTTP attempt. + return nil, err + } + } + + // Note: accepting a non-200 OK here, so people can serve a + // meta import in their http 404 page. + if cfg.BuildX { + fmt.Fprintf(os.Stderr, "# get %s: %v (%.3fs)\n", fetched.Redacted(), res.Status, time.Since(start).Seconds()) + } + + r := &Response{ + URL: fetched.Redacted(), + Status: res.Status, + StatusCode: res.StatusCode, + Header: map[string][]string(res.Header), + Body: res.Body, + } + + if res.StatusCode != http.StatusOK { + contentType := res.Header.Get("Content-Type") + if mediaType, params, _ := mime.ParseMediaType(contentType); mediaType == "text/plain" { + switch charset := strings.ToLower(params["charset"]); charset { + case "us-ascii", "utf-8", "": + // Body claims to be plain text in UTF-8 or a subset thereof. + // Try to extract a useful error message from it. + r.errorDetail.r = res.Body + r.Body = &r.errorDetail + } + } + } + + return r, nil +} + +func getFile(u *urlpkg.URL) (*Response, error) { + path, err := urlToFilePath(u) + if err != nil { + return nil, err + } + f, err := os.Open(path) + + if os.IsNotExist(err) { + return &Response{ + URL: u.Redacted(), + Status: http.StatusText(http.StatusNotFound), + StatusCode: http.StatusNotFound, + Body: http.NoBody, + fileErr: err, + }, nil + } + + if os.IsPermission(err) { + return &Response{ + URL: u.Redacted(), + Status: http.StatusText(http.StatusForbidden), + StatusCode: http.StatusForbidden, + Body: http.NoBody, + fileErr: err, + }, nil + } + + if err != nil { + return nil, err + } + + return &Response{ + URL: u.Redacted(), + Status: http.StatusText(http.StatusOK), + StatusCode: http.StatusOK, + Body: f, + }, nil +} + +func openBrowser(url string) bool { return browser.Open(url) } diff --git a/src/cmd/go/internal/web/url.go b/src/cmd/go/internal/web/url.go new file mode 100644 index 0000000..146c51f --- /dev/null +++ b/src/cmd/go/internal/web/url.go @@ -0,0 +1,95 @@ +// Copyright 2019 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 web + +import ( + "errors" + "net/url" + "path/filepath" + "strings" +) + +// TODO(golang.org/issue/32456): If accepted, move these functions into the +// net/url package. + +var errNotAbsolute = errors.New("path is not absolute") + +func urlToFilePath(u *url.URL) (string, error) { + if u.Scheme != "file" { + return "", errors.New("non-file URL") + } + + checkAbs := func(path string) (string, error) { + if !filepath.IsAbs(path) { + return "", errNotAbsolute + } + return path, nil + } + + if u.Path == "" { + if u.Host != "" || u.Opaque == "" { + return "", errors.New("file URL missing path") + } + return checkAbs(filepath.FromSlash(u.Opaque)) + } + + path, err := convertFileURLPath(u.Host, u.Path) + if err != nil { + return path, err + } + return checkAbs(path) +} + +func urlFromFilePath(path string) (*url.URL, error) { + if !filepath.IsAbs(path) { + return nil, errNotAbsolute + } + + // If path has a Windows volume name, convert the volume to a host and prefix + // per https://blogs.msdn.microsoft.com/ie/2006/12/06/file-uris-in-windows/. + if vol := filepath.VolumeName(path); vol != "" { + if strings.HasPrefix(vol, `\\`) { + path = filepath.ToSlash(path[2:]) + i := strings.IndexByte(path, '/') + + if i < 0 { + // A degenerate case. + // \\host.example.com (without a share name) + // becomes + // file://host.example.com/ + return &url.URL{ + Scheme: "file", + Host: path, + Path: "/", + }, nil + } + + // \\host.example.com\Share\path\to\file + // becomes + // file://host.example.com/Share/path/to/file + return &url.URL{ + Scheme: "file", + Host: path[:i], + Path: filepath.ToSlash(path[i:]), + }, nil + } + + // C:\path\to\file + // becomes + // file:///C:/path/to/file + return &url.URL{ + Scheme: "file", + Path: "/" + filepath.ToSlash(path), + }, nil + } + + // /path/to/file + // becomes + // file:///path/to/file + return &url.URL{ + Scheme: "file", + Path: filepath.ToSlash(path), + }, nil +} diff --git a/src/cmd/go/internal/web/url_other.go b/src/cmd/go/internal/web/url_other.go new file mode 100644 index 0000000..2641ee6 --- /dev/null +++ b/src/cmd/go/internal/web/url_other.go @@ -0,0 +1,21 @@ +// Copyright 2019 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 + +package web + +import ( + "errors" + "path/filepath" +) + +func convertFileURLPath(host, path string) (string, error) { + switch host { + case "", "localhost": + default: + return "", errors.New("file URL specifies non-local host") + } + return filepath.FromSlash(path), nil +} diff --git a/src/cmd/go/internal/web/url_other_test.go b/src/cmd/go/internal/web/url_other_test.go new file mode 100644 index 0000000..aa56633 --- /dev/null +++ b/src/cmd/go/internal/web/url_other_test.go @@ -0,0 +1,36 @@ +// Copyright 2019 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 + +package web + +var urlTests = []struct { + url string + filePath string + canonicalURL string // If empty, assume equal to url. + wantErr string +}{ + // Examples from RFC 8089: + { + url: `file:///path/to/file`, + filePath: `/path/to/file`, + }, + { + url: `file:/path/to/file`, + filePath: `/path/to/file`, + canonicalURL: `file:///path/to/file`, + }, + { + url: `file://localhost/path/to/file`, + filePath: `/path/to/file`, + canonicalURL: `file:///path/to/file`, + }, + + // We reject non-local files. + { + url: `file://host.example.com/path/to/file`, + wantErr: "file URL specifies non-local host", + }, +} diff --git a/src/cmd/go/internal/web/url_test.go b/src/cmd/go/internal/web/url_test.go new file mode 100644 index 0000000..8f462f5 --- /dev/null +++ b/src/cmd/go/internal/web/url_test.go @@ -0,0 +1,77 @@ +// Copyright 2019 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 web + +import ( + "net/url" + "testing" +) + +func TestURLToFilePath(t *testing.T) { + for _, tc := range urlTests { + if tc.url == "" { + continue + } + tc := tc + + t.Run(tc.url, func(t *testing.T) { + u, err := url.Parse(tc.url) + if err != nil { + t.Fatalf("url.Parse(%q): %v", tc.url, err) + } + + path, err := urlToFilePath(u) + if err != nil { + if err.Error() == tc.wantErr { + return + } + if tc.wantErr == "" { + t.Fatalf("urlToFilePath(%v): %v; want ", u, err) + } else { + t.Fatalf("urlToFilePath(%v): %v; want %s", u, err, tc.wantErr) + } + } + + if path != tc.filePath || tc.wantErr != "" { + t.Fatalf("urlToFilePath(%v) = %q, ; want %q, %s", u, path, tc.filePath, tc.wantErr) + } + }) + } +} + +func TestURLFromFilePath(t *testing.T) { + for _, tc := range urlTests { + if tc.filePath == "" { + continue + } + tc := tc + + t.Run(tc.filePath, func(t *testing.T) { + u, err := urlFromFilePath(tc.filePath) + if err != nil { + if err.Error() == tc.wantErr { + return + } + if tc.wantErr == "" { + t.Fatalf("urlFromFilePath(%v): %v; want ", tc.filePath, err) + } else { + t.Fatalf("urlFromFilePath(%v): %v; want %s", tc.filePath, err, tc.wantErr) + } + } + + if tc.wantErr != "" { + t.Fatalf("urlFromFilePath(%v) = ; want error: %s", tc.filePath, tc.wantErr) + } + + wantURL := tc.url + if tc.canonicalURL != "" { + wantURL = tc.canonicalURL + } + if u.String() != wantURL { + t.Errorf("urlFromFilePath(%v) = %v; want %s", tc.filePath, u, wantURL) + } + }) + } +} diff --git a/src/cmd/go/internal/web/url_windows.go b/src/cmd/go/internal/web/url_windows.go new file mode 100644 index 0000000..2a65ec8 --- /dev/null +++ b/src/cmd/go/internal/web/url_windows.go @@ -0,0 +1,43 @@ +// Copyright 2019 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 web + +import ( + "errors" + "path/filepath" + "strings" +) + +func convertFileURLPath(host, path string) (string, error) { + if len(path) == 0 || path[0] != '/' { + return "", errNotAbsolute + } + + path = filepath.FromSlash(path) + + // We interpret Windows file URLs per the description in + // https://blogs.msdn.microsoft.com/ie/2006/12/06/file-uris-in-windows/. + + // The host part of a file URL (if any) is the UNC volume name, + // but RFC 8089 reserves the authority "localhost" for the local machine. + if host != "" && host != "localhost" { + // A common "legacy" format omits the leading slash before a drive letter, + // encoding the drive letter as the host instead of part of the path. + // (See https://blogs.msdn.microsoft.com/freeassociations/2005/05/19/the-bizarre-and-unhappy-story-of-file-urls/.) + // We do not support that format, but we should at least emit a more + // helpful error message for it. + if filepath.VolumeName(host) != "" { + return "", errors.New("file URL encodes volume in host field: too few slashes?") + } + return `\\` + host + path, nil + } + + // If host is empty, path must contain an initial slash followed by a + // drive letter and path. Remove the slash and verify that the path is valid. + if vol := filepath.VolumeName(path[1:]); vol == "" || strings.HasPrefix(vol, `\\`) { + return "", errors.New("file URL missing drive letter") + } + return path[1:], nil +} diff --git a/src/cmd/go/internal/web/url_windows_test.go b/src/cmd/go/internal/web/url_windows_test.go new file mode 100644 index 0000000..06386a0 --- /dev/null +++ b/src/cmd/go/internal/web/url_windows_test.go @@ -0,0 +1,94 @@ +// Copyright 2019 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 web + +var urlTests = []struct { + url string + filePath string + canonicalURL string // If empty, assume equal to url. + wantErr string +}{ + // Examples from https://blogs.msdn.microsoft.com/ie/2006/12/06/file-uris-in-windows/: + + { + url: `file://laptop/My%20Documents/FileSchemeURIs.doc`, + filePath: `\\laptop\My Documents\FileSchemeURIs.doc`, + }, + { + url: `file:///C:/Documents%20and%20Settings/davris/FileSchemeURIs.doc`, + filePath: `C:\Documents and Settings\davris\FileSchemeURIs.doc`, + }, + { + url: `file:///D:/Program%20Files/Viewer/startup.htm`, + filePath: `D:\Program Files\Viewer\startup.htm`, + }, + { + url: `file:///C:/Program%20Files/Music/Web%20Sys/main.html?REQUEST=RADIO`, + filePath: `C:\Program Files\Music\Web Sys\main.html`, + canonicalURL: `file:///C:/Program%20Files/Music/Web%20Sys/main.html`, + }, + { + url: `file://applib/products/a-b/abc_9/4148.920a/media/start.swf`, + filePath: `\\applib\products\a-b\abc_9\4148.920a\media\start.swf`, + }, + { + url: `file:////applib/products/a%2Db/abc%5F9/4148.920a/media/start.swf`, + wantErr: "file URL missing drive letter", + }, + { + url: `C:\Program Files\Music\Web Sys\main.html?REQUEST=RADIO`, + wantErr: "non-file URL", + }, + + // The example "file://D:\Program Files\Viewer\startup.htm" errors out in + // url.Parse, so we substitute a slash-based path for testing instead. + { + url: `file://D:/Program Files/Viewer/startup.htm`, + wantErr: "file URL encodes volume in host field: too few slashes?", + }, + + // The blog post discourages the use of non-ASCII characters because they + // depend on the user's current codepage. However, when we are working with Go + // strings we assume UTF-8 encoding, and our url package refuses to encode + // URLs to non-ASCII strings. + { + url: `file:///C:/exampleㄓ.txt`, + filePath: `C:\exampleㄓ.txt`, + canonicalURL: `file:///C:/example%E3%84%93.txt`, + }, + { + url: `file:///C:/example%E3%84%93.txt`, + filePath: `C:\exampleㄓ.txt`, + }, + + // Examples from RFC 8089: + + // We allow the drive-letter variation from section E.2, because it is + // simpler to support than not to. However, we do not generate the shorter + // form in the reverse direction. + { + url: `file:c:/path/to/file`, + filePath: `c:\path\to\file`, + canonicalURL: `file:///c:/path/to/file`, + }, + + // We encode the UNC share name as the authority following section E.3.1, + // because that is what the Microsoft blog post explicitly recommends. + { + url: `file://host.example.com/Share/path/to/file.txt`, + filePath: `\\host.example.com\Share\path\to\file.txt`, + }, + + // We decline the four- and five-slash variations from section E.3.2. + // The paths in these URLs would change meaning under path.Clean. + { + url: `file:////host.example.com/path/to/file`, + wantErr: "file URL missing drive letter", + }, + { + url: `file://///host.example.com/path/to/file`, + wantErr: "file URL missing drive letter", + }, +} diff --git a/src/cmd/go/internal/work/action.go b/src/cmd/go/internal/work/action.go new file mode 100644 index 0000000..9d141ae --- /dev/null +++ b/src/cmd/go/internal/work/action.go @@ -0,0 +1,859 @@ +// Copyright 2011 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. + +// Action graph creation (planning). + +package work + +import ( + "bufio" + "bytes" + "container/heap" + "context" + "debug/elf" + "encoding/json" + "fmt" + "os" + "path/filepath" + "runtime" + "strings" + "sync" + "time" + + "cmd/go/internal/base" + "cmd/go/internal/cache" + "cmd/go/internal/cfg" + "cmd/go/internal/load" + "cmd/go/internal/trace" + "cmd/internal/buildid" +) + +// A Builder holds global state about a build. +// It does not hold per-package state, because we +// build packages in parallel, and the builder is shared. +type Builder struct { + WorkDir string // the temporary work directory (ends in filepath.Separator) + actionCache map[cacheKey]*Action // a cache of already-constructed actions + mkdirCache map[string]bool // a cache of created directories + flagCache map[[2]string]bool // a cache of supported compiler flags + Print func(args ...interface{}) (int, error) + + 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 + + output sync.Mutex + scriptDir string // current directory in printed script + + exec sync.Mutex + readySema chan bool + ready actionQueue + + id sync.Mutex + toolIDCache map[string]string // tool name -> tool ID + buildIDCache map[string]string // file name -> build ID +} + +// NOTE: Much of Action would not need to be exported if not for test. +// Maybe test functionality should move into this package too? + +// An Action represents a single action in the action graph. +type Action struct { + Mode string // description of action operation + Package *load.Package // the package this action works on + Deps []*Action // actions that must happen before this one + Func func(*Builder, context.Context, *Action) error // the action itself (nil = no-op) + IgnoreFail bool // whether to run f even if dependencies fail + TestOutput *bytes.Buffer // test output buffer + Args []string // additional args for runProgram + + triggers []*Action // inverse of deps + + buggyInstall bool // is this a buggy install (see -linkshared)? + + TryCache func(*Builder, *Action) bool // callback for cache bypass + + // Generated files, directories. + Objdir string // directory for intermediate objects + Target string // goal of the action: the created package or executable + built string // the actual created package or executable + actionID cache.ActionID // cache ID of action input + buildID string // build ID of action output + + VetxOnly bool // Mode=="vet": only being called to supply info about dependencies + needVet bool // Mode=="build": need to fill in vet config + needBuild bool // Mode=="build": need to do actual build (can be false if needVet is true) + vetCfg *vetConfig // vet config + output []byte // output redirect buffer (nil means use b.Print) + + // Execution state. + pending int // number of deps yet to complete + priority int // relative execution priority + Failed bool // whether the action failed + json *actionJSON // action graph information + nonGoOverlay map[string]string // map from non-.go source files to copied files in objdir. Nil if no overlay is used. + traceSpan *trace.Span +} + +// BuildActionID returns the action ID section of a's build ID. +func (a *Action) BuildActionID() string { return actionID(a.buildID) } + +// BuildContentID returns the content ID section of a's build ID. +func (a *Action) BuildContentID() string { return contentID(a.buildID) } + +// BuildID returns a's build ID. +func (a *Action) BuildID() string { return a.buildID } + +// BuiltTarget returns the actual file that was built. This differs +// from Target when the result was cached. +func (a *Action) BuiltTarget() string { return a.built } + +// An actionQueue is a priority queue of actions. +type actionQueue []*Action + +// Implement heap.Interface +func (q *actionQueue) Len() int { return len(*q) } +func (q *actionQueue) Swap(i, j int) { (*q)[i], (*q)[j] = (*q)[j], (*q)[i] } +func (q *actionQueue) Less(i, j int) bool { return (*q)[i].priority < (*q)[j].priority } +func (q *actionQueue) Push(x interface{}) { *q = append(*q, x.(*Action)) } +func (q *actionQueue) Pop() interface{} { + n := len(*q) - 1 + x := (*q)[n] + *q = (*q)[:n] + return x +} + +func (q *actionQueue) push(a *Action) { + if a.json != nil { + a.json.TimeReady = time.Now() + } + heap.Push(q, a) +} + +func (q *actionQueue) pop() *Action { + return heap.Pop(q).(*Action) +} + +type actionJSON struct { + ID int + Mode string + Package string + Deps []int `json:",omitempty"` + IgnoreFail bool `json:",omitempty"` + Args []string `json:",omitempty"` + Link bool `json:",omitempty"` + Objdir string `json:",omitempty"` + Target string `json:",omitempty"` + Priority int `json:",omitempty"` + Failed bool `json:",omitempty"` + Built string `json:",omitempty"` + VetxOnly bool `json:",omitempty"` + NeedVet bool `json:",omitempty"` + NeedBuild bool `json:",omitempty"` + ActionID string `json:",omitempty"` + BuildID string `json:",omitempty"` + TimeReady time.Time `json:",omitempty"` + TimeStart time.Time `json:",omitempty"` + TimeDone time.Time `json:",omitempty"` + + Cmd []string // `json:",omitempty"` + CmdReal time.Duration `json:",omitempty"` + CmdUser time.Duration `json:",omitempty"` + CmdSys time.Duration `json:",omitempty"` +} + +// cacheKey is the key for the action cache. +type cacheKey struct { + mode string + p *load.Package +} + +func actionGraphJSON(a *Action) string { + var workq []*Action + var inWorkq = make(map[*Action]int) + + add := func(a *Action) { + if _, ok := inWorkq[a]; ok { + return + } + inWorkq[a] = len(workq) + workq = append(workq, a) + } + add(a) + + for i := 0; i < len(workq); i++ { + for _, dep := range workq[i].Deps { + add(dep) + } + } + + var list []*actionJSON + for id, a := range workq { + if a.json == nil { + a.json = &actionJSON{ + Mode: a.Mode, + ID: id, + IgnoreFail: a.IgnoreFail, + Args: a.Args, + Objdir: a.Objdir, + Target: a.Target, + Failed: a.Failed, + Priority: a.priority, + Built: a.built, + VetxOnly: a.VetxOnly, + NeedBuild: a.needBuild, + NeedVet: a.needVet, + } + if a.Package != nil { + // TODO(rsc): Make this a unique key for a.Package somehow. + a.json.Package = a.Package.ImportPath + } + for _, a1 := range a.Deps { + a.json.Deps = append(a.json.Deps, inWorkq[a1]) + } + } + list = append(list, a.json) + } + + js, err := json.MarshalIndent(list, "", "\t") + if err != nil { + fmt.Fprintf(os.Stderr, "go: writing debug action graph: %v\n", err) + return "" + } + return string(js) +} + +// BuildMode specifies the build mode: +// are we just building things or also installing the results? +type BuildMode int + +const ( + ModeBuild BuildMode = iota + ModeInstall + ModeBuggyInstall + + ModeVetOnly = 1 << 8 +) + +func (b *Builder) Init() { + b.Print = func(a ...interface{}) (int, error) { + return fmt.Fprint(os.Stderr, a...) + } + b.actionCache = make(map[cacheKey]*Action) + b.mkdirCache = make(map[string]bool) + b.toolIDCache = make(map[string]string) + b.buildIDCache = make(map[string]string) + + if cfg.BuildN { + b.WorkDir = "$WORK" + } else { + tmp, err := os.MkdirTemp(cfg.Getenv("GOTMPDIR"), "go-build") + if err != nil { + 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) + } + if !cfg.BuildWork { + workdir := b.WorkDir + base.AtExit(func() { + start := time.Now() + for { + err := os.RemoveAll(workdir) + if err == nil { + return + } + + // On some configurations of Windows, directories containing executable + // files may be locked for a while after the executable exits (perhaps + // due to antivirus scans?). It's probably worth a little extra latency + // on exit to avoid filling up the user's temporary directory with leaked + // files. (See golang.org/issue/30789.) + if runtime.GOOS != "windows" || time.Since(start) >= 500*time.Millisecond { + fmt.Fprintf(os.Stderr, "go: failed to remove work dir: %s\n", err) + return + } + time.Sleep(5 * time.Millisecond) + } + }) + } + } + + if err := CheckGOOSARCHPair(cfg.Goos, cfg.Goarch); err != nil { + fmt.Fprintf(os.Stderr, "cmd/go: %v\n", err) + base.SetExitStatus(2) + base.Exit() + } + + for _, tag := range cfg.BuildContext.BuildTags { + if strings.Contains(tag, ",") { + fmt.Fprintf(os.Stderr, "cmd/go: -tags space-separated list contains comma\n") + base.SetExitStatus(2) + base.Exit() + } + } +} + +func CheckGOOSARCHPair(goos, goarch string) error { + if _, ok := cfg.OSArchSupportsCgo[goos+"/"+goarch]; !ok && cfg.BuildContext.Compiler == "gc" { + return fmt.Errorf("unsupported GOOS/GOARCH pair %s/%s", goos, goarch) + } + return nil +} + +// NewObjdir returns the name of a fresh object directory under b.WorkDir. +// It is up to the caller to call b.Mkdir on the result at an appropriate time. +// The result ends in a slash, so that file names in that directory +// can be constructed with direct string addition. +// +// NewObjdir must be called only from a single goroutine at a time, +// so it is safe to call during action graph construction, but it must not +// be called during action graph execution. +func (b *Builder) NewObjdir() string { + b.objdirSeq++ + return filepath.Join(b.WorkDir, fmt.Sprintf("b%03d", b.objdirSeq)) + string(filepath.Separator) +} + +// readpkglist returns the list of packages that were built into the shared library +// at shlibpath. For the native toolchain this list is stored, newline separated, in +// an ELF note with name "Go\x00\x00" and type 1. For GCCGO it is extracted from the +// .go_export section. +func readpkglist(shlibpath string) (pkgs []*load.Package) { + var stk load.ImportStack + if cfg.BuildToolchainName == "gccgo" { + f, _ := elf.Open(shlibpath) + sect := f.Section(".go_export") + data, _ := sect.Data() + scanner := bufio.NewScanner(bytes.NewBuffer(data)) + for scanner.Scan() { + t := scanner.Text() + if strings.HasPrefix(t, "pkgpath ") { + t = strings.TrimPrefix(t, "pkgpath ") + t = strings.TrimSuffix(t, ";") + pkgs = append(pkgs, load.LoadImportWithFlags(t, base.Cwd, nil, &stk, nil, 0)) + } + } + } else { + pkglistbytes, err := buildid.ReadELFNote(shlibpath, "Go\x00\x00", 1) + if err != nil { + base.Fatalf("readELFNote failed: %v", err) + } + scanner := bufio.NewScanner(bytes.NewBuffer(pkglistbytes)) + for scanner.Scan() { + t := scanner.Text() + pkgs = append(pkgs, load.LoadImportWithFlags(t, base.Cwd, nil, &stk, nil, 0)) + } + } + return +} + +// cacheAction looks up {mode, p} in the cache and returns the resulting action. +// If the cache has no such action, f() is recorded and returned. +// TODO(rsc): Change the second key from *load.Package to interface{}, +// to make the caching in linkShared less awkward? +func (b *Builder) cacheAction(mode string, p *load.Package, f func() *Action) *Action { + a := b.actionCache[cacheKey{mode, p}] + if a == nil { + a = f() + b.actionCache[cacheKey{mode, p}] = a + } + return a +} + +// AutoAction returns the "right" action for go build or go install of p. +func (b *Builder) AutoAction(mode, depMode BuildMode, p *load.Package) *Action { + if p.Name == "main" { + return b.LinkAction(mode, depMode, p) + } + return b.CompileAction(mode, depMode, p) +} + +// CompileAction returns the action for compiling and possibly installing +// (according to mode) the given package. The resulting action is only +// for building packages (archives), never for linking executables. +// 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 { + vetOnly := mode&ModeVetOnly != 0 + mode &^= ModeVetOnly + + 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" { + // We never install the .a file for a main package. + mode = ModeBuild + } + + // Construct package build action. + a := b.cacheAction("build", p, func() *Action { + a := &Action{ + Mode: "build", + Package: p, + Func: (*Builder).build, + Objdir: b.NewObjdir(), + } + + 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 { + switch p.ImportPath { + case "builtin", "unsafe": + // Fake packages - nothing to build. + a.Mode = "built-in package" + a.Func = nil + return a + } + + // gccgo standard library is "fake" too. + if cfg.BuildToolchainName == "gccgo" { + // the target name is needed for cgo. + a.Mode = "gccgo stdlib" + a.Target = p.Target + a.Func = nil + return a + } + } + + return a + }) + + // Find the build action; the cache entry may have been replaced + // by the install action during (*Builder).installAction. + buildAction := a + switch buildAction.Mode { + case "build", "built-in package", "gccgo stdlib": + // ok + case "build-install": + buildAction = a.Deps[0] + default: + panic("lost build action: " + buildAction.Mode) + } + buildAction.needBuild = buildAction.needBuild || !vetOnly + + // Construct install action. + if mode == ModeInstall || mode == ModeBuggyInstall { + a = b.installAction(a, mode) + } + + return a +} + +// VetAction returns the action for running go vet on package p. +// It depends on the action for compiling p. +// 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|ModeVetOnly, depMode, p) + + // vet expects to be able to import "fmt". + var stk load.ImportStack + stk.Push("vet") + p1 := load.LoadImportWithFlags("fmt", p.Dir, p, &stk, nil, 0) + 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 p.Internal.Imports { + deps = append(deps, b.vetAction(mode, depMode, p1)) + } + + a := &Action{ + 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 + } + deps[0].needVet = true + a.Func = (*Builder).vet + return a + }) + return a +} + +// LinkAction returns the action for linking p into an executable +// and possibly installing the result (according to mode). +// depMode is the action (build or install) to use when compiling dependencies. +func (b *Builder) LinkAction(mode, depMode BuildMode, p *load.Package) *Action { + // Construct link action. + a := b.cacheAction("link", p, func() *Action { + a := &Action{ + Mode: "link", + Package: p, + } + + a1 := b.CompileAction(ModeBuild, depMode, p) + a.Func = (*Builder).link + a.Deps = []*Action{a1} + a.Objdir = a1.Objdir + + // An executable file. (This is the name of a temporary file.) + // Because we run the temporary file in 'go run' and 'go test', + // the name will show up in ps listings. If the caller has specified + // a name, use that instead of a.out. The binary is generated + // in an otherwise empty subdirectory named exe to avoid + // naming conflicts. The only possible conflict is if we were + // to create a top-level package named exe. + name := "a.out" + if p.Internal.ExeName != "" { + name = p.Internal.ExeName + } else if (cfg.Goos == "darwin" || cfg.Goos == "windows") && cfg.BuildBuildmode == "c-shared" && p.Target != "" { + // On OS X, the linker output name gets recorded in the + // shared library's LC_ID_DYLIB load command. + // The code invoking the linker knows to pass only the final + // path element. Arrange that the path element matches what + // we'll install it as; otherwise the library is only loadable as "a.out". + // On Windows, DLL file name is recorded in PE file + // export section, so do like on OS X. + _, name = filepath.Split(p.Target) + } + a.Target = a.Objdir + filepath.Join("exe", name) + cfg.ExeSuffix + a.built = a.Target + b.addTransitiveLinkDeps(a, a1, "") + + // Sequence the build of the main package (a1) strictly after the build + // of all other dependencies that go into the link. It is likely to be after + // them anyway, but just make sure. This is required by the build ID-based + // shortcut in (*Builder).useCache(a1), which will call b.linkActionID(a). + // In order for that linkActionID call to compute the right action ID, all the + // dependencies of a (except a1) must have completed building and have + // recorded their build IDs. + a1.Deps = append(a1.Deps, &Action{Mode: "nop", Deps: a.Deps[1:]}) + return a + }) + + if mode == ModeInstall || mode == ModeBuggyInstall { + a = b.installAction(a, mode) + } + + return a +} + +// installAction returns the action for installing the result of a1. +func (b *Builder) installAction(a1 *Action, mode BuildMode) *Action { + // Because we overwrite the build action with the install action below, + // a1 may already be an install action fetched from the "build" cache key, + // and the caller just doesn't realize. + if strings.HasSuffix(a1.Mode, "-install") { + if a1.buggyInstall && mode == ModeInstall { + // Congratulations! The buggy install is now a proper install. + a1.buggyInstall = false + } + return a1 + } + + // If there's no actual action to build a1, + // there's nothing to install either. + // This happens if a1 corresponds to reusing an already-built object. + if a1.Func == nil { + return a1 + } + + p := a1.Package + return b.cacheAction(a1.Mode+"-install", p, func() *Action { + // The install deletes the temporary build result, + // so we need all other actions, both past and future, + // that attempt to depend on the build to depend instead + // on the install. + + // Make a private copy of a1 (the build action), + // no longer accessible to any other rules. + buildAction := new(Action) + *buildAction = *a1 + + // Overwrite a1 with the install action. + // This takes care of updating past actions that + // point at a1 for the build action; now they will + // point at a1 and get the install action. + // We also leave a1 in the action cache as the result + // for "build", so that actions not yet created that + // try to depend on the build will instead depend + // on the install. + *a1 = Action{ + Mode: buildAction.Mode + "-install", + Func: BuildInstallFunc, + Package: p, + Objdir: buildAction.Objdir, + Deps: []*Action{buildAction}, + Target: p.Target, + built: p.Target, + + buggyInstall: mode == ModeBuggyInstall, + } + + b.addInstallHeaderAction(a1) + return a1 + }) +} + +// addTransitiveLinkDeps adds to the link action a all packages +// that are transitive dependencies of a1.Deps. +// That is, if a is a link of package main, a1 is the compile of package main +// and a1.Deps is the actions for building packages directly imported by +// package main (what the compiler needs). The linker needs all packages +// transitively imported by the whole program; addTransitiveLinkDeps +// makes sure those are present in a.Deps. +// If shlib is non-empty, then a corresponds to the build and installation of shlib, +// so any rebuild of shlib should not be added as a dependency. +func (b *Builder) addTransitiveLinkDeps(a, a1 *Action, shlib string) { + // Expand Deps to include all built packages, for the linker. + // Use breadth-first search to find rebuilt-for-test packages + // before the standard ones. + // TODO(rsc): Eliminate the standard ones from the action graph, + // which will require doing a little bit more rebuilding. + workq := []*Action{a1} + haveDep := map[string]bool{} + if a1.Package != nil { + haveDep[a1.Package.ImportPath] = true + } + for i := 0; i < len(workq); i++ { + a1 := workq[i] + for _, a2 := range a1.Deps { + // TODO(rsc): Find a better discriminator than the Mode strings, once the dust settles. + if a2.Package == nil || (a2.Mode != "build-install" && a2.Mode != "build") || haveDep[a2.Package.ImportPath] { + continue + } + haveDep[a2.Package.ImportPath] = true + a.Deps = append(a.Deps, a2) + if a2.Mode == "build-install" { + a2 = a2.Deps[0] // walk children of "build" action + } + workq = append(workq, a2) + } + } + + // If this is go build -linkshared, then the link depends on the shared libraries + // in addition to the packages themselves. (The compile steps do not.) + if cfg.BuildLinkshared { + haveShlib := map[string]bool{shlib: true} + for _, a1 := range a.Deps { + p1 := a1.Package + if p1 == nil || p1.Shlib == "" || haveShlib[filepath.Base(p1.Shlib)] { + continue + } + haveShlib[filepath.Base(p1.Shlib)] = true + // TODO(rsc): The use of ModeInstall here is suspect, but if we only do ModeBuild, + // we'll end up building an overall library or executable that depends at runtime + // on other libraries that are out-of-date, which is clearly not good either. + // We call it ModeBuggyInstall to make clear that this is not right. + a.Deps = append(a.Deps, b.linkSharedAction(ModeBuggyInstall, ModeBuggyInstall, p1.Shlib, nil)) + } + } +} + +// addInstallHeaderAction adds an install header action to a, if needed. +// The action a should be an install action as generated by either +// b.CompileAction or b.LinkAction with mode=ModeInstall, +// and so a.Deps[0] is the corresponding build action. +func (b *Builder) addInstallHeaderAction(a *Action) { + // Install header for cgo in c-archive and c-shared modes. + p := a.Package + if p.UsesCgo() && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared") { + hdrTarget := a.Target[:len(a.Target)-len(filepath.Ext(a.Target))] + ".h" + if cfg.BuildContext.Compiler == "gccgo" && cfg.BuildO == "" { + // For the header file, remove the "lib" + // added by go/build, so we generate pkg.h + // rather than libpkg.h. + dir, file := filepath.Split(hdrTarget) + file = strings.TrimPrefix(file, "lib") + hdrTarget = filepath.Join(dir, file) + } + ah := &Action{ + Mode: "install header", + Package: a.Package, + Deps: []*Action{a.Deps[0]}, + Func: (*Builder).installHeader, + Objdir: a.Deps[0].Objdir, + Target: hdrTarget, + } + a.Deps = append(a.Deps, ah) + } +} + +// buildmodeShared takes the "go build" action a1 into the building of a shared library of a1.Deps. +// That is, the input a1 represents "go build pkgs" and the result represents "go build -buildmode=shared pkgs". +func (b *Builder) buildmodeShared(mode, depMode BuildMode, args []string, pkgs []*load.Package, a1 *Action) *Action { + name, err := libname(args, pkgs) + if err != nil { + base.Fatalf("%v", err) + } + return b.linkSharedAction(mode, depMode, name, a1) +} + +// linkSharedAction takes a grouping action a1 corresponding to a list of built packages +// and returns an action that links them together into a shared library with the name shlib. +// If a1 is nil, shlib should be an absolute path to an existing shared library, +// and then linkSharedAction reads that library to find out the package list. +func (b *Builder) linkSharedAction(mode, depMode BuildMode, shlib string, a1 *Action) *Action { + fullShlib := shlib + shlib = filepath.Base(shlib) + a := b.cacheAction("build-shlib "+shlib, nil, func() *Action { + if a1 == nil { + // TODO(rsc): Need to find some other place to store config, + // not in pkg directory. See golang.org/issue/22196. + pkgs := readpkglist(fullShlib) + a1 = &Action{ + Mode: "shlib packages", + } + for _, p := range pkgs { + a1.Deps = append(a1.Deps, b.CompileAction(mode, depMode, p)) + } + } + + // Fake package to hold ldflags. + // As usual shared libraries are a kludgy, abstraction-violating special case: + // we let them use the flags specified for the command-line arguments. + p := &load.Package{} + p.Internal.CmdlinePkg = true + p.Internal.Ldflags = load.BuildLdflags.For(p) + p.Internal.Gccgoflags = load.BuildGccgoflags.For(p) + + // Add implicit dependencies to pkgs list. + // Currently buildmode=shared forces external linking mode, and + // external linking mode forces an import of runtime/cgo (and + // math on arm). So if it was not passed on the command line and + // it is not present in another shared library, add it here. + // TODO(rsc): Maybe this should only happen if "runtime" is in the original package set. + // TODO(rsc): This should probably be changed to use load.LinkerDeps(p). + // TODO(rsc): We don't add standard library imports for gccgo + // because they are all always linked in anyhow. + // Maybe load.LinkerDeps should be used and updated. + a := &Action{ + Mode: "go build -buildmode=shared", + Package: p, + Objdir: b.NewObjdir(), + Func: (*Builder).linkShared, + Deps: []*Action{a1}, + } + a.Target = filepath.Join(a.Objdir, shlib) + if cfg.BuildToolchainName != "gccgo" { + add := func(a1 *Action, pkg string, force bool) { + for _, a2 := range a1.Deps { + if a2.Package != nil && a2.Package.ImportPath == pkg { + return + } + } + var stk load.ImportStack + p := load.LoadImportWithFlags(pkg, base.Cwd, nil, &stk, nil, 0) + if p.Error != nil { + base.Fatalf("load %s: %v", pkg, p.Error) + } + // Assume that if pkg (runtime/cgo or math) + // is already accounted for in a different shared library, + // then that shared library also contains runtime, + // so that anything we do will depend on that library, + // so we don't need to include pkg in our shared library. + if force || p.Shlib == "" || filepath.Base(p.Shlib) == pkg { + a1.Deps = append(a1.Deps, b.CompileAction(depMode, depMode, p)) + } + } + add(a1, "runtime/cgo", false) + if cfg.Goarch == "arm" { + add(a1, "math", false) + } + + // The linker step still needs all the usual linker deps. + // (For example, the linker always opens runtime.a.) + for _, dep := range load.LinkerDeps(nil) { + add(a, dep, true) + } + } + b.addTransitiveLinkDeps(a, a1, shlib) + return a + }) + + // Install result. + if (mode == ModeInstall || mode == ModeBuggyInstall) && a.Func != nil { + buildAction := a + + a = b.cacheAction("install-shlib "+shlib, nil, func() *Action { + // Determine the eventual install target. + // The install target is root/pkg/shlib, where root is the source root + // in which all the packages lie. + // TODO(rsc): Perhaps this cross-root check should apply to the full + // transitive package dependency list, not just the ones named + // on the command line? + pkgDir := a1.Deps[0].Package.Internal.Build.PkgTargetRoot + for _, a2 := range a1.Deps { + if dir := a2.Package.Internal.Build.PkgTargetRoot; dir != pkgDir { + base.Fatalf("installing shared library: cannot use packages %s and %s from different roots %s and %s", + a1.Deps[0].Package.ImportPath, + a2.Package.ImportPath, + pkgDir, + dir) + } + } + // TODO(rsc): Find out and explain here why gccgo is different. + if cfg.BuildToolchainName == "gccgo" { + pkgDir = filepath.Join(pkgDir, "shlibs") + } + target := filepath.Join(pkgDir, shlib) + + a := &Action{ + Mode: "go install -buildmode=shared", + Objdir: buildAction.Objdir, + Func: BuildInstallFunc, + Deps: []*Action{buildAction}, + Target: target, + } + for _, a2 := range buildAction.Deps[0].Deps { + p := a2.Package + if p.Target == "" { + continue + } + a.Deps = append(a.Deps, &Action{ + Mode: "shlibname", + Package: p, + Func: (*Builder).installShlibname, + Target: strings.TrimSuffix(p.Target, ".a") + ".shlibname", + Deps: []*Action{a.Deps[0]}, + }) + } + return a + }) + } + + return a +} diff --git a/src/cmd/go/internal/work/build.go b/src/cmd/go/internal/work/build.go new file mode 100644 index 0000000..f024b07 --- /dev/null +++ b/src/cmd/go/internal/work/build.go @@ -0,0 +1,929 @@ +// Copyright 2011 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 work + +import ( + "context" + "errors" + "fmt" + "go/build" + exec "internal/execabs" + "internal/goroot" + "os" + "path" + "path/filepath" + "runtime" + "strings" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/fsys" + "cmd/go/internal/load" + "cmd/go/internal/modfetch" + "cmd/go/internal/modload" + "cmd/go/internal/search" + "cmd/go/internal/trace" + + "golang.org/x/mod/modfile" + "golang.org/x/mod/module" +) + +var CmdBuild = &base.Command{ + UsageLine: "go build [-o output] [build flags] [packages]", + Short: "compile packages and dependencies", + Long: ` +Build compiles the packages named by the import paths, +along with their dependencies, but it does not install the results. + +If the arguments to build are a list of .go files from a single directory, +build treats them as a list of source files specifying a single package. + +When compiling packages, build ignores files that end in '_test.go'. + +When compiling a single main package, build writes +the resulting executable to an output file named after +the first source file ('go build ed.go rx.go' writes 'ed' or 'ed.exe') +or the source code directory ('go build unix/sam' writes 'sam' or 'sam.exe'). +The '.exe' suffix is added when writing a Windows executable. + +When compiling multiple packages or a single non-main package, +build compiles the packages but discards the resulting object, +serving only as a check that the packages can be built. + +The -o flag forces build to write the resulting executable or object +to the named output file or directory, instead of the default behavior described +in the last two paragraphs. If the named output is an existing directory or +ends with a slash or backslash, then any resulting executables +will be written to that directory. + +The -i flag installs the packages that are dependencies of the target. +The -i flag is deprecated. Compiled packages are cached automatically. + +The build flags are shared by the build, clean, get, install, list, run, +and test commands: + + -a + force rebuilding of packages that are already up-to-date. + -n + print the commands but do not run them. + -p n + the number of programs, such as build commands or + test binaries, that can be run in parallel. + The default is the number of CPUs available. + -race + enable data race detection. + Supported only on linux/amd64, freebsd/amd64, darwin/amd64, windows/amd64, + linux/ppc64le and linux/arm64 (only for 48-bit VMA). + -msan + enable interoperation with memory sanitizer. + Supported only on linux/amd64, linux/arm64 + and only with Clang/LLVM as the host C compiler. + On linux/arm64, pie build mode will be used. + -v + print the names of packages as they are compiled. + -work + print the name of the temporary work directory and + do not delete it when exiting. + -x + print the commands. + + -asmflags '[pattern=]arg list' + arguments to pass on each go tool asm invocation. + -buildmode mode + build mode to use. See 'go help buildmode' for more. + -compiler name + name of compiler to use, as in runtime.Compiler (gccgo or gc). + -gccgoflags '[pattern=]arg list' + arguments to pass on each gccgo compiler/linker invocation. + -gcflags '[pattern=]arg list' + arguments to pass on each go tool compile invocation. + -installsuffix suffix + a suffix to use in the name of the package installation directory, + in order to keep output separate from default builds. + If using the -race flag, the install suffix is automatically set to race + or, if set explicitly, has _race appended to it. Likewise for the -msan + flag. Using a -buildmode option that requires non-default compile flags + has a similar effect. + -ldflags '[pattern=]arg list' + arguments to pass on each go tool link invocation. + -linkshared + build code that will be linked against shared libraries previously + created with -buildmode=shared. + -mod mode + module download mode to use: readonly, vendor, or mod. + By default, if a vendor directory is present and the go version in go.mod + is 1.14 or higher, the go command acts as if -mod=vendor were set. + Otherwise, the go command acts as if -mod=readonly were set. + See https://golang.org/ref/mod#build-commands for details. + -modcacherw + leave newly-created directories in the module cache read-write + instead of making them read-only. + -modfile file + in module aware mode, read (and possibly write) an alternate go.mod + file instead of the one in the module root directory. A file named + "go.mod" must still be present in order to determine the module root + directory, but it is not accessed. When -modfile is specified, an + alternate go.sum file is also used: its path is derived from the + -modfile flag by trimming the ".mod" extension and appending ".sum". + -overlay file + read a JSON config file that provides an overlay for build operations. + The file is a JSON struct with a single field, named 'Replace', that + maps each disk file path (a string) to its backing file path, so that + a build will run as if the disk file path exists with the contents + given by the backing file paths, or as if the disk file path does not + exist if its backing file path is empty. Support for the -overlay flag + has some limitations:importantly, cgo files included from outside the + include path must be in the same directory as the Go package they are + included from, and overlays will not appear when binaries and tests are + run through go run and go test respectively. + -pkgdir dir + install and load all packages from dir instead of the usual locations. + For example, when building with a non-standard configuration, + use -pkgdir to keep generated packages in a separate location. + -tags tag,list + a comma-separated list of build tags to consider satisfied during the + build. For more information about build tags, see the description of + build constraints in the documentation for the go/build package. + (Earlier versions of Go used a space-separated list, and that form + is deprecated but still recognized.) + -trimpath + remove all file system paths from the resulting executable. + Instead of absolute file system paths, the recorded file names + will begin with either "go" (for the standard library), + or a module path@version (when using modules), + or a plain import path (when using GOPATH). + -toolexec 'cmd args' + a program to use to invoke toolchain programs like vet and asm. + For example, instead of running asm, the go command will run + 'cmd args /path/to/asm '. + +The -asmflags, -gccgoflags, -gcflags, and -ldflags flags accept a +space-separated list of arguments to pass to an underlying tool +during the build. To embed spaces in an element in the list, surround +it with either single or double quotes. The argument list may be +preceded by a package pattern and an equal sign, which restricts +the use of that argument list to the building of packages matching +that pattern (see 'go help packages' for a description of package +patterns). Without a pattern, the argument list applies only to the +packages named on the command line. The flags may be repeated +with different patterns in order to specify different arguments for +different sets of packages. If a package matches patterns given in +multiple flags, the latest match on the command line wins. +For example, 'go build -gcflags=-S fmt' prints the disassembly +only for package fmt, while 'go build -gcflags=all=-S fmt' +prints the disassembly for fmt and all its dependencies. + +For more about specifying packages, see 'go help packages'. +For more about where packages and binaries are installed, +run 'go help gopath'. +For more about calling between Go and C/C++, run 'go help c'. + +Note: Build adheres to certain conventions such as those described +by 'go help gopath'. Not all projects can follow these conventions, +however. Installations that have their own conventions or that use +a separate software build system may choose to use lower-level +invocations such as 'go tool compile' and 'go tool link' to avoid +some of the overheads and design decisions of the build tool. + +See also: go install, go get, go clean. + `, +} + +const concurrentGCBackendCompilationEnabledByDefault = true + +func init() { + // break init cycle + CmdBuild.Run = runBuild + CmdInstall.Run = runInstall + + CmdBuild.Flag.BoolVar(&cfg.BuildI, "i", false, "") + CmdBuild.Flag.StringVar(&cfg.BuildO, "o", "", "output file or directory") + + CmdInstall.Flag.BoolVar(&cfg.BuildI, "i", false, "") + + AddBuildFlags(CmdBuild, DefaultBuildFlags) + AddBuildFlags(CmdInstall, DefaultBuildFlags) +} + +// Note that flags consulted by other parts of the code +// (for example, buildV) are in cmd/go/internal/cfg. + +var ( + forcedAsmflags []string // internally-forced flags for cmd/asm + forcedGcflags []string // internally-forced flags for cmd/compile + forcedLdflags []string // internally-forced flags for cmd/link + forcedGccgoflags []string // internally-forced flags for gccgo +) + +var BuildToolchain toolchain = noToolchain{} +var ldBuildmode string + +// buildCompiler implements flag.Var. +// It implements Set by updating both +// BuildToolchain and buildContext.Compiler. +type buildCompiler struct{} + +func (c buildCompiler) Set(value string) error { + switch value { + case "gc": + BuildToolchain = gcToolchain{} + case "gccgo": + BuildToolchain = gccgoToolchain{} + default: + return fmt.Errorf("unknown compiler %q", value) + } + cfg.BuildToolchainName = value + cfg.BuildToolchainCompiler = BuildToolchain.compiler + cfg.BuildToolchainLinker = BuildToolchain.linker + cfg.BuildContext.Compiler = value + return nil +} + +func (c buildCompiler) String() string { + return cfg.BuildContext.Compiler +} + +func init() { + switch build.Default.Compiler { + case "gc", "gccgo": + buildCompiler{}.Set(build.Default.Compiler) + } +} + +type BuildFlagMask int + +const ( + DefaultBuildFlags BuildFlagMask = 0 + OmitModFlag BuildFlagMask = 1 << iota + OmitModCommonFlags + OmitVFlag +) + +// AddBuildFlags adds the flags common to the build, clean, get, +// install, list, run, and test commands. +func AddBuildFlags(cmd *base.Command, mask BuildFlagMask) { + base.AddBuildFlagsNX(&cmd.Flag) + cmd.Flag.BoolVar(&cfg.BuildA, "a", false, "") + cmd.Flag.IntVar(&cfg.BuildP, "p", cfg.BuildP, "") + if mask&OmitVFlag == 0 { + cmd.Flag.BoolVar(&cfg.BuildV, "v", false, "") + } + + cmd.Flag.Var(&load.BuildAsmflags, "asmflags", "") + cmd.Flag.Var(buildCompiler{}, "compiler", "") + cmd.Flag.StringVar(&cfg.BuildBuildmode, "buildmode", "default", "") + cmd.Flag.Var(&load.BuildGcflags, "gcflags", "") + cmd.Flag.Var(&load.BuildGccgoflags, "gccgoflags", "") + if mask&OmitModFlag == 0 { + base.AddModFlag(&cmd.Flag) + } + if mask&OmitModCommonFlags == 0 { + base.AddModCommonFlags(&cmd.Flag) + } else { + // Add the overlay flag even when we don't add the rest of the mod common flags. + // This only affects 'go get' in GOPATH mode, but add the flag anyway for + // consistency. + cmd.Flag.StringVar(&fsys.OverlayFile, "overlay", "", "") + } + cmd.Flag.StringVar(&cfg.BuildContext.InstallSuffix, "installsuffix", "", "") + cmd.Flag.Var(&load.BuildLdflags, "ldflags", "") + cmd.Flag.BoolVar(&cfg.BuildLinkshared, "linkshared", false, "") + cmd.Flag.StringVar(&cfg.BuildPkgdir, "pkgdir", "", "") + cmd.Flag.BoolVar(&cfg.BuildRace, "race", false, "") + cmd.Flag.BoolVar(&cfg.BuildMSan, "msan", false, "") + cmd.Flag.Var((*tagsFlag)(&cfg.BuildContext.BuildTags), "tags", "") + cmd.Flag.Var((*base.StringsFlag)(&cfg.BuildToolexec), "toolexec", "") + cmd.Flag.BoolVar(&cfg.BuildTrimpath, "trimpath", false, "") + cmd.Flag.BoolVar(&cfg.BuildWork, "work", false, "") + + // Undocumented, unstable debugging flags. + cmd.Flag.StringVar(&cfg.DebugActiongraph, "debug-actiongraph", "", "") + cmd.Flag.StringVar(&cfg.DebugTrace, "debug-trace", "", "") +} + +// tagsFlag is the implementation of the -tags flag. +type tagsFlag []string + +func (v *tagsFlag) Set(s string) error { + // For compatibility with Go 1.12 and earlier, allow "-tags='a b c'" or even just "-tags='a'". + if strings.Contains(s, " ") || strings.Contains(s, "'") { + return (*base.StringsFlag)(v).Set(s) + } + + // Split on commas, ignore empty strings. + *v = []string{} + for _, s := range strings.Split(s, ",") { + if s != "" { + *v = append(*v, s) + } + } + return nil +} + +func (v *tagsFlag) String() string { + return "" +} + +// fileExtSplit expects a filename and returns the name +// and ext (without the dot). If the file has no +// extension, ext will be empty. +func fileExtSplit(file string) (name, ext string) { + dotExt := filepath.Ext(file) + name = file[:len(file)-len(dotExt)] + if dotExt != "" { + ext = dotExt[1:] + } + return +} + +func pkgsMain(pkgs []*load.Package) (res []*load.Package) { + for _, p := range pkgs { + if p.Name == "main" { + res = append(res, p) + } + } + return res +} + +func pkgsNotMain(pkgs []*load.Package) (res []*load.Package) { + for _, p := range pkgs { + if p.Name != "main" { + res = append(res, p) + } + } + return res +} + +func oneMainPkg(pkgs []*load.Package) []*load.Package { + if len(pkgs) != 1 || pkgs[0].Name != "main" { + base.Fatalf("-buildmode=%s requires exactly one main package", cfg.BuildBuildmode) + } + return pkgs +} + +var pkgsFilter = func(pkgs []*load.Package) []*load.Package { return pkgs } + +var runtimeVersion = runtime.Version() + +func runBuild(ctx context.Context, cmd *base.Command, args []string) { + BuildInit() + var b Builder + b.Init() + + pkgs := load.PackagesAndErrors(ctx, args) + load.CheckPackageErrors(pkgs) + + explicitO := len(cfg.BuildO) > 0 + + if len(pkgs) == 1 && pkgs[0].Name == "main" && cfg.BuildO == "" { + cfg.BuildO = pkgs[0].DefaultExecName() + cfg.BuildO += cfg.ExeSuffix + } + + // sanity check some often mis-used options + switch cfg.BuildContext.Compiler { + case "gccgo": + if load.BuildGcflags.Present() { + fmt.Println("go build: when using gccgo toolchain, please pass compiler flags using -gccgoflags, not -gcflags") + } + if load.BuildLdflags.Present() { + fmt.Println("go build: when using gccgo toolchain, please pass linker flags using -gccgoflags, not -ldflags") + } + case "gc": + if load.BuildGccgoflags.Present() { + fmt.Println("go build: when using gc toolchain, please pass compile flags using -gcflags, and linker flags using -ldflags") + } + } + + depMode := ModeBuild + if cfg.BuildI { + depMode = ModeInstall + fmt.Fprint(os.Stderr, "go build: -i flag is deprecated\n") + } + + pkgs = omitTestOnly(pkgsFilter(pkgs)) + + // Special case -o /dev/null by not writing at all. + if cfg.BuildO == os.DevNull { + cfg.BuildO = "" + } + + if cfg.BuildO != "" { + // If the -o name exists and is a directory or + // ends with a slash or backslash, then + // write all main packages to that directory. + // Otherwise require only a single package be built. + if fi, err := os.Stat(cfg.BuildO); (err == nil && fi.IsDir()) || + strings.HasSuffix(cfg.BuildO, "/") || + strings.HasSuffix(cfg.BuildO, string(os.PathSeparator)) { + if !explicitO { + base.Fatalf("go build: build output %q already exists and is a directory", cfg.BuildO) + } + a := &Action{Mode: "go build"} + for _, p := range pkgs { + if p.Name != "main" { + continue + } + + p.Target = filepath.Join(cfg.BuildO, p.DefaultExecName()) + p.Target += cfg.ExeSuffix + p.Stale = true + p.StaleReason = "build -o flag in use" + a.Deps = append(a.Deps, b.AutoAction(ModeInstall, depMode, p)) + } + if len(a.Deps) == 0 { + base.Fatalf("go build: no main packages to build") + } + b.Do(ctx, a) + return + } + if len(pkgs) > 1 { + base.Fatalf("go build: cannot write multiple packages to non-directory %s", cfg.BuildO) + } else if len(pkgs) == 0 { + base.Fatalf("no packages to build") + } + p := pkgs[0] + p.Target = cfg.BuildO + p.Stale = true // must build - not up to date + p.StaleReason = "build -o flag in use" + a := b.AutoAction(ModeInstall, depMode, p) + b.Do(ctx, a) + return + } + + a := &Action{Mode: "go build"} + for _, p := range pkgs { + a.Deps = append(a.Deps, b.AutoAction(ModeBuild, depMode, p)) + } + if cfg.BuildBuildmode == "shared" { + a = b.buildmodeShared(ModeBuild, depMode, args, pkgs, a) + } + b.Do(ctx, a) +} + +var CmdInstall = &base.Command{ + UsageLine: "go install [build flags] [packages]", + Short: "compile and install packages and dependencies", + Long: ` +Install compiles and installs the packages named by the import paths. + +Executables are installed in the directory named by the GOBIN environment +variable, which defaults to $GOPATH/bin or $HOME/go/bin if the GOPATH +environment variable is not set. Executables in $GOROOT +are installed in $GOROOT/bin or $GOTOOLDIR instead of $GOBIN. + +If the arguments have version suffixes (like @latest or @v1.0.0), "go install" +builds packages in module-aware mode, ignoring the go.mod file in the current +directory or any parent directory, if there is one. This is useful for +installing executables without affecting the dependencies of the main module. +To eliminate ambiguity about which module versions are used in the build, the +arguments must satisfy the following constraints: + +- Arguments must be package paths or package patterns (with "..." wildcards). +They must not be standard packages (like fmt), meta-patterns (std, cmd, +all), or relative or absolute file paths. + +- All arguments must have the same version suffix. Different queries are not +allowed, even if they refer to the same version. + +- All arguments must refer to packages in the same module at the same version. + +- No module is considered the "main" module. If the module containing +packages named on the command line has a go.mod file, it must not contain +directives (replace and exclude) that would cause it to be interpreted +differently than if it were the main module. The module must not require +a higher version of itself. + +- Package path arguments must refer to main packages. Pattern arguments +will only match main packages. + +If the arguments don't have version suffixes, "go install" may run in +module-aware mode or GOPATH mode, depending on the GO111MODULE environment +variable and the presence of a go.mod file. See 'go help modules' for details. +If module-aware mode is enabled, "go install" runs in the context of the main +module. + +When module-aware mode is disabled, other packages are installed in the +directory $GOPATH/pkg/$GOOS_$GOARCH. When module-aware mode is enabled, +other packages are built and cached but not installed. + +The -i flag installs the dependencies of the named packages as well. +The -i flag is deprecated. Compiled packages are cached automatically. + +For more about the build flags, see 'go help build'. +For more about specifying packages, see 'go help packages'. + +See also: go build, go get, go clean. + `, +} + +// libname returns the filename to use for the shared library when using +// -buildmode=shared. The rules we use are: +// Use arguments for special 'meta' packages: +// std --> libstd.so +// std cmd --> libstd,cmd.so +// A single non-meta argument with trailing "/..." is special cased: +// foo/... --> libfoo.so +// (A relative path like "./..." expands the "." first) +// Use import paths for other cases, changing '/' to '-': +// somelib --> libsubdir-somelib.so +// ./ or ../ --> libsubdir-somelib.so +// gopkg.in/tomb.v2 -> libgopkg.in-tomb.v2.so +// a/... b/... ---> liba/c,b/d.so - all matching import paths +// Name parts are joined with ','. +func libname(args []string, pkgs []*load.Package) (string, error) { + var libname string + appendName := func(arg string) { + if libname == "" { + libname = arg + } else { + libname += "," + arg + } + } + var haveNonMeta bool + for _, arg := range args { + if search.IsMetaPackage(arg) { + appendName(arg) + } else { + haveNonMeta = true + } + } + if len(libname) == 0 { // non-meta packages only. use import paths + if len(args) == 1 && strings.HasSuffix(args[0], "/...") { + // Special case of "foo/..." as mentioned above. + arg := strings.TrimSuffix(args[0], "/...") + if build.IsLocalImport(arg) { + cwd, _ := os.Getwd() + bp, _ := cfg.BuildContext.ImportDir(filepath.Join(cwd, arg), build.FindOnly) + if bp.ImportPath != "" && bp.ImportPath != "." { + arg = bp.ImportPath + } + } + appendName(strings.ReplaceAll(arg, "/", "-")) + } else { + for _, pkg := range pkgs { + appendName(strings.ReplaceAll(pkg.ImportPath, "/", "-")) + } + } + } else if haveNonMeta { // have both meta package and a non-meta one + return "", errors.New("mixing of meta and non-meta packages is not allowed") + } + // TODO(mwhudson): Needs to change for platforms that use different naming + // conventions... + return "lib" + libname + ".so", nil +} + +func runInstall(ctx context.Context, cmd *base.Command, args []string) { + // TODO(golang.org/issue/41696): print a deprecation message for the -i flag + // whenever it's set (or just remove it). For now, we don't print a message + // if all named packages are in GOROOT. cmd/dist (run by make.bash) uses + // 'go install -i' when bootstrapping, and we don't want to show deprecation + // messages in that case. + for _, arg := range args { + if strings.Contains(arg, "@") && !build.IsLocalImport(arg) && !filepath.IsAbs(arg) { + if cfg.BuildI { + fmt.Fprint(os.Stderr, "go install: -i flag is deprecated\n") + } + installOutsideModule(ctx, args) + return + } + } + + BuildInit() + pkgs := load.PackagesAndErrors(ctx, args) + if cfg.ModulesEnabled && !modload.HasModRoot() { + haveErrors := false + allMissingErrors := true + for _, pkg := range pkgs { + if pkg.Error == nil { + continue + } + haveErrors = true + if missingErr := (*modload.ImportMissingError)(nil); !errors.As(pkg.Error, &missingErr) { + allMissingErrors = false + break + } + } + if haveErrors && allMissingErrors { + latestArgs := make([]string, len(args)) + for i := range args { + latestArgs[i] = args[i] + "@latest" + } + hint := strings.Join(latestArgs, " ") + base.Fatalf("go install: version is required when current directory is not in a module\n\tTry 'go install %s' to install the latest version", hint) + } + } + load.CheckPackageErrors(pkgs) + if cfg.BuildI { + allGoroot := true + for _, pkg := range pkgs { + if !pkg.Goroot { + allGoroot = false + break + } + } + if !allGoroot { + fmt.Fprint(os.Stderr, "go install: -i flag is deprecated\n") + } + } + + InstallPackages(ctx, args, pkgs) +} + +// 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(ctx context.Context, patterns []string, pkgs []*load.Package) { + ctx, span := trace.StartSpan(ctx, "InstallPackages "+strings.Join(patterns, " ")) + defer span.Done() + + if cfg.GOBIN != "" && !filepath.IsAbs(cfg.GOBIN) { + base.Fatalf("cannot install, GOBIN must be an absolute path") + } + + pkgs = omitTestOnly(pkgsFilter(pkgs)) + for _, p := range pkgs { + 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: + base.Errorf("go %s: no install location for .go files listed on command line (GOBIN not set)", cfg.CmdName) + case p.ConflictDir != "": + base.Errorf("go %s: no install location for %s: hidden by %s", cfg.CmdName, p.Dir, p.ConflictDir) + default: + base.Errorf("go %s: no install location for directory %s outside GOPATH\n"+ + "\tFor more details see: 'go help gopath'", cfg.CmdName, p.Dir) + } + } + } + base.ExitIfErrors() + + var b Builder + b.Init() + depMode := ModeBuild + if cfg.BuildI { + depMode = ModeInstall + } + a := &Action{Mode: "go install"} + var tools []*Action + for _, p := range pkgs { + // 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. + a1 := b.AutoAction(ModeInstall, depMode, p) + if load.InstallTargetDir(p) == load.ToTool { + a.Deps = append(a.Deps, a1.Deps...) + a1.Deps = append(a1.Deps, a) + tools = append(tools, a1) + continue + } + a.Deps = append(a.Deps, a1) + } + if len(tools) > 0 { + a = &Action{ + Mode: "go install (tools)", + Deps: tools, + } + } + + if cfg.BuildBuildmode == "shared" { + // Note: If buildmode=shared then only non-main packages + // are present in the pkgs list, so all the special case code about + // 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, patterns, pkgs, a) + } + + b.Do(ctx, a) + base.ExitIfErrors() + + // Success. If this command is 'go install' with no arguments + // and the current directory (the implicit argument) is a command, + // remove any leftover command binary from a previous 'go build'. + // The binary is installed; it's not needed here anymore. + // And worse it might be a stale copy, which you don't want to find + // instead of the installed one if $PATH contains dot. + // 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(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 := pkgs[0].DefaultExecName() + targ += cfg.ExeSuffix + if filepath.Join(pkgs[0].Dir, targ) != pkgs[0].Target { // maybe $GOBIN is the current directory + fi, err := os.Stat(targ) + if err == nil { + m := fi.Mode() + if m.IsRegular() { + if m&0111 != 0 || cfg.Goos == "windows" { // windows never sets executable bit + os.Remove(targ) + } + } + } + } + } +} + +// installOutsideModule implements 'go install pkg@version'. It builds and +// installs one or more main packages in module mode while ignoring any go.mod +// in the current directory or parent directories. +// +// See golang.org/issue/40276 for details and rationale. +func installOutsideModule(ctx context.Context, args []string) { + modload.ForceUseModules = true + modload.RootMode = modload.NoRoot + modload.AllowMissingModuleImports() + modload.Init() + + // Check that the arguments satisfy syntactic constraints. + var version string + for _, arg := range args { + if i := strings.Index(arg, "@"); i >= 0 { + version = arg[i+1:] + if version == "" { + base.Fatalf("go install %s: version must not be empty", arg) + } + break + } + } + patterns := make([]string, len(args)) + for i, arg := range args { + if !strings.HasSuffix(arg, "@"+version) { + base.Errorf("go install %s: all arguments must have the same version (@%s)", arg, version) + continue + } + p := arg[:len(arg)-len(version)-1] + switch { + case build.IsLocalImport(p): + base.Errorf("go install %s: argument must be a package path, not a relative path", arg) + case filepath.IsAbs(p): + base.Errorf("go install %s: argument must be a package path, not an absolute path", arg) + case search.IsMetaPackage(p): + base.Errorf("go install %s: argument must be a package path, not a meta-package", arg) + case path.Clean(p) != p: + base.Errorf("go install %s: argument must be a clean package path", arg) + case !strings.Contains(p, "...") && search.IsStandardImportPath(p) && goroot.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, p): + base.Errorf("go install %s: argument must not be a package in the standard library", arg) + default: + patterns[i] = p + } + } + base.ExitIfErrors() + BuildInit() + + // Query the module providing the first argument, load its go.mod file, and + // check that it doesn't contain directives that would cause it to be + // interpreted differently if it were the main module. + // + // If multiple modules match the first argument, accept the longest match + // (first result). It's possible this module won't provide packages named by + // later arguments, and other modules would. Let's not try to be too + // magical though. + allowed := modload.CheckAllowed + if modload.IsRevisionQuery(version) { + // Don't check for retractions if a specific revision is requested. + allowed = nil + } + noneSelected := func(path string) (version string) { return "none" } + qrs, err := modload.QueryPackages(ctx, patterns[0], version, noneSelected, allowed) + if err != nil { + base.Fatalf("go install %s: %v", args[0], err) + } + installMod := qrs[0].Mod + data, err := modfetch.GoMod(installMod.Path, installMod.Version) + if err != nil { + base.Fatalf("go install %s: %v", args[0], err) + } + f, err := modfile.Parse("go.mod", data, nil) + if err != nil { + base.Fatalf("go install %s: %s: %v", args[0], installMod, err) + } + directiveFmt := "go install %s: %s\n" + + "\tThe go.mod file for the module providing named packages contains one or\n" + + "\tmore %s directives. It must not contain directives that would cause\n" + + "\tit to be interpreted differently than if it were the main module." + if len(f.Replace) > 0 { + base.Fatalf(directiveFmt, args[0], installMod, "replace") + } + if len(f.Exclude) > 0 { + base.Fatalf(directiveFmt, args[0], installMod, "exclude") + } + + // Since we are in NoRoot mode, the build list initially contains only + // the dummy command-line-arguments module. Add a requirement on the + // module that provides the packages named on the command line. + if err := modload.EditBuildList(ctx, nil, []module.Version{installMod}); err != nil { + base.Fatalf("go install %s: %v", args[0], err) + } + + // Load packages for all arguments. Ignore non-main packages. + // Print a warning if an argument contains "..." and matches no main packages. + // PackagesAndErrors already prints warnings for patterns that don't match any + // packages, so be careful not to double print. + matchers := make([]func(string) bool, len(patterns)) + for i, p := range patterns { + if strings.Contains(p, "...") { + matchers[i] = search.MatchPattern(p) + } + } + + // TODO(golang.org/issue/40276): don't report errors loading non-main packages + // matched by a pattern. + pkgs := load.PackagesAndErrors(ctx, patterns) + load.CheckPackageErrors(pkgs) + mainPkgs := make([]*load.Package, 0, len(pkgs)) + mainCount := make([]int, len(patterns)) + nonMainCount := make([]int, len(patterns)) + for _, pkg := range pkgs { + if pkg.Name == "main" { + mainPkgs = append(mainPkgs, pkg) + for i := range patterns { + if matchers[i] != nil && matchers[i](pkg.ImportPath) { + mainCount[i]++ + } + } + } else { + for i := range patterns { + if matchers[i] == nil && patterns[i] == pkg.ImportPath { + base.Errorf("go install: package %s is not a main package", pkg.ImportPath) + } else if matchers[i] != nil && matchers[i](pkg.ImportPath) { + nonMainCount[i]++ + } + } + } + } + base.ExitIfErrors() + for i, p := range patterns { + if matchers[i] != nil && mainCount[i] == 0 && nonMainCount[i] > 0 { + fmt.Fprintf(os.Stderr, "go: warning: %q matched no main packages\n", p) + } + } + + // Check that named packages are all provided by the same module. + for _, pkg := range mainPkgs { + if pkg.Module == nil { + // Packages in std, cmd, and their vendored dependencies + // don't have this field set. + base.Errorf("go install: package %s not provided by module %s", pkg.ImportPath, installMod) + } else if pkg.Module.Path != installMod.Path || pkg.Module.Version != installMod.Version { + base.Errorf("go install: package %s provided by module %s@%s\n\tAll packages must be provided by the same module (%s).", pkg.ImportPath, pkg.Module.Path, pkg.Module.Version, installMod) + } + } + base.ExitIfErrors() + + // Build and install the packages. + InstallPackages(ctx, patterns, mainPkgs) +} + +// ExecCmd is the command to use to run user binaries. +// Normally it is empty, meaning run the binaries directly. +// If cross-compiling and running on a remote system or +// simulator, it is typically go_GOOS_GOARCH_exec, with +// the target GOOS and GOARCH substituted. +// The -exec flag overrides these defaults. +var ExecCmd []string + +// FindExecCmd derives the value of ExecCmd to use. +// It returns that value and leaves ExecCmd set for direct use. +func FindExecCmd() []string { + if ExecCmd != nil { + return ExecCmd + } + ExecCmd = []string{} // avoid work the second time + if cfg.Goos == runtime.GOOS && cfg.Goarch == runtime.GOARCH { + return ExecCmd + } + path, err := exec.LookPath(fmt.Sprintf("go_%s_%s_exec", cfg.Goos, cfg.Goarch)) + if err == nil { + ExecCmd = []string{path} + } + return ExecCmd +} diff --git a/src/cmd/go/internal/work/build_test.go b/src/cmd/go/internal/work/build_test.go new file mode 100644 index 0000000..eaf2639 --- /dev/null +++ b/src/cmd/go/internal/work/build_test.go @@ -0,0 +1,277 @@ +// Copyright 2016 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 work + +import ( + "bytes" + "fmt" + "io/fs" + "os" + "path/filepath" + "reflect" + "runtime" + "strings" + "testing" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/load" +) + +func TestRemoveDevNull(t *testing.T) { + fi, err := os.Lstat(os.DevNull) + if err != nil { + t.Skip(err) + } + if fi.Mode().IsRegular() { + t.Errorf("Lstat(%s).Mode().IsRegular() = true; expected false", os.DevNull) + } + mayberemovefile(os.DevNull) + _, err = os.Lstat(os.DevNull) + if err != nil { + t.Errorf("mayberemovefile(%s) did remove it; oops", os.DevNull) + } +} + +func TestSplitPkgConfigOutput(t *testing.T) { + for _, test := range []struct { + in []byte + want []string + }{ + {[]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("\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, 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) { + // TODO(avdva) - make these values platform-specific + prefix := "lib" + suffix := ".so" + testData := []struct { + args []string + pkgs []*load.Package + expected string + expectErr bool + rootedAt string + }{ + { + args: []string{"std"}, + pkgs: []*load.Package{}, + expected: "std", + }, + { + args: []string{"std", "cmd"}, + pkgs: []*load.Package{}, + expected: "std,cmd", + }, + { + args: []string{}, + pkgs: []*load.Package{pkgImportPath("gopkg.in/somelib")}, + expected: "gopkg.in-somelib", + }, + { + args: []string{"./..."}, + pkgs: []*load.Package{pkgImportPath("somelib")}, + expected: "somelib", + rootedAt: "somelib", + }, + { + args: []string{"../somelib", "../somelib"}, + pkgs: []*load.Package{pkgImportPath("somelib")}, + expected: "somelib", + }, + { + args: []string{"../lib1", "../lib2"}, + pkgs: []*load.Package{pkgImportPath("gopkg.in/lib1"), pkgImportPath("gopkg.in/lib2")}, + expected: "gopkg.in-lib1,gopkg.in-lib2", + }, + { + args: []string{"./..."}, + pkgs: []*load.Package{ + pkgImportPath("gopkg.in/dir/lib1"), + pkgImportPath("gopkg.in/lib2"), + pkgImportPath("gopkg.in/lib3"), + }, + expected: "gopkg.in", + rootedAt: "gopkg.in", + }, + { + args: []string{"std", "../lib2"}, + pkgs: []*load.Package{}, + expectErr: true, + }, + { + args: []string{"all", "./"}, + pkgs: []*load.Package{}, + expectErr: true, + }, + { + args: []string{"cmd", "fmt"}, + pkgs: []*load.Package{}, + expectErr: true, + }, + } + for _, data := range testData { + func() { + if data.rootedAt != "" { + tmpGopath, err := os.MkdirTemp("", "gopath") + if err != nil { + t.Fatal(err) + } + oldGopath := cfg.BuildContext.GOPATH + defer func() { + cfg.BuildContext.GOPATH = oldGopath + os.Chdir(base.Cwd) + err := os.RemoveAll(tmpGopath) + if err != nil { + t.Error(err) + } + }() + root := filepath.Join(tmpGopath, "src", data.rootedAt) + err = os.MkdirAll(root, 0755) + if err != nil { + t.Fatal(err) + } + cfg.BuildContext.GOPATH = tmpGopath + os.Chdir(root) + } + computed, err := libname(data.args, data.pkgs) + if err != nil { + if !data.expectErr { + t.Errorf("libname returned an error %q, expected a name", err.Error()) + } + } else if data.expectErr { + t.Errorf("libname returned %q, expected an error", computed) + } else { + expected := prefix + data.expected + suffix + if expected != computed { + t.Errorf("libname returned %q, expected %q", computed, expected) + } + } + }() + } +} + +func pkgImportPath(pkgpath string) *load.Package { + return &load.Package{ + PackagePublic: load.PackagePublic{ + ImportPath: pkgpath, + }, + } +} + +// When installing packages, the installed package directory should +// respect the SetGID bit and group name of the destination +// directory. +// See https://golang.org/issue/18878. +func TestRespectSetgidDir(t *testing.T) { + switch runtime.GOOS { + case "ios": + t.Skip("can't set SetGID bit with chmod on iOS") + case "windows", "plan9": + t.Skip("chown/chmod setgid are not supported on Windows or Plan 9") + } + + var b Builder + + // Check that `cp` is called instead of `mv` by looking at the output + // of `(*Builder).ShowCmd` afterwards as a sanity check. + cfg.BuildX = true + var cmdBuf bytes.Buffer + b.Print = func(a ...interface{}) (int, error) { + return cmdBuf.WriteString(fmt.Sprint(a...)) + } + + setgiddir, err := os.MkdirTemp("", "SetGroupID") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(setgiddir) + + // BSD mkdir(2) inherits the parent directory group, and other platforms + // can inherit the parent directory group via setgid. The test setup (chmod + // setgid) will fail if the process does not have the group permission to + // the new temporary directory. + err = os.Chown(setgiddir, os.Getuid(), os.Getgid()) + if err != nil { + t.Fatal(err) + } + + // Change setgiddir's permissions to include the SetGID bit. + if err := os.Chmod(setgiddir, 0755|fs.ModeSetgid); err != nil { + t.Fatal(err) + } + + pkgfile, err := os.CreateTemp("", "pkgfile") + if err != nil { + t.Fatalf("os.CreateTemp(\"\", \"pkgfile\"): %v", err) + } + defer os.Remove(pkgfile.Name()) + defer pkgfile.Close() + + dirGIDFile := filepath.Join(setgiddir, "setgid") + if err := b.moveOrCopyFile(dirGIDFile, pkgfile.Name(), 0666, true); err != nil { + t.Fatalf("moveOrCopyFile: %v", err) + } + + got := strings.TrimSpace(cmdBuf.String()) + want := b.fmtcmd("", "cp %s %s", pkgfile.Name(), dirGIDFile) + if got != want { + t.Fatalf("moveOrCopyFile(%q, %q): want %q, got %q", dirGIDFile, pkgfile.Name(), want, got) + } +} diff --git a/src/cmd/go/internal/work/buildid.go b/src/cmd/go/internal/work/buildid.go new file mode 100644 index 0000000..c555d4a --- /dev/null +++ b/src/cmd/go/internal/work/buildid.go @@ -0,0 +1,698 @@ +// 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 work + +import ( + "bytes" + "fmt" + exec "internal/execabs" + "os" + "strings" + + "cmd/go/internal/base" + "cmd/go/internal/cache" + "cmd/go/internal/cfg" + "cmd/go/internal/fsys" + "cmd/go/internal/str" + "cmd/internal/buildid" +) + +// Build IDs +// +// Go packages and binaries are stamped with build IDs that record both +// the action ID, which is a hash of the inputs to the action that produced +// the packages or binary, and the content ID, which is a hash of the action +// output, namely the archive or binary itself. The hash is the same one +// used by the build artifact cache (see cmd/go/internal/cache), but +// truncated when stored in packages and binaries, as the full length is not +// needed and is a bit unwieldy. The precise form is +// +// actionID/[.../]contentID +// +// where the actionID and contentID are prepared by buildid.HashToString below. +// and are found by looking for the first or last slash. +// Usually the buildID is simply actionID/contentID, but see below for an +// exception. +// +// The build ID serves two primary purposes. +// +// 1. The action ID half allows installed packages and binaries to serve as +// one-element cache entries. If we intend to build math.a with a given +// set of inputs summarized in the action ID, and the installed math.a already +// has that action ID, we can reuse the installed math.a instead of rebuilding it. +// +// 2. The content ID half allows the easy preparation of action IDs for steps +// that consume a particular package or binary. The content hash of every +// input file for a given action must be included in the action ID hash. +// Storing the content ID in the build ID lets us read it from the file with +// minimal I/O, instead of reading and hashing the entire file. +// This is especially effective since packages and binaries are typically +// the largest inputs to an action. +// +// Separating action ID from content ID is important for reproducible builds. +// The compiler is compiled with itself. If an output were represented by its +// own action ID (instead of content ID) when computing the action ID of +// the next step in the build process, then the compiler could never have its +// own input action ID as its output action ID (short of a miraculous hash collision). +// Instead we use the content IDs to compute the next action ID, and because +// the content IDs converge, so too do the action IDs and therefore the +// build IDs and the overall compiler binary. See cmd/dist's cmdbootstrap +// for the actual convergence sequence. +// +// The “one-element cache” purpose is a bit more complex for installed +// binaries. For a binary, like cmd/gofmt, there are two steps: compile +// cmd/gofmt/*.go into main.a, and then link main.a into the gofmt binary. +// We do not install gofmt's main.a, only the gofmt binary. Being able to +// decide that the gofmt binary is up-to-date means computing the action ID +// for the final link of the gofmt binary and comparing it against the +// already-installed gofmt binary. But computing the action ID for the link +// means knowing the content ID of main.a, which we did not keep. +// To sidestep this problem, each binary actually stores an expanded build ID: +// +// actionID(binary)/actionID(main.a)/contentID(main.a)/contentID(binary) +// +// (Note that this can be viewed equivalently as: +// +// actionID(binary)/buildID(main.a)/contentID(binary) +// +// Storing the buildID(main.a) in the middle lets the computations that care +// about the prefix or suffix halves ignore the middle and preserves the +// original build ID as a contiguous string.) +// +// During the build, when it's time to build main.a, the gofmt binary has the +// information needed to decide whether the eventual link would produce +// the same binary: if the action ID for main.a's inputs matches and then +// the action ID for the link step matches when assuming the given main.a +// content ID, then the binary as a whole is up-to-date and need not be rebuilt. +// +// This is all a bit complex and may be simplified once we can rely on the +// main cache, but at least at the start we will be using the content-based +// staleness determination without a cache beyond the usual installed +// package and binary locations. + +const buildIDSeparator = "/" + +// actionID returns the action ID half of a build ID. +func actionID(buildID string) string { + i := strings.Index(buildID, buildIDSeparator) + if i < 0 { + return buildID + } + return buildID[:i] +} + +// contentID returns the content ID half of a build ID. +func contentID(buildID string) string { + return buildID[strings.LastIndex(buildID, buildIDSeparator)+1:] +} + +// toolID returns the unique ID to use for the current copy of the +// named tool (asm, compile, cover, link). +// +// It is important that if the tool changes (for example a compiler bug is fixed +// and the compiler reinstalled), toolID returns a different string, so that old +// package archives look stale and are rebuilt (with the fixed compiler). +// This suggests using a content hash of the tool binary, as stored in the build ID. +// +// Unfortunately, we can't just open the tool binary, because the tool might be +// invoked via a wrapper program specified by -toolexec and we don't know +// what the wrapper program does. In particular, we want "-toolexec toolstash" +// to continue working: it does no good if "-toolexec toolstash" is executing a +// stashed copy of the compiler but the go command is acting as if it will run +// the standard copy of the compiler. The solution is to ask the tool binary to tell +// us its own build ID using the "-V=full" flag now supported by all tools. +// Then we know we're getting the build ID of the compiler that will actually run +// during the build. (How does the compiler binary know its own content hash? +// We store it there using updateBuildID after the standard link step.) +// +// A final twist is that we'd prefer to have reproducible builds for release toolchains. +// It should be possible to cross-compile for Windows from either Linux or Mac +// or Windows itself and produce the same binaries, bit for bit. If the tool ID, +// which influences the action ID half of the build ID, is based on the content ID, +// then the Linux compiler binary and Mac compiler binary will have different tool IDs +// and therefore produce executables with different action IDs. +// To avoid this problem, for releases we use the release version string instead +// of the compiler binary's content hash. This assumes that all compilers built +// on all different systems are semantically equivalent, which is of course only true +// modulo bugs. (Producing the exact same executables also requires that the different +// build setups agree on details like $GOROOT and file name paths, but at least the +// tool IDs do not make it impossible.) +func (b *Builder) toolID(name string) string { + b.id.Lock() + id := b.toolIDCache[name] + b.id.Unlock() + + if id != "" { + return id + } + + path := base.Tool(name) + desc := "go tool " + name + + // Special case: undocumented -vettool overrides usual vet, + // for testing vet or supplying an alternative analysis tool. + 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.AppendPWD(os.Environ(), cmd.Dir) + var stdout, stderr bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = &stderr + if err := cmd.Run(); err != nil { + 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 && 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. + id = contentID(f[len(f)-1]) + } else { + // For a release, the output is like: "compile version go1.9.1 X:framepointer". + // Use the whole line. + id = strings.TrimSpace(line) + } + + b.id.Lock() + b.toolIDCache[name] = id + b.id.Unlock() + + return id +} + +// gccToolID returns the unique ID to use for a tool that is invoked +// by the GCC driver. This is used particularly for gccgo, but this can also +// be used for gcc, g++, gfortran, etc.; those tools all use the GCC +// driver under different names. The approach used here should also +// work for sufficiently new versions of clang. Unlike toolID, the +// name argument is the program to run. The language argument is the +// type of input file as passed to the GCC driver's -x option. +// +// For these tools we have no -V=full option to dump the build ID, +// but we can run the tool with -v -### to reliably get the compiler proper +// and hash that. That will work in the presence of -toolexec. +// +// In order to get reproducible builds for released compilers, we +// detect a released compiler by the absence of "experimental" in the +// --version output, and in that case we just use the version string. +func (b *Builder) gccgoToolID(name, language string) (string, error) { + key := name + "." + language + b.id.Lock() + id := b.toolIDCache[key] + b.id.Unlock() + + if id != "" { + return id, nil + } + + // Invoke the driver with -### to see the subcommands and the + // version strings. Use -x to set the language. Pretend to + // compile an empty file on standard input. + cmdline := str.StringList(cfg.BuildToolexec, name, "-###", "-x", language, "-c", "-") + cmd := exec.Command(cmdline[0], cmdline[1:]...) + cmd.Env = base.AppendPWD(os.Environ(), cmd.Dir) + // Force untranslated output so that we see the string "version". + cmd.Env = append(cmd.Env, "LC_ALL=C") + out, err := cmd.CombinedOutput() + if err != nil { + return "", fmt.Errorf("%s: %v; output: %q", name, err, out) + } + + version := "" + lines := strings.Split(string(out), "\n") + for _, line := range lines { + if fields := strings.Fields(line); len(fields) > 1 && fields[1] == "version" { + version = line + break + } + } + if version == "" { + return "", fmt.Errorf("%s: can not find version number in %q", name, out) + } + + if !strings.Contains(version, "experimental") { + // This is a release. Use this line as the tool ID. + id = version + } else { + // This is a development version. The first line with + // a leading space is the compiler proper. + compiler := "" + for _, line := range lines { + if len(line) > 1 && line[0] == ' ' { + compiler = line + break + } + } + if compiler == "" { + return "", fmt.Errorf("%s: can not find compilation command in %q", name, out) + } + + fields := strings.Fields(compiler) + if len(fields) == 0 { + return "", fmt.Errorf("%s: compilation command confusion %q", name, out) + } + exe := fields[0] + if !strings.ContainsAny(exe, `/\`) { + if lp, err := exec.LookPath(exe); err == nil { + exe = lp + } + } + id, err = buildid.ReadFile(exe) + if err != nil { + return "", err + } + + // If we can't find a build ID, use a hash. + if id == "" { + id = b.fileHash(exe) + } + } + + b.id.Lock() + b.toolIDCache[key] = id + b.id.Unlock() + + return id, nil +} + +// Check if assembler used by gccgo is GNU as. +func assemblerIsGas() bool { + cmd := exec.Command(BuildToolchain.compiler(), "-print-prog-name=as") + assembler, err := cmd.Output() + if err == nil { + cmd := exec.Command(strings.TrimSpace(string(assembler)), "--version") + out, err := cmd.Output() + return err == nil && strings.Contains(string(out), "GNU") + } else { + return false + } +} + +// gccgoBuildIDFile creates an assembler file that records the +// action's build ID in an SHF_EXCLUDE section for ELF files or +// in a CSECT in XCOFF files. +func (b *Builder) gccgoBuildIDFile(a *Action) (string, error) { + sfile := a.Objdir + "_buildid.s" + + var buf bytes.Buffer + if cfg.Goos == "aix" { + fmt.Fprintf(&buf, "\t.csect .go.buildid[XO]\n") + } else if (cfg.Goos != "solaris" && cfg.Goos != "illumos") || assemblerIsGas() { + fmt.Fprintf(&buf, "\t"+`.section .go.buildid,"e"`+"\n") + } else if cfg.Goarch == "sparc" || cfg.Goarch == "sparc64" { + fmt.Fprintf(&buf, "\t"+`.section ".go.buildid",#exclude`+"\n") + } else { // cfg.Goarch == "386" || cfg.Goarch == "amd64" + fmt.Fprintf(&buf, "\t"+`.section .go.buildid,#exclude`+"\n") + } + fmt.Fprintf(&buf, "\t.byte ") + for i := 0; i < len(a.buildID); i++ { + if i > 0 { + if i%8 == 0 { + fmt.Fprintf(&buf, "\n\t.byte ") + } else { + fmt.Fprintf(&buf, ",") + } + } + fmt.Fprintf(&buf, "%#02x", a.buildID[i]) + } + fmt.Fprintf(&buf, "\n") + if cfg.Goos != "solaris" && cfg.Goos != "illumos" && cfg.Goos != "aix" { + secType := "@progbits" + if cfg.Goarch == "arm" { + secType = "%progbits" + } + fmt.Fprintf(&buf, "\t"+`.section .note.GNU-stack,"",%s`+"\n", secType) + fmt.Fprintf(&buf, "\t"+`.section .note.GNU-split-stack,"",%s`+"\n", secType) + } + + if cfg.BuildN || cfg.BuildX { + for _, line := range bytes.Split(buf.Bytes(), []byte("\n")) { + b.Showcmd("", "echo '%s' >> %s", line, sfile) + } + if cfg.BuildN { + return sfile, nil + } + } + + if err := os.WriteFile(sfile, buf.Bytes(), 0666); err != nil { + return "", err + } + + return sfile, nil +} + +// buildID returns the build ID found in the given file. +// If no build ID is found, buildID returns the content hash of the file. +func (b *Builder) buildID(file string) string { + b.id.Lock() + id := b.buildIDCache[file] + b.id.Unlock() + + if id != "" { + return id + } + + id, err := buildid.ReadFile(file) + if err != nil { + id = b.fileHash(file) + } + + b.id.Lock() + b.buildIDCache[file] = id + b.id.Unlock() + + return id +} + +// fileHash returns the content hash of the named file. +func (b *Builder) fileHash(file string) string { + file, _ = fsys.OverlayPath(file) + sum, err := cache.FileHash(file) + if err != nil { + return "" + } + return buildid.HashToString(sum) +} + +// useCache tries to satisfy the action a, which has action ID actionHash, +// by using a cached result from an earlier build. At the moment, the only +// cached result is the installed package or binary at target. +// If useCache decides that the cache can be used, it sets a.buildID +// and a.built for use by parent actions and then returns true. +// Otherwise it sets a.buildID to a temporary build ID for use in the build +// and returns false. When useCache returns false the expectation is that +// the caller will build the target and then call updateBuildID to finish the +// build ID computation. +// When useCache returns false, it may have initiated buffering of output +// during a's work. The caller should defer b.flushOutput(a), to make sure +// that flushOutput is eventually called regardless of whether the action +// succeeds. The flushOutput call must happen after updateBuildID. +func (b *Builder) useCache(a *Action, actionHash cache.ActionID, target string) bool { + // The second half of the build ID here is a placeholder for the content hash. + // It's important that the overall buildID be unlikely verging on impossible + // to appear in the output by chance, but that should be taken care of by + // the actionID half; if it also appeared in the input that would be like an + // engineered 120-bit partial SHA256 collision. + a.actionID = actionHash + actionID := buildid.HashToString(actionHash) + if a.json != nil { + a.json.ActionID = actionID + } + contentID := actionID // temporary placeholder, likely unique + a.buildID = actionID + buildIDSeparator + contentID + + // Executable binaries also record the main build ID in the middle. + // See "Build IDs" comment above. + if a.Mode == "link" { + mainpkg := a.Deps[0] + a.buildID = actionID + buildIDSeparator + mainpkg.buildID + buildIDSeparator + contentID + } + + // Check to see if target exists and matches the expected action ID. + // If so, it's up to date and we can reuse it instead of rebuilding it. + var buildID string + if target != "" && !cfg.BuildA { + buildID, _ = buildid.ReadFile(target) + if strings.HasPrefix(buildID, actionID+buildIDSeparator) { + a.buildID = buildID + if a.json != nil { + a.json.BuildID = a.buildID + } + a.built = target + // Poison a.Target to catch uses later in the build. + a.Target = "DO NOT USE - " + a.Mode + return true + } + } + + // Special case for building a main package: if the only thing we + // want the package for is to link a binary, and the binary is + // 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 && !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) + if len(id) == 4 && id[1] == actionID { + // Temporarily assume a.buildID is the package build ID + // stored in the installed binary, and see if that makes + // the upcoming link action ID a match. If so, report that + // we built the package, safe in the knowledge that the + // link step will not ask us for the actual package file. + // Note that (*Builder).LinkAction arranged that all of + // a.triggers[0]'s dependencies other than a are also + // dependencies of a, so that we can be sure that, + // other than a.buildID, b.linkActionID is only accessing + // build IDs of completed actions. + oldBuildID := a.buildID + a.buildID = id[1] + buildIDSeparator + id[2] + linkID := buildid.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" + if a.json != nil { + a.json.BuildID = a.buildID + } + return true + } + // Otherwise restore old build ID for main build. + a.buildID = oldBuildID + } + } + } + + // Special case for linking a test binary: if the only thing we + // want the binary for is to run the test, and the test result is cached, + // then to avoid the link step, report the link as up-to-date. + // 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.IsCmdList { + // Invoked during go list to compute and record staleness. + if p := a.Package; p != nil && !p.Stale { + p.Stale = true + if cfg.BuildA { + p.StaleReason = "build -a flag in use" + } else { + p.StaleReason = "build ID mismatch" + for _, p1 := range p.Internal.Imports { + if p1.Stale && p1.StaleReason != "" { + if strings.HasPrefix(p1.StaleReason, "stale dependency: ") { + p.StaleReason = p1.StaleReason + break + } + if strings.HasPrefix(p.StaleReason, "build ID mismatch") { + p.StaleReason = "stale dependency: " + p1.ImportPath + } + } + } + } + } + + // Fall through to update a.buildID from the build artifact cache, + // which will affect the computation of buildIDs for targets + // higher up in the dependency graph. + } + + // Check the build artifact cache. + // We treat hits in this cache as being "stale" for the purposes of go list + // (in effect, "stale" means whether p.Target is up-to-date), + // but we're still happy to use results from the build artifact cache. + if c := cache.Default(); c != nil { + if !cfg.BuildA { + 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 + if a.json != nil { + a.json.BuildID = a.buildID + } + if p := a.Package; p != nil { + // Clearer than explaining that something else is stale. + p.StaleReason = "not installed but available in build cache" + } + return true + } + } + } + } + + // Begin saving output for later writing to cache. + a.output = []byte{} + } + + 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 + } + + 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. +func (b *Builder) flushOutput(a *Action) { + b.Print(string(a.output)) + a.output = nil +} + +// updateBuildID updates the build ID in the target written by action a. +// It requires that useCache was called for action a and returned false, +// and that the build was then carried out and given the temporary +// a.buildID to record as the build ID in the resulting package or binary. +// updateBuildID computes the final content ID and updates the build IDs +// in the binary. +// +// Keep in sync with src/cmd/buildid/buildid.go +func (b *Builder) updateBuildID(a *Action, target string, rewrite bool) error { + if cfg.BuildX || cfg.BuildN { + if rewrite { + b.Showcmd("", "%s # internal", joinUnambiguously(str.StringList(base.Tool("buildid"), "-w", target))) + } + if cfg.BuildN { + return nil + } + } + + // 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 { + return err + } + matches, hash, err := buildid.FindAndHash(r, a.buildID, 0) + r.Close() + if err != nil { + return err + } + newID := a.buildID[:strings.LastIndex(a.buildID, buildIDSeparator)] + buildIDSeparator + buildid.HashToString(hash) + if len(newID) != len(a.buildID) { + return fmt.Errorf("internal error: build ID length mismatch %q vs %q", a.buildID, newID) + } + + // Replace with new content-based ID. + a.buildID = newID + if a.json != nil { + a.json.BuildID = a.buildID + } + if len(matches) == 0 { + // Assume the user specified -buildid= to override what we were going to choose. + return nil + } + + if rewrite { + w, err := os.OpenFile(target, os.O_RDWR, 0) + if err != nil { + return err + } + err = buildid.Rewrite(w, matches, newID) + if err != nil { + w.Close() + return err + } + if err := w.Close(); err != nil { + return err + } + } + + // Cache package builds, but not binaries (link steps). + // The expectation is that binaries are not reused + // nearly as often as individual packages, and they're + // much larger, so the cache-footprint-to-utility ratio + // of binaries is much lower for binaries. + // Not caching the link step also makes sure that repeated "go run" at least + // always rerun the linker, so that they don't get too fast. + // (We don't want people thinking go is a scripting language.) + // Note also that if we start caching binaries, then we will + // copy the binaries out of the cache to run them, and then + // that will mean the go process is itself writing a binary + // and then executing it, so we will need to defend against + // ETXTBSY problems as discussed in exec.go and golang.org/issue/22220. + if c := cache.Default(); c != nil && a.Mode == "build" { + r, err := os.Open(target) + if err == nil { + if a.output == nil { + 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)))) + } + if b.NeedExport { + if err != nil { + return err + } + a.Package.Export = c.OutputFile(outputID) + a.Package.BuildID = a.buildID + } + } + } + + return nil +} diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go new file mode 100644 index 0000000..422e83c --- /dev/null +++ b/src/cmd/go/internal/work/exec.go @@ -0,0 +1,3316 @@ +// Copyright 2011 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. + +// Action graph execution. + +package work + +import ( + "bytes" + "cmd/go/internal/fsys" + "context" + "encoding/json" + "errors" + "fmt" + exec "internal/execabs" + "internal/lazyregexp" + "io" + "io/fs" + "log" + "math/rand" + "os" + "path/filepath" + "regexp" + "runtime" + "strconv" + "strings" + "sync" + "time" + + "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/trace" +) + +// actionList returns the list of actions in the dag rooted at root +// as visited in a depth-first post-order traversal. +func actionList(root *Action) []*Action { + seen := map[*Action]bool{} + all := []*Action{} + var walk func(*Action) + walk = func(a *Action) { + if seen[a] { + return + } + seen[a] = true + for _, a1 := range a.Deps { + walk(a1) + } + all = append(all, a) + } + walk(root) + return all +} + +// do runs the action graph rooted at root. +func (b *Builder) Do(ctx context.Context, root *Action) { + ctx, span := trace.StartSpan(ctx, "exec.Builder.Do ("+root.Mode+" "+root.Target+")") + defer span.Done() + + if !b.IsCmdList { + // If we're doing real work, take time at the end to trim the cache. + c := cache.Default() + defer c.Trim() + } + + // Build list of all actions, assigning depth-first post-order priority. + // The original implementation here was a true queue + // (using a channel) but it had the effect of getting + // distracted by low-level leaf actions to the detriment + // of completing higher-level actions. The order of + // work does not matter much to overall execution time, + // but when running "go test std" it is nice to see each test + // results as soon as possible. The priorities assigned + // ensure that, all else being equal, the execution prefers + // to do what it would have done first in a simple depth-first + // dependency order traversal. + all := actionList(root) + for i, a := range all { + a.priority = i + } + + // Write action graph, without timing information, in case we fail and exit early. + writeActionGraph := func() { + if file := cfg.DebugActiongraph; file != "" { + if strings.HasSuffix(file, ".go") { + // Do not overwrite Go source code in: + // go build -debug-actiongraph x.go + base.Fatalf("go: refusing to write action graph to %v\n", file) + } + js := actionGraphJSON(root) + if err := os.WriteFile(file, []byte(js), 0666); err != nil { + fmt.Fprintf(os.Stderr, "go: writing action graph: %v\n", err) + base.SetExitStatus(1) + } + } + } + writeActionGraph() + + b.readySema = make(chan bool, len(all)) + + // Initialize per-action execution state. + for _, a := range all { + for _, a1 := range a.Deps { + a1.triggers = append(a1.triggers, a) + } + a.pending = len(a.Deps) + if a.pending == 0 { + b.ready.push(a) + b.readySema <- true + } + } + + // Handle runs a single action and takes care of triggering + // any actions that are runnable as a result. + handle := func(ctx context.Context, a *Action) { + if a.json != nil { + a.json.TimeStart = time.Now() + } + var err error + if a.Func != nil && (!a.Failed || a.IgnoreFail) { + // TODO(matloob): Better action descriptions + desc := "Executing action " + if a.Package != nil { + desc += "(" + a.Mode + " " + a.Package.Desc() + ")" + } + ctx, span := trace.StartSpan(ctx, desc) + a.traceSpan = span + for _, d := range a.Deps { + trace.Flow(ctx, d.traceSpan, a.traceSpan) + } + err = a.Func(b, ctx, a) + span.Done() + } + if a.json != nil { + a.json.TimeDone = time.Now() + } + + // The actions run in parallel but all the updates to the + // shared work state are serialized through b.exec. + b.exec.Lock() + defer b.exec.Unlock() + + if err != nil { + if err == errPrintedOutput { + base.SetExitStatus(2) + } else { + base.Errorf("%s", err) + } + a.Failed = true + } + + for _, a0 := range a.triggers { + if a.Failed { + a0.Failed = true + } + if a0.pending--; a0.pending == 0 { + b.ready.push(a0) + b.readySema <- true + } + } + + if a == root { + close(b.readySema) + } + } + + var wg sync.WaitGroup + + // Kick off goroutines according to parallelism. + // If we are using the -n flag (just printing commands) + // drop the parallelism to 1, both to make the output + // deterministic and because there is no real work anyway. + par := cfg.BuildP + if cfg.BuildN { + par = 1 + } + for i := 0; i < par; i++ { + wg.Add(1) + go func() { + ctx := trace.StartGoroutine(ctx) + defer wg.Done() + for { + select { + case _, ok := <-b.readySema: + if !ok { + return + } + // Receiving a value from b.readySema entitles + // us to take from the ready queue. + b.exec.Lock() + a := b.ready.pop() + b.exec.Unlock() + handle(ctx, a) + case <-base.Interrupted: + base.SetExitStatus(1) + return + } + } + }() + } + + wg.Wait() + + // Write action graph again, this time with timing information. + writeActionGraph() +} + +// buildActionID computes the action ID for a build action. +func (b *Builder) buildActionID(a *Action) cache.ActionID { + p := a.Package + h := cache.NewHash("build " + p.ImportPath) + + // Configuration independent of compiler toolchain. + // Note: buildmode has already been accounted for in buildGcflags + // and should not be inserted explicitly. Most buildmodes use the + // same compiler settings and can reuse each other's results. + // If not, the reason is already recorded in buildGcflags. + fmt.Fprintf(h, "compile\n") + // Only include the package directory if it may affect the output. + // We trim workspace paths for all packages when -trimpath is set. + // The compiler hides the exact value of $GOROOT + // when building things in GOROOT. + // Assume b.WorkDir is being trimmed properly. + // When -trimpath is used with a package built from the module cache, + // use the module path and version instead of the directory. + if !p.Goroot && !cfg.BuildTrimpath && !strings.HasPrefix(p.Dir, b.WorkDir) { + fmt.Fprintf(h, "dir %s\n", p.Dir) + } else if cfg.BuildTrimpath && p.Module != nil { + fmt.Fprintf(h, "module %s@%s\n", p.Module.Path, p.Module.Version) + } + if p.Module != nil { + fmt.Fprintf(h, "go %s\n", p.Module.GoVersion) + } + 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 cfg.BuildTrimpath { + fmt.Fprintln(h, "trimpath") + } + 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, 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) + } + if len(p.FFiles) > 0 { + fmt.Fprintf(h, "FC=%q %q\n", b.fcExe(), fflags) + } + // TODO(rsc): Should we include the SWIG version or Fortran/GCC/G++/Objective-C compiler versions? + } + if p.Internal.CoverMode != "" { + fmt.Fprintf(h, "cover %q %q\n", p.Internal.CoverMode, b.toolID("cover")) + } + fmt.Fprintf(h, "modinfo %q\n", p.Internal.BuildInfo) + + // Configuration specific to compiler toolchain. + switch cfg.BuildToolchainName { + default: + base.Fatalf("buildActionID: unknown build toolchain %q", cfg.BuildToolchainName) + case "gc": + fmt.Fprintf(h, "compile %s %q %q\n", b.toolID("compile"), forcedGcflags, p.Internal.Gcflags) + if len(p.SFiles) > 0 { + fmt.Fprintf(h, "asm %q %q %q\n", b.toolID("asm"), forcedAsmflags, p.Internal.Asmflags) + } + + // GOARM, GOMIPS, etc. + key, val := cfg.GetArchEnv() + fmt.Fprintf(h, "%s=%s\n", key, val) + + // TODO(rsc): Convince compiler team not to add more magic environment variables, + // or perhaps restrict the environment variables passed to subprocesses. + // Because these are clumsy, undocumented special-case hacks + // for debugging the compiler, they are not settable using 'go env -w', + // and so here we use os.Getenv, not cfg.Getenv. + magic := []string{ + "GOCLOBBERDEADHASH", + "GOSSAFUNC", + "GO_SSA_PHI_LOC_CUTOFF", + "GOSSAHASH", + } + for _, env := range magic { + if x := os.Getenv(env); x != "" { + fmt.Fprintf(h, "magic %s=%s\n", env, x) + } + } + if os.Getenv("GOSSAHASH") != "" { + for i := 0; ; i++ { + env := fmt.Sprintf("GOSSAHASH%d", i) + x := os.Getenv(env) + if x == "" { + break + } + fmt.Fprintf(h, "magic %s=%s\n", env, x) + } + } + if os.Getenv("GSHS_LOGFILE") != "" { + // Clumsy hack. Compiler writes to this log file, + // so do not allow use of cache at all. + // We will still write to the cache but it will be + // essentially unfindable. + fmt.Fprintf(h, "nocache %d\n", time.Now().UnixNano()) + } + + case "gccgo": + id, err := b.gccgoToolID(BuildToolchain.compiler(), "go") + if err != nil { + base.Fatalf("%v", err) + } + fmt.Fprintf(h, "compile %s %q %q\n", id, forcedGccgoflags, p.Internal.Gccgoflags) + fmt.Fprintf(h, "pkgpath %s\n", gccgoPkgpath(p)) + fmt.Fprintf(h, "ar %q\n", BuildToolchain.(gccgoToolchain).ar()) + if len(p.SFiles) > 0 { + id, _ = b.gccgoToolID(BuildToolchain.compiler(), "assembler-with-cpp") + // Ignore error; different assembler versions + // are unlikely to make any difference anyhow. + fmt.Fprintf(h, "asm %q\n", id) + } + } + + // Input files. + inputFiles := str.StringList( + p.GoFiles, + p.CgoFiles, + p.CFiles, + p.CXXFiles, + p.FFiles, + p.MFiles, + p.HFiles, + p.SFiles, + p.SysoFiles, + p.SwigFiles, + p.SwigCXXFiles, + p.EmbedFiles, + ) + for _, file := range inputFiles { + fmt.Fprintf(h, "file %s %s\n", file, b.fileHash(filepath.Join(p.Dir, file))) + } + for _, a1 := range a.Deps { + p1 := a1.Package + if p1 != nil { + fmt.Fprintf(h, "import %s %s\n", p1.ImportPath, contentID(a1.buildID)) + } + } + + 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(ctx context.Context, a *Action) (err error) { + p := a.Package + + bit := func(x uint32, b bool) uint32 { + if b { + return x + } + return 0 + } + + cachedBuild := false + need := bit(needBuild, !b.IsCmdList && a.needBuild || b.NeedExport) | + bit(needCgoHdr, b.needCgoHdr(a)) | + bit(needVet, a.needVet) | + bit(needCompiledGoFiles, b.NeedCompiledGoFiles) + + if !p.BinaryOnly { + if b.useCache(a, b.buildActionID(a), p.Target) { + // We found the main output in the cache. + // If we don't need any other outputs, we can stop. + // 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. + cachedBuild = true + a.output = []byte{} // start saving output in case we miss any cache results + need &^= needBuild + if b.NeedExport { + p.Export = a.built + p.BuildID = a.buildID + } + if need&needCompiledGoFiles != 0 { + if err := b.loadCachedSrcFiles(a); err == nil { + need &^= needCompiledGoFiles + } + } + } + + // Source files might be cached, even if the full action is not + // (e.g., go list -compiled -find). + if !cachedBuild && need&needCompiledGoFiles != 0 { + if err := b.loadCachedSrcFiles(a); err == nil { + need &^= needCompiledGoFiles + } + } + + if need == 0 { + return nil + } + defer b.flushOutput(a) + } + + defer func() { + 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} + } + }() + if cfg.BuildN { + // In -n mode, print a banner between packages. + // The banner is five lines so that when changes to + // different sections of the bootstrap script have to + // be merged, the banners give patch something + // to use to find its context. + b.Print("\n#\n# " + a.Package.ImportPath + "\n#\n\n") + } + + if cfg.BuildV { + b.Print(a.Package.ImportPath + "\n") + } + + if a.Package.BinaryOnly { + p.Stale = true + p.StaleReason = "binary-only packages are no longer supported" + if b.IsCmdList { + return nil + } + return errors.New("binary-only packages are no longer supported") + } + + if err := b.Mkdir(a.Objdir); err != nil { + return err + } + objdir := a.Objdir + + // Load cached cgo header, but only if we're skipping the main build (cachedBuild==true). + if cachedBuild && need&needCgoHdr != 0 { + if err := b.loadCachedCgoHdr(a); err == nil { + 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 { + if err := b.loadCachedVet(a); err == nil { + need &^= needVet + } + } + if need == 0 { + return nil + } + + if err := allowInstall(a); err != nil { + return err + } + + // make target directory + dir, _ := filepath.Split(a.Target) + if dir != "" { + if err := b.Mkdir(dir); err != nil { + return err + } + } + + 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 { + return + } + } + + // Compute overlays for .c/.cc/.h/etc. and if there are any overlays + // put correct contents of all those files in the objdir, to ensure + // the correct headers are included. nonGoOverlay is the overlay that + // points from nongo files to the copied files in objdir. + nonGoFileLists := [][]string{a.Package.CFiles, a.Package.SFiles, a.Package.CXXFiles, a.Package.HFiles, a.Package.FFiles} +OverlayLoop: + for _, fs := range nonGoFileLists { + for _, f := range fs { + if _, ok := fsys.OverlayPath(mkAbs(p.Dir, f)); ok { + a.nonGoOverlay = make(map[string]string) + break OverlayLoop + } + } + } + if a.nonGoOverlay != nil { + for _, fs := range nonGoFileLists { + for i := range fs { + from := mkAbs(p.Dir, fs[i]) + opath, _ := fsys.OverlayPath(from) + dst := objdir + filepath.Base(fs[i]) + if err := b.copyFile(dst, opath, 0666, false); err != nil { + return err + } + a.nonGoOverlay[from] = dst + } + } + } + + // Run SWIG on each .swig and .swigcxx file. + // Each run will generate two files, a .go file and a .c or .cxx file. + // The .go file will use import "C" and is to be processed by cgo. + if a.Package.UsesSwig() { + outGo, outC, outCXX, err := b.swig(a, a.Package, objdir, pcCFLAGS) + if err != nil { + return err + } + cgofiles = append(cgofiles, outGo...) + cfiles = append(cfiles, outC...) + cxxfiles = append(cxxfiles, outCXX...) + } + + // If we're doing coverage, preprocess the .go files and put them in the work directory + if a.Package.Internal.CoverMode != "" { + for i, file := range str.StringList(gofiles, cgofiles) { + var sourceFile string + var coverFile string + var key string + if strings.HasSuffix(file, ".cgo1.go") { + // cgo files have absolute paths + base := filepath.Base(file) + sourceFile = file + coverFile = objdir + base + key = strings.TrimSuffix(base, ".cgo1.go") + ".go" + } else { + sourceFile = filepath.Join(a.Package.Dir, file) + coverFile = objdir + file + key = file + } + coverFile = strings.TrimSuffix(coverFile, ".go") + ".cover.go" + cover := a.Package.Internal.CoverVars[key] + if cover == nil || base.IsTestFile(file) { + // Not covering this file. + continue + } + if err := b.cover(a, coverFile, sourceFile, cover.Var); err != nil { + return err + } + if i < len(gofiles) { + gofiles[i] = coverFile + } else { + cgofiles[i-len(gofiles)] = coverFile + } + } + } + + // Run cgo. + if a.Package.UsesCgo() || a.Package.UsesSwig() { + // In a package using cgo, cgo compiles the C, C++ and assembly files with gcc. + // There is one exception: runtime/cgo's job is to bridge the + // cgo and non-cgo worlds, so it necessarily has files in both. + // In that case gcc only gets the gcc_* files. + var gccfiles []string + gccfiles = append(gccfiles, cfiles...) + cfiles = nil + if a.Package.Standard && a.Package.ImportPath == "runtime/cgo" { + filter := func(files, nongcc, gcc []string) ([]string, []string) { + for _, f := range files { + if strings.HasPrefix(f, "gcc_") { + gcc = append(gcc, f) + } else { + nongcc = append(nongcc, f) + } + } + return nongcc, gcc + } + sfiles, gccfiles = filter(sfiles, sfiles[:0], gccfiles) + } else { + for _, sfile := range sfiles { + data, err := os.ReadFile(filepath.Join(a.Package.Dir, sfile)) + if err == nil { + if bytes.HasPrefix(data, []byte("TEXT")) || bytes.Contains(data, []byte("\nTEXT")) || + bytes.HasPrefix(data, []byte("DATA")) || bytes.Contains(data, []byte("\nDATA")) || + bytes.HasPrefix(data, []byte("GLOBL")) || bytes.Contains(data, []byte("\nGLOBL")) { + return fmt.Errorf("package using cgo has Go assembly file %s", sfile) + } + } + } + gccfiles = append(gccfiles, sfiles...) + sfiles = nil + } + + outGo, outObj, err := b.cgo(a, base.Tool("cgo"), objdir, pcCFLAGS, pcLDFLAGS, mkAbsFiles(a.Package.Dir, cgofiles), gccfiles, cxxfiles, a.Package.MFiles, a.Package.FFiles) + if err != nil { + return err + } + if cfg.BuildToolchainName == "gccgo" { + cgoObjects = append(cgoObjects, a.Objdir+"_cgo_flags") + } + cgoObjects = append(cgoObjects, outObj...) + gofiles = append(gofiles, outGo...) + + switch cfg.BuildBuildmode { + case "c-archive", "c-shared": + b.cacheCgoHdr(a) + } + } + + var srcfiles []string // .go and non-.go + srcfiles = append(srcfiles, gofiles...) + srcfiles = append(srcfiles, sfiles...) + srcfiles = append(srcfiles, cfiles...) + srcfiles = append(srcfiles, cxxfiles...) + b.cacheSrcFiles(a, srcfiles) + + // Running cgo generated the cgo header. + need &^= needCgoHdr + + // Sanity check only, since Package.load already checked as well. + if len(gofiles) == 0 { + return &load.NoGoError{Package: a.Package} + } + + // Prepare Go vet config if needed. + if need&needVet != 0 { + buildVetConfig(a, srcfiles) + need &^= needVet + } + if need&needCompiledGoFiles != 0 { + if err := b.loadCachedSrcFiles(a); err != nil { + return fmt.Errorf("loading compiled Go files from cache: %w", err) + } + need &^= needCompiledGoFiles + } + if need == 0 { + // Nothing left to do. + return nil + } + + // Collect symbol ABI requirements from assembly. + symabis, err := BuildToolchain.symabis(b, a, sfiles) + if err != nil { + return err + } + + // Prepare Go import config. + // We start it off with a comment so it can't be empty, so icfg.Bytes() below is never nil. + // It should never be empty anyway, but there have been bugs in the past that resulted + // in empty configs, which then unfortunately turn into "no config passed to compiler", + // and the compiler falls back to looking in pkg itself, which mostly works, + // 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) + } + } + for _, a1 := range a.Deps { + p1 := a1.Package + if p1 == nil || p1.ImportPath == "" || a1.built == "" { + continue + } + fmt.Fprintf(&icfg, "packagefile %s=%s\n", p1.ImportPath, a1.built) + } + + // Prepare Go embed config if needed. + // Unlike the import config, it's okay for the embed config to be empty. + var embedcfg []byte + if len(p.Internal.Embed) > 0 { + var embed struct { + Patterns map[string][]string + Files map[string]string + } + embed.Patterns = p.Internal.Embed + embed.Files = make(map[string]string) + for _, file := range p.EmbedFiles { + embed.Files[file] = filepath.Join(p.Dir, file) + } + js, err := json.MarshalIndent(&embed, "", "\t") + if err != nil { + return fmt.Errorf("marshal embedcfg: %v", err) + } + embedcfg = js + } + + if p.Internal.BuildInfo != "" && cfg.ModulesEnabled { + if err := b.writeFile(objdir+"_gomod_.go", modload.ModInfoProg(p.Internal.BuildInfo, cfg.BuildToolchainName == "gccgo")); 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(), embedcfg, symabis, len(sfiles) > 0, gofiles) + if len(out) > 0 { + output := b.processOutput(out) + if p.Module != nil && !allowedVersion(p.Module.GoVersion) { + output += "note: module requires Go " + p.Module.GoVersion + "\n" + } + b.showOutput(a, a.Package.Dir, a.Package.Desc(), output) + if err != nil { + return errPrintedOutput + } + } + if err != nil { + if p.Module != nil && !allowedVersion(p.Module.GoVersion) { + b.showOutput(a, a.Package.Dir, a.Package.Desc(), "note: module requires Go "+p.Module.GoVersion+"\n") + } + return err + } + if ofile != objpkg { + objects = append(objects, ofile) + } + + // Copy .h files named for goos or goarch or goos_goarch + // to names using GOOS and GOARCH. + // For example, defs_linux_amd64.h becomes defs_GOOS_GOARCH.h. + _goos_goarch := "_" + cfg.Goos + "_" + cfg.Goarch + _goos := "_" + cfg.Goos + _goarch := "_" + cfg.Goarch + for _, file := range a.Package.HFiles { + name, ext := fileExtSplit(file) + switch { + case strings.HasSuffix(name, _goos_goarch): + targ := file[:len(name)-len(_goos_goarch)] + "_GOOS_GOARCH." + ext + 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(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(objdir+targ, filepath.Join(a.Package.Dir, file), 0666, true); err != nil { + return err + } + } + } + + for _, file := range cfiles { + out := file[:len(file)-len(".c")] + ".o" + if err := BuildToolchain.cc(b, a, objdir+out, file); err != nil { + return err + } + objects = append(objects, out) + } + + // Assemble .s files. + if len(sfiles) > 0 { + ofiles, err := BuildToolchain.asm(b, a, sfiles) + if err != nil { + return err + } + objects = append(objects, ofiles...) + } + + // For gccgo on ELF systems, we write the build ID as an assembler file. + // 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 { + case "aix", "android", "dragonfly", "freebsd", "illumos", "linux", "netbsd", "openbsd", "solaris": + asmfile, err := b.gccgoBuildIDFile(a) + if err != nil { + return err + } + ofiles, err := BuildToolchain.asm(b, a, []string{asmfile}) + if err != nil { + return err + } + objects = append(objects, ofiles...) + } + } + + // NOTE(rsc): On Windows, it is critically important that the + // gcc-compiled objects (cgoObjects) be listed after the ordinary + // objects in the archive. I do not know why this is. + // https://golang.org/issue/2601 + objects = append(objects, cgoObjects...) + + // Add system object files. + for _, syso := range a.Package.SysoFiles { + objects = append(objects, filepath.Join(a.Package.Dir, syso)) + } + + // Pack into archive in objdir directory. + // If the Go compiler wrote an archive, we only need to add the + // object files for non-Go sources to the archive. + // If the Go compiler wrote an archive and the package is entirely + // Go sources, there is no pack to execute at all. + if len(objects) > 0 { + if err := BuildToolchain.pack(b, a, objpkg, objects); err != nil { + return err + } + } + + if err := b.updateBuildID(a, objpkg, true); err != nil { + return err + } + + a.built = objpkg + 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 "", fmt.Errorf("loading cached file %s: %w", name, 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() + b.cacheObjdirFile(a, c, "_cgo_install.h") +} + +func (b *Builder) loadCachedCgoHdr(a *Action) error { + c := cache.Default() + return b.loadCachedObjdirFile(a, c, "_cgo_install.h") +} + +func (b *Builder) cacheSrcFiles(a *Action, srcfiles []string) { + c := cache.Default() + var buf bytes.Buffer + for _, file := range srcfiles { + 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, "srcfiles"), buf.Bytes()) +} + +func (b *Builder) loadCachedVet(a *Action) error { + c := cache.Default() + list, _, err := c.GetBytes(cache.Subkey(a.actionID, "srcfiles")) + if err != nil { + return fmt.Errorf("reading srcfiles list: %w", err) + } + var srcfiles []string + for _, name := range strings.Split(string(list), "\n") { + if name == "" { // end of list + continue + } + if strings.HasPrefix(name, "./") { + srcfiles = append(srcfiles, name[2:]) + continue + } + if err := b.loadCachedObjdirFile(a, c, name); err != nil { + return err + } + srcfiles = append(srcfiles, a.Objdir+name) + } + buildVetConfig(a, srcfiles) + return nil +} + +func (b *Builder) loadCachedSrcFiles(a *Action) error { + c := cache.Default() + list, _, err := c.GetBytes(cache.Subkey(a.actionID, "srcfiles")) + if err != nil { + return fmt.Errorf("reading srcfiles list: %w", err) + } + 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 fmt.Errorf("finding %s: %w", name, err) + } + files = append(files, file) + } + a.Package.CompiledGoFiles = files + return nil +} + +// vetConfig is the configuration passed to vet describing a single package. +type vetConfig struct { + ID string // package ID (example: "fmt [fmt.test]") + 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 + NonGoFiles []string // absolute paths to package non-Go files + IgnoredFiles []string // absolute paths to ignored 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, srcfiles []string) { + // Classify files based on .go extension. + // srcfiles does not include raw cgo files. + var gofiles, nongofiles []string + for _, name := range srcfiles { + if strings.HasSuffix(name, ".go") { + gofiles = append(gofiles, name) + } else { + nongofiles = append(nongofiles, name) + } + } + + ignored := str.StringList(a.Package.IgnoredGoFiles, a.Package.IgnoredOtherFiles) + + // 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{ + ID: a.Package.ImportPath, + Compiler: cfg.BuildToolchainName, + Dir: a.Package.Dir, + GoFiles: mkAbsFiles(a.Package.Dir, gofiles), + NonGoFiles: mkAbsFiles(a.Package.Dir, nongofiles), + IgnoredFiles: mkAbsFiles(a.Package.Dir, ignored), + 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 + } + + // 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. +// The caller is expected to set it (if needed) before executing any vet actions. +var VetTool string + +// VetFlags are the default flags to pass to vet. +// The caller is expected to set them before executing any vet actions. +var VetFlags []string + +// VetExplicit records whether the vet flags were set explicitly on the command line. +var VetExplicit bool + +func (b *Builder) vet(ctx context.Context, 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. + 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")) + + vetFlags := VetFlags + + // In GOROOT, we enable all the vet tests during 'go test', + // not just the high-confidence subset. This gets us extra + // checking for the standard library (at some compliance cost) + // and helps us gain experience about how well the checks + // work, to help decide which should be turned on by default. + // The command-line still wins. + // + // Note that this flag change applies even when running vet as + // a dependency of vetting a package outside std. + // (Otherwise we'd have to introduce a whole separate + // space of "vet fmt as a dependency of a std top-level vet" + // versus "vet fmt as a dependency of a non-std top-level vet".) + // This is OK as long as the packages that are farther down the + // dependency tree turn on *more* analysis, as here. + // (The unsafeptr check does not write any facts for use by + // later vet runs, nor does unreachable.) + if a.Package.Goroot && !VetExplicit && VetTool == "" { + // Turn off -unsafeptr checks. + // There's too much unsafe.Pointer code + // that vet doesn't like in low-level packages + // like runtime, sync, and reflect. + // Note that $GOROOT/src/buildall.bash + // does the same for the misc-compile trybots + // and should be updated if these flags are + // changed here. + vetFlags = []string{"-unsafeptr=false"} + + // Also turn off -unreachable checks during go test. + // During testing it is very common to make changes + // like hard-coded forced returns or panics that make + // code unreachable. It's unreasonable to insist on files + // not having any unreachable code during "go test". + // (buildall.bash still runs with -unreachable enabled + // for the overall whole-tree scan.) + if cfg.CmdName == "test" { + vetFlags = append(vetFlags, "-unreachable=false") + } + } + + // 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 && !cfg.BuildA { + c := cache.Default() + if file, _, err := c.GetFile(key); err == nil { + a.built = file + return nil + } + } + + js, err := json.MarshalIndent(vcfg, "", "\t") + if err != nil { + return fmt.Errorf("internal error marshaling vet config: %v", err) + } + js = append(js, '\n') + if err := b.writeFile(a.Objdir+"vet.cfg", js); err != nil { + return err + } + + // TODO(rsc): Why do we pass $GCCGO to go vet? + env := b.cCompilerEnv() + if cfg.BuildToolchainName == "gccgo" { + env = append(env, "GCCGO="+BuildToolchain.compiler()) + } + + p := a.Package + tool := VetTool + if tool == "" { + tool = base.Tool("vet") + } + 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 + cache.Default().Put(key, f) + f.Close() + } + + return runErr +} + +// linkActionID computes the action ID for a link action. +func (b *Builder) linkActionID(a *Action) cache.ActionID { + p := a.Package + h := cache.NewHash("link " + p.ImportPath) + + // Toolchain-independent configuration. + fmt.Fprintf(h, "link\n") + fmt.Fprintf(h, "buildmode %s goos %s goarch %s\n", cfg.BuildBuildmode, 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 cfg.BuildTrimpath { + fmt.Fprintln(h, "trimpath") + } + + // Toolchain-dependent configuration, shared with b.linkSharedActionID. + b.printLinkerConfig(h, p) + + // Input files. + for _, a1 := range a.Deps { + p1 := a1.Package + if p1 != nil { + if a1.built != "" || a1.buildID != "" { + buildID := a1.buildID + if buildID == "" { + buildID = b.buildID(a1.built) + } + fmt.Fprintf(h, "packagefile %s=%s\n", p1.ImportPath, contentID(buildID)) + } + // Because we put package main's full action ID into the binary's build ID, + // we must also put the full action ID into the binary's action ID hash. + if p1.Name == "main" { + fmt.Fprintf(h, "packagemain %s\n", a1.buildID) + } + if p1.Shlib != "" { + fmt.Fprintf(h, "packageshlib %s=%s\n", p1.ImportPath, contentID(b.buildID(p1.Shlib))) + } + } + } + + return h.Sum() +} + +// printLinkerConfig prints the linker config into the hash h, +// as part of the computation of a linker-related action ID. +func (b *Builder) printLinkerConfig(h io.Writer, p *load.Package) { + switch cfg.BuildToolchainName { + default: + base.Fatalf("linkActionID: unknown toolchain %q", cfg.BuildToolchainName) + + case "gc": + fmt.Fprintf(h, "link %s %q %s\n", b.toolID("link"), forcedLdflags, ldBuildmode) + if p != nil { + fmt.Fprintf(h, "linkflags %q\n", p.Internal.Ldflags) + } + + // GOARM, GOMIPS, etc. + key, val := cfg.GetArchEnv() + fmt.Fprintf(h, "%s=%s\n", key, val) + + // The linker writes source file paths that say GOROOT_FINAL, but + // only if -trimpath is not specified (see ld() in gc.go). + gorootFinal := cfg.GOROOT_FINAL + if cfg.BuildTrimpath { + gorootFinal = trimPathGoRootFinal + } + fmt.Fprintf(h, "GOROOT=%s\n", gorootFinal) + + // GO_EXTLINK_ENABLED controls whether the external linker is used. + fmt.Fprintf(h, "GO_EXTLINK_ENABLED=%s\n", cfg.Getenv("GO_EXTLINK_ENABLED")) + + // TODO(rsc): Do cgo settings and flags need to be included? + // Or external linker settings and flags? + + case "gccgo": + id, err := b.gccgoToolID(BuildToolchain.linker(), "go") + if err != nil { + base.Fatalf("%v", err) + } + fmt.Fprintf(h, "link %s %s\n", id, ldBuildmode) + // TODO(iant): Should probably include cgo flags here. + } +} + +// 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(ctx context.Context, a *Action) (err error) { + if b.useCache(a, b.linkActionID(a), a.Package.Target) || b.IsCmdList { + return nil + } + defer b.flushOutput(a) + + if err := b.Mkdir(a.Objdir); err != nil { + return err + } + + importcfg := a.Objdir + "importcfg.link" + if err := b.writeLinkImportcfg(a, importcfg); err != nil { + return err + } + + if err := allowInstall(a); err != nil { + return err + } + + // make target directory + dir, _ := filepath.Split(a.Target) + if dir != "" { + if err := b.Mkdir(dir); err != nil { + return err + } + } + + if err := BuildToolchain.ld(b, a, a.Target, importcfg, a.Deps[0].built); err != nil { + return err + } + + // Update the binary with the final build ID. + // But if OmitDebug is set, don't rewrite the binary, because we set OmitDebug + // on binaries that we are going to run and then delete. + // There's no point in doing work on such a binary. + // Worse, opening the binary for write here makes it + // essentially impossible to safely fork+exec due to a fundamental + // incompatibility between ETXTBSY and threads on modern Unix systems. + // See golang.org/issue/22220. + // 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. 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 + } + + a.built = a.Target + return nil +} + +func (b *Builder) writeLinkImportcfg(a *Action, file string) error { + // Prepare Go import cfg. + var icfg bytes.Buffer + for _, a1 := range a.Deps { + p1 := a1.Package + if p1 == nil { + continue + } + fmt.Fprintf(&icfg, "packagefile %s=%s\n", p1.ImportPath, a1.built) + if p1.Shlib != "" { + fmt.Fprintf(&icfg, "packageshlib %s=%s\n", p1.ImportPath, p1.Shlib) + } + } + return b.writeFile(file, icfg.Bytes()) +} + +// PkgconfigCmd returns a pkg-config binary name +// defaultPkgConfig is defined in zdefaultcc.go, written by cmd/dist. +func (b *Builder) PkgconfigCmd() string { + return envList("PKG_CONFIG", cfg.DefaultPkgConfig)[0] +} + +// splitPkgConfigOutput parses the pkg-config output into a slice of +// flags. This implements the algorithm from pkgconf/libpkgconf/argvsplit.c. +func splitPkgConfigOutput(out []byte) ([]string, error) { + if len(out) == 0 { + return nil, nil + } + var flags []string + 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) + } + 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] + } + } + 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, nil +} + +// Calls pkg-config if needed and returns the cflags/ldflags needed to build the package. +func (b *Builder) getPkgConfigFlags(p *load.Package) (cflags, ldflags []string, err error) { + if pcargs := p.CgoPkgConfig; len(pcargs) > 0 { + // pkg-config permits arguments to appear anywhere in + // the command line. Move them all to the front, before --. + var pcflags []string + var pkgs []string + for _, pcarg := range pcargs { + if pcarg == "--" { + // We're going to add our own "--" argument. + } else if strings.HasPrefix(pcarg, "--") { + pcflags = append(pcflags, pcarg) + } else { + pkgs = append(pkgs, pcarg) + } + } + for _, pkg := range pkgs { + if !load.SafeArg(pkg) { + return nil, nil, fmt.Errorf("invalid pkg-config package name: %s", pkg) + } + } + var out []byte + out, err = b.runOut(nil, 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.Print(err.Error() + "\n") + return nil, nil, errPrintedOutput + } + if len(out) > 0 { + 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(nil, 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.Print(err.Error() + "\n") + return nil, nil, errPrintedOutput + } + if len(out) > 0 { + ldflags = strings.Fields(string(out)) + if err := checkLinkerFlags("LDFLAGS", "pkg-config --libs", ldflags); err != nil { + return nil, nil, err + } + } + } + + return +} + +func (b *Builder) installShlibname(ctx context.Context, a *Action) error { + if err := allowInstall(a); err != nil { + return err + } + + // TODO: BuildN + a1 := a.Deps[0] + err := os.WriteFile(a.Target, []byte(filepath.Base(a1.Target)+"\n"), 0666) + if err != nil { + return err + } + if cfg.BuildX { + b.Showcmd("", "echo '%s' > %s # internal", filepath.Base(a1.Target), a.Target) + } + return nil +} + +func (b *Builder) linkSharedActionID(a *Action) cache.ActionID { + h := cache.NewHash("linkShared") + + // Toolchain-independent configuration. + fmt.Fprintf(h, "linkShared\n") + fmt.Fprintf(h, "goos %s goarch %s\n", cfg.Goos, cfg.Goarch) + + // Toolchain-dependent configuration, shared with b.linkActionID. + b.printLinkerConfig(h, nil) + + // Input files. + for _, a1 := range a.Deps { + p1 := a1.Package + if a1.built == "" { + continue + } + if p1 != nil { + fmt.Fprintf(h, "packagefile %s=%s\n", p1.ImportPath, contentID(b.buildID(a1.built))) + if p1.Shlib != "" { + fmt.Fprintf(h, "packageshlib %s=%s\n", p1.ImportPath, contentID(b.buildID(p1.Shlib))) + } + } + } + // Files named on command line are special. + for _, a1 := range a.Deps[0].Deps { + p1 := a1.Package + fmt.Fprintf(h, "top %s=%s\n", p1.ImportPath, contentID(b.buildID(a1.built))) + } + + return h.Sum() +} + +func (b *Builder) linkShared(ctx context.Context, a *Action) (err error) { + if b.useCache(a, b.linkSharedActionID(a), a.Target) || b.IsCmdList { + return nil + } + defer b.flushOutput(a) + + if err := allowInstall(a); err != nil { + return err + } + + if err := b.Mkdir(a.Objdir); err != nil { + return err + } + + importcfg := a.Objdir + "importcfg.link" + if err := b.writeLinkImportcfg(a, importcfg); err != nil { + return err + } + + // TODO(rsc): There is a missing updateBuildID here, + // but we have to decide where to store the build ID in these files. + a.built = a.Target + return BuildToolchain.ldShared(b, a, a.Deps[0].Deps, a.Target, importcfg, a.Deps) +} + +// BuildInstallFunc is the action for installing a single package or executable. +func BuildInstallFunc(b *Builder, ctx context.Context, a *Action) (err error) { + defer func() { + if err != nil && err != errPrintedOutput { + // a.Package == nil is possible for the go install -buildmode=shared + // action that installs libmangledname.so, which corresponds to + // a list of packages, not just one. + sep, path := "", "" + if a.Package != nil { + sep, path = " ", a.Package.ImportPath + } + err = fmt.Errorf("go %s%s%s: %v", cfg.CmdName, sep, path, err) + } + }() + + a1 := a.Deps[0] + a.buildID = a1.buildID + if a.json != nil { + a.json.BuildID = a.buildID + } + + // If we are using the eventual install target as an up-to-date + // cached copy of the thing we built, then there's no need to + // copy it into itself (and that would probably fail anyway). + // In this case a1.built == a.Target because a1.built == p.Target, + // 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 + 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. + // We don't really want users to be able to infer (or worse start depending on) + // those details from whether the modification time changes during + // "go install", so do a best-effort update of the file times to make it + // look like we rewrote a.Target even if we did not. Updating the mtime + // may also help other mtime-based systems that depend on our + // previous mtime updates that happened more often. + // This is still not perfect - we ignore the error result, and if the file was + // unwritable for some reason then pretending to have written it is also + // confusing - but it's probably better than not doing the mtime update. + // + // But don't do that for the special case where building an executable + // with -linkshared implicitly installs all its dependent libraries. + // 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.IsCmdList { + if cfg.BuildN { + b.Showcmd("", "touch %s", a.Target) + } else if err := allowInstall(a); err == nil { + now := time.Now() + os.Chtimes(a.Target, now, now) + } + } + return nil + } + + // 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 + } + if err := allowInstall(a); err != nil { + return err + } + + if err := b.Mkdir(a.Objdir); err != nil { + return err + } + + perm := fs.FileMode(0666) + if a1.Mode == "link" { + switch cfg.BuildBuildmode { + case "c-archive", "c-shared", "plugin": + default: + perm = 0777 + } + } + + // make target directory + dir, _ := filepath.Split(a.Target) + if dir != "" { + if err := b.Mkdir(dir); err != nil { + return err + } + } + + if !a.buggyInstall { + defer b.cleanup(a1) + } + + return b.moveOrCopyFile(a.Target, a1.built, perm, false) +} + +// allowInstall returns a non-nil error if this invocation of the go command is +// allowed to install a.Target. +// +// (The build of cmd/go running under its own test is forbidden from installing +// to its original GOROOT.) +var allowInstall = func(*Action) error { return nil } + +// cleanup removes a's object dir to keep the amount of +// on-disk garbage down in a large build. On an operating system +// with aggressive buffering, cleaning incrementally like +// this keeps the intermediate objects from hitting the disk. +func (b *Builder) cleanup(a *Action) { + if !cfg.BuildWork { + if cfg.BuildX { + // 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(dst, src string, perm fs.FileMode, force bool) error { + if cfg.BuildN { + b.Showcmd("", "mv %s %s", src, dst) + return nil + } + + // If we can update the mode and rename to the dst, do it. + // Otherwise fall back to standard copy. + + // If the source is in the build cache, we need to copy it. + if strings.HasPrefix(src, cache.DefaultDir()) { + return b.copyFile(dst, src, perm, force) + } + + // On Windows, always copy the file, so that we respect the NTFS + // permissions of the parent folder. https://golang.org/issue/22343. + // 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(dst, src, perm, force) + } + + // If the destination directory has the group sticky bit set, + // we have to copy the file to retain the correct permissions. + // https://golang.org/issue/18878 + if fi, err := os.Stat(filepath.Dir(dst)); err == nil { + if fi.IsDir() && (fi.Mode()&fs.ModeSetgid) != 0 { + return b.copyFile(dst, src, perm, force) + } + } + + // The perm argument is meant to be adjusted according to umask, + // but we don't know what the umask is. + // Create a dummy file to find out. + // This avoids build tags and works even on systems like Plan 9 + // where the file mask computation incorporates other information. + mode := perm + f, err := os.OpenFile(filepath.Clean(dst)+"-go-tmp-umask", os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm) + if err == nil { + fi, err := f.Stat() + if err == nil { + mode = fi.Mode() & 0777 + } + name := f.Name() + f.Close() + os.Remove(name) + } + + if err := os.Chmod(src, mode); err == nil { + if err := os.Rename(src, dst); err == nil { + if cfg.BuildX { + b.Showcmd("", "mv %s %s", src, dst) + } + return nil + } + } + + return b.copyFile(dst, src, perm, force) +} + +// copyFile is like 'cp src dst'. +func (b *Builder) copyFile(dst, src string, perm fs.FileMode, force bool) error { + if cfg.BuildN || cfg.BuildX { + b.Showcmd("", "cp %s %s", src, dst) + if cfg.BuildN { + return nil + } + } + + sf, err := os.Open(src) + if err != nil { + return err + } + defer sf.Close() + + // Be careful about removing/overwriting dst. + // Do not remove/overwrite if dst exists and is a directory + // or a non-empty non-object file. + if fi, err := os.Stat(dst); err == nil { + if fi.IsDir() { + return fmt.Errorf("build output %q already exists and is a directory", dst) + } + if !force && fi.Mode().IsRegular() && fi.Size() != 0 && !isObject(dst) { + return fmt.Errorf("build output %q already exists and is not an object file", dst) + } + } + + // On Windows, remove lingering ~ file from last attempt. + if base.ToolIsWindows { + if _, err := os.Stat(dst + "~"); err == nil { + os.Remove(dst + "~") + } + } + + mayberemovefile(dst) + df, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) + if err != nil && base.ToolIsWindows { + // Windows does not allow deletion of a binary file + // while it is executing. Try to move it out of the way. + // If the move fails, which is likely, we'll try again the + // next time we do an install of this binary. + if err := os.Rename(dst, dst+"~"); err == nil { + os.Remove(dst + "~") + } + df, err = os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) + } + if err != nil { + return fmt.Errorf("copying %s: %w", src, err) // err should already refer to dst + } + + _, err = io.Copy(df, sf) + df.Close() + if err != nil { + mayberemovefile(dst) + return fmt.Errorf("copying %s to %s: %v", src, dst, err) + } + return nil +} + +// writeFile writes the text to file. +func (b *Builder) writeFile(file string, text []byte) error { + if cfg.BuildN || cfg.BuildX { + b.Showcmd("", "cat >%s << 'EOF' # internal\n%sEOF", file, text) + } + if cfg.BuildN { + return nil + } + return os.WriteFile(file, text, 0666) +} + +// Install the cgo export header file, if there is one. +func (b *Builder) installHeader(ctx context.Context, a *Action) error { + src := a.Objdir + "_cgo_install.h" + if _, err := os.Stat(src); os.IsNotExist(err) { + // If the file does not exist, there are no exported + // functions, and we do not install anything. + // TODO(rsc): Once we know that caching is rebuilding + // at the right times (not missing rebuilds), here we should + // probably delete the installed header, if any. + if cfg.BuildX { + b.Showcmd("", "# %s not created", src) + } + return nil + } + + if err := allowInstall(a); err != nil { + return err + } + + dir, _ := filepath.Split(a.Target) + if dir != "" { + if err := b.Mkdir(dir); err != nil { + return err + } + } + + 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, varName string) error { + return b.run(a, a.Objdir, "cover "+a.Package.ImportPath, nil, + cfg.BuildToolexec, + base.Tool("cover"), + "-mode", a.Package.Internal.CoverMode, + "-var", varName, + "-o", dst, + src) +} + +var objectMagic = [][]byte{ + {'!', '<', 'a', 'r', 'c', 'h', '>', '\n'}, // Package archive + {'<', 'b', 'i', 'g', 'a', 'f', '>', '\n'}, // Package AIX big archive + {'\x7F', 'E', 'L', 'F'}, // ELF + {0xFE, 0xED, 0xFA, 0xCE}, // Mach-O big-endian 32-bit + {0xFE, 0xED, 0xFA, 0xCF}, // Mach-O big-endian 64-bit + {0xCE, 0xFA, 0xED, 0xFE}, // Mach-O little-endian 32-bit + {0xCF, 0xFA, 0xED, 0xFE}, // Mach-O little-endian 64-bit + {0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00}, // PE (Windows) as generated by 6l/8l and gcc + {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}, // XCOFF 32bit + {0x01, 0xF7}, // XCOFF 64bit +} + +func isObject(s string) bool { + f, err := os.Open(s) + if err != nil { + return false + } + defer f.Close() + buf := make([]byte, 64) + io.ReadFull(f, buf) + for _, magic := range objectMagic { + if bytes.HasPrefix(buf, magic) { + return true + } + } + return false +} + +// mayberemovefile removes a file only if it is a regular file +// When running as a user with sufficient privileges, we may delete +// even device files, for example, which is not intended. +func mayberemovefile(s string) { + if fi, err := os.Lstat(s); err == nil && !fi.Mode().IsRegular() { + return + } + os.Remove(s) +} + +// fmtcmd formats a command in the manner of fmt.Sprintf but also: +// +// If dir is non-empty and the script is not in dir right now, +// fmtcmd inserts "cd dir\n" before the command. +// +// fmtcmd replaces the value of b.WorkDir with $WORK. +// fmtcmd replaces the value of goroot with $GOROOT. +// fmtcmd replaces the value of b.gobin with $GOBIN. +// +// fmtcmd replaces the name of the current directory with dot (.) +// but only when it is at the beginning of a space-separated token. +// +func (b *Builder) fmtcmd(dir string, format string, args ...interface{}) string { + cmd := fmt.Sprintf(format, args...) + if dir != "" && dir != "/" { + dot := " ." + if dir[len(dir)-1] == filepath.Separator { + dot += string(filepath.Separator) + } + cmd = strings.ReplaceAll(" "+cmd, " "+dir, dot)[1:] + if b.scriptDir != dir { + b.scriptDir = dir + cmd = "cd " + dir + "\n" + cmd + } + } + if b.WorkDir != "" { + cmd = strings.ReplaceAll(cmd, b.WorkDir, "$WORK") + escaped := strconv.Quote(b.WorkDir) + escaped = escaped[1 : len(escaped)-1] // strip quote characters + if escaped != b.WorkDir { + cmd = strings.ReplaceAll(cmd, escaped, "$WORK") + } + } + return cmd +} + +// showcmd prints the given command to standard output +// for the implementation of -n or -x. +func (b *Builder) Showcmd(dir string, format string, args ...interface{}) { + b.output.Lock() + defer b.output.Unlock() + b.Print(b.fmtcmd(dir, format, args...) + "\n") +} + +// showOutput prints "# desc" followed by the given output. +// The output is expected to contain references to 'dir', usually +// the source directory for the package that has failed to build. +// showOutput rewrites mentions of dir with a relative path to dir +// when the relative path is shorter. This is usually more pleasant. +// For example, if fmt doesn't compile and we are in src/html, +// the output is +// +// $ go build +// # fmt +// ../fmt/print.go:1090: undefined: asdf +// $ +// +// instead of +// +// $ go build +// # fmt +// /usr/gopher/go/src/fmt/print.go:1090: undefined: asdf +// $ +// +// showOutput also replaces references to the work directory with $WORK. +// +// If a is not nil and a.output is not nil, showOutput appends to that slice instead of +// printing to b.Print. +// +func (b *Builder) showOutput(a *Action, dir, desc, out string) { + prefix := "# " + desc + suffix := "\n" + out + if reldir := base.ShortPath(dir); reldir != dir { + suffix = strings.ReplaceAll(suffix, " "+dir, " "+reldir) + suffix = strings.ReplaceAll(suffix, "\n"+dir, "\n"+reldir) + } + suffix = strings.ReplaceAll(suffix, " "+b.WorkDir, " $WORK") + + if a != nil && a.output != nil { + a.output = append(a.output, prefix...) + a.output = append(a.output, suffix...) + return + } + + b.output.Lock() + defer b.output.Unlock() + b.Print(prefix, suffix) +} + +// errPrintedOutput is a special error indicating that a command failed +// but that it generated output as well, and that output has already +// been printed, so there's no point showing 'exit status 1' or whatever +// the wait status was. The main executor, builder.do, knows not to +// print this error. +var errPrintedOutput = errors.New("already printed output - no need to show error") + +var cgoLine = lazyregexp.New(`\[[^\[\]]+\.(cgo1|cover)\.go:[0-9]+(:[0-9]+)?\]`) +var cgoTypeSigRe = lazyregexp.New(`\b_C2?(type|func|var|macro)_\B`) + +// run runs the command given by cmdline in the directory dir. +// 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(a, dir, env, cmdargs...) + if len(out) > 0 { + if desc == "" { + desc = b.fmtcmd(dir, "%s", strings.Join(str.StringList(cmdargs...), " ")) + } + b.showOutput(a, dir, desc, b.processOutput(out)) + if err != nil { + err = errPrintedOutput + } + } + return err +} + +// processOutput prepares the output of runOut to be output to the console. +func (b *Builder) processOutput(out []byte) string { + if out[len(out)-1] != '\n' { + out = append(out, '\n') + } + messages := string(out) + // Fix up output referring to cgo-generated code to be more readable. + // Replace x.go:19[/tmp/.../x.cgo1.go:18] with x.go:19. + // Replace *[100]_Ctype_foo with *[100]C.foo. + // If we're using -x, assume we're debugging and want the full dump, so disable the rewrite. + if !cfg.BuildX && cgoLine.MatchString(messages) { + messages = cgoLine.ReplaceAllString(messages, "") + messages = cgoTypeSigRe.ReplaceAllString(messages, "C.") + } + return messages +} + +// runOut runs the command given by cmdline in the directory dir. +// It returns the command output and any errors that occurred. +// It accumulates execution time in a. +func (b *Builder) runOut(a *Action, dir string, env []string, cmdargs ...interface{}) ([]byte, error) { + cmdline := str.StringList(cmdargs...) + + for _, arg := range cmdline { + // GNU binutils commands, including gcc and gccgo, interpret an argument + // @foo anywhere in the command line (even following --) as meaning + // "read and insert arguments from the file named foo." + // Don't say anything that might be misinterpreted that way. + if strings.HasPrefix(arg, "@") { + return nil, fmt.Errorf("invalid command-line argument %s in command: %s", arg, joinUnambiguously(cmdline)) + } + } + + if cfg.BuildN || cfg.BuildX { + var envcmdline string + for _, e := range env { + if j := strings.IndexByte(e, '='); j != -1 { + if strings.ContainsRune(e[j+1:], '\'') { + envcmdline += fmt.Sprintf("%s=%q", e[:j], e[j+1:]) + } else { + envcmdline += fmt.Sprintf("%s='%s'", e[:j], e[j+1:]) + } + envcmdline += " " + } + } + envcmdline += joinUnambiguously(cmdline) + b.Showcmd(dir, "%s", envcmdline) + if cfg.BuildN { + return nil, nil + } + } + + var buf bytes.Buffer + cmd := exec.Command(cmdline[0], cmdline[1:]...) + if cmd.Path != "" { + cmd.Args[0] = cmd.Path + } + cmd.Stdout = &buf + cmd.Stderr = &buf + cleanup := passLongArgsInResponseFiles(cmd) + defer cleanup() + cmd.Dir = dir + cmd.Env = base.AppendPWD(os.Environ(), cmd.Dir) + + // Add the TOOLEXEC_IMPORTPATH environment variable for -toolexec tools. + // It doesn't really matter if -toolexec isn't being used. + if a != nil && a.Package != nil { + cmd.Env = append(cmd.Env, "TOOLEXEC_IMPORTPATH="+a.Package.ImportPath) + } + + cmd.Env = append(cmd.Env, env...) + start := time.Now() + err := cmd.Run() + if a != nil && a.json != nil { + aj := a.json + aj.Cmd = append(aj.Cmd, joinUnambiguously(cmdline)) + aj.CmdReal += time.Since(start) + if ps := cmd.ProcessState; ps != nil { + aj.CmdUser += ps.UserTime() + aj.CmdSys += ps.SystemTime() + } + } + + // err can be something like 'exit status 1'. + // Add information about what program was running. + // Note that if buf.Bytes() is non-empty, the caller usually + // shows buf.Bytes() and does not print err at all, so the + // prefix here does not make most output any more verbose. + if err != nil { + err = errors.New(cmdline[0] + ": " + err.Error()) + } + return buf.Bytes(), err +} + +// joinUnambiguously prints the slice, quoting where necessary to make the +// output unambiguous. +// TODO: See issue 5279. The printing of commands needs a complete redo. +func joinUnambiguously(a []string) string { + var buf bytes.Buffer + for i, s := range a { + if i > 0 { + buf.WriteByte(' ') + } + q := strconv.Quote(s) + // A gccgo command line can contain -( and -). + // Make sure we quote them since they are special to the shell. + // The trimpath argument can also contain > (part of =>) and ;. Quote those too. + if s == "" || strings.ContainsAny(s, " ()>;") || len(q) > len(s)+2 { + buf.WriteString(q) + } else { + buf.WriteString(s) + } + } + 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 == "". + if dir == "" { + return nil + } + + b.exec.Lock() + defer b.exec.Unlock() + // We can be a little aggressive about being + // sure directories exist. Skip repeated calls. + if b.mkdirCache[dir] { + return nil + } + b.mkdirCache[dir] = true + + if cfg.BuildN || cfg.BuildX { + b.Showcmd("", "mkdir -p %s", dir) + if cfg.BuildN { + return nil + } + } + + if err := os.MkdirAll(dir, 0777); err != nil { + return err + } + return nil +} + +// symlink creates a symlink newname -> oldname. +func (b *Builder) Symlink(oldname, newname string) error { + // It's not an error to try to recreate an existing symlink. + if link, err := os.Readlink(newname); err == nil && link == oldname { + return nil + } + + if cfg.BuildN || cfg.BuildX { + b.Showcmd("", "ln -s %s %s", oldname, newname) + if cfg.BuildN { + return nil + } + } + return os.Symlink(oldname, newname) +} + +// mkAbs returns an absolute path corresponding to +// evaluating f in the directory dir. +// We always pass absolute paths of source files so that +// the error messages will include the full path to a file +// in need of attention. +func mkAbs(dir, f string) string { + // Leave absolute paths alone. + // Also, during -n mode we use the pseudo-directory $WORK + // instead of creating an actual work directory that won't be used. + // Leave paths beginning with $WORK alone too. + if filepath.IsAbs(f) || strings.HasPrefix(f, "$WORK") { + return f + } + return filepath.Join(dir, f) +} + +type toolchain interface { + // gc runs the compiler in a specific directory on a set of files + // and returns the name of the generated output file. + gc(b *Builder, a *Action, archive string, importcfg, embedcfg []byte, symabis string, asmhdr bool, gofiles []string) (ofile string, out []byte, err error) + // cc runs the toolchain's C compiler in a directory on a C file + // to produce an output file. + cc(b *Builder, a *Action, ofile, cfile string) error + // asm runs the assembler in a specific directory on specific files + // and returns a list of named output files. + asm(b *Builder, a *Action, sfiles []string) ([]string, error) + // symabis scans the symbol ABIs from sfiles and returns the + // path to the output symbol ABIs file, or "" if none. + symabis(b *Builder, a *Action, sfiles []string) (string, error) + // pack runs the archive packer in a specific directory to create + // an archive from a set of object files. + // typically it is run in the object directory. + pack(b *Builder, a *Action, afile string, ofiles []string) error + // ld runs the linker to create an executable starting at mainpkg. + ld(b *Builder, root *Action, out, importcfg, mainpkg string) error + // ldShared runs the linker to create a shared library containing the pkgs built by toplevelactions + ldShared(b *Builder, root *Action, toplevelactions []*Action, out, importcfg string, allactions []*Action) error + + compiler() string + linker() string +} + +type noToolchain struct{} + +func noCompiler() error { + log.Fatalf("unknown compiler %q", cfg.BuildContext.Compiler) + return nil +} + +func (noToolchain) compiler() string { + noCompiler() + return "" +} + +func (noToolchain) linker() string { + noCompiler() + return "" +} + +func (noToolchain) gc(b *Builder, a *Action, archive string, importcfg, embedcfg []byte, symabis string, asmhdr bool, gofiles []string) (ofile string, out []byte, err error) { + return "", nil, noCompiler() +} + +func (noToolchain) asm(b *Builder, a *Action, sfiles []string) ([]string, error) { + return nil, noCompiler() +} + +func (noToolchain) symabis(b *Builder, a *Action, sfiles []string) (string, error) { + return "", noCompiler() +} + +func (noToolchain) pack(b *Builder, a *Action, afile string, ofiles []string) error { + return noCompiler() +} + +func (noToolchain) ld(b *Builder, root *Action, out, importcfg, mainpkg string) error { + return noCompiler() +} + +func (noToolchain) ldShared(b *Builder, root *Action, toplevelactions []*Action, out, importcfg string, allactions []*Action) error { + return noCompiler() +} + +func (noToolchain) cc(b *Builder, a *Action, ofile, cfile string) error { + return noCompiler() +} + +// gcc runs the gcc C compiler to create an object from a single C file. +func (b *Builder) gcc(a *Action, p *load.Package, workdir, out string, flags []string, cfile string) error { + return b.ccompile(a, p, out, flags, cfile, b.GccCmd(p.Dir, workdir)) +} + +// gxx runs the g++ C++ compiler to create an object from a single C++ file. +func (b *Builder) gxx(a *Action, p *load.Package, workdir, out string, flags []string, cxxfile string) error { + return b.ccompile(a, p, out, flags, cxxfile, b.GxxCmd(p.Dir, workdir)) +} + +// gfortran runs the gfortran Fortran compiler to create an object from a single Fortran file. +func (b *Builder) gfortran(a *Action, p *load.Package, workdir, out string, flags []string, ffile string) error { + return b.ccompile(a, p, out, flags, ffile, b.gfortranCmd(p.Dir, workdir)) +} + +// ccompile runs the given C or C++ compiler and creates an object from a single source file. +func (b *Builder) ccompile(a *Action, p *load.Package, outfile string, flags []string, file string, compiler []string) error { + file = mkAbs(p.Dir, file) + desc := p.ImportPath + outfile = mkAbs(p.Dir, outfile) + + // Elide source directory paths if -trimpath or GOROOT_FINAL is set. + // This is needed for source files (e.g., a .c file in a package directory). + // TODO(golang.org/issue/36072): cgo also generates files with #line + // directives pointing to the source directory. It should not generate those + // when -trimpath is enabled. + if b.gccSupportsFlag(compiler, "-fdebug-prefix-map=a=b") { + if cfg.BuildTrimpath { + // Keep in sync with Action.trimpath. + // The trimmed paths are a little different, but we need to trim in the + // same situations. + var from, toPath string + if m := p.Module; m != nil { + from = m.Dir + toPath = m.Path + "@" + m.Version + } else { + from = p.Dir + toPath = p.ImportPath + } + // -fdebug-prefix-map requires an absolute "to" path (or it joins the path + // with the working directory). Pick something that makes sense for the + // target platform. + var to string + if cfg.BuildContext.GOOS == "windows" { + to = filepath.Join(`\\_\_`, toPath) + } else { + to = filepath.Join("/_", toPath) + } + flags = append(flags[:len(flags):len(flags)], "-fdebug-prefix-map="+from+"="+to) + } else if p.Goroot && cfg.GOROOT_FINAL != cfg.GOROOT { + flags = append(flags[:len(flags):len(flags)], "-fdebug-prefix-map="+cfg.GOROOT+"="+cfg.GOROOT_FINAL) + } + } + + overlayPath := file + if p, ok := a.nonGoOverlay[overlayPath]; ok { + overlayPath = p + } + output, err := b.runOut(a, filepath.Dir(overlayPath), b.cCompilerEnv(), compiler, flags, "-o", outfile, "-c", filepath.Base(overlayPath)) + if len(output) > 0 { + // On FreeBSD 11, when we pass -g to clang 3.8 it + // invokes its internal assembler with -dwarf-version=2. + // When it sees .section .note.GNU-stack, it warns + // "DWARF2 only supports one section per compilation unit". + // This warning makes no sense, since the section is empty, + // but it confuses people. + // We work around the problem by detecting the warning + // and dropping -g and trying again. + if bytes.Contains(output, []byte("DWARF2 only supports one section per compilation unit")) { + newFlags := make([]string, 0, len(flags)) + for _, f := range flags { + if !strings.HasPrefix(f, "-g") { + newFlags = append(newFlags, f) + } + } + if len(newFlags) < len(flags) { + return b.ccompile(a, p, outfile, newFlags, file, compiler) + } + } + + b.showOutput(a, p.Dir, desc, b.processOutput(output)) + if err != nil { + err = errPrintedOutput + } else if os.Getenv("GO_BUILDER_NAME") != "" { + return errors.New("C compiler warning promoted to error on Go builders") + } + } + return err +} + +// gccld runs the gcc linker to create an executable from a set of object files. +func (b *Builder) gccld(a *Action, p *load.Package, objdir, outfile string, flags []string, objs []string) error { + var cmd []string + if len(p.CXXFiles) > 0 || len(p.SwigCXXFiles) > 0 { + cmd = b.GxxCmd(p.Dir, objdir) + } else { + cmd = b.GccCmd(p.Dir, objdir) + } + + cmdargs := []interface{}{cmd, "-o", outfile, objs, flags} + dir := p.Dir + out, err := b.runOut(a, base.Cwd, b.cCompilerEnv(), cmdargs...) + + if len(out) > 0 { + // Filter out useless linker warnings caused by bugs outside Go. + // See also cmd/link/internal/ld's hostlink method. + var save [][]byte + var skipLines int + for _, line := range bytes.SplitAfter(out, []byte("\n")) { + // golang.org/issue/26073 - Apple Xcode bug + if bytes.Contains(line, []byte("ld: warning: text-based stub file")) { + continue + } + + if skipLines > 0 { + skipLines-- + continue + } + + // Remove duplicate main symbol with runtime/cgo on AIX. + // With runtime/cgo, two main are available: + // One is generated by cgo tool with {return 0;}. + // The other one is the main calling runtime.rt0_go + // in runtime/cgo. + // The second can't be used by cgo programs because + // runtime.rt0_go is unknown to them. + // Therefore, we let ld remove this main version + // and used the cgo generated one. + if p.ImportPath == "runtime/cgo" && bytes.Contains(line, []byte("ld: 0711-224 WARNING: Duplicate symbol: .main")) { + skipLines = 1 + continue + } + + save = append(save, line) + } + out = bytes.Join(save, nil) + if len(out) > 0 { + b.showOutput(nil, dir, p.ImportPath, b.processOutput(out)) + if err != nil { + err = errPrintedOutput + } + } + } + return err +} + +// Grab these before main helpfully overwrites them. +var ( + origCC = cfg.Getenv("CC") + origCXX = cfg.Getenv("CXX") +) + +// gccCmd returns a gcc command line prefix +// defaultCC is defined in zdefaultcc.go, written by cmd/dist. +func (b *Builder) GccCmd(incdir, workdir string) []string { + return b.compilerCmd(b.ccExe(), incdir, workdir) +} + +// gxxCmd returns a g++ command line prefix +// defaultCXX is defined in zdefaultcc.go, written by cmd/dist. +func (b *Builder) GxxCmd(incdir, workdir string) []string { + return b.compilerCmd(b.cxxExe(), incdir, workdir) +} + +// gfortranCmd returns a gfortran command line prefix. +func (b *Builder) gfortranCmd(incdir, workdir string) []string { + return b.compilerCmd(b.fcExe(), incdir, workdir) +} + +// ccExe returns the CC compiler setting without all the extra flags we add implicitly. +func (b *Builder) ccExe() []string { + return b.compilerExe(origCC, cfg.DefaultCC(cfg.Goos, cfg.Goarch)) +} + +// cxxExe returns the CXX compiler setting without all the extra flags we add implicitly. +func (b *Builder) cxxExe() []string { + return b.compilerExe(origCXX, cfg.DefaultCXX(cfg.Goos, cfg.Goarch)) +} + +// fcExe returns the FC compiler setting without all the extra flags we add implicitly. +func (b *Builder) fcExe() []string { + return b.compilerExe(cfg.Getenv("FC"), "gfortran") +} + +// compilerExe returns the compiler to use given an +// environment variable setting (the value not the name) +// and a default. The resulting slice is usually just the name +// of the compiler but can have additional arguments if they +// were present in the environment value. +// For example if CC="gcc -DGOPHER" then the result is ["gcc", "-DGOPHER"]. +func (b *Builder) compilerExe(envValue string, def string) []string { + compiler := strings.Fields(envValue) + if len(compiler) == 0 { + compiler = strings.Fields(def) + } + return compiler +} + +// compilerCmd returns a command line prefix for the given environment +// variable and using the default command when the variable is empty. +func (b *Builder) compilerCmd(compiler []string, incdir, workdir string) []string { + // NOTE: env.go's mkEnv knows that the first three + // strings returned are "gcc", "-I", incdir (and cuts them off). + a := []string{compiler[0], "-I", incdir} + a = append(a, compiler[1:]...) + + // Definitely want -fPIC but on Windows gcc complains + // "-fPIC ignored for target (all code is position independent)" + if cfg.Goos != "windows" { + a = append(a, "-fPIC") + } + a = append(a, b.gccArchArgs()...) + // gcc-4.5 and beyond require explicit "-pthread" flag + // for multithreading with pthread library. + if cfg.BuildContext.CgoEnabled { + switch cfg.Goos { + case "windows": + a = append(a, "-mthreads") + default: + a = append(a, "-pthread") + } + } + + if cfg.Goos == "aix" { + // mcmodel=large must always be enabled to allow large TOC. + a = append(a, "-mcmodel=large") + } + + // disable ASCII art in clang errors, if possible + if b.gccSupportsFlag(compiler, "-fno-caret-diagnostics") { + a = append(a, "-fno-caret-diagnostics") + } + // clang is too smart about command-line arguments + if b.gccSupportsFlag(compiler, "-Qunused-arguments") { + a = append(a, "-Qunused-arguments") + } + + // disable word wrapping in error messages + a = append(a, "-fmessage-length=0") + + // Tell gcc not to include the work directory in object files. + if b.gccSupportsFlag(compiler, "-fdebug-prefix-map=a=b") { + if workdir == "" { + workdir = b.WorkDir + } + workdir = strings.TrimSuffix(workdir, string(filepath.Separator)) + a = append(a, "-fdebug-prefix-map="+workdir+"=/tmp/go-build") + } + + // Tell gcc not to include flags in object files, which defeats the + // point of -fdebug-prefix-map above. + if b.gccSupportsFlag(compiler, "-gno-record-gcc-switches") { + a = append(a, "-gno-record-gcc-switches") + } + + // On OS X, some of the compilers behave as if -fno-common + // is always set, and the Mach-O linker in 6l/8l assumes this. + // See https://golang.org/issue/3253. + if cfg.Goos == "darwin" || cfg.Goos == "ios" { + a = append(a, "-fno-common") + } + + return a +} + +// gccNoPie returns the flag to use to request non-PIE. On systems +// with PIE (position independent executables) enabled by default, +// -no-pie must be passed when doing a partial link with -Wl,-r. +// But -no-pie is not supported by all compilers, and clang spells it -nopie. +func (b *Builder) gccNoPie(linker []string) string { + if b.gccSupportsFlag(linker, "-no-pie") { + return "-no-pie" + } + if b.gccSupportsFlag(linker, "-nopie") { + return "-nopie" + } + return "" +} + +// gccSupportsFlag checks to see if the compiler supports a flag. +func (b *Builder) gccSupportsFlag(compiler []string, flag string) bool { + key := [2]string{compiler[0], flag} + + b.exec.Lock() + defer b.exec.Unlock() + if b, ok := b.flagCache[key]; ok { + return b + } + if b.flagCache == nil { + b.flagCache = make(map[[2]string]bool) + } + + tmp := os.DevNull + if runtime.GOOS == "windows" { + f, err := os.CreateTemp(b.WorkDir, "") + if err != nil { + return false + } + f.Close() + tmp = f.Name() + defer os.Remove(tmp) + } + + // We used to write an empty C file, but that gets complicated with + // go build -n. We tried using a file that does not exist, but that + // fails on systems with GCC version 4.2.1; that is the last GPLv2 + // version of GCC, so some systems have frozen on it. + // Now we pass an empty file on stdin, which should work at least for + // GCC and clang. + cmdArgs := str.StringList(compiler, flag, "-c", "-x", "c", "-", "-o", tmp) + if cfg.BuildN || cfg.BuildX { + b.Showcmd(b.WorkDir, "%s || true", joinUnambiguously(cmdArgs)) + if cfg.BuildN { + return false + } + } + cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...) + cmd.Dir = b.WorkDir + cmd.Env = base.AppendPWD(os.Environ(), cmd.Dir) + cmd.Env = append(cmd.Env, "LC_ALL=C") + out, _ := cmd.CombinedOutput() + // GCC says "unrecognized command line option". + // clang says "unknown argument". + // Older versions of GCC say "unrecognised debug output level". + // For -fsplit-stack GCC says "'-fsplit-stack' is not supported". + supported := !bytes.Contains(out, []byte("unrecognized")) && + !bytes.Contains(out, []byte("unknown")) && + !bytes.Contains(out, []byte("unrecognised")) && + !bytes.Contains(out, []byte("is not supported")) + b.flagCache[key] = supported + return supported +} + +// gccArchArgs returns arguments to pass to gcc based on the architecture. +func (b *Builder) gccArchArgs() []string { + switch cfg.Goarch { + case "386": + return []string{"-m32"} + case "amd64": + if cfg.Goos == "darwin" { + return []string{"-arch", "x86_64", "-m64"} + } + return []string{"-m64"} + case "arm64": + if cfg.Goos == "darwin" { + return []string{"-arch", "arm64"} + } + case "arm": + return []string{"-marm"} // not thumb + case "s390x": + return []string{"-m64", "-march=z196"} + case "mips64", "mips64le": + return []string{"-mabi=64"} + case "mips", "mipsle": + return []string{"-mabi=32", "-march=mips32"} + case "ppc64": + if cfg.Goos == "aix" { + return []string{"-maix64"} + } + } + return nil +} + +// envList returns the value of the given environment variable broken +// into fields, using the default value when the variable is empty. +func envList(key, def string) []string { + v := cfg.Getenv(key) + if v == "" { + v = def + } + return strings.Fields(v) +} + +// CFlags returns the flags to use when invoking the C, C++ or Fortran compilers, or cgo. +func (b *Builder) CFlags(p *load.Package) (cppflags, cflags, cxxflags, fflags, ldflags []string, err error) { + defaults := "-g -O2" + + if cppflags, err = buildFlags("CPPFLAGS", "", p.CgoCPPFLAGS, checkCompilerFlags); err != nil { + return + } + if cflags, err = buildFlags("CFLAGS", defaults, p.CgoCFLAGS, checkCompilerFlags); err != nil { + return + } + if cxxflags, err = buildFlags("CXXFLAGS", defaults, p.CgoCXXFLAGS, checkCompilerFlags); err != nil { + return + } + if fflags, err = buildFlags("FFLAGS", defaults, p.CgoFFLAGS, checkCompilerFlags); err != nil { + return + } + if ldflags, err = buildFlags("LDFLAGS", defaults, p.CgoLDFLAGS, checkLinkerFlags); err != nil { + return + } + + return +} + +func buildFlags(name, defaults string, fromPackage []string, check func(string, string, []string) error) ([]string, error) { + if err := check(name, "#cgo "+name, fromPackage); err != nil { + return nil, err + } + return str.StringList(envList("CGO_"+name, defaults), fromPackage), nil +} + +var cgoRe = lazyregexp.New(`[/\\:]`) + +func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, gxxfiles, mfiles, ffiles []string) (outGo, outObj []string, err error) { + p := a.Package + cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS, cgoLDFLAGS, err := b.CFlags(p) + if err != nil { + return nil, nil, err + } + + cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...) + cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...) + // If we are compiling Objective-C code, then we need to link against libobjc + if len(mfiles) > 0 { + cgoLDFLAGS = append(cgoLDFLAGS, "-lobjc") + } + + // Likewise for Fortran, except there are many Fortran compilers. + // Support gfortran out of the box and let others pass the correct link options + // via CGO_LDFLAGS + if len(ffiles) > 0 { + fc := cfg.Getenv("FC") + if fc == "" { + fc = "gfortran" + } + if strings.Contains(fc, "gfortran") { + cgoLDFLAGS = append(cgoLDFLAGS, "-lgfortran") + } + } + + if cfg.BuildMSan { + cgoCFLAGS = append([]string{"-fsanitize=memory"}, cgoCFLAGS...) + cgoLDFLAGS = append([]string{"-fsanitize=memory"}, cgoLDFLAGS...) + } + + // Allows including _cgo_export.h, as well as the user's .h files, + // from .[ch] files in the package. + cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", objdir) + + // cgo + // TODO: CGO_FLAGS? + gofiles := []string{objdir + "_cgo_gotypes.go"} + cfiles := []string{"_cgo_export.c"} + for _, fn := range cgofiles { + f := strings.TrimSuffix(filepath.Base(fn), ".go") + gofiles = append(gofiles, objdir+f+".cgo1.go") + cfiles = append(cfiles, f+".cgo2.c") + } + + // TODO: make cgo not depend on $GOARCH? + + cgoflags := []string{} + if p.Standard && p.ImportPath == "runtime/cgo" { + cgoflags = append(cgoflags, "-import_runtime_cgo=false") + } + if p.Standard && (p.ImportPath == "runtime/race" || p.ImportPath == "runtime/msan" || p.ImportPath == "runtime/cgo") { + cgoflags = append(cgoflags, "-import_syscall=false") + } + + // Update $CGO_LDFLAGS with p.CgoLDFLAGS. + // These flags are recorded in the generated _cgo_gotypes.go file + // using //go:cgo_ldflag directives, the compiler records them in the + // object file for the package, and then the Go linker passes them + // 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). + cgoenv := b.cCompilerEnv() + if len(cgoLDFLAGS) > 0 { + flags := make([]string, len(cgoLDFLAGS)) + for i, f := range cgoLDFLAGS { + flags[i] = strconv.Quote(f) + } + cgoenv = append(cgoenv, "CGO_LDFLAGS="+strings.Join(flags, " ")) + } + + if cfg.BuildToolchainName == "gccgo" { + if b.gccSupportsFlag([]string{BuildToolchain.compiler()}, "-fsplit-stack") { + cgoCFLAGS = append(cgoCFLAGS, "-fsplit-stack") + } + cgoflags = append(cgoflags, "-gccgo") + if pkgpath := gccgoPkgpath(p); pkgpath != "" { + cgoflags = append(cgoflags, "-gccgopkgpath="+pkgpath) + } + } + + switch cfg.BuildBuildmode { + case "c-archive", "c-shared": + // Tell cgo that if there are any exported functions + // it should generate a header file that C code can + // #include. + cgoflags = append(cgoflags, "-exportheader="+objdir+"_cgo_install.h") + } + + execdir := p.Dir + + // Rewrite overlaid paths in cgo files. + // cgo adds //line and #line pragmas in generated files with these paths. + var trimpath []string + for i := range cgofiles { + path := mkAbs(p.Dir, cgofiles[i]) + if opath, ok := fsys.OverlayPath(path); ok { + cgofiles[i] = opath + trimpath = append(trimpath, opath+"=>"+path) + } + } + if len(trimpath) > 0 { + cgoflags = append(cgoflags, "-trimpath", strings.Join(trimpath, ";")) + } + + if err := b.run(a, execdir, p.ImportPath, cgoenv, cfg.BuildToolexec, cgoExe, "-objdir", objdir, "-importpath", p.ImportPath, cgoflags, "--", cgoCPPFLAGS, cgoCFLAGS, cgofiles); err != nil { + return nil, nil, err + } + outGo = append(outGo, gofiles...) + + // Use sequential object file names to keep them distinct + // and short enough to fit in the .a header file name slots. + // We no longer collect them all into _all.o, and we'd like + // tools to see both the .o suffix and unique names, so + // we need to make them short enough not to be truncated + // in the final archive. + oseq := 0 + nextOfile := func() string { + oseq++ + return objdir + fmt.Sprintf("_x%03d.o", oseq) + } + + // gcc + cflags := str.StringList(cgoCPPFLAGS, cgoCFLAGS) + for _, cfile := range cfiles { + ofile := nextOfile() + if err := b.gcc(a, p, a.Objdir, ofile, cflags, objdir+cfile); err != nil { + return nil, nil, err + } + outObj = append(outObj, ofile) + } + + for _, file := range gccfiles { + ofile := nextOfile() + if err := b.gcc(a, p, a.Objdir, ofile, cflags, file); err != nil { + return nil, nil, err + } + outObj = append(outObj, ofile) + } + + cxxflags := str.StringList(cgoCPPFLAGS, cgoCXXFLAGS) + for _, file := range gxxfiles { + ofile := nextOfile() + if err := b.gxx(a, p, a.Objdir, ofile, cxxflags, file); err != nil { + return nil, nil, err + } + outObj = append(outObj, ofile) + } + + for _, file := range mfiles { + ofile := nextOfile() + if err := b.gcc(a, p, a.Objdir, ofile, cflags, file); err != nil { + return nil, nil, err + } + outObj = append(outObj, ofile) + } + + fflags := str.StringList(cgoCPPFLAGS, cgoFFLAGS) + for _, file := range ffiles { + ofile := nextOfile() + if err := b.gfortran(a, p, a.Objdir, ofile, fflags, file); err != nil { + return nil, nil, err + } + outObj = append(outObj, ofile) + } + + switch cfg.BuildToolchainName { + case "gc": + importGo := objdir + "_cgo_import.go" + if err := b.dynimport(a, p, objdir, importGo, cgoExe, cflags, cgoLDFLAGS, outObj); err != nil { + return nil, nil, err + } + outGo = append(outGo, importGo) + + case "gccgo": + defunC := objdir + "_cgo_defun.c" + defunObj := objdir + "_cgo_defun.o" + if err := BuildToolchain.cc(b, a, defunObj, defunC); err != nil { + return nil, nil, err + } + outObj = append(outObj, defunObj) + + default: + noCompiler() + } + + // Double check the //go:cgo_ldflag comments in the generated files. + // The compiler only permits such comments in files whose base name + // starts with "_cgo_". Make sure that the comments in those files + // are safe. This is a backstop against people somehow smuggling + // such a comment into a file generated by cgo. + if cfg.BuildToolchainName == "gc" && !cfg.BuildN { + var flags []string + for _, f := range outGo { + if !strings.HasPrefix(filepath.Base(f), "_cgo_") { + continue + } + + src, err := os.ReadFile(f) + if err != nil { + return nil, nil, err + } + + const cgoLdflag = "//go:cgo_ldflag" + idx := bytes.Index(src, []byte(cgoLdflag)) + for idx >= 0 { + // We are looking at //go:cgo_ldflag. + // Find start of line. + start := bytes.LastIndex(src[:idx], []byte("\n")) + if start == -1 { + start = 0 + } + + // Find end of line. + end := bytes.Index(src[idx:], []byte("\n")) + if end == -1 { + end = len(src) + } else { + end += idx + } + + // Check for first line comment in line. + // We don't worry about /* */ comments, + // which normally won't appear in files + // generated by cgo. + commentStart := bytes.Index(src[start:], []byte("//")) + commentStart += start + // If that line comment is //go:cgo_ldflag, + // it's a match. + if bytes.HasPrefix(src[commentStart:], []byte(cgoLdflag)) { + // Pull out the flag, and unquote it. + // This is what the compiler does. + flag := string(src[idx+len(cgoLdflag) : end]) + flag = strings.TrimSpace(flag) + flag = strings.Trim(flag, `"`) + flags = append(flags, flag) + } + src = src[end:] + idx = bytes.Index(src, []byte(cgoLdflag)) + } + } + + // We expect to find the contents of cgoLDFLAGS in flags. + if len(cgoLDFLAGS) > 0 { + outer: + for i := range flags { + for j, f := range cgoLDFLAGS { + if f != flags[i+j] { + continue outer + } + } + flags = append(flags[:i], flags[i+len(cgoLDFLAGS):]...) + break + } + } + + if err := checkLinkerFlags("LDFLAGS", "go:cgo_ldflag", flags); err != nil { + return nil, nil, err + } + } + + return outGo, outObj, nil +} + +// dynimport creates a Go source file named importGo containing +// //go:cgo_import_dynamic directives for each symbol or library +// dynamically imported by the object files outObj. +func (b *Builder) dynimport(a *Action, p *load.Package, objdir, importGo, cgoExe string, cflags, cgoLDFLAGS, outObj []string) error { + cfile := objdir + "_cgo_main.c" + ofile := objdir + "_cgo_main.o" + if err := b.gcc(a, p, objdir, ofile, cflags, cfile); err != nil { + return err + } + + linkobj := str.StringList(ofile, outObj, mkAbsFiles(p.Dir, p.SysoFiles)) + dynobj := objdir + "_cgo_.o" + + // 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" { + // -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(a, p, objdir, dynobj, ldflags, linkobj); err != nil { + return err + } + + // cgo -dynimport + var cgoflags []string + if p.Standard && p.ImportPath == "runtime/cgo" { + cgoflags = []string{"-dynlinker"} // record path to dynamic linker + } + return b.run(a, base.Cwd, p.ImportPath, b.cCompilerEnv(), cfg.BuildToolexec, cgoExe, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags) +} + +// Run SWIG on all SWIG input files. +// TODO: Don't build a shared library, once SWIG emits the necessary +// pragmas for external linking. +func (b *Builder) swig(a *Action, p *load.Package, objdir string, pcCFLAGS []string) (outGo, outC, outCXX []string, err error) { + if err := b.swigVersionCheck(); err != nil { + return nil, nil, nil, err + } + + intgosize, err := b.swigIntSize(objdir) + if err != nil { + return nil, nil, nil, err + } + + for _, f := range p.SwigFiles { + goFile, cFile, err := b.swigOne(a, p, f, objdir, pcCFLAGS, false, intgosize) + if err != nil { + return nil, nil, nil, err + } + if goFile != "" { + outGo = append(outGo, goFile) + } + if cFile != "" { + outC = append(outC, cFile) + } + } + for _, f := range p.SwigCXXFiles { + goFile, cxxFile, err := b.swigOne(a, p, f, objdir, pcCFLAGS, true, intgosize) + if err != nil { + return nil, nil, nil, err + } + if goFile != "" { + outGo = append(outGo, goFile) + } + if cxxFile != "" { + outCXX = append(outCXX, cxxFile) + } + } + return outGo, outC, outCXX, nil +} + +// Make sure SWIG is new enough. +var ( + swigCheckOnce sync.Once + swigCheck error +) + +func (b *Builder) swigDoVersionCheck() error { + out, err := b.runOut(nil, "", nil, "swig", "-version") + if err != nil { + return err + } + re := regexp.MustCompile(`[vV]ersion +([\d]+)([.][\d]+)?([.][\d]+)?`) + matches := re.FindSubmatch(out) + if matches == nil { + // Can't find version number; hope for the best. + return nil + } + + major, err := strconv.Atoi(string(matches[1])) + if err != nil { + // Can't find version number; hope for the best. + return nil + } + const errmsg = "must have SWIG version >= 3.0.6" + if major < 3 { + return errors.New(errmsg) + } + if major > 3 { + // 4.0 or later + return nil + } + + // We have SWIG version 3.x. + if len(matches[2]) > 0 { + minor, err := strconv.Atoi(string(matches[2][1:])) + if err != nil { + return nil + } + if minor > 0 { + // 3.1 or later + return nil + } + } + + // We have SWIG version 3.0.x. + if len(matches[3]) > 0 { + patch, err := strconv.Atoi(string(matches[3][1:])) + if err != nil { + return nil + } + if patch < 6 { + // Before 3.0.6. + return errors.New(errmsg) + } + } + + return nil +} + +func (b *Builder) swigVersionCheck() error { + swigCheckOnce.Do(func() { + swigCheck = b.swigDoVersionCheck() + }) + return swigCheck +} + +// Find the value to pass for the -intgosize option to swig. +var ( + swigIntSizeOnce sync.Once + swigIntSize string + swigIntSizeError error +) + +// This code fails to build if sizeof(int) <= 32 +const swigIntSizeCode = ` +package main +const i int = 1 << 32 +` + +// Determine the size of int on the target system for the -intgosize option +// of swig >= 2.0.9. Run only once. +func (b *Builder) swigDoIntSize(objdir string) (intsize string, err error) { + if cfg.BuildN { + return "$INTBITS", nil + } + src := filepath.Join(b.WorkDir, "swig_intsize.go") + if err = os.WriteFile(src, []byte(swigIntSizeCode), 0666); err != nil { + return + } + srcs := []string{src} + + p := load.GoFilesPackage(context.TODO(), srcs) + + if _, _, e := BuildToolchain.gc(b, &Action{Mode: "swigDoIntSize", Package: p, Objdir: objdir}, "", nil, nil, "", false, srcs); e != nil { + return "32", nil + } + return "64", nil +} + +// Determine the size of int on the target system for the -intgosize option +// of swig >= 2.0.9. +func (b *Builder) swigIntSize(objdir string) (intsize string, err error) { + swigIntSizeOnce.Do(func() { + swigIntSize, swigIntSizeError = b.swigDoIntSize(objdir) + }) + return swigIntSize, swigIntSizeError +} + +// Run SWIG on one SWIG input file. +func (b *Builder) swigOne(a *Action, p *load.Package, file, objdir string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outC string, err error) { + cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _, err := b.CFlags(p) + if err != nil { + return "", "", err + } + + var cflags []string + if cxx { + cflags = str.StringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS) + } else { + cflags = str.StringList(cgoCPPFLAGS, pcCFLAGS, cgoCFLAGS) + } + + n := 5 // length of ".swig" + if cxx { + n = 8 // length of ".swigcxx" + } + base := file[:len(file)-n] + goFile := base + ".go" + gccBase := base + "_wrap." + gccExt := "c" + if cxx { + gccExt = "cxx" + } + + gccgo := cfg.BuildToolchainName == "gccgo" + + // swig + args := []string{ + "-go", + "-cgo", + "-intgosize", intgosize, + "-module", base, + "-o", objdir + gccBase + gccExt, + "-outdir", objdir, + } + + for _, f := range cflags { + if len(f) > 3 && f[:2] == "-I" { + args = append(args, f) + } + } + + if gccgo { + args = append(args, "-gccgo") + if pkgpath := gccgoPkgpath(p); pkgpath != "" { + args = append(args, "-go-pkgpath", pkgpath) + } + } + if cxx { + args = append(args, "-c++") + } + + out, err := b.runOut(a, 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.Desc(), b.processOutput(out)) // swig error + return "", "", errPrintedOutput + } + return "", "", err + } + if len(out) > 0 { + 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. + // But there might be an x.go in the original dir too, and if it + // uses cgo as well, cgo will be processing both and will + // translate both into x.cgo1.go in the objdir, overwriting one. + // Rename x.go to _x_swig.go to avoid this problem. + // We ignore files in the original dir that begin with underscore + // so _x_swig.go cannot conflict with an original file we were + // going to compile. + goFile = objdir + goFile + newGoFile := objdir + "_" + base + "_swig.go" + if err := os.Rename(goFile, newGoFile); err != nil { + return "", "", err + } + return newGoFile, objdir + gccBase + gccExt, nil +} + +// disableBuildID adjusts a linker command line to avoid creating a +// build ID when creating an object file rather than an executable or +// shared library. Some systems, such as Ubuntu, always add +// --build-id to every link, but we don't want a build ID when we are +// producing an object file. On some of those system a plain -r (not +// -Wl,-r) will turn off --build-id, but clang 3.0 doesn't support a +// plain -r. I don't know how to turn off --build-id when using clang +// other than passing a trailing --build-id=none. So that is what we +// do, but only on systems likely to support it, which is to say, +// systems that normally use gold or the GNU linker. +func (b *Builder) disableBuildID(ldflags []string) []string { + switch cfg.Goos { + case "android", "dragonfly", "linux", "netbsd": + ldflags = append(ldflags, "-Wl,--build-id=none") + } + return ldflags +} + +// mkAbsFiles converts files into a list of absolute files, +// assuming they were originally relative to dir, +// and returns that new list. +func mkAbsFiles(dir string, files []string) []string { + abs := make([]string, len(files)) + for i, f := range files { + if !filepath.IsAbs(f) { + f = filepath.Join(dir, f) + } + abs[i] = f + } + return abs +} + +// passLongArgsInResponseFiles modifies cmd 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 issues 18468 (Windows) and 37768 (Darwin). +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 := os.CreateTemp("", "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", encodeArg(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 +} + +// 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. Darwin's limit is +// less clear. The OS claims 256KB, but we've seen failures with arglen as +// small as 50KB. +const ArgLengthForResponseFile = (30 << 10) + +func useResponseFile(path string, argLen int) bool { + // 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 + } + + if argLen > ArgLengthForResponseFile { + return true + } + + // On the Go build system, use response files about 10% of the + // time, just to exercise this codepath. + isBuilder := os.Getenv("GO_BUILDER_NAME") != "" + if isBuilder && rand.Intn(10) == 0 { + return true + } + + return false +} + +// encodeArg encodes an argument for response file writing. +func encodeArg(arg string) string { + // If there aren't any characters we need to reencode, fastpath out. + if !strings.ContainsAny(arg, "\\\n") { + return arg + } + var b strings.Builder + for _, r := range arg { + switch r { + case '\\': + b.WriteByte('\\') + b.WriteByte('\\') + case '\n': + b.WriteByte('\\') + b.WriteByte('n') + default: + b.WriteRune(r) + } + } + return b.String() +} diff --git a/src/cmd/go/internal/work/exec_test.go b/src/cmd/go/internal/work/exec_test.go new file mode 100644 index 0000000..4eb762c --- /dev/null +++ b/src/cmd/go/internal/work/exec_test.go @@ -0,0 +1,86 @@ +// Copyright 2011 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 work + +import ( + "bytes" + "cmd/internal/objabi" + "fmt" + "math/rand" + "testing" + "time" + "unicode/utf8" +) + +func TestEncodeArgs(t *testing.T) { + t.Parallel() + tests := []struct { + arg, want string + }{ + {"", ""}, + {"hello", "hello"}, + {"hello\n", "hello\\n"}, + {"hello\\", "hello\\\\"}, + {"hello\nthere", "hello\\nthere"}, + {"\\\n", "\\\\\\n"}, + } + for _, test := range tests { + if got := encodeArg(test.arg); got != test.want { + t.Errorf("encodeArg(%q) = %q, want %q", test.arg, got, test.want) + } + } +} + +func TestEncodeDecode(t *testing.T) { + t.Parallel() + tests := []string{ + "", + "hello", + "hello\\there", + "hello\nthere", + "hello 中国", + "hello \n中\\国", + } + for _, arg := range tests { + if got := objabi.DecodeArg(encodeArg(arg)); got != arg { + t.Errorf("objabi.DecodeArg(encodeArg(%q)) = %q", arg, got) + } + } +} + +func TestEncodeDecodeFuzz(t *testing.T) { + if testing.Short() { + t.Skip("fuzz test is slow") + } + t.Parallel() + + nRunes := ArgLengthForResponseFile + 100 + rBuffer := make([]rune, nRunes) + buf := bytes.NewBuffer([]byte(string(rBuffer))) + + seed := time.Now().UnixNano() + t.Logf("rand seed: %v", seed) + rng := rand.New(rand.NewSource(seed)) + + for i := 0; i < 50; i++ { + // Generate a random string of runes. + buf.Reset() + for buf.Len() < ArgLengthForResponseFile+1 { + var r rune + for { + r = rune(rng.Intn(utf8.MaxRune + 1)) + if utf8.ValidRune(r) { + break + } + } + fmt.Fprintf(buf, "%c", r) + } + arg := buf.String() + + if got := objabi.DecodeArg(encodeArg(arg)); got != arg { + t.Errorf("[%d] objabi.DecodeArg(encodeArg(%q)) = %q [seed: %v]", i, arg, got, seed) + } + } +} diff --git a/src/cmd/go/internal/work/gc.go b/src/cmd/go/internal/work/gc.go new file mode 100644 index 0000000..cc4e2b2 --- /dev/null +++ b/src/cmd/go/internal/work/gc.go @@ -0,0 +1,693 @@ +// Copyright 2011 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 work + +import ( + "bufio" + "bytes" + "fmt" + "io" + "log" + "os" + "path/filepath" + "runtime" + "strings" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/fsys" + "cmd/go/internal/load" + "cmd/go/internal/str" + "cmd/internal/objabi" + "cmd/internal/sys" + "crypto/sha1" +) + +// The 'path' used for GOROOT_FINAL when -trimpath is specified +const trimPathGoRootFinal = "go" + +// The Go toolchain. + +type gcToolchain struct{} + +func (gcToolchain) compiler() string { + return base.Tool("compile") +} + +func (gcToolchain) linker() string { + return base.Tool("link") +} + +func pkgPath(a *Action) string { + p := a.Package + ppath := p.ImportPath + if cfg.BuildBuildmode == "plugin" { + ppath = pluginPath(a) + } else if p.Name == "main" && !p.Internal.ForceLibrary { + ppath = "main" + } + return ppath +} + +func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg, embedcfg []byte, symabis string, asmhdr bool, gofiles []string) (ofile string, output []byte, err error) { + p := a.Package + objdir := a.Objdir + if archive != "" { + ofile = archive + } else { + out := "_go_.o" + ofile = objdir + out + } + + pkgpath := pkgPath(a) + gcargs := []string{"-p", pkgpath} + if p.Module != nil && p.Module.GoVersion != "" && allowedVersion(p.Module.GoVersion) { + gcargs = append(gcargs, "-lang=go"+p.Module.GoVersion) + } + if p.Standard { + 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 check for + // memory allocations that are invalid in the runtime package, + // and to implement some special compiler pragmas. + gcargs = append(gcargs, "-+") + } + + // If we're giving the compiler the entire package (no C etc files), tell it that, + // so that it can give good error messages about forward declarations. + // Exceptions: a few standard packages have forward declarations for + // pieces supplied behind-the-scenes by package runtime. + 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": + fallthrough + case "runtime/metrics", "runtime/pprof", "runtime/trace": + fallthrough + case "sync", "syscall", "time": + extFiles++ + } + } + if extFiles == 0 { + gcargs = append(gcargs, "-complete") + } + if cfg.BuildContext.InstallSuffix != "" { + gcargs = append(gcargs, "-installsuffix", cfg.BuildContext.InstallSuffix) + } + if a.buildID != "" { + gcargs = append(gcargs, "-buildid", a.buildID) + } + if p.Internal.OmitDebug || cfg.Goos == "plan9" || cfg.Goarch == "wasm" { + gcargs = append(gcargs, "-dwarf=false") + } + if strings.HasPrefix(runtimeVersion, "go1") && !strings.Contains(os.Args[0], "go_bootstrap") { + gcargs = append(gcargs, "-goversion", runtimeVersion) + } + if symabis != "" { + gcargs = append(gcargs, "-symabis", symabis) + } + + gcflags := str.StringList(forcedGcflags, p.Internal.Gcflags) + if compilingRuntime { + // Remove -N, if present. + // It is not possible to build the runtime with no optimizations, + // because the compiler cannot eliminate enough write barriers. + for i := 0; i < len(gcflags); i++ { + if gcflags[i] == "-N" { + copy(gcflags[i:], gcflags[i+1:]) + gcflags = gcflags[:len(gcflags)-1] + i-- + } + } + } + + args := []interface{}{cfg.BuildToolexec, base.Tool("compile"), "-o", ofile, "-trimpath", a.trimpath(), gcflags, gcargs, "-D", p.Internal.LocalPrefix} + if importcfg != nil { + if err := b.writeFile(objdir+"importcfg", importcfg); err != nil { + return "", nil, err + } + args = append(args, "-importcfg", objdir+"importcfg") + } + if embedcfg != nil { + if err := b.writeFile(objdir+"embedcfg", embedcfg); err != nil { + return "", nil, err + } + args = append(args, "-embedcfg", objdir+"embedcfg") + } + if ofile == archive { + args = append(args, "-pack") + } + if asmhdr { + args = append(args, "-asmhdr", objdir+"go_asm.h") + } + + // Add -c=N to use concurrent backend compilation, if possible. + if c := gcBackendConcurrency(gcflags); c > 1 { + args = append(args, fmt.Sprintf("-c=%d", c)) + } + + for _, f := range gofiles { + f := mkAbs(p.Dir, f) + + // Handle overlays. Convert path names using OverlayPath + // so these paths can be handed directly to tools. + // Deleted files won't show up in when scanning directories earlier, + // so OverlayPath will never return "" (meaning a deleted file) here. + // TODO(#39958): Handle cases where the package directory + // doesn't exist on disk (this can happen when all the package's + // files are in an overlay): the code expects the package directory + // to exist and runs some tools in that directory. + // TODO(#39958): Process the overlays when the + // gofiles, cgofiles, cfiles, sfiles, and cxxfiles variables are + // created in (*Builder).build. Doing that requires rewriting the + // code that uses those values to expect absolute paths. + f, _ = fsys.OverlayPath(f) + + args = append(args, f) + } + + output, err = b.runOut(a, base.Cwd, nil, args...) + return ofile, output, err +} + +// gcBackendConcurrency returns the backend compiler concurrency level for a package compilation. +func gcBackendConcurrency(gcflags []string) int { + // First, check whether we can use -c at all for this compilation. + canDashC := concurrentGCBackendCompilationEnabledByDefault + + switch e := os.Getenv("GO19CONCURRENTCOMPILATION"); e { + case "0": + canDashC = false + case "1": + canDashC = true + case "": + // Not set. Use default. + default: + log.Fatalf("GO19CONCURRENTCOMPILATION must be 0, 1, or unset, got %q", e) + } + +CheckFlags: + for _, flag := range gcflags { + // Concurrent compilation is presumed incompatible with any gcflags, + // except for known commonly used flags. + // If the user knows better, they can manually add their own -c to the gcflags. + switch flag { + case "-N", "-l", "-S", "-B", "-C", "-I": + // OK + default: + canDashC = false + break CheckFlags + } + } + + // TODO: Test and delete these conditions. + if objabi.Fieldtrack_enabled != 0 || objabi.Preemptibleloops_enabled != 0 { + canDashC = false + } + + if !canDashC { + return 1 + } + + // Decide how many concurrent backend compilations to allow. + // + // If we allow too many, in theory we might end up with p concurrent processes, + // each with c concurrent backend compiles, all fighting over the same resources. + // However, in practice, that seems not to happen too much. + // Most build graphs are surprisingly serial, so p==1 for much of the build. + // Furthermore, concurrent backend compilation is only enabled for a part + // of the overall compiler execution, so c==1 for much of the build. + // So don't worry too much about that interaction for now. + // + // However, in practice, setting c above 4 tends not to help very much. + // See the analysis in CL 41192. + // + // TODO(josharian): attempt to detect whether this particular compilation + // is likely to be a bottleneck, e.g. when: + // - it has no successor packages to compile (usually package main) + // - all paths through the build graph pass through it + // - critical path scheduling says it is high priority + // and in such a case, set c to runtime.NumCPU. + // We do this now when p==1. + if cfg.BuildP == 1 { + // No process parallelism. Max out c. + return runtime.NumCPU() + } + // Some process parallelism. Set c to min(4, numcpu). + c := 4 + if ncpu := runtime.NumCPU(); ncpu < c { + c = ncpu + } + return c +} + +// trimpath returns the -trimpath argument to use +// when compiling the action. +func (a *Action) trimpath() string { + // Keep in sync with Builder.ccompile + // The trimmed paths are a little different, but we need to trim in the + // same situations. + + // Strip the object directory entirely. + objdir := a.Objdir + if len(objdir) > 1 && objdir[len(objdir)-1] == filepath.Separator { + objdir = objdir[:len(objdir)-1] + } + rewrite := "" + + rewriteDir := a.Package.Dir + if cfg.BuildTrimpath { + if m := a.Package.Module; m != nil && m.Version != "" { + rewriteDir = m.Path + "@" + m.Version + strings.TrimPrefix(a.Package.ImportPath, m.Path) + } else { + rewriteDir = a.Package.ImportPath + } + rewrite += a.Package.Dir + "=>" + rewriteDir + ";" + } + + // Add rewrites for overlays. The 'from' and 'to' paths in overlays don't need to have + // same basename, so go from the overlay contents file path (passed to the compiler) + // to the path the disk path would be rewritten to. + + cgoFiles := make(map[string]bool) + for _, f := range a.Package.CgoFiles { + cgoFiles[f] = true + } + + // TODO(matloob): Higher up in the stack, when the logic for deciding when to make copies + // of c/c++/m/f/hfiles is consolidated, use the same logic that Build uses to determine + // whether to create the copies in objdir to decide whether to rewrite objdir to the + // package directory here. + var overlayNonGoRewrites string // rewrites for non-go files + hasCgoOverlay := false + if fsys.OverlayFile != "" { + for _, filename := range a.Package.AllFiles() { + path := filename + if !filepath.IsAbs(path) { + path = filepath.Join(a.Package.Dir, path) + } + base := filepath.Base(path) + isGo := strings.HasSuffix(filename, ".go") || strings.HasSuffix(filename, ".s") + isCgo := cgoFiles[filename] || !isGo + overlayPath, isOverlay := fsys.OverlayPath(path) + if isCgo && isOverlay { + hasCgoOverlay = true + } + if !isCgo && isOverlay { + rewrite += overlayPath + "=>" + filepath.Join(rewriteDir, base) + ";" + } else if isCgo { + // Generate rewrites for non-Go files copied to files in objdir. + if filepath.Dir(path) == a.Package.Dir { + // This is a file copied to objdir. + overlayNonGoRewrites += filepath.Join(objdir, base) + "=>" + filepath.Join(rewriteDir, base) + ";" + } + } else { + // Non-overlay Go files are covered by the a.Package.Dir rewrite rule above. + } + } + } + if hasCgoOverlay { + rewrite += overlayNonGoRewrites + } + rewrite += objdir + "=>" + + return rewrite +} + +func asmArgs(a *Action, p *load.Package) []interface{} { + // Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files. + inc := filepath.Join(cfg.GOROOT, "pkg", "include") + pkgpath := pkgPath(a) + args := []interface{}{cfg.BuildToolexec, base.Tool("asm"), "-p", pkgpath, "-trimpath", a.trimpath(), "-I", a.Objdir, "-I", inc, "-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch, forcedAsmflags, p.Internal.Asmflags} + if p.ImportPath == "runtime" && cfg.Goarch == "386" { + for _, arg := range forcedAsmflags { + if arg == "-dynlink" { + args = append(args, "-D=GOBUILDMODE_shared=1") + } + } + } + if objabi.IsRuntimePackagePath(pkgpath) { + args = append(args, "-compiling-runtime") + if objabi.Regabi_enabled != 0 { + // In order to make it easier to port runtime assembly + // to the register ABI, we introduce a macro + // indicating the experiment is enabled. + // + // Note: a similar change also appears in + // cmd/dist/build.go. + // + // TODO(austin): Remove this once we commit to the + // register ABI (#40724). + args = append(args, "-D=GOEXPERIMENT_REGABI=1") + } + } + + if cfg.Goarch == "mips" || cfg.Goarch == "mipsle" { + // Define GOMIPS_value from cfg.GOMIPS. + 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) + } + + return args +} + +func (gcToolchain) asm(b *Builder, a *Action, sfiles []string) ([]string, error) { + p := a.Package + args := asmArgs(a, p) + + var ofiles []string + for _, sfile := range sfiles { + overlayPath, _ := fsys.OverlayPath(mkAbs(p.Dir, sfile)) + ofile := a.Objdir + sfile[:len(sfile)-len(".s")] + ".o" + ofiles = append(ofiles, ofile) + args1 := append(args, "-o", ofile, overlayPath) + if err := b.run(a, p.Dir, p.ImportPath, nil, args1...); err != nil { + return nil, err + } + } + return ofiles, nil +} + +func (gcToolchain) symabis(b *Builder, a *Action, sfiles []string) (string, error) { + mkSymabis := func(p *load.Package, sfiles []string, path string) error { + args := asmArgs(a, p) + args = append(args, "-gensymabis", "-o", path) + for _, sfile := range sfiles { + if p.ImportPath == "runtime/cgo" && strings.HasPrefix(sfile, "gcc_") { + continue + } + op, _ := fsys.OverlayPath(mkAbs(p.Dir, sfile)) + args = append(args, op) + } + + // Supply an empty go_asm.h as if the compiler had been run. + // -gensymabis parsing is lax enough that we don't need the + // actual definitions that would appear in go_asm.h. + if err := b.writeFile(a.Objdir+"go_asm.h", nil); err != nil { + return err + } + + return b.run(a, p.Dir, p.ImportPath, nil, args...) + } + + var symabis string // Only set if we actually create the file + p := a.Package + if len(sfiles) != 0 { + symabis = a.Objdir + "symabis" + if err := mkSymabis(p, sfiles, symabis); err != nil { + return "", err + } + } + + return symabis, nil +} + +// toolVerify checks that the command line args writes the same output file +// if run using newTool instead. +// Unused now but kept around for future use. +func toolVerify(a *Action, b *Builder, p *load.Package, newTool string, ofile string, args []interface{}) error { + newArgs := make([]interface{}, len(args)) + copy(newArgs, args) + newArgs[1] = base.Tool(newTool) + newArgs[3] = ofile + ".new" // x.6 becomes x.6.new + if err := b.run(a, p.Dir, p.ImportPath, nil, newArgs...); err != nil { + return err + } + data1, err := os.ReadFile(ofile) + if err != nil { + return err + } + data2, err := os.ReadFile(ofile + ".new") + if err != nil { + return err + } + if !bytes.Equal(data1, data2) { + return fmt.Errorf("%s and %s produced different output files:\n%s\n%s", filepath.Base(args[1].(string)), newTool, strings.Join(str.StringList(args...), " "), strings.Join(str.StringList(newArgs...), " ")) + } + os.Remove(ofile + ".new") + return nil +} + +func (gcToolchain) pack(b *Builder, a *Action, afile string, ofiles []string) error { + var absOfiles []string + for _, f := range ofiles { + absOfiles = append(absOfiles, mkAbs(a.Objdir, f)) + } + absAfile := mkAbs(a.Objdir, afile) + + // The archive file should have been created by the compiler. + // Since it used to not work that way, verify. + if !cfg.BuildN { + if _, err := os.Stat(absAfile); err != nil { + base.Fatalf("os.Stat of archive file failed: %v", err) + } + } + + p := a.Package + if cfg.BuildN || cfg.BuildX { + cmdline := str.StringList(base.Tool("pack"), "r", absAfile, absOfiles) + b.Showcmd(p.Dir, "%s # internal", joinUnambiguously(cmdline)) + } + if cfg.BuildN { + return nil + } + if err := packInternal(absAfile, absOfiles); err != nil { + b.showOutput(a, p.Dir, p.Desc(), err.Error()+"\n") + return errPrintedOutput + } + return nil +} + +func packInternal(afile string, ofiles []string) error { + dst, err := os.OpenFile(afile, os.O_WRONLY|os.O_APPEND, 0) + if err != nil { + return err + } + defer dst.Close() // only for error returns or panics + w := bufio.NewWriter(dst) + + for _, ofile := range ofiles { + src, err := os.Open(ofile) + if err != nil { + return err + } + fi, err := src.Stat() + if err != nil { + src.Close() + return err + } + // Note: Not using %-16.16s format because we care + // about bytes, not runes. + name := fi.Name() + if len(name) > 16 { + name = name[:16] + } else { + name += strings.Repeat(" ", 16-len(name)) + } + size := fi.Size() + fmt.Fprintf(w, "%s%-12d%-6d%-6d%-8o%-10d`\n", + name, 0, 0, 0, 0644, size) + n, err := io.Copy(w, src) + src.Close() + if err == nil && n < size { + err = io.ErrUnexpectedEOF + } else if err == nil && n > size { + err = fmt.Errorf("file larger than size reported by stat") + } + if err != nil { + return fmt.Errorf("copying %s to %s: %v", ofile, afile, err) + } + if size&1 != 0 { + w.WriteByte(0) + } + } + + if err := w.Flush(); err != nil { + return err + } + return dst.Close() +} + +// setextld sets the appropriate linker flags for the specified compiler. +func setextld(ldflags []string, compiler []string) []string { + for _, f := range ldflags { + if f == "-extld" || strings.HasPrefix(f, "-extld=") { + // don't override -extld if supplied + return ldflags + } + } + ldflags = append(ldflags, "-extld="+compiler[0]) + if len(compiler) > 1 { + extldflags := false + add := strings.Join(compiler[1:], " ") + for i, f := range ldflags { + if f == "-extldflags" && i+1 < len(ldflags) { + ldflags[i+1] = add + " " + ldflags[i+1] + extldflags = true + break + } else if strings.HasPrefix(f, "-extldflags=") { + ldflags[i] = "-extldflags=" + add + " " + ldflags[i][len("-extldflags="):] + extldflags = true + break + } + } + if !extldflags { + ldflags = append(ldflags, "-extldflags="+add) + } + } + return ldflags +} + +// pluginPath computes the package path for a plugin main package. +// +// This is typically the import path of the main package p, unless the +// plugin is being built directly from source files. In that case we +// combine the package build ID with the contents of the main package +// source files. This allows us to identify two different plugins +// built from two source files with the same name. +func pluginPath(a *Action) string { + p := a.Package + if p.ImportPath != "command-line-arguments" { + return p.ImportPath + } + h := sha1.New() + buildID := a.buildID + if a.Mode == "link" { + // For linking, use the main package's build ID instead of + // the binary's build ID, so it is the same hash used in + // compiling and linking. + // When compiling, we use actionID/actionID (instead of + // actionID/contentID) as a temporary build ID to compute + // the hash. Do the same here. (See buildid.go:useCache) + // The build ID matters because it affects the overall hash + // in the plugin's pseudo-import path returned below. + // We need to use the same import path when compiling and linking. + id := strings.Split(buildID, buildIDSeparator) + buildID = id[1] + buildIDSeparator + id[1] + } + fmt.Fprintf(h, "build ID: %s\n", buildID) + for _, file := range str.StringList(p.GoFiles, p.CgoFiles, p.SFiles) { + data, err := os.ReadFile(filepath.Join(p.Dir, file)) + if err != nil { + base.Fatalf("go: %s", err) + } + h.Write(data) + } + return fmt.Sprintf("plugin/unnamed-%x", h.Sum(nil)) +} + +func (gcToolchain) ld(b *Builder, root *Action, out, importcfg, mainpkg string) error { + cxx := len(root.Package.CXXFiles) > 0 || len(root.Package.SwigCXXFiles) > 0 + for _, a := range root.Deps { + if a.Package != nil && (len(a.Package.CXXFiles) > 0 || len(a.Package.SwigCXXFiles) > 0) { + cxx = true + } + } + var ldflags []string + if cfg.BuildContext.InstallSuffix != "" { + ldflags = append(ldflags, "-installsuffix", cfg.BuildContext.InstallSuffix) + } + if root.Package.Internal.OmitDebug { + ldflags = append(ldflags, "-s", "-w") + } + if cfg.BuildBuildmode == "plugin" { + ldflags = append(ldflags, "-pluginpath", pluginPath(root)) + } + + // Store BuildID inside toolchain binaries as a unique identifier of the + // tool being run, for use by content-based staleness determination. + if root.Package.Goroot && strings.HasPrefix(root.Package.ImportPath, "cmd/") { + // External linking will include our build id in the external + // linker's build id, which will cause our build id to not + // match the next time the tool is built. + // Rely on the external build id instead. + if !sys.MustLinkExternal(cfg.Goos, cfg.Goarch) { + ldflags = append(ldflags, "-X=cmd/internal/objabi.buildID="+root.buildID) + } + } + + // If the user has not specified the -extld option, then specify the + // appropriate linker. In case of C++ code, use the compiler named + // by the CXX environment variable or defaultCXX if CXX is not set. + // Else, use the CC environment variable and defaultCC as fallback. + var compiler []string + if cxx { + compiler = envList("CXX", cfg.DefaultCXX(cfg.Goos, cfg.Goarch)) + } else { + compiler = envList("CC", cfg.DefaultCC(cfg.Goos, cfg.Goarch)) + } + ldflags = append(ldflags, "-buildmode="+ldBuildmode) + if root.buildID != "" { + ldflags = append(ldflags, "-buildid="+root.buildID) + } + ldflags = append(ldflags, forcedLdflags...) + ldflags = append(ldflags, root.Package.Internal.Ldflags...) + ldflags = setextld(ldflags, compiler) + + // On OS X when using external linking to build a shared library, + // the argument passed here to -o ends up recorded in the final + // shared library in the LC_ID_DYLIB load command. + // To avoid putting the temporary output directory name there + // (and making the resulting shared library useless), + // run the link in the output directory so that -o can name + // just the final path element. + // On Windows, DLL file name is recorded in PE file + // export section, so do like on OS X. + dir := "." + if (cfg.Goos == "darwin" || cfg.Goos == "windows") && cfg.BuildBuildmode == "c-shared" { + dir, out = filepath.Split(out) + } + + env := []string{} + if cfg.BuildTrimpath { + env = append(env, "GOROOT_FINAL="+trimPathGoRootFinal) + } + return b.run(root, dir, root.Package.ImportPath, env, cfg.BuildToolexec, base.Tool("link"), "-o", out, "-importcfg", importcfg, ldflags, mainpkg) +} + +func (gcToolchain) ldShared(b *Builder, root *Action, toplevelactions []*Action, out, importcfg string, allactions []*Action) error { + ldflags := []string{"-installsuffix", cfg.BuildContext.InstallSuffix} + ldflags = append(ldflags, "-buildmode=shared") + ldflags = append(ldflags, forcedLdflags...) + ldflags = append(ldflags, root.Package.Internal.Ldflags...) + cxx := false + for _, a := range allactions { + if a.Package != nil && (len(a.Package.CXXFiles) > 0 || len(a.Package.SwigCXXFiles) > 0) { + cxx = true + } + } + // If the user has not specified the -extld option, then specify the + // appropriate linker. In case of C++ code, use the compiler named + // by the CXX environment variable or defaultCXX if CXX is not set. + // Else, use the CC environment variable and defaultCC as fallback. + var compiler []string + if cxx { + compiler = envList("CXX", cfg.DefaultCXX(cfg.Goos, cfg.Goarch)) + } else { + compiler = envList("CC", cfg.DefaultCC(cfg.Goos, cfg.Goarch)) + } + ldflags = setextld(ldflags, compiler) + for _, d := range toplevelactions { + if !strings.HasSuffix(d.Target, ".a") { // omit unsafe etc and actions for other shared libraries + continue + } + ldflags = append(ldflags, d.Package.ImportPath+"="+d.Target) + } + return b.run(root, ".", out, nil, cfg.BuildToolexec, base.Tool("link"), "-o", out, "-importcfg", importcfg, ldflags) +} + +func (gcToolchain) cc(b *Builder, a *Action, ofile, cfile string) error { + return fmt.Errorf("%s: C source files not supported without cgo", mkAbs(a.Package.Dir, cfile)) +} diff --git a/src/cmd/go/internal/work/gccgo.go b/src/cmd/go/internal/work/gccgo.go new file mode 100644 index 0000000..b58c8aa --- /dev/null +++ b/src/cmd/go/internal/work/gccgo.go @@ -0,0 +1,618 @@ +// Copyright 2011 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 work + +import ( + "fmt" + exec "internal/execabs" + "os" + "path/filepath" + "strings" + "sync" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/fsys" + "cmd/go/internal/load" + "cmd/go/internal/str" + "cmd/internal/pkgpath" +) + +// The Gccgo toolchain. + +type gccgoToolchain struct{} + +var GccgoName, GccgoBin string +var gccgoErr error + +func init() { + GccgoName = cfg.Getenv("GCCGO") + if GccgoName == "" { + GccgoName = "gccgo" + } + GccgoBin, gccgoErr = exec.LookPath(GccgoName) +} + +func (gccgoToolchain) compiler() string { + checkGccgoBin() + return GccgoBin +} + +func (gccgoToolchain) linker() string { + checkGccgoBin() + return GccgoBin +} + +func (gccgoToolchain) ar() string { + ar := cfg.Getenv("AR") + if ar == "" { + ar = "ar" + } + return ar +} + +func checkGccgoBin() { + if gccgoErr == nil { + return + } + fmt.Fprintf(os.Stderr, "cmd/go: gccgo: %s\n", gccgoErr) + base.SetExitStatus(2) + base.Exit() +} + +func (tools gccgoToolchain) gc(b *Builder, a *Action, archive string, importcfg, embedcfg []byte, symabis string, asmhdr bool, gofiles []string) (ofile string, output []byte, err error) { + p := a.Package + objdir := a.Objdir + out := "_go_.o" + ofile = objdir + out + gcargs := []string{"-g"} + gcargs = append(gcargs, b.gccArchArgs()...) + gcargs = append(gcargs, "-fdebug-prefix-map="+b.WorkDir+"=/tmp/go-build") + gcargs = append(gcargs, "-gno-record-gcc-switches") + if pkgpath := gccgoPkgpath(p); pkgpath != "" { + gcargs = append(gcargs, "-fgo-pkgpath="+pkgpath) + } + if p.Internal.LocalPrefix != "" { + gcargs = append(gcargs, "-fgo-relative-import-path="+p.Internal.LocalPrefix) + } + + args := str.StringList(tools.compiler(), "-c", gcargs, "-o", ofile, forcedGccgoflags) + if importcfg != nil { + if b.gccSupportsFlag(args[:1], "-fgo-importcfg=/dev/null") { + if err := b.writeFile(objdir+"importcfg", importcfg); err != nil { + return "", nil, err + } + args = append(args, "-fgo-importcfg="+objdir+"importcfg") + } else { + root := objdir + "_importcfgroot_" + if err := buildImportcfgSymlinks(b, root, importcfg); err != nil { + return "", nil, err + } + args = append(args, "-I", root) + } + } + if embedcfg != nil && b.gccSupportsFlag(args[:1], "-fgo-embedcfg=/dev/null") { + if err := b.writeFile(objdir+"embedcfg", embedcfg); err != nil { + return "", nil, err + } + args = append(args, "-fgo-embedcfg="+objdir+"embedcfg") + } + + if b.gccSupportsFlag(args[:1], "-ffile-prefix-map=a=b") { + if cfg.BuildTrimpath { + args = append(args, "-ffile-prefix-map="+base.Cwd+"=.") + args = append(args, "-ffile-prefix-map="+b.WorkDir+"=/tmp/go-build") + } + if fsys.OverlayFile != "" { + for _, name := range gofiles { + absPath := mkAbs(p.Dir, name) + overlayPath, ok := fsys.OverlayPath(absPath) + if !ok { + continue + } + toPath := absPath + // gccgo only applies the last matching rule, so also handle the case where + // BuildTrimpath is true and the path is relative to base.Cwd. + if cfg.BuildTrimpath && str.HasFilePathPrefix(toPath, base.Cwd) { + toPath = "." + toPath[len(base.Cwd):] + } + args = append(args, "-ffile-prefix-map="+overlayPath+"="+toPath) + } + } + } + + args = append(args, a.Package.Internal.Gccgoflags...) + for _, f := range gofiles { + f := mkAbs(p.Dir, f) + // Overlay files if necessary. + // See comment on gctoolchain.gc about overlay TODOs + f, _ = fsys.OverlayPath(f) + args = append(args, f) + } + + output, err = b.runOut(a, p.Dir, nil, args) + return ofile, output, err +} + +// buildImportcfgSymlinks builds in root a tree of symlinks +// implementing the directives from importcfg. +// This serves as a temporary transition mechanism until +// we can depend on gccgo reading an importcfg directly. +// (The Go 1.9 and later gc compilers already do.) +func buildImportcfgSymlinks(b *Builder, root string, importcfg []byte) error { + for lineNum, line := range strings.Split(string(importcfg), "\n") { + lineNum++ // 1-based + line = strings.TrimSpace(line) + if line == "" { + continue + } + if line == "" || strings.HasPrefix(line, "#") { + continue + } + var verb, args string + if i := strings.Index(line, " "); i < 0 { + verb = line + } else { + verb, args = line[:i], strings.TrimSpace(line[i+1:]) + } + var before, after string + if i := strings.Index(args, "="); i >= 0 { + before, after = args[:i], args[i+1:] + } + switch verb { + default: + base.Fatalf("importcfg:%d: unknown directive %q", lineNum, verb) + case "packagefile": + if before == "" || after == "" { + return fmt.Errorf(`importcfg:%d: invalid packagefile: syntax is "packagefile path=filename": %s`, lineNum, line) + } + archive := gccgoArchive(root, before) + if err := b.Mkdir(filepath.Dir(archive)); err != nil { + return err + } + if err := b.Symlink(after, archive); err != nil { + return err + } + case "importmap": + if before == "" || after == "" { + return fmt.Errorf(`importcfg:%d: invalid importmap: syntax is "importmap old=new": %s`, lineNum, line) + } + beforeA := gccgoArchive(root, before) + afterA := gccgoArchive(root, after) + if err := b.Mkdir(filepath.Dir(beforeA)); err != nil { + return err + } + if err := b.Mkdir(filepath.Dir(afterA)); err != nil { + return err + } + if err := b.Symlink(afterA, beforeA); err != nil { + return err + } + case "packageshlib": + return fmt.Errorf("gccgo -importcfg does not support shared libraries") + } + } + return nil +} + +func (tools gccgoToolchain) asm(b *Builder, a *Action, sfiles []string) ([]string, error) { + p := a.Package + var ofiles []string + for _, sfile := range sfiles { + base := filepath.Base(sfile) + ofile := a.Objdir + base[:len(base)-len(".s")] + ".o" + ofiles = append(ofiles, ofile) + sfile, _ = fsys.OverlayPath(mkAbs(p.Dir, sfile)) + defs := []string{"-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch} + if pkgpath := tools.gccgoCleanPkgpath(b, p); pkgpath != "" { + defs = append(defs, `-D`, `GOPKGPATH=`+pkgpath) + } + defs = tools.maybePIC(defs) + defs = append(defs, b.gccArchArgs()...) + err := b.run(a, p.Dir, p.ImportPath, nil, tools.compiler(), "-xassembler-with-cpp", "-I", a.Objdir, "-c", "-o", ofile, defs, sfile) + if err != nil { + return nil, err + } + } + return ofiles, nil +} + +func (gccgoToolchain) symabis(b *Builder, a *Action, sfiles []string) (string, error) { + return "", nil +} + +func gccgoArchive(basedir, imp string) string { + end := filepath.FromSlash(imp + ".a") + afile := filepath.Join(basedir, end) + // add "lib" to the final element + return filepath.Join(filepath.Dir(afile), "lib"+filepath.Base(afile)) +} + +func (tools gccgoToolchain) pack(b *Builder, a *Action, afile string, ofiles []string) error { + p := a.Package + objdir := a.Objdir + var absOfiles []string + for _, f := range ofiles { + absOfiles = append(absOfiles, mkAbs(objdir, f)) + } + var arArgs []string + if cfg.Goos == "aix" && cfg.Goarch == "ppc64" { + // AIX puts both 32-bit and 64-bit objects in the same archive. + // Tell the AIX "ar" command to only care about 64-bit objects. + arArgs = []string{"-X64"} + } + absAfile := mkAbs(objdir, afile) + // Try with D modifier first, then without if that fails. + output, err := b.runOut(a, p.Dir, nil, tools.ar(), arArgs, "rcD", absAfile, absOfiles) + if err != nil { + return b.run(a, p.Dir, p.ImportPath, nil, tools.ar(), arArgs, "rc", absAfile, absOfiles) + } + + if len(output) > 0 { + // Show the output if there is any even without errors. + b.showOutput(a, p.Dir, p.ImportPath, b.processOutput(output)) + } + + return nil +} + +func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string, allactions []*Action, buildmode, desc string) error { + // gccgo needs explicit linking with all package dependencies, + // and all LDFLAGS from cgo dependencies. + afiles := []string{} + shlibs := []string{} + ldflags := b.gccArchArgs() + cgoldflags := []string{} + usesCgo := false + cxx := false + objc := false + fortran := false + if root.Package != nil { + cxx = len(root.Package.CXXFiles) > 0 || len(root.Package.SwigCXXFiles) > 0 + objc = len(root.Package.MFiles) > 0 + fortran = len(root.Package.FFiles) > 0 + } + + readCgoFlags := func(flagsFile string) error { + flags, err := os.ReadFile(flagsFile) + if err != nil { + return err + } + const ldflagsPrefix = "_CGO_LDFLAGS=" + for _, line := range strings.Split(string(flags), "\n") { + if strings.HasPrefix(line, ldflagsPrefix) { + newFlags := strings.Fields(line[len(ldflagsPrefix):]) + for _, flag := range newFlags { + // Every _cgo_flags file has -g and -O2 in _CGO_LDFLAGS + // but they don't mean anything to the linker so filter + // them out. + if flag != "-g" && !strings.HasPrefix(flag, "-O") { + cgoldflags = append(cgoldflags, flag) + } + } + } + } + return nil + } + + var arArgs []string + if cfg.Goos == "aix" && cfg.Goarch == "ppc64" { + // AIX puts both 32-bit and 64-bit objects in the same archive. + // Tell the AIX "ar" command to only care about 64-bit objects. + arArgs = []string{"-X64"} + } + + newID := 0 + readAndRemoveCgoFlags := func(archive string) (string, error) { + newID++ + newArchive := root.Objdir + fmt.Sprintf("_pkg%d_.a", newID) + if err := b.copyFile(newArchive, archive, 0666, false); err != nil { + return "", err + } + if cfg.BuildN || cfg.BuildX { + b.Showcmd("", "ar d %s _cgo_flags", newArchive) + if cfg.BuildN { + // TODO(rsc): We could do better about showing the right _cgo_flags even in -n mode. + // Either the archive is already built and we can read them out, + // or we're printing commands to build the archive and can + // forward the _cgo_flags directly to this step. + return "", nil + } + } + err := b.run(root, root.Objdir, desc, nil, tools.ar(), arArgs, "x", newArchive, "_cgo_flags") + if err != nil { + return "", err + } + err = b.run(root, ".", desc, nil, tools.ar(), arArgs, "d", newArchive, "_cgo_flags") + if err != nil { + return "", err + } + err = readCgoFlags(filepath.Join(root.Objdir, "_cgo_flags")) + if err != nil { + return "", err + } + return newArchive, nil + } + + // If using -linkshared, find the shared library deps. + haveShlib := make(map[string]bool) + targetBase := filepath.Base(root.Target) + if cfg.BuildLinkshared { + for _, a := range root.Deps { + p := a.Package + if p == nil || p.Shlib == "" { + continue + } + + // The .a we are linking into this .so + // will have its Shlib set to this .so. + // Don't start thinking we want to link + // this .so into itself. + base := filepath.Base(p.Shlib) + if base != targetBase { + haveShlib[base] = true + } + } + } + + // Arrange the deps into afiles and shlibs. + addedShlib := make(map[string]bool) + for _, a := range root.Deps { + p := a.Package + if p != nil && p.Shlib != "" && haveShlib[filepath.Base(p.Shlib)] { + // This is a package linked into a shared + // library that we will put into shlibs. + continue + } + + if haveShlib[filepath.Base(a.Target)] { + // This is a shared library we want to link against. + if !addedShlib[a.Target] { + shlibs = append(shlibs, a.Target) + addedShlib[a.Target] = true + } + continue + } + + if p != nil { + target := a.built + if p.UsesCgo() || p.UsesSwig() { + var err error + target, err = readAndRemoveCgoFlags(target) + if err != nil { + continue + } + } + + afiles = append(afiles, target) + } + } + + for _, a := range allactions { + // Gather CgoLDFLAGS, but not from standard packages. + // The go tool can dig up runtime/cgo from GOROOT and + // think that it should use its CgoLDFLAGS, but gccgo + // doesn't use runtime/cgo. + if a.Package == nil { + continue + } + if !a.Package.Standard { + cgoldflags = append(cgoldflags, a.Package.CgoLDFLAGS...) + } + if len(a.Package.CgoFiles) > 0 { + usesCgo = true + } + if a.Package.UsesSwig() { + usesCgo = true + } + if len(a.Package.CXXFiles) > 0 || len(a.Package.SwigCXXFiles) > 0 { + cxx = true + } + if len(a.Package.MFiles) > 0 { + objc = true + } + if len(a.Package.FFiles) > 0 { + fortran = true + } + } + + wholeArchive := []string{"-Wl,--whole-archive"} + noWholeArchive := []string{"-Wl,--no-whole-archive"} + if cfg.Goos == "aix" { + wholeArchive = nil + noWholeArchive = nil + } + ldflags = append(ldflags, wholeArchive...) + ldflags = append(ldflags, afiles...) + ldflags = append(ldflags, noWholeArchive...) + + ldflags = append(ldflags, cgoldflags...) + ldflags = append(ldflags, envList("CGO_LDFLAGS", "")...) + if root.Package != nil { + ldflags = append(ldflags, root.Package.CgoLDFLAGS...) + } + if cfg.Goos != "aix" { + ldflags = str.StringList("-Wl,-(", ldflags, "-Wl,-)") + } + + if root.buildID != "" { + // On systems that normally use gold or the GNU linker, + // use the --build-id option to write a GNU build ID note. + switch cfg.Goos { + case "android", "dragonfly", "linux", "netbsd": + ldflags = append(ldflags, fmt.Sprintf("-Wl,--build-id=0x%x", root.buildID)) + } + } + + var rLibPath string + if cfg.Goos == "aix" { + rLibPath = "-Wl,-blibpath=" + } else { + rLibPath = "-Wl,-rpath=" + } + for _, shlib := range shlibs { + ldflags = append( + ldflags, + "-L"+filepath.Dir(shlib), + rLibPath+filepath.Dir(shlib), + "-l"+strings.TrimSuffix( + strings.TrimPrefix(filepath.Base(shlib), "lib"), + ".so")) + } + + var realOut string + goLibBegin := str.StringList(wholeArchive, "-lgolibbegin", noWholeArchive) + switch buildmode { + case "exe": + if usesCgo && cfg.Goos == "linux" { + ldflags = append(ldflags, "-Wl,-E") + } + + case "c-archive": + // Link the Go files into a single .o, and also link + // in -lgolibbegin. + // + // We need to use --whole-archive with -lgolibbegin + // because it doesn't define any symbols that will + // cause the contents to be pulled in; it's just + // initialization code. + // + // The user remains responsible for linking against + // -lgo -lpthread -lm in the final link. We can't use + // -r to pick them up because we can't combine + // split-stack and non-split-stack code in a single -r + // link, and libgo picks up non-split-stack code from + // libffi. + ldflags = append(ldflags, "-Wl,-r", "-nostdlib") + ldflags = append(ldflags, goLibBegin...) + + if nopie := b.gccNoPie([]string{tools.linker()}); nopie != "" { + ldflags = append(ldflags, nopie) + } + + // We are creating an object file, so we don't want a build ID. + if root.buildID == "" { + ldflags = b.disableBuildID(ldflags) + } + + realOut = out + out = out + ".o" + + case "c-shared": + ldflags = append(ldflags, "-shared", "-nostdlib") + ldflags = append(ldflags, goLibBegin...) + ldflags = append(ldflags, "-lgo", "-lgcc_s", "-lgcc", "-lc", "-lgcc") + + case "shared": + if cfg.Goos != "aix" { + ldflags = append(ldflags, "-zdefs") + } + ldflags = append(ldflags, "-shared", "-nostdlib", "-lgo", "-lgcc_s", "-lgcc", "-lc") + + default: + base.Fatalf("-buildmode=%s not supported for gccgo", buildmode) + } + + switch buildmode { + case "exe", "c-shared": + if cxx { + ldflags = append(ldflags, "-lstdc++") + } + if objc { + ldflags = append(ldflags, "-lobjc") + } + if fortran { + fc := cfg.Getenv("FC") + if fc == "" { + fc = "gfortran" + } + // support gfortran out of the box and let others pass the correct link options + // via CGO_LDFLAGS + if strings.Contains(fc, "gfortran") { + ldflags = append(ldflags, "-lgfortran") + } + } + } + + if err := b.run(root, ".", desc, nil, tools.linker(), "-o", out, ldflags, forcedGccgoflags, root.Package.Internal.Gccgoflags); err != nil { + return err + } + + switch buildmode { + case "c-archive": + if err := b.run(root, ".", desc, nil, tools.ar(), arArgs, "rc", realOut, out); err != nil { + return err + } + } + return nil +} + +func (tools gccgoToolchain) ld(b *Builder, root *Action, out, importcfg, mainpkg string) error { + return tools.link(b, root, out, importcfg, root.Deps, ldBuildmode, root.Package.ImportPath) +} + +func (tools gccgoToolchain) ldShared(b *Builder, root *Action, toplevelactions []*Action, out, importcfg string, allactions []*Action) error { + return tools.link(b, root, out, importcfg, allactions, "shared", out) +} + +func (tools gccgoToolchain) cc(b *Builder, a *Action, ofile, cfile string) error { + p := a.Package + inc := filepath.Join(cfg.GOROOT, "pkg", "include") + cfile = mkAbs(p.Dir, cfile) + defs := []string{"-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch} + defs = append(defs, b.gccArchArgs()...) + if pkgpath := tools.gccgoCleanPkgpath(b, p); pkgpath != "" { + defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`) + } + compiler := envList("CC", cfg.DefaultCC(cfg.Goos, cfg.Goarch)) + if b.gccSupportsFlag(compiler, "-fsplit-stack") { + defs = append(defs, "-fsplit-stack") + } + defs = tools.maybePIC(defs) + if b.gccSupportsFlag(compiler, "-ffile-prefix-map=a=b") { + defs = append(defs, "-ffile-prefix-map="+base.Cwd+"=.") + defs = append(defs, "-ffile-prefix-map="+b.WorkDir+"=/tmp/go-build") + } else if b.gccSupportsFlag(compiler, "-fdebug-prefix-map=a=b") { + defs = append(defs, "-fdebug-prefix-map="+b.WorkDir+"=/tmp/go-build") + } + if b.gccSupportsFlag(compiler, "-gno-record-gcc-switches") { + defs = append(defs, "-gno-record-gcc-switches") + } + return b.run(a, p.Dir, p.ImportPath, nil, compiler, "-Wall", "-g", + "-I", a.Objdir, "-I", inc, "-o", ofile, defs, "-c", cfile) +} + +// maybePIC adds -fPIC to the list of arguments if needed. +func (tools gccgoToolchain) maybePIC(args []string) []string { + switch cfg.BuildBuildmode { + case "c-shared", "shared", "plugin": + args = append(args, "-fPIC") + } + return args +} + +func gccgoPkgpath(p *load.Package) string { + if p.Internal.Build.IsCommand() && !p.Internal.ForceLibrary { + return "" + } + return p.ImportPath +} + +var gccgoToSymbolFuncOnce sync.Once +var gccgoToSymbolFunc func(string) string + +func (tools gccgoToolchain) gccgoCleanPkgpath(b *Builder, p *load.Package) string { + gccgoToSymbolFuncOnce.Do(func() { + fn, err := pkgpath.ToSymbolFunc(tools.compiler(), b.WorkDir) + if err != nil { + fmt.Fprintf(os.Stderr, "cmd/go: %v\n", err) + base.SetExitStatus(2) + base.Exit() + } + gccgoToSymbolFunc = fn + }) + + return gccgoToSymbolFunc(gccgoPkgpath(p)) +} diff --git a/src/cmd/go/internal/work/init.go b/src/cmd/go/internal/work/init.go new file mode 100644 index 0000000..ba7c7c2 --- /dev/null +++ b/src/cmd/go/internal/work/init.go @@ -0,0 +1,286 @@ +// 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. + +// Build initialization (after flag parsing). + +package work + +import ( + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/fsys" + "cmd/go/internal/modload" + "cmd/internal/objabi" + "cmd/internal/sys" + "flag" + "fmt" + "os" + "path/filepath" + "runtime" + "strings" +) + +func BuildInit() { + modload.Init() + instrumentInit() + buildModeInit() + if err := fsys.Init(base.Cwd); err != nil { + base.Fatalf("go: %v", err) + } + + // Make sure -pkgdir is absolute, because we run commands + // in different directories. + if cfg.BuildPkgdir != "" && !filepath.IsAbs(cfg.BuildPkgdir) { + p, err := filepath.Abs(cfg.BuildPkgdir) + if err != nil { + fmt.Fprintf(os.Stderr, "go %s: evaluating -pkgdir: %v\n", flag.Args()[0], err) + base.SetExitStatus(2) + base.Exit() + } + cfg.BuildPkgdir = p + } + + // Make sure CC and CXX are absolute paths + for _, key := range []string{"CC", "CXX"} { + if path := cfg.Getenv(key); !filepath.IsAbs(path) && path != "" && path != filepath.Base(path) { + base.Fatalf("go %s: %s environment variable is relative; must be absolute path: %s\n", flag.Args()[0], key, path) + } + } + + // For each experiment that has been enabled in the toolchain, define a + // build tag with the same name but prefixed by "goexperiment." which can be + // used for compiling alternative files for the experiment. This allows + // changes for the experiment, like extra struct fields in the runtime, + // without affecting the base non-experiment code at all. [2:] strips the + // leading "X:" from objabi.Expstring(). + exp := objabi.Expstring()[2:] + if exp != "none" { + experiments := strings.Split(exp, ",") + for _, expt := range experiments { + cfg.BuildContext.BuildTags = append(cfg.BuildContext.BuildTags, "goexperiment."+expt) + } + } +} + +func instrumentInit() { + if !cfg.BuildRace && !cfg.BuildMSan { + return + } + if cfg.BuildRace && cfg.BuildMSan { + fmt.Fprintf(os.Stderr, "go %s: may not use -race and -msan simultaneously\n", flag.Args()[0]) + base.SetExitStatus(2) + base.Exit() + } + if cfg.BuildMSan && !sys.MSanSupported(cfg.Goos, cfg.Goarch) { + fmt.Fprintf(os.Stderr, "-msan is not supported on %s/%s\n", cfg.Goos, cfg.Goarch) + base.SetExitStatus(2) + base.Exit() + } + if cfg.BuildRace { + if !sys.RaceDetectorSupported(cfg.Goos, cfg.Goarch) { + fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, linux/ppc64le, linux/arm64, freebsd/amd64, netbsd/amd64, darwin/amd64, darwin/arm64, and windows/amd64\n", flag.Args()[0]) + base.SetExitStatus(2) + base.Exit() + } + } + mode := "race" + if cfg.BuildMSan { + mode = "msan" + // MSAN does not support non-PIE binaries on ARM64. + // See issue #33712 for details. + if cfg.Goos == "linux" && cfg.Goarch == "arm64" && cfg.BuildBuildmode == "default" { + cfg.BuildBuildmode = "pie" + } + } + modeFlag := "-" + mode + + if !cfg.BuildContext.CgoEnabled { + if runtime.GOOS != cfg.Goos || runtime.GOARCH != cfg.Goarch { + fmt.Fprintf(os.Stderr, "go %s: %s requires cgo\n", flag.Args()[0], modeFlag) + } else { + fmt.Fprintf(os.Stderr, "go %s: %s requires cgo; enable cgo by setting CGO_ENABLED=1\n", flag.Args()[0], modeFlag) + } + + base.SetExitStatus(2) + base.Exit() + } + forcedGcflags = append(forcedGcflags, modeFlag) + forcedLdflags = append(forcedLdflags, modeFlag) + + if cfg.BuildContext.InstallSuffix != "" { + cfg.BuildContext.InstallSuffix += "_" + } + cfg.BuildContext.InstallSuffix += mode + cfg.BuildContext.BuildTags = append(cfg.BuildContext.BuildTags, mode) +} + +func buildModeInit() { + gccgo := cfg.BuildToolchainName == "gccgo" + var codegenArg string + + // Configure the build mode first, then verify that it is supported. + // That way, if the flag is completely bogus we will prefer to error out with + // "-buildmode=%s not supported" instead of naming the specific platform. + + switch cfg.BuildBuildmode { + case "archive": + pkgsFilter = pkgsNotMain + case "c-archive": + pkgsFilter = oneMainPkg + if gccgo { + codegenArg = "-fPIC" + } else { + switch cfg.Goos { + case "darwin", "ios": + switch cfg.Goarch { + case "arm64": + codegenArg = "-shared" + } + + case "dragonfly", "freebsd", "illumos", "linux", "netbsd", "openbsd", "solaris": + // Use -shared so that the result is + // suitable for inclusion in a PIE or + // shared library. + codegenArg = "-shared" + } + } + cfg.ExeSuffix = ".a" + ldBuildmode = "c-archive" + case "c-shared": + pkgsFilter = oneMainPkg + if gccgo { + codegenArg = "-fPIC" + } else { + switch cfg.Goos { + case "linux", "android", "freebsd": + codegenArg = "-shared" + case "windows": + // Do not add usual .exe suffix to the .dll file. + cfg.ExeSuffix = "" + } + } + ldBuildmode = "c-shared" + case "default": + switch cfg.Goos { + case "android": + codegenArg = "-shared" + ldBuildmode = "pie" + case "windows": + ldBuildmode = "pie" + case "ios": + codegenArg = "-shared" + ldBuildmode = "pie" + case "darwin": + switch cfg.Goarch { + case "arm64": + codegenArg = "-shared" + } + fallthrough + default: + ldBuildmode = "exe" + } + if gccgo { + codegenArg = "" + } + case "exe": + pkgsFilter = pkgsMain + ldBuildmode = "exe" + // Set the pkgsFilter to oneMainPkg if the user passed a specific binary output + // and is using buildmode=exe for a better error message. + // See issue #20017. + if cfg.BuildO != "" { + pkgsFilter = oneMainPkg + } + case "pie": + if cfg.BuildRace { + base.Fatalf("-buildmode=pie not supported when -race is enabled") + } + if gccgo { + codegenArg = "-fPIE" + } else { + switch cfg.Goos { + case "aix", "windows": + default: + codegenArg = "-shared" + } + } + ldBuildmode = "pie" + case "shared": + pkgsFilter = pkgsNotMain + if gccgo { + codegenArg = "-fPIC" + } else { + codegenArg = "-dynlink" + } + if cfg.BuildO != "" { + base.Fatalf("-buildmode=shared and -o not supported together") + } + ldBuildmode = "shared" + case "plugin": + pkgsFilter = oneMainPkg + if gccgo { + codegenArg = "-fPIC" + } else { + codegenArg = "-dynlink" + } + cfg.ExeSuffix = ".so" + ldBuildmode = "plugin" + default: + base.Fatalf("buildmode=%s not supported", cfg.BuildBuildmode) + } + + if !sys.BuildModeSupported(cfg.BuildToolchainName, cfg.BuildBuildmode, cfg.Goos, cfg.Goarch) { + base.Fatalf("-buildmode=%s not supported on %s/%s\n", cfg.BuildBuildmode, cfg.Goos, cfg.Goarch) + } + + if cfg.BuildLinkshared { + if !sys.BuildModeSupported(cfg.BuildToolchainName, "shared", cfg.Goos, cfg.Goarch) { + base.Fatalf("-linkshared not supported on %s/%s\n", cfg.Goos, cfg.Goarch) + } + if gccgo { + codegenArg = "-fPIC" + } else { + forcedAsmflags = append(forcedAsmflags, "-D=GOBUILDMODE_shared=1", + "-linkshared") + codegenArg = "-dynlink" + forcedGcflags = append(forcedGcflags, "-linkshared") + // TODO(mwhudson): remove -w when that gets fixed in linker. + forcedLdflags = append(forcedLdflags, "-linkshared", "-w") + } + } + if codegenArg != "" { + if gccgo { + forcedGccgoflags = append([]string{codegenArg}, forcedGccgoflags...) + } else { + forcedAsmflags = append([]string{codegenArg}, forcedAsmflags...) + forcedGcflags = append([]string{codegenArg}, forcedGcflags...) + } + // Don't alter InstallSuffix when modifying default codegen args. + if cfg.BuildBuildmode != "default" || cfg.BuildLinkshared { + if cfg.BuildContext.InstallSuffix != "" { + cfg.BuildContext.InstallSuffix += "_" + } + cfg.BuildContext.InstallSuffix += codegenArg[1:] + } + } + + switch cfg.BuildMod { + case "": + // Behavior will be determined automatically, as if no flag were passed. + case "readonly", "vendor", "mod": + if !cfg.ModulesEnabled && !base.InGOFLAGS("-mod") { + base.Fatalf("build flag -mod=%s only valid when using modules", cfg.BuildMod) + } + default: + base.Fatalf("-mod=%s not supported (can be '', 'mod', 'readonly', or 'vendor')", cfg.BuildMod) + } + if !cfg.ModulesEnabled { + if cfg.ModCacheRW && !base.InGOFLAGS("-modcacherw") { + base.Fatalf("build flag -modcacherw only valid when using modules") + } + if cfg.ModFile != "" && !base.InGOFLAGS("-mod") { + base.Fatalf("build flag -modfile only valid when using modules") + } + } +} diff --git a/src/cmd/go/internal/work/security.go b/src/cmd/go/internal/work/security.go new file mode 100644 index 0000000..36bbab3 --- /dev/null +++ b/src/cmd/go/internal/work/security.go @@ -0,0 +1,310 @@ +// 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. + +// Checking of compiler and linker flags. +// We must avoid flags like -fplugin=, which can allow +// arbitrary code execution during the build. +// Do not make changes here without carefully +// considering the implications. +// (That's why the code is isolated in a file named security.go.) +// +// Note that -Wl,foo means split foo on commas and pass to +// the linker, so that -Wl,-foo,bar means pass -foo bar to +// the linker. Similarly -Wa,foo for the assembler and so on. +// If any of these are permitted, the wildcard portion must +// disallow commas. +// +// Note also that GNU binutils accept any argument @foo +// as meaning "read more flags from the file foo", so we must +// guard against any command-line argument beginning with @, +// even things like "-I @foo". +// We use load.SafeArg (which is even more conservative) +// to reject these. +// +// Even worse, gcc -I@foo (one arg) turns into cc1 -I @foo (two args), +// so although gcc doesn't expand the @foo, cc1 will. +// So out of paranoia, we reject @ at the beginning of every +// flag argument that might be split into its own argument. + +package work + +import ( + "fmt" + "internal/lazyregexp" + "regexp" + "strings" + + "cmd/go/internal/cfg" + "cmd/go/internal/load" +) + +var re = lazyregexp.New + +var validCompilerFlags = []*lazyregexp.Regexp{ + re(`-D([A-Za-z_][A-Za-z0-9_]*)(=[^@\-]*)?`), + re(`-U([A-Za-z_][A-Za-z0-9_]*)`), + re(`-F([^@\-].*)`), + re(`-I([^@\-].*)`), + re(`-O`), + re(`-O([^@\-].*)`), + re(`-W`), + re(`-W([^@,]+)`), // -Wall but not -Wa,-foo. + re(`-Wa,-mbig-obj`), + re(`-Wp,-D([A-Za-z_][A-Za-z0-9_]*)(=[^@,\-]*)?`), + re(`-Wp,-U([A-Za-z_][A-Za-z0-9_]*)`), + re(`-ansi`), + re(`-f(no-)?asynchronous-unwind-tables`), + re(`-f(no-)?blocks`), + re(`-f(no-)builtin-[a-zA-Z0-9_]*`), + re(`-f(no-)?common`), + re(`-f(no-)?constant-cfstrings`), + re(`-fdiagnostics-show-note-include-stack`), + re(`-f(no-)?eliminate-unused-debug-types`), + re(`-f(no-)?exceptions`), + re(`-f(no-)?fast-math`), + re(`-f(no-)?inline-functions`), + re(`-finput-charset=([^@\-].*)`), + re(`-f(no-)?fat-lto-objects`), + re(`-f(no-)?keep-inline-dllexport`), + re(`-f(no-)?lto`), + re(`-fmacro-backtrace-limit=(.+)`), + re(`-fmessage-length=(.+)`), + re(`-f(no-)?modules`), + re(`-f(no-)?objc-arc`), + re(`-f(no-)?objc-nonfragile-abi`), + re(`-f(no-)?objc-legacy-dispatch`), + re(`-f(no-)?omit-frame-pointer`), + re(`-f(no-)?openmp(-simd)?`), + re(`-f(no-)?permissive`), + re(`-f(no-)?(pic|PIC|pie|PIE)`), + re(`-f(no-)?plt`), + re(`-f(no-)?rtti`), + re(`-f(no-)?split-stack`), + re(`-f(no-)?stack-(.+)`), + re(`-f(no-)?strict-aliasing`), + re(`-f(un)signed-char`), + re(`-f(no-)?use-linker-plugin`), // safe if -B is not used; we don't permit -B + re(`-f(no-)?visibility-inlines-hidden`), + re(`-fsanitize=(.+)`), + re(`-ftemplate-depth-(.+)`), + re(`-fvisibility=(.+)`), + re(`-g([^@\-].*)?`), + re(`-m32`), + re(`-m64`), + re(`-m(abi|arch|cpu|fpu|tune)=([^@\-].*)`), + re(`-m(no-)?v?aes`), + re(`-marm`), + re(`-m(no-)?avx[0-9a-z]*`), + re(`-mfloat-abi=([^@\-].*)`), + re(`-mfpmath=[0-9a-z,+]*`), + re(`-m(no-)?avx[0-9a-z.]*`), + re(`-m(no-)?ms-bitfields`), + re(`-m(no-)?stack-(.+)`), + re(`-mmacosx-(.+)`), + re(`-mios-simulator-version-min=(.+)`), + re(`-miphoneos-version-min=(.+)`), + re(`-mtvos-simulator-version-min=(.+)`), + re(`-mtvos-version-min=(.+)`), + re(`-mwatchos-simulator-version-min=(.+)`), + re(`-mwatchos-version-min=(.+)`), + re(`-mnop-fun-dllimport`), + re(`-m(no-)?sse[0-9.]*`), + re(`-m(no-)?ssse3`), + re(`-mthumb(-interwork)?`), + re(`-mthreads`), + re(`-mwindows`), + re(`--param=ssp-buffer-size=[0-9]*`), + re(`-pedantic(-errors)?`), + re(`-pipe`), + re(`-pthread`), + re(`-?-std=([^@\-].*)`), + re(`-?-stdlib=([^@\-].*)`), + re(`--sysroot=([^@\-].*)`), + re(`-w`), + re(`-x([^@\-].*)`), + re(`-v`), +} + +var validCompilerFlagsWithNextArg = []string{ + "-arch", + "-D", + "-U", + "-I", + "-framework", + "-include", + "-isysroot", + "-isystem", + "--sysroot", + "-target", + "-x", +} + +var validLinkerFlags = []*lazyregexp.Regexp{ + re(`-F([^@\-].*)`), + re(`-l([^@\-].*)`), + re(`-L([^@\-].*)`), + re(`-O`), + re(`-O([^@\-].*)`), + 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)=([^@\-].*)`), + re(`-mfloat-abi=([^@\-].*)`), + re(`-mmacosx-(.+)`), + re(`-mios-simulator-version-min=(.+)`), + re(`-miphoneos-version-min=(.+)`), + re(`-mthreads`), + re(`-mwindows`), + re(`-(pic|PIC|pie|PIE)`), + re(`-pthread`), + re(`-rdynamic`), + 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 + // them all to the linker uninterpreted. Allowing comma + // in a wildcard would allow tunnelling arbitrary additional + // linker arguments through one of these. + re(`-Wl,--(no-)?allow-multiple-definition`), + re(`-Wl,--(no-)?allow-shlib-undefined`), + re(`-Wl,--(no-)?as-needed`), + re(`-Wl,-Bdynamic`), + re(`-Wl,-berok`), + re(`-Wl,-Bstatic`), + re(`-Wl,-Bsymbolic-functions`), + re(`-Wl,-O([^@,\-][^,]*)?`), + re(`-Wl,-d[ny]`), + re(`-Wl,--disable-new-dtags`), + re(`-Wl,-e[=,][a-zA-Z0-9]*`), + re(`-Wl,--enable-new-dtags`), + re(`-Wl,--end-group`), + re(`-Wl,--(no-)?export-dynamic`), + re(`-Wl,-E`), + re(`-Wl,-framework,[^,@\-][^,]+`), + re(`-Wl,--hash-style=(sysv|gnu|both)`), + re(`-Wl,-headerpad_max_install_names`), + re(`-Wl,--no-undefined`), + re(`-Wl,-R([^@\-][^,@]*$)`), + re(`-Wl,--just-symbols[=,]([^,@\-][^,@]+)`), + re(`-Wl,-rpath(-link)?[=,]([^,@\-][^,]+)`), + re(`-Wl,-s`), + re(`-Wl,-search_paths_first`), + re(`-Wl,-sectcreate,([^,@\-][^,]+),([^,@\-][^,]+),([^,@\-][^,]+)`), + re(`-Wl,--start-group`), + re(`-Wl,-?-static`), + re(`-Wl,-?-subsystem,(native|windows|console|posix|xbox)`), + re(`-Wl,-syslibroot[=,]([^,@\-][^,]+)`), + re(`-Wl,-undefined[=,]([^,@\-][^,]+)`), + re(`-Wl,-?-unresolved-symbols=[^,]+`), + re(`-Wl,--(no-)?warn-([^,]+)`), + re(`-Wl,-?-wrap[=,][^,@\-][^,]*`), + re(`-Wl,-z,(no)?execstack`), + re(`-Wl,-z,relro`), + + re(`[a-zA-Z0-9_/].*\.(a|o|obj|dll|dylib|so)`), // direct linker inputs: x.o or libfoo.so (but not -foo.o or @foo.o) + re(`\./.*\.(a|o|obj|dll|dylib|so)`), +} + +var validLinkerFlagsWithNextArg = []string{ + "-arch", + "-F", + "-l", + "-L", + "-framework", + "-isysroot", + "--sysroot", + "-target", + "-Wl,-framework", + "-Wl,-rpath", + "-Wl,-R", + "-Wl,--just-symbols", + "-Wl,-undefined", +} + +func checkCompilerFlags(name, source string, list []string) error { + return checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg) +} + +func checkLinkerFlags(name, source string, list []string) error { + return checkFlags(name, source, list, validLinkerFlags, validLinkerFlagsWithNextArg) +} + +func checkFlags(name, source string, list []string, valid []*lazyregexp.Regexp, validNext []string) error { + // Let users override rules with $CGO_CFLAGS_ALLOW, $CGO_CFLAGS_DISALLOW, etc. + var ( + allow *regexp.Regexp + disallow *regexp.Regexp + ) + if env := cfg.Getenv("CGO_" + name + "_ALLOW"); env != "" { + r, err := regexp.Compile(env) + if err != nil { + return fmt.Errorf("parsing $CGO_%s_ALLOW: %v", name, err) + } + allow = r + } + if env := cfg.Getenv("CGO_" + name + "_DISALLOW"); env != "" { + r, err := regexp.Compile(env) + if err != nil { + return fmt.Errorf("parsing $CGO_%s_DISALLOW: %v", name, err) + } + disallow = r + } + +Args: + for i := 0; i < len(list); i++ { + arg := list[i] + if disallow != nil && disallow.FindString(arg) == arg { + goto Bad + } + if allow != nil && allow.FindString(arg) == arg { + continue Args + } + for _, re := range valid { + if re.FindString(arg) == arg { // must be complete match + continue Args + } + } + for _, x := range validNext { + if arg == x { + if i+1 < len(list) && load.SafeArg(list[i+1]) { + i++ + continue Args + } + + // Permit -Wl,-framework -Wl,name. + if i+1 < len(list) && + strings.HasPrefix(arg, "-Wl,") && + strings.HasPrefix(list[i+1], "-Wl,") && + load.SafeArg(list[i+1][4:]) && + !strings.Contains(list[i+1][4:], ",") { + i++ + continue Args + } + + // Permit -I= /path, -I $SYSROOT. + if i+1 < len(list) && arg == "-I" { + if (strings.HasPrefix(list[i+1], "=") || strings.HasPrefix(list[i+1], "$SYSROOT")) && + load.SafeArg(list[i+1][1:]) { + i++ + continue Args + } + } + + if i+1 < len(list) { + return fmt.Errorf("invalid flag in %s: %s %s (see https://golang.org/s/invalidflag)", source, arg, list[i+1]) + } + return fmt.Errorf("invalid flag in %s: %s without argument (see https://golang.org/s/invalidflag)", source, arg) + } + } + Bad: + return fmt.Errorf("invalid flag in %s: %s", source, arg) + } + return nil +} diff --git a/src/cmd/go/internal/work/security_test.go b/src/cmd/go/internal/work/security_test.go new file mode 100644 index 0000000..4f2e0eb --- /dev/null +++ b/src/cmd/go/internal/work/security_test.go @@ -0,0 +1,277 @@ +// 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 work + +import ( + "os" + "testing" +) + +var goodCompilerFlags = [][]string{ + {"-DFOO"}, + {"-Dfoo=bar"}, + {"-Ufoo"}, + {"-Ufoo1"}, + {"-F/Qt"}, + {"-I/"}, + {"-I/etc/passwd"}, + {"-I."}, + {"-O"}, + {"-O2"}, + {"-Osmall"}, + {"-W"}, + {"-Wall"}, + {"-Wp,-Dfoo=bar"}, + {"-Wp,-Ufoo"}, + {"-Wp,-Dfoo1"}, + {"-Wp,-Ufoo1"}, + {"-fobjc-arc"}, + {"-fno-objc-arc"}, + {"-fomit-frame-pointer"}, + {"-fno-omit-frame-pointer"}, + {"-fpic"}, + {"-fno-pic"}, + {"-fPIC"}, + {"-fno-PIC"}, + {"-fpie"}, + {"-fno-pie"}, + {"-fPIE"}, + {"-fno-PIE"}, + {"-fsplit-stack"}, + {"-fno-split-stack"}, + {"-fstack-xxx"}, + {"-fno-stack-xxx"}, + {"-fsanitize=hands"}, + {"-g"}, + {"-ggdb"}, + {"-march=souza"}, + {"-mcpu=123"}, + {"-mfpu=123"}, + {"-mtune=happybirthday"}, + {"-mstack-overflow"}, + {"-mno-stack-overflow"}, + {"-mmacosx-version"}, + {"-mnop-fun-dllimport"}, + {"-pthread"}, + {"-std=c99"}, + {"-xc"}, + {"-D", "FOO"}, + {"-D", "foo=bar"}, + {"-I", "."}, + {"-I", "/etc/passwd"}, + {"-I", "世界"}, + {"-I", "=/usr/include/libxml2"}, + {"-I", "dir"}, + {"-I", "$SYSROOT/dir"}, + {"-isystem", "/usr/include/mozjs-68"}, + {"-include", "/usr/include/mozjs-68/RequiredDefines.h"}, + {"-framework", "Chocolate"}, + {"-x", "c"}, + {"-v"}, +} + +var badCompilerFlags = [][]string{ + {"-D@X"}, + {"-D-X"}, + {"-Ufoo=bar"}, + {"-F@dir"}, + {"-F-dir"}, + {"-I@dir"}, + {"-I-dir"}, + {"-O@1"}, + {"-Wa,-foo"}, + {"-W@foo"}, + {"-Wp,-DX,-D@X"}, + {"-Wp,-UX,-U@X"}, + {"-g@gdb"}, + {"-g-gdb"}, + {"-march=@dawn"}, + {"-march=-dawn"}, + {"-std=@c99"}, + {"-std=-c99"}, + {"-x@c"}, + {"-x-c"}, + {"-D", "@foo"}, + {"-D", "-foo"}, + {"-I", "@foo"}, + {"-I", "-foo"}, + {"-I", "=@obj"}, + {"-include", "@foo"}, + {"-framework", "-Caffeine"}, + {"-framework", "@Home"}, + {"-x", "--c"}, + {"-x", "@obj"}, +} + +func TestCheckCompilerFlags(t *testing.T) { + for _, f := range goodCompilerFlags { + if err := checkCompilerFlags("test", "test", f); err != nil { + t.Errorf("unexpected error for %q: %v", f, err) + } + } + for _, f := range badCompilerFlags { + if err := checkCompilerFlags("test", "test", f); err == nil { + t.Errorf("missing error for %q", f) + } + } +} + +var goodLinkerFlags = [][]string{ + {"-Fbar"}, + {"-lbar"}, + {"-Lbar"}, + {"-fpic"}, + {"-fno-pic"}, + {"-fPIC"}, + {"-fno-PIC"}, + {"-fpie"}, + {"-fno-pie"}, + {"-fPIE"}, + {"-fno-PIE"}, + {"-fsanitize=hands"}, + {"-g"}, + {"-ggdb"}, + {"-march=souza"}, + {"-mcpu=123"}, + {"-mfpu=123"}, + {"-mtune=happybirthday"}, + {"-pic"}, + {"-pthread"}, + {"-Wl,--hash-style=both"}, + {"-Wl,-rpath,foo"}, + {"-Wl,-rpath,$ORIGIN/foo"}, + {"-Wl,-R", "/foo"}, + {"-Wl,-R", "foo"}, + {"-Wl,-R,foo"}, + {"-Wl,--just-symbols=foo"}, + {"-Wl,--just-symbols,foo"}, + {"-Wl,--warn-error"}, + {"-Wl,--no-warn-error"}, + {"foo.so"}, + {"_世界.dll"}, + {"./x.o"}, + {"libcgosotest.dylib"}, + {"-F", "framework"}, + {"-l", "."}, + {"-l", "/etc/passwd"}, + {"-l", "世界"}, + {"-L", "framework"}, + {"-framework", "Chocolate"}, + {"-v"}, + {"-Wl,-sectcreate,__TEXT,__info_plist,${SRCDIR}/Info.plist"}, + {"-Wl,-framework", "-Wl,Chocolate"}, + {"-Wl,-framework,Chocolate"}, + {"-Wl,-unresolved-symbols=ignore-all"}, +} + +var badLinkerFlags = [][]string{ + {"-DFOO"}, + {"-Dfoo=bar"}, + {"-W"}, + {"-Wall"}, + {"-fobjc-arc"}, + {"-fno-objc-arc"}, + {"-fomit-frame-pointer"}, + {"-fno-omit-frame-pointer"}, + {"-fsplit-stack"}, + {"-fno-split-stack"}, + {"-fstack-xxx"}, + {"-fno-stack-xxx"}, + {"-mstack-overflow"}, + {"-mno-stack-overflow"}, + {"-mnop-fun-dllimport"}, + {"-std=c99"}, + {"-xc"}, + {"-D", "FOO"}, + {"-D", "foo=bar"}, + {"-I", "FOO"}, + {"-L", "@foo"}, + {"-L", "-foo"}, + {"-x", "c"}, + {"-D@X"}, + {"-D-X"}, + {"-I@dir"}, + {"-I-dir"}, + {"-O@1"}, + {"-Wa,-foo"}, + {"-W@foo"}, + {"-g@gdb"}, + {"-g-gdb"}, + {"-march=@dawn"}, + {"-march=-dawn"}, + {"-std=@c99"}, + {"-std=-c99"}, + {"-x@c"}, + {"-x-c"}, + {"-D", "@foo"}, + {"-D", "-foo"}, + {"-I", "@foo"}, + {"-I", "-foo"}, + {"-l", "@foo"}, + {"-l", "-foo"}, + {"-framework", "-Caffeine"}, + {"-framework", "@Home"}, + {"-Wl,-framework,-Caffeine"}, + {"-Wl,-framework", "-Wl,@Home"}, + {"-Wl,-framework", "@Home"}, + {"-Wl,-framework,Chocolate,@Home"}, + {"-Wl,--hash-style=foo"}, + {"-x", "--c"}, + {"-x", "@obj"}, + {"-Wl,-rpath,@foo"}, + {"-Wl,-R,foo,bar"}, + {"-Wl,-R,@foo"}, + {"-Wl,--just-symbols,@foo"}, + {"../x.o"}, +} + +func TestCheckLinkerFlags(t *testing.T) { + for _, f := range goodLinkerFlags { + if err := checkLinkerFlags("test", "test", f); err != nil { + t.Errorf("unexpected error for %q: %v", f, err) + } + } + for _, f := range badLinkerFlags { + if err := checkLinkerFlags("test", "test", f); err == nil { + t.Errorf("missing error for %q", f) + } + } +} + +func TestCheckFlagAllowDisallow(t *testing.T) { + if err := checkCompilerFlags("TEST", "test", []string{"-disallow"}); err == nil { + t.Fatalf("missing error for -disallow") + } + os.Setenv("CGO_TEST_ALLOW", "-disallo") + if err := checkCompilerFlags("TEST", "test", []string{"-disallow"}); err == nil { + t.Fatalf("missing error for -disallow with CGO_TEST_ALLOW=-disallo") + } + os.Setenv("CGO_TEST_ALLOW", "-disallow") + if err := checkCompilerFlags("TEST", "test", []string{"-disallow"}); err != nil { + t.Fatalf("unexpected error for -disallow with CGO_TEST_ALLOW=-disallow: %v", err) + } + os.Unsetenv("CGO_TEST_ALLOW") + + if err := checkCompilerFlags("TEST", "test", []string{"-Wall"}); err != nil { + t.Fatalf("unexpected error for -Wall: %v", err) + } + os.Setenv("CGO_TEST_DISALLOW", "-Wall") + if err := checkCompilerFlags("TEST", "test", []string{"-Wall"}); err == nil { + t.Fatalf("missing error for -Wall with CGO_TEST_DISALLOW=-Wall") + } + os.Setenv("CGO_TEST_ALLOW", "-Wall") // disallow wins + if err := checkCompilerFlags("TEST", "test", []string{"-Wall"}); err == nil { + t.Fatalf("missing error for -Wall with CGO_TEST_DISALLOW=-Wall and CGO_TEST_ALLOW=-Wall") + } + + os.Setenv("CGO_TEST_ALLOW", "-fplugin.*") + os.Setenv("CGO_TEST_DISALLOW", "-fplugin=lint.so") + if err := checkCompilerFlags("TEST", "test", []string{"-fplugin=faster.so"}); err != nil { + t.Fatalf("unexpected error for -fplugin=faster.so: %v", err) + } + if err := checkCompilerFlags("TEST", "test", []string{"-fplugin=lint.so"}); err == nil { + t.Fatalf("missing error for -fplugin=lint.so: %v", err) + } +} diff --git a/src/cmd/go/internal/work/testgo.go b/src/cmd/go/internal/work/testgo.go new file mode 100644 index 0000000..931f49a --- /dev/null +++ b/src/cmd/go/internal/work/testgo.go @@ -0,0 +1,48 @@ +// 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. + +// This file contains extra hooks for testing the go command. + +// +build testgo + +package work + +import ( + "cmd/go/internal/cfg" + "cmd/go/internal/search" + "fmt" + "os" + "path/filepath" + "runtime" +) + +func init() { + if v := os.Getenv("TESTGO_VERSION"); v != "" { + runtimeVersion = v + } + + if testGOROOT := os.Getenv("TESTGO_GOROOT"); testGOROOT != "" { + // Disallow installs to the GOROOT from which testgo was built. + // Installs to other GOROOTs — such as one set explicitly within a test — are ok. + allowInstall = func(a *Action) error { + if cfg.BuildN { + return nil + } + + rel := search.InDir(a.Target, testGOROOT) + if rel == "" { + return nil + } + + callerPos := "" + if _, file, line, ok := runtime.Caller(1); ok { + if shortFile := search.InDir(file, filepath.Join(testGOROOT, "src")); shortFile != "" { + file = shortFile + } + callerPos = fmt.Sprintf("%s:%d: ", file, line) + } + return fmt.Errorf("%stestgo must not write to GOROOT (installing to %s)", callerPos, filepath.Join("GOROOT", rel)) + } + } +} diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go new file mode 100644 index 0000000..9cc44da --- /dev/null +++ b/src/cmd/go/main.go @@ -0,0 +1,235 @@ +// Copyright 2011 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:generate ./mkalldocs.sh + +package main + +import ( + "context" + "flag" + "fmt" + "log" + "os" + "path/filepath" + "runtime" + "strings" + + "cmd/go/internal/base" + "cmd/go/internal/bug" + "cmd/go/internal/cfg" + "cmd/go/internal/clean" + "cmd/go/internal/doc" + "cmd/go/internal/envcmd" + "cmd/go/internal/fix" + "cmd/go/internal/fmtcmd" + "cmd/go/internal/generate" + "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" + "cmd/go/internal/trace" + "cmd/go/internal/version" + "cmd/go/internal/vet" + "cmd/go/internal/work" +) + +func init() { + base.Go.Commands = []*base.Command{ + bug.CmdBug, + work.CmdBuild, + clean.CmdClean, + doc.CmdDoc, + envcmd.CmdEnv, + fix.CmdFix, + fmtcmd.CmdFmt, + generate.CmdGenerate, + modget.CmdGet, + work.CmdInstall, + list.CmdList, + modcmd.CmdMod, + run.CmdRun, + test.CmdTest, + tool.CmdTool, + version.CmdVersion, + vet.CmdVet, + + help.HelpBuildConstraint, + help.HelpBuildmode, + help.HelpC, + help.HelpCache, + help.HelpEnvironment, + help.HelpFileType, + modload.HelpGoMod, + help.HelpGopath, + get.HelpGopathGet, + modfetch.HelpGoproxy, + help.HelpImportPath, + modload.HelpModules, + modget.HelpModuleGet, + modfetch.HelpModuleAuth, + help.HelpPackages, + modfetch.HelpPrivate, + test.HelpTestflag, + test.HelpTestfunc, + modget.HelpVCS, + } +} + +func main() { + _ = go11tag + flag.Usage = base.Usage + flag.Parse() + log.SetFlags(0) + + args := flag.Args() + if len(args) < 1 { + base.Usage() + } + + if args[0] == "get" || args[0] == "help" { + if !modload.WillBeEnabled() { + // Replace module-aware get with GOPATH get if appropriate. + *modget.CmdGet = *get.CmdGet + } + } + + cfg.CmdName = args[0] // for error messages + if args[0] == "help" { + help.Help(os.Stdout, args[1:]) + return + } + + // Diagnose common mistake: GOPATH==GOROOT. + // This setting is equivalent to not setting GOPATH at all, + // which is not what most people want when they do it. + if gopath := cfg.BuildContext.GOPATH; filepath.Clean(gopath) == filepath.Clean(runtime.GOROOT()) { + fmt.Fprintf(os.Stderr, "warning: GOPATH set to GOROOT (%s) has no effect\n", gopath) + } else { + for _, p := range filepath.SplitList(gopath) { + // Some GOPATHs have empty directory elements - ignore them. + // See issue 21928 for details. + if p == "" { + continue + } + // Note: using HasPrefix instead of Contains because a ~ can appear + // in the middle of directory elements, such as /tmp/git-1.8.2~rc3 + // or C:\PROGRA~1. Only ~ as a path prefix has meaning to the shell. + if strings.HasPrefix(p, "~") { + fmt.Fprintf(os.Stderr, "go: GOPATH entry cannot start with shell metacharacter '~': %q\n", p) + os.Exit(2) + } + if !filepath.IsAbs(p) { + if cfg.Getenv("GOPATH") == "" { + // We inferred $GOPATH from $HOME and did a bad job at it. + // Instead of dying, uninfer it. + cfg.BuildContext.GOPATH = "" + } else { + fmt.Fprintf(os.Stderr, "go: GOPATH entry is relative; must be absolute path: %q.\nFor more details see: 'go help gopath'\n", p) + os.Exit(2) + } + } + } + } + + if fi, err := os.Stat(cfg.GOROOT); err != nil || !fi.IsDir() { + fmt.Fprintf(os.Stderr, "go: cannot find GOROOT directory: %v\n", cfg.GOROOT) + os.Exit(2) + } + + // Set environment (GOOS, GOARCH, etc) explicitly. + // In theory all the commands we invoke should have + // the same default computation of these as we do, + // but in practice there might be skew + // This makes sure we all agree. + cfg.OrigEnv = os.Environ() + cfg.CmdEnv = envcmd.MkEnv() + for _, env := range cfg.CmdEnv { + if os.Getenv(env.Name) != env.Value { + os.Setenv(env.Name, env.Value) + } + } + +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(os.Stdout, 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() + } + ctx := maybeStartTrace(context.Background()) + ctx, span := trace.StartSpan(ctx, fmt.Sprint("Running ", cmd.Name(), " command")) + cmd.Run(ctx, cmd, args) + span.Done() + 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() + } +} + +func init() { + base.Usage = mainUsage +} + +func mainUsage() { + help.PrintUsage(os.Stderr, base.Go) + os.Exit(2) +} + +func maybeStartTrace(pctx context.Context) context.Context { + if cfg.DebugTrace == "" { + return pctx + } + + ctx, close, err := trace.Start(pctx, cfg.DebugTrace) + if err != nil { + base.Fatalf("failed to start trace: %v", err) + } + base.AtExit(func() { + if err := close(); err != nil { + base.Fatalf("failed to stop trace: %v", err) + } + }) + + return ctx +} diff --git a/src/cmd/go/mkalldocs.sh b/src/cmd/go/mkalldocs.sh new file mode 100755 index 0000000..a2b0aca --- /dev/null +++ b/src/cmd/go/mkalldocs.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# 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. + +set -e + +go build -o go.latest +# If the command used to generate alldocs.go changes, update TestDocsUpToDate in +# help_test.go. +GO111MODULE='' ./go.latest help documentation >alldocs.go +gofmt -w alldocs.go +rm go.latest diff --git a/src/cmd/go/note_test.go b/src/cmd/go/note_test.go new file mode 100644 index 0000000..659366d --- /dev/null +++ b/src/cmd/go/note_test.go @@ -0,0 +1,72 @@ +// Copyright 2015 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 ( + "go/build" + "runtime" + "testing" + + "cmd/internal/buildid" +) + +func TestNoteReading(t *testing.T) { + // cmd/internal/buildid already has tests that the basic reading works. + // This test is essentially checking that -ldflags=-buildid=XXX works, + // both in internal and external linking mode. + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + + tg.tempFile("hello.go", `package main; func main() { print("hello, world\n") }`) + const buildID = "TestNoteReading-Build-ID" + tg.run("build", "-ldflags", "-buildid="+buildID, "-o", tg.path("hello.exe"), tg.path("hello.go")) + id, err := buildid.ReadFile(tg.path("hello.exe")) + if err != nil { + t.Fatalf("reading build ID from hello binary: %v", err) + } + if id != buildID { + t.Fatalf("buildID in hello binary = %q, want %q", id, buildID) + } + + switch { + case !build.Default.CgoEnabled: + t.Skipf("skipping - no cgo, so assuming external linking not available") + case runtime.GOOS == "plan9": + t.Skipf("skipping - external linking not supported") + } + + tg.run("build", "-ldflags", "-buildid="+buildID+" -linkmode=external", "-o", tg.path("hello2.exe"), tg.path("hello.go")) + id, err = buildid.ReadFile(tg.path("hello2.exe")) + if err != nil { + t.Fatalf("reading build ID from hello binary (linkmode=external): %v", err) + } + if id != buildID { + t.Fatalf("buildID in hello binary = %q, want %q (linkmode=external)", id, buildID) + } + + switch runtime.GOOS { + case "dragonfly", "freebsd", "linux", "netbsd", "openbsd": + // Test while forcing use of the gold linker, since in the past + // we've had trouble reading the notes generated by gold. + err := tg.doRun([]string{"build", "-ldflags", "-buildid=" + buildID + " -linkmode=external -extldflags=-fuse-ld=gold", "-o", tg.path("hello3.exe"), tg.path("hello.go")}) + if err != nil { + if tg.grepCountBoth("(invalid linker|gold|cannot find [‘']ld[’'])") > 0 { + // It's not an error if gold isn't there. gcc claims it "cannot find 'ld'" if + // ld.gold is missing, see issue #22340. + t.Log("skipping gold test") + break + } + t.Fatalf("building hello binary: %v", err) + } + id, err = buildid.ReadFile(tg.path("hello3.exe")) + if err != nil { + t.Fatalf("reading build ID from hello binary (linkmode=external -extldflags=-fuse-ld=gold): %v", err) + } + if id != buildID { + t.Fatalf("buildID in hello binary = %q, want %q (linkmode=external -extldflags=-fuse-ld=gold)", id, buildID) + } + } +} diff --git a/src/cmd/go/proxy_test.go b/src/cmd/go/proxy_test.go new file mode 100644 index 0000000..e390c73 --- /dev/null +++ b/src/cmd/go/proxy_test.go @@ -0,0 +1,492 @@ +// 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" + "errors" + "flag" + "fmt" + "io" + "io/fs" + "log" + "net" + "net/http" + "os" + "path/filepath" + "strconv" + "strings" + "sync" + "testing" + + "cmd/go/internal/modfetch" + "cmd/go/internal/modfetch/codehost" + "cmd/go/internal/par" + "cmd/go/internal/txtar" + + "golang.org/x/mod/module" + "golang.org/x/mod/semver" + "golang.org/x/mod/sumdb" + "golang.org/x/mod/sumdb/dirhash" +) + +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() { + 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))) + }() + + // Prepopulate main sumdb. + for _, mod := range modList { + sumdbOps.Lookup(nil, mod) + } + }) +} + +var modList []module.Version + +func readModList() { + files, err := os.ReadDir("testdata/mod") + if err != nil { + log.Fatal(err) + } + for _, f := range files { + name := f.Name() + if !strings.HasSuffix(name, ".txt") { + continue + } + name = strings.TrimSuffix(name, ".txt") + i := strings.LastIndex(name, "_v") + if i < 0 { + continue + } + encPath := strings.ReplaceAll(name[:i], "_", "/") + path, err := module.UnescapePath(encPath) + if err != nil { + if testing.Verbose() && encPath != "example.com/invalidpath/v1" { + fmt.Fprintf(os.Stderr, "go proxy_test: %v\n", err) + } + continue + } + encVers := name[i+1:] + vers, err := module.UnescapeVersion(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 + +const ( + testSumDBName = "localhost.localdev/sumdb" + testSumDBVerifierKey = "localhost.localdev/sumdb+00000c67+AcTrnkbUA+TU4heY3hkjiSES/DSQniBqIeQ/YppAUtK6" + testSumDBSignerKey = "PRIVATE+KEY+localhost.localdev/sumdb+00000c67+AXu6+oaVaOYuQOFrf1V59JK1owcFlJcHwwXHDfDGxSPk" +) + +var ( + sumdbOps = sumdb.NewTestServer(testSumDBSignerKey, proxyGoSum) + sumdbServer = sumdb.NewServer(sumdbOps) + + sumdbWrongOps = sumdb.NewTestServer(testSumDBSignerKey, proxyGoSumWrong) + sumdbWrongServer = sumdb.NewServer(sumdbWrongOps) +) + +// 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 := r.URL.Path[len("/mod/"):] + + // /mod/invalid returns faulty responses. + if strings.HasPrefix(path, "invalid/") { + w.Write([]byte("invalid")) + return + } + + // Next element may opt into special behavior. + if j := strings.Index(path, "/"); j >= 0 { + n, err := strconv.Atoi(path[:j]) + if err == nil && n >= 200 { + w.WriteHeader(n) + return + } + if strings.HasPrefix(path, "sumdb-") { + n, err := strconv.Atoi(path[len("sumdb-"):j]) + if err == nil && n >= 200 { + if strings.HasPrefix(path[j:], "/sumdb/") { + w.WriteHeader(n) + return + } + path = path[j+1:] + } + } + } + + // Request for $GOPROXY/sumdb-direct is direct sumdb access. + // (Client thinks it is talking directly to a sumdb.) + if strings.HasPrefix(path, "sumdb-direct/") { + r.URL.Path = path[len("sumdb-direct"):] + sumdbServer.ServeHTTP(w, r) + return + } + + // Request for $GOPROXY/sumdb-wrong is direct sumdb access + // but all the hashes are wrong. + // (Client thinks it is talking directly to a sumdb.) + if strings.HasPrefix(path, "sumdb-wrong/") { + r.URL.Path = path[len("sumdb-wrong"):] + sumdbWrongServer.ServeHTTP(w, r) + return + } + + // Request for $GOPROXY/redirect//... goes to redirects. + if strings.HasPrefix(path, "redirect/") { + path = path[len("redirect/"):] + if j := strings.Index(path, "/"); j >= 0 { + count, err := strconv.Atoi(path[:j]) + if err != nil { + return + } + + // The last redirect. + if count <= 1 { + http.Redirect(w, r, fmt.Sprintf("/mod/%s", path[j+1:]), 302) + return + } + http.Redirect(w, r, fmt.Sprintf("/mod/redirect/%d/%s", count-1, path[j+1:]), 302) + return + } + } + + // Request for $GOPROXY/sumdb//supported + // is checking whether it's OK to access sumdb via the proxy. + if path == "sumdb/"+testSumDBName+"/supported" { + w.WriteHeader(200) + return + } + + // Request for $GOPROXY/sumdb//... goes to sumdb. + if sumdbPrefix := "sumdb/" + testSumDBName + "/"; strings.HasPrefix(path, sumdbPrefix) { + r.URL.Path = path[len(sumdbPrefix)-1:] + sumdbServer.ServeHTTP(w, r) + return + } + + // Module proxy request: /mod/path/@latest + // Rewrite to /mod/path/@v/.info where is the semantically + // latest version, including pseudo-versions. + if i := strings.LastIndex(path, "/@latest"); i >= 0 { + enc := path[:i] + modPath, err := module.UnescapePath(enc) + if err != nil { + if testing.Verbose() { + fmt.Fprintf(os.Stderr, "go proxy_test: %v\n", err) + } + http.NotFound(w, r) + return + } + + // Imitate what "latest" does in direct mode and what proxy.golang.org does. + // Use the latest released version. + // If there is no released version, use the latest prereleased version. + // Otherwise, use the latest pseudoversion. + var latestRelease, latestPrerelease, latestPseudo string + for _, m := range modList { + if m.Path != modPath { + continue + } + if modfetch.IsPseudoVersion(m.Version) && (latestPseudo == "" || semver.Compare(latestPseudo, m.Version) > 0) { + latestPseudo = m.Version + } else if semver.Prerelease(m.Version) != "" && (latestPrerelease == "" || semver.Compare(latestPrerelease, m.Version) > 0) { + latestPrerelease = m.Version + } else if latestRelease == "" || semver.Compare(latestRelease, m.Version) > 0 { + latestRelease = m.Version + } + } + var latest string + if latestRelease != "" { + latest = latestRelease + } else if latestPrerelease != "" { + latest = latestPrerelease + } else if latestPseudo != "" { + latest = latestPseudo + } else { + http.NotFound(w, r) + return + } + + encVers, err := module.EscapeVersion(latest) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + path = fmt.Sprintf("%s/@v/%s.info", enc, encVers) + } + + // Module proxy request: /mod/path/@v/version[.suffix] + i := strings.Index(path, "/@v/") + if i < 0 { + http.NotFound(w, r) + return + } + enc, file := path[:i], path[i+len("/@v/"):] + path, err := module.UnescapePath(enc) + if err != nil { + if testing.Verbose() { + fmt.Fprintf(os.Stderr, "go proxy_test: %v\n", err) + } + http.NotFound(w, r) + return + } + if file == "list" { + // list returns a list of versions, not including pseudo-versions. + // If the module has no tagged versions, we should serve an empty 200. + // If the module doesn't exist, we should serve 404 or 410. + found := false + for _, m := range modList { + if m.Path != path { + continue + } + found = true + if !modfetch.IsPseudoVersion(m.Version) { + if err := module.Check(m.Path, m.Version); err == nil { + fmt.Fprintf(w, "%s\n", m.Version) + } + } + } + if !found { + 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.UnescapeVersion(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, err := readArchive(path, vers) + if err != nil { + if testing.Verbose() { + fmt.Fprintf(os.Stderr, "go proxy: no archive %s %s: %v\n", path, vers, err) + } + if errors.Is(err, fs.ErrNotExist) { + http.NotFound(w, r) + } else { + 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 + } + var zipName string + if strings.HasPrefix(f.Name, "/") { + zipName = f.Name[1:] + } else { + zipName = path + "@" + vers + "/" + f.Name + } + zf, err := z.Create(zipName) + 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 { + if testing.Verbose() { + 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, err := readArchive(m.Path, m.Version) + if err != 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, error) { + enc, err := module.EscapePath(path) + if err != nil { + return nil, err + } + encVers, err := module.EscapeVersion(vers) + if err != nil { + return nil, err + } + + prefix := strings.ReplaceAll(enc, "/", "_") + 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) + if a == nil { + return nil, fs.ErrNotExist + } + return a, nil +} + +// proxyGoSum returns the two go.sum lines for path@vers. +func proxyGoSum(path, vers string) ([]byte, error) { + a, err := readArchive(path, vers) + if err != nil { + return nil, err + } + var names []string + files := make(map[string][]byte) + var gomod []byte + for _, f := range a.Files { + if strings.HasPrefix(f.Name, ".") { + if f.Name == ".mod" { + gomod = f.Data + } + continue + } + name := path + "@" + vers + "/" + f.Name + names = append(names, name) + files[name] = f.Data + } + h1, err := dirhash.Hash1(names, func(name string) (io.ReadCloser, error) { + data := files[name] + return io.NopCloser(bytes.NewReader(data)), nil + }) + if err != nil { + return nil, err + } + h1mod, err := dirhash.Hash1([]string{"go.mod"}, func(string) (io.ReadCloser, error) { + return io.NopCloser(bytes.NewReader(gomod)), nil + }) + if err != nil { + return nil, err + } + data := []byte(fmt.Sprintf("%s %s %s\n%s %s/go.mod %s\n", path, vers, h1, path, vers, h1mod)) + return data, nil +} + +// proxyGoSumWrong returns the wrong lines. +func proxyGoSumWrong(path, vers string) ([]byte, error) { + data := []byte(fmt.Sprintf("%s %s %s\n%s %s/go.mod %s\n", path, vers, "h1:wrong", path, vers, "h1:wrong")) + return data, nil +} diff --git a/src/cmd/go/script_test.go b/src/cmd/go/script_test.go new file mode 100644 index 0000000..dfaa405 --- /dev/null +++ b/src/cmd/go/script_test.go @@ -0,0 +1,1448 @@ +// 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" + "context" + "errors" + "fmt" + "go/build" + "internal/testenv" + "io/fs" + "os" + "os/exec" + "path/filepath" + "regexp" + "runtime" + "strconv" + "strings" + "sync" + "testing" + "time" + + "cmd/go/internal/cfg" + "cmd/go/internal/imports" + "cmd/go/internal/par" + "cmd/go/internal/robustio" + "cmd/go/internal/txtar" + "cmd/go/internal/work" + "cmd/internal/objabi" + "cmd/internal/sys" +) + +// TestScript runs the tests in testdata/script/*.txt. +func TestScript(t *testing.T) { + testenv.MustHaveGoBuild(t) + testenv.SkipIfShortAndSlow(t) + + 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 + background []*backgroundCmd // backgrounded 'exec' and 'go' commands +} + +type backgroundCmd struct { + want simpleStatus + args []string + cancel context.CancelFunc + done <-chan struct{} + err error + stdout, stderr strings.Builder +} + +type simpleStatus string + +const ( + success simpleStatus = "" + failure simpleStatus = "!" + successOrFailure simpleStatus = "?" +) + +var extraEnvKeys = []string{ + "SYSTEMROOT", // must be preserved on Windows to find DLLs; golang.org/issue/25210 + "WINDIR", // must be preserved on Windows to be able to run PowerShell command; golang.org/issue/30711 + "LD_LIBRARY_PATH", // must be preserved on Unix systems to find shared libraries + "CC", // don't lose user settings when invoking cgo + "GO_TESTING_GOTOOLS", // for gccgo testing + "GCCGO", // for gccgo testing + "GCCGOTOOLDIR", // for gccgo testing +} + +// 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, + "GODEBUG=" + os.Getenv("GODEBUG"), + "GOEXE=" + cfg.ExeSuffix, + "GOEXPSTRING=" + objabi.Expstring()[2:], + "GOOS=" + runtime.GOOS, + "GOPATH=" + filepath.Join(ts.workdir, "gopath"), + "GOPROXY=" + proxyURL, + "GOPRIVATE=", + "GOROOT=" + testGOROOT, + "GOROOT_FINAL=" + os.Getenv("GOROOT_FINAL"), // causes spurious rebuilds and breaks the "stale" built-in if not propagated + "TESTGO_GOROOT=" + testGOROOT, + "GOSUMDB=" + testSumDBVerifierKey, + "GONOPROXY=", + "GONOSUMDB=", + "GOVCS=*:all", + "PWD=" + ts.cd, + tempEnvName() + "=" + filepath.Join(ts.workdir, "tmp"), + "devnull=" + os.DevNull, + "goversion=" + goVersion(ts), + ":=" + string(os.PathListSeparator), + } + if !testenv.HasExternalNetwork() { + ts.env = append(ts.env, "TESTGONETWORK=panic", "TESTGOVCS=panic") + } + + if runtime.GOOS == "plan9" { + ts.env = append(ts.env, "path="+testBin+string(filepath.ListSeparator)+os.Getenv("path")) + } + + 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:] + } + } +} + +// goVersion returns the current Go version. +func goVersion(ts *testScript) string { + tags := build.Default.ReleaseTags + version := tags[len(tags)-1] + if !regexp.MustCompile(`^go([1-9][0-9]*)\.(0|[1-9][0-9]*)$`).MatchString(version) { + ts.fatalf("invalid go version %q", version) + } + return version[2:] +} + +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() { + // On a normal exit from the test loop, background processes are cleaned up + // before we print PASS. If we return early (e.g., due to a test failure), + // don't print anything about the processes that were still running. + for _, bg := range ts.background { + bg.cancel() + } + for _, bg := range ts.background { + <-bg.done + } + ts.background = nil + + 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, false)) + ts.check(os.MkdirAll(filepath.Dir(name), 0777)) + ts.check(os.WriteFile(name, f.Data, 0666)) + } + + // With -v or -testwork, start log with full environment. + if *testWork || testing.Verbose() { + // Display environment. + ts.cmdEnv(success, 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. + parsed := ts.parse(line) + if parsed.name == "" { + if parsed.want != "" || len(parsed.conds) > 0 { + ts.fatalf("missing command") + } + continue + } + + // Echo command to log. + fmt.Fprintf(&ts.log, "> %s\n", line) + + for _, cond := range parsed.conds { + // 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.tag { + 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 "root": + ok = os.Geteuid() == 0 + case "symlink": + ok = testenv.HasSymlink() + case "case-sensitive": + ok = isCaseSensitive(ts.t) + default: + if strings.HasPrefix(cond.tag, "exec:") { + prog := cond.tag[len("exec:"):] + ok = execCache.Do(prog, func() interface{} { + if runtime.GOOS == "plan9" && prog == "git" { + // The Git command is usually not the real Git on Plan 9. + // See https://golang.org/issues/29640. + return false + } + _, err := exec.LookPath(prog) + return err == nil + }).(bool) + break + } + if strings.HasPrefix(cond.tag, "GODEBUG:") { + value := strings.TrimPrefix(cond.tag, "GODEBUG:") + parts := strings.Split(os.Getenv("GODEBUG"), ",") + for _, p := range parts { + if strings.TrimSpace(p) == value { + ok = true + break + } + } + break + } + if strings.HasPrefix(cond.tag, "buildmode:") { + value := strings.TrimPrefix(cond.tag, "buildmode:") + ok = sys.BuildModeSupported(runtime.Compiler, value, runtime.GOOS, runtime.GOARCH) + break + } + if !imports.KnownArch[cond.tag] && !imports.KnownOS[cond.tag] && cond.tag != "gc" && cond.tag != "gccgo" { + ts.fatalf("unknown condition %q", cond.tag) + } + } + if ok != cond.want { + // Don't run rest of line. + continue Script + } + } + + // Run command. + cmd := scriptCmds[parsed.name] + if cmd == nil { + ts.fatalf("unknown command %q", parsed.name) + } + cmd(ts, parsed.want, parsed.args) + + // Command can ask script to stop early. + if ts.stopped { + // Break instead of returning, so that we check the status of any + // background processes and print PASS. + break + } + } + + for _, bg := range ts.background { + bg.cancel() + } + ts.cmdWait(success, nil) + + // Final phase ended. + rewind() + markTime() + if !ts.stopped { + fmt.Fprintf(&ts.log, "PASS\n") + } +} + +var ( + onceCaseSensitive sync.Once + caseSensitive bool +) + +func isCaseSensitive(t *testing.T) bool { + onceCaseSensitive.Do(func() { + tmpdir, err := os.MkdirTemp("", "case-sensitive") + if err != nil { + t.Fatal("failed to create directory to determine case-sensitivity:", err) + } + defer os.RemoveAll(tmpdir) + + fcap := filepath.Join(tmpdir, "FILE") + if err := os.WriteFile(fcap, []byte{}, 0644); err != nil { + t.Fatal("error writing file to determine case-sensitivity:", err) + } + + flow := filepath.Join(tmpdir, "file") + _, err = os.ReadFile(flow) + switch { + case err == nil: + caseSensitive = false + return + case os.IsNotExist(err): + caseSensitive = true + return + default: + t.Fatal("unexpected error reading file when determining case-sensitivity:", err) + } + }) + + return caseSensitive +} + +// 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, simpleStatus, []string){ + "addcrlf": (*testScript).cmdAddcrlf, + "cc": (*testScript).cmdCc, + "cd": (*testScript).cmdCd, + "chmod": (*testScript).cmdChmod, + "cmp": (*testScript).cmdCmp, + "cmpenv": (*testScript).cmdCmpenv, + "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, + "wait": (*testScript).cmdWait, +} + +// When expanding shell variables for these commands, we apply regexp quoting to +// expanded strings within the first argument. +var regexpCmd = map[string]bool{ + "grep": true, + "stderr": true, + "stdout": true, +} + +// addcrlf adds CRLF line endings to the named files. +func (ts *testScript) cmdAddcrlf(want simpleStatus, args []string) { + if len(args) == 0 { + ts.fatalf("usage: addcrlf file...") + } + + for _, file := range args { + file = ts.mkabs(file) + data, err := os.ReadFile(file) + ts.check(err) + ts.check(os.WriteFile(file, bytes.ReplaceAll(data, []byte("\n"), []byte("\r\n")), 0666)) + } +} + +// cc runs the C compiler along with platform specific options. +func (ts *testScript) cmdCc(want simpleStatus, args []string) { + if len(args) < 1 || (len(args) == 1 && args[0] == "&") { + ts.fatalf("usage: cc args... [&]") + } + + var b work.Builder + b.Init() + ts.cmdExec(want, append(b.GccCmd(".", ""), args...)) + robustio.RemoveAll(b.WorkDir) +} + +// cd changes to a different directory. +func (ts *testScript) cmdCd(want simpleStatus, args []string) { + if want != success { + ts.fatalf("unsupported: %v cd", want) + } + 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 + ts.envMap["PWD"] = dir + fmt.Fprintf(&ts.log, "%s\n", ts.cd) +} + +// chmod changes permissions for a file or directory. +func (ts *testScript) cmdChmod(want simpleStatus, args []string) { + if want != success { + ts.fatalf("unsupported: %v chmod", want) + } + if len(args) < 2 { + ts.fatalf("usage: chmod perm paths...") + } + perm, err := strconv.ParseUint(args[0], 0, 32) + if err != nil || perm&uint64(fs.ModePerm) != perm { + ts.fatalf("invalid mode: %s", args[0]) + } + for _, arg := range args[1:] { + path := arg + if !filepath.IsAbs(path) { + path = filepath.Join(ts.cd, arg) + } + err := os.Chmod(path, fs.FileMode(perm)) + ts.check(err) + } +} + +// cmp compares two files. +func (ts *testScript) cmdCmp(want simpleStatus, args []string) { + if want != success { + // It would be strange to say "this file can have any content except this precise byte sequence". + ts.fatalf("unsupported: %v cmp", want) + } + quiet := false + if len(args) > 0 && args[0] == "-q" { + quiet = true + args = args[1:] + } + if len(args) != 2 { + ts.fatalf("usage: cmp file1 file2") + } + ts.doCmdCmp(args, false, quiet) +} + +// cmpenv compares two files with environment variable substitution. +func (ts *testScript) cmdCmpenv(want simpleStatus, args []string) { + if want != success { + ts.fatalf("unsupported: %v cmpenv", want) + } + quiet := false + if len(args) > 0 && args[0] == "-q" { + quiet = true + args = args[1:] + } + if len(args) != 2 { + ts.fatalf("usage: cmpenv file1 file2") + } + ts.doCmdCmp(args, true, quiet) +} + +func (ts *testScript) doCmdCmp(args []string, env, quiet bool) { + 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 := os.ReadFile(ts.mkabs(name1)) + ts.check(err) + text1 = string(data) + } + + data, err := os.ReadFile(ts.mkabs(name2)) + ts.check(err) + text2 = string(data) + + if env { + text1 = ts.expand(text1, false) + text2 = ts.expand(text2, false) + } + + if text1 == text2 { + return + } + + if !quiet { + 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(want simpleStatus, args []string) { + 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] { + var ( + src string + data []byte + mode fs.FileMode + ) + switch arg { + case "stdout": + src = arg + data = []byte(ts.stdout) + mode = 0666 + case "stderr": + src = arg + data = []byte(ts.stderr) + mode = 0666 + default: + src = ts.mkabs(arg) + info, err := os.Stat(src) + ts.check(err) + mode = info.Mode() & 0777 + data, err = os.ReadFile(src) + ts.check(err) + } + targ := dst + if dstDir { + targ = filepath.Join(dst, filepath.Base(src)) + } + err := os.WriteFile(targ, data, mode) + switch want { + case failure: + if err == nil { + ts.fatalf("unexpected command success") + } + case success: + ts.check(err) + } + } +} + +// env displays or adds to the environment. +func (ts *testScript) cmdEnv(want simpleStatus, args []string) { + if want != success { + ts.fatalf("unsupported: %v env", want) + } + + conv := func(s string) string { return s } + if len(args) > 0 && args[0] == "-r" { + conv = regexp.QuoteMeta + args = args[1:] + } + + var out strings.Builder + 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(&out, "%s=%s\n", k, ts.envMap[k]) + } + } + } else { + for _, env := range args { + i := strings.Index(env, "=") + if i < 0 { + // Display value instead of setting it. + fmt.Fprintf(&out, "%s=%s\n", env, ts.envMap[env]) + continue + } + key, val := env[:i], conv(env[i+1:]) + ts.env = append(ts.env, key+"="+val) + ts.envMap[key] = val + } + } + if out.Len() > 0 || len(args) > 0 { + ts.stdout = out.String() + ts.log.WriteString(out.String()) + } +} + +// exec runs the given command. +func (ts *testScript) cmdExec(want simpleStatus, args []string) { + if len(args) < 1 || (len(args) == 1 && args[0] == "&") { + ts.fatalf("usage: exec program [args...] [&]") + } + + background := false + if len(args) > 0 && args[len(args)-1] == "&" { + background = true + args = args[:len(args)-1] + } + + bg, err := ts.startBackground(want, args[0], args[1:]...) + if err != nil { + ts.fatalf("unexpected error starting command: %v", err) + } + if background { + ts.stdout, ts.stderr = "", "" + ts.background = append(ts.background, bg) + return + } + + <-bg.done + ts.stdout = bg.stdout.String() + ts.stderr = bg.stderr.String() + 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 bg.err != nil { + fmt.Fprintf(&ts.log, "[%v]\n", bg.err) + } + ts.checkCmd(bg) +} + +// exists checks that the list of files exists. +func (ts *testScript) cmdExists(want simpleStatus, args []string) { + if want == successOrFailure { + ts.fatalf("unsupported: %v exists", want) + } + var readonly, exec bool +loop: + for len(args) > 0 { + switch args[0] { + case "-readonly": + readonly = true + args = args[1:] + case "-exec": + exec = true + args = args[1:] + default: + break loop + } + } + if len(args) == 0 { + ts.fatalf("usage: exists [-readonly] [-exec] file...") + } + + for _, file := range args { + file = ts.mkabs(file) + info, err := os.Stat(file) + if err == nil && want == failure { + what := "file" + if info.IsDir() { + what = "directory" + } + ts.fatalf("%s %s unexpectedly exists", what, file) + } + if err != nil && want == success { + ts.fatalf("%s does not exist", file) + } + if err == nil && want == success && readonly && info.Mode()&0222 != 0 { + ts.fatalf("%s exists but is writable", file) + } + if err == nil && want == success && exec && runtime.GOOS != "windows" && info.Mode()&0111 == 0 { + ts.fatalf("%s exists but is not executable", file) + } + } +} + +// go runs the go command. +func (ts *testScript) cmdGo(want simpleStatus, args []string) { + ts.cmdExec(want, append([]string{testGo}, args...)) +} + +// mkdir creates directories. +func (ts *testScript) cmdMkdir(want simpleStatus, args []string) { + if want != success { + ts.fatalf("unsupported: %v mkdir", want) + } + 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(want simpleStatus, args []string) { + if want != success { + ts.fatalf("unsupported: %v rm", want) + } + 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(robustio.RemoveAll(file)) // report error + } +} + +// skip marks the test skipped. +func (ts *testScript) cmdSkip(want simpleStatus, args []string) { + if len(args) > 1 { + ts.fatalf("usage: skip [msg]") + } + if want != success { + ts.fatalf("unsupported: %v skip", want) + } + + // Before we mark the test as skipped, shut down any background processes and + // make sure they have returned the correct status. + for _, bg := range ts.background { + bg.cancel() + } + ts.cmdWait(success, nil) + + 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(want simpleStatus, args []string) { + if len(args) == 0 { + ts.fatalf("usage: stale target...") + } + tmpl := "{{if .Error}}{{.ImportPath}}: {{.Error.Err}}{{else}}" + switch want { + case failure: + tmpl += "{{if .Stale}}{{.ImportPath}} is unexpectedly stale{{end}}" + case success: + tmpl += "{{if not .Stale}}{{.ImportPath}} is unexpectedly NOT stale{{end}}" + default: + ts.fatalf("unsupported: %v stale", want) + } + 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(want simpleStatus, args []string) { + scriptMatch(ts, want, args, ts.stdout, "stdout") +} + +// stderr checks that the last go command standard output matches a regexp. +func (ts *testScript) cmdStderr(want simpleStatus, args []string) { + scriptMatch(ts, want, 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(want simpleStatus, args []string) { + scriptMatch(ts, want, args, "", "grep") +} + +// scriptMatch implements both stdout and stderr. +func scriptMatch(ts *testScript, want simpleStatus, args []string, text, name string) { + if want == successOrFailure { + ts.fatalf("unsupported: %v %s", want, name) + } + + n := 0 + if len(args) >= 1 && strings.HasPrefix(args[0], "-count=") { + if want == failure { + 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:] + } + quiet := false + if len(args) >= 1 && args[0] == "-q" { + quiet = true + args = args[1:] + } + + extraUsage := "" + wantArgs := 1 + if name == "grep" { + extraUsage = " file" + wantArgs = 2 + } + if len(args) != wantArgs { + ts.fatalf("usage: %s [-count=N] 'pattern'%s", name, extraUsage) + } + + pattern := `(?m)` + args[0] + re, err := regexp.Compile(pattern) + if err != nil { + ts.fatalf("regexp.Compile(%q): %v", pattern, err) + } + + isGrep := name == "grep" + if isGrep { + name = args[1] // for error messages + data, err := os.ReadFile(ts.mkabs(args[1])) + ts.check(err) + text = string(data) + } + + // Matching against workdir would be misleading. + text = strings.ReplaceAll(text, ts.workdir, "$WORK") + + switch want { + case failure: + if re.MatchString(text) { + if isGrep && !quiet { + 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)) + } + + case success: + if !re.MatchString(text) { + if isGrep && !quiet { + 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 && !quiet { + 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(want simpleStatus, args []string) { + if want != success { + ts.fatalf("unsupported: %v stop", want) + } + 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(want simpleStatus, args []string) { + if want != success { + ts.fatalf("unsupported: %v symlink", want) + } + 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]))) +} + +// wait waits for background commands to exit, setting stderr and stdout to their result. +func (ts *testScript) cmdWait(want simpleStatus, args []string) { + if want != success { + ts.fatalf("unsupported: %v wait", want) + } + if len(args) > 0 { + ts.fatalf("usage: wait") + } + + var stdouts, stderrs []string + for _, bg := range ts.background { + <-bg.done + + args := append([]string{filepath.Base(bg.args[0])}, bg.args[1:]...) + fmt.Fprintf(&ts.log, "[background] %s: %v\n", strings.Join(args, " "), bg.err) + + cmdStdout := bg.stdout.String() + if cmdStdout != "" { + fmt.Fprintf(&ts.log, "[stdout]\n%s", cmdStdout) + stdouts = append(stdouts, cmdStdout) + } + + cmdStderr := bg.stderr.String() + if cmdStderr != "" { + fmt.Fprintf(&ts.log, "[stderr]\n%s", cmdStderr) + stderrs = append(stderrs, cmdStderr) + } + + ts.checkCmd(bg) + } + + ts.stdout = strings.Join(stdouts, "") + ts.stderr = strings.Join(stderrs, "") + ts.background = nil +} + +// 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.ReplaceAll(s, ts.workdir, "$WORK") + 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) + } +} + +func (ts *testScript) checkCmd(bg *backgroundCmd) { + select { + case <-bg.done: + default: + panic("checkCmd called when not done") + } + + if bg.err == nil { + if bg.want == failure { + ts.fatalf("unexpected command success") + } + return + } + + if errors.Is(bg.err, context.DeadlineExceeded) { + ts.fatalf("test timed out while running command") + } + + if errors.Is(bg.err, context.Canceled) { + // The process was still running at the end of the test. + // The test must not depend on its exit status. + if bg.want != successOrFailure { + ts.fatalf("unexpected background command remaining at test end") + } + return + } + + if bg.want == success { + ts.fatalf("unexpected command failure") + } +} + +// 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) { + bg, err := ts.startBackground(success, command, args...) + if err != nil { + return "", "", err + } + <-bg.done + return bg.stdout.String(), bg.stderr.String(), bg.err +} + +// startBackground starts the given command line (an actual subprocess, not simulated) +// in ts.cd with environment ts.env. +func (ts *testScript) startBackground(want simpleStatus, command string, args ...string) (*backgroundCmd, error) { + done := make(chan struct{}) + bg := &backgroundCmd{ + want: want, + args: append([]string{command}, args...), + done: done, + cancel: func() {}, + } + + ctx := context.Background() + gracePeriod := 100 * time.Millisecond + if deadline, ok := ts.t.Deadline(); ok { + timeout := time.Until(deadline) + // If time allows, increase the termination grace period to 5% of the + // remaining time. + if gp := timeout / 20; gp > gracePeriod { + gracePeriod = gp + } + + // Send the first termination signal with two grace periods remaining. + // If it still hasn't finished after the first period has elapsed, + // we'll escalate to os.Kill with a second period remaining until the + // test deadline.. + timeout -= 2 * gracePeriod + + if timeout <= 0 { + // The test has less than the grace period remaining. There is no point in + // even starting the command, because it will be terminated immediately. + // Save the expense of starting it in the first place. + bg.err = context.DeadlineExceeded + close(done) + return bg, nil + } + + ctx, bg.cancel = context.WithTimeout(ctx, timeout) + } + + cmd := exec.Command(command, args...) + cmd.Dir = ts.cd + cmd.Env = append(ts.env, "PWD="+ts.cd) + cmd.Stdout = &bg.stdout + cmd.Stderr = &bg.stderr + if err := cmd.Start(); err != nil { + bg.cancel() + return nil, err + } + + go func() { + bg.err = waitOrStop(ctx, cmd, stopSignal(), gracePeriod) + close(done) + }() + return bg, nil +} + +// stopSignal returns the appropriate signal to use to request that a process +// stop execution. +func stopSignal() os.Signal { + if runtime.GOOS == "windows" { + // Per https://golang.org/pkg/os/#Signal, “Interrupt is not implemented on + // Windows; using it with os.Process.Signal will return an error.” + // Fall back to Kill instead. + return os.Kill + } + return os.Interrupt +} + +// waitOrStop waits for the already-started command cmd by calling its Wait method. +// +// If cmd does not return before ctx is done, waitOrStop sends it the given interrupt signal. +// If killDelay is positive, waitOrStop waits that additional period for Wait to return before sending os.Kill. +// +// This function is copied from the one added to x/playground/internal in +// http://golang.org/cl/228438. +func waitOrStop(ctx context.Context, cmd *exec.Cmd, interrupt os.Signal, killDelay time.Duration) error { + if cmd.Process == nil { + panic("waitOrStop called with a nil cmd.Process — missing Start call?") + } + if interrupt == nil { + panic("waitOrStop requires a non-nil interrupt signal") + } + + errc := make(chan error) + go func() { + select { + case errc <- nil: + return + case <-ctx.Done(): + } + + err := cmd.Process.Signal(interrupt) + if err == nil { + err = ctx.Err() // Report ctx.Err() as the reason we interrupted. + } else if err.Error() == "os: process already finished" { + errc <- nil + return + } + + if killDelay > 0 { + timer := time.NewTimer(killDelay) + select { + // Report ctx.Err() as the reason we interrupted the process... + case errc <- ctx.Err(): + timer.Stop() + return + // ...but after killDelay has elapsed, fall back to a stronger signal. + case <-timer.C: + } + + // Wait still hasn't returned. + // Kill the process harder to make sure that it exits. + // + // Ignore any error: if cmd.Process has already terminated, we still + // want to send ctx.Err() (or the error from the Interrupt call) + // to properly attribute the signal that may have terminated it. + _ = cmd.Process.Kill() + } + + errc <- err + }() + + waitErr := cmd.Wait() + if interruptErr := <-errc; interruptErr != nil { + return interruptErr + } + return waitErr +} + +// expand applies environment variable expansion to the string s. +func (ts *testScript) expand(s string, inRegexp bool) string { + return os.Expand(s, func(key string) string { + e := ts.envMap[key] + if inRegexp { + // Replace workdir with $WORK, since we have done the same substitution in + // the text we're about to compare against. + e = strings.ReplaceAll(e, ts.workdir, "$WORK") + + // Quote to literal strings: we want paths like C:\work\go1.4 to remain + // paths rather than regular expressions. + e = regexp.QuoteMeta(e) + } + return e + }) +} + +// 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) +} + +// A condition guards execution of a command. +type condition struct { + want bool + tag string +} + +// A command is a complete command parsed from a script. +type command struct { + want simpleStatus + conds []condition // all must be satisfied + name string // the name of the command; must be non-empty + args []string // shell-expanded arguments following name +} + +// 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) command { + ts.line = line + + var ( + cmd command + 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 + isRegexp = false // currently processing unquoted regular expression + ) + + flushArg := func() { + defer func() { + arg = "" + start = -1 + }() + + if cmd.name != "" { + cmd.args = append(cmd.args, arg) + // Commands take only one regexp argument (after the optional flags), + // so no subsequent args are regexps. Liberally assume an argument that + // starts with a '-' is a flag. + if len(arg) == 0 || arg[0] != '-' { + isRegexp = false + } + return + } + + // Command prefix ! means negate the expectations about this command: + // go command should fail, match should not be found, etc. + // Prefix ? means allow either success or failure. + switch want := simpleStatus(arg); want { + case failure, successOrFailure: + if cmd.want != "" { + ts.fatalf("duplicated '!' or '?' token") + } + cmd.want = want + return + } + + // Command prefix [cond] means only run this command if cond is satisfied. + if strings.HasPrefix(arg, "[") && strings.HasSuffix(arg, "]") { + want := true + arg = strings.TrimSpace(arg[1 : len(arg)-1]) + if strings.HasPrefix(arg, "!") { + want = false + arg = strings.TrimSpace(arg[1:]) + } + if arg == "" { + ts.fatalf("empty condition") + } + cmd.conds = append(cmd.conds, condition{want: want, tag: arg}) + return + } + + cmd.name = arg + isRegexp = regexpCmd[cmd.name] + } + + 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], isRegexp) + flushArg() + } + 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], isRegexp) + } + 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 cmd +} + +// 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) { + t.Parallel() + + for _, tt := range diffTests { + // Turn spaces into \n. + text1 := strings.ReplaceAll(tt.text1, " ", "\n") + if text1 != "" { + text1 += "\n" + } + text2 := strings.ReplaceAll(tt.text2, " ", "\n") + if text2 != "" { + text2 += "\n" + } + out := diff(text1, text2) + // Cut final \n, cut spaces, turn remaining \n into spaces. + out = strings.ReplaceAll(strings.ReplaceAll(strings.TrimSuffix(out, "\n"), " ", ""), "\n", " ") + if out != tt.diff { + t.Errorf("diff(%q, %q) = %q, want %q", text1, text2, out, tt.diff) + } + } +} diff --git a/src/cmd/go/testdata/addmod.go b/src/cmd/go/testdata/addmod.go new file mode 100644 index 0000000..09fc8e7 --- /dev/null +++ b/src/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/fs" + "log" + "os" + exec "internal/execabs" + "path/filepath" + "strings" + + "cmd/go/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 = "go" + +func main() { + flag.Usage = usage + flag.Parse() + if flag.NArg() == 0 { + usage() + } + + log.SetPrefix("addmod: ") + log.SetFlags(0) + + var err error + tmpdir, err = os.MkdirTemp("", "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 := os.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 := os.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 := os.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.WalkDir(dir, func(path string, info fs.DirEntry, err error) error { + if !info.Type().IsRegular() { + return nil + } + name := info.Name() + if name == "go.mod" || strings.HasSuffix(name, ".go") { + data, err := os.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.ReplaceAll(path, "/", "_")+"_"+vers+".txt") + if err := os.WriteFile(target, data, 0666); err != nil { + log.Printf("%s: %v", arg, err) + exitCode = 1 + continue + } + } + os.RemoveAll(tmpdir) + os.Exit(exitCode) +} diff --git a/src/cmd/go/testdata/failssh/ssh b/src/cmd/go/testdata/failssh/ssh new file mode 100755 index 0000000..ecdbef9 --- /dev/null +++ b/src/cmd/go/testdata/failssh/ssh @@ -0,0 +1,2 @@ +#!/bin/sh +exit 1 diff --git a/src/cmd/go/testdata/mod/README b/src/cmd/go/testdata/mod/README new file mode 100644 index 0000000..43ddf77 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/example.com_ambiguous_a_b_v0.0.0-empty.txt b/src/cmd/go/testdata/mod/example.com_ambiguous_a_b_v0.0.0-empty.txt new file mode 100644 index 0000000..a869519 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_ambiguous_a_b_v0.0.0-empty.txt @@ -0,0 +1,12 @@ +Module example.com/ambiguous/a/b is a suffix of example.com/a. +This version contains no package. +-- .mod -- +module example.com/ambiguous/a/b + +go 1.16 +-- .info -- +{"Version":"v0.0.0-empty"} +-- go.mod -- +module example.com/ambiguous/a/b + +go 1.16 diff --git a/src/cmd/go/testdata/mod/example.com_ambiguous_a_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_ambiguous_a_v1.0.0.txt new file mode 100644 index 0000000..bb43826 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_ambiguous_a_v1.0.0.txt @@ -0,0 +1,18 @@ +Module example.com/ambiguous/a is a prefix of example.com/a/b. +It contains package example.com/a/b. +-- .mod -- +module example.com/ambiguous/a + +go 1.16 + +require example.com/ambiguous/a/b v0.0.0-empty +-- .info -- +{"Version":"v1.0.0"} +-- go.mod -- +module example.com/ambiguous/a + +go 1.16 + +require example.com/ambiguous/a/b v0.0.0-empty +-- b/b.go -- +package b diff --git a/src/cmd/go/testdata/mod/example.com_badchain_a_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_badchain_a_v1.0.0.txt new file mode 100644 index 0000000..d7bf647 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_badchain_a_v1.0.0.txt @@ -0,0 +1,12 @@ +example.com/badchain/a v1.0.0 + +-- .mod -- +module example.com/badchain/a + +require example.com/badchain/b v1.0.0 +-- .info -- +{"Version":"v1.0.0"} +-- a.go -- +package a + +import _ "example.com/badchain/b" diff --git a/src/cmd/go/testdata/mod/example.com_badchain_a_v1.1.0.txt b/src/cmd/go/testdata/mod/example.com_badchain_a_v1.1.0.txt new file mode 100644 index 0000000..92190d8 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_badchain_a_v1.1.0.txt @@ -0,0 +1,12 @@ +example.com/badchain/a v1.1.0 + +-- .mod -- +module example.com/badchain/a + +require example.com/badchain/b v1.1.0 +-- .info -- +{"Version":"v1.1.0"} +-- a.go -- +package a + +import _ "example.com/badchain/b" diff --git a/src/cmd/go/testdata/mod/example.com_badchain_b_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_badchain_b_v1.0.0.txt new file mode 100644 index 0000000..d42b8aa --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_badchain_b_v1.0.0.txt @@ -0,0 +1,12 @@ +example.com/badchain/b v1.0.0 + +-- .mod -- +module example.com/badchain/b + +require example.com/badchain/c v1.0.0 +-- .info -- +{"Version":"v1.0.0"} +-- b.go -- +package b + +import _ "example.com/badchain/c" diff --git a/src/cmd/go/testdata/mod/example.com_badchain_b_v1.1.0.txt b/src/cmd/go/testdata/mod/example.com_badchain_b_v1.1.0.txt new file mode 100644 index 0000000..6648184 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_badchain_b_v1.1.0.txt @@ -0,0 +1,12 @@ +example.com/badchain/b v1.1.0 + +-- .mod -- +module example.com/badchain/b + +require example.com/badchain/c v1.1.0 +-- .info -- +{"Version":"v1.1.0"} +-- b.go -- +package b + +import _ "example.com/badchain/c" diff --git a/src/cmd/go/testdata/mod/example.com_badchain_c_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_badchain_c_v1.0.0.txt new file mode 100644 index 0000000..9c717cb --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_badchain_c_v1.0.0.txt @@ -0,0 +1,8 @@ +example.com/badchain/c v1.0.0 + +-- .mod -- +module example.com/badchain/c +-- .info -- +{"Version":"v1.0.0"} +-- c.go -- +package c diff --git a/src/cmd/go/testdata/mod/example.com_badchain_c_v1.1.0.txt b/src/cmd/go/testdata/mod/example.com_badchain_c_v1.1.0.txt new file mode 100644 index 0000000..36bc2c6 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_badchain_c_v1.1.0.txt @@ -0,0 +1,8 @@ +example.com/badchain/c v1.1.0 + +-- .mod -- +module badchain.example.com/c +-- .info -- +{"Version":"v1.1.0"} +-- c.go -- +package c diff --git a/src/cmd/go/testdata/mod/example.com_cmd_v1.0.0-exclude.txt b/src/cmd/go/testdata/mod/example.com_cmd_v1.0.0-exclude.txt new file mode 100644 index 0000000..c883d8a --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_cmd_v1.0.0-exclude.txt @@ -0,0 +1,28 @@ +example.com/cmd contains main packages. + +-- .info -- +{"Version":"v1.0.0-exclude"} +-- .mod -- +module example.com/cmd + +go 1.16 + +exclude rsc.io/quote v1.5.2 +-- go.mod -- +module example.com/cmd + +go 1.16 + +exclude rsc.io/quote v1.5.2 +-- a/a.go -- +package main + +func main() {} +-- b/b.go -- +package main + +func main() {} +-- err/err.go -- +package err + +var X = DoesNotCompile diff --git a/src/cmd/go/testdata/mod/example.com_cmd_v1.0.0-newerself.txt b/src/cmd/go/testdata/mod/example.com_cmd_v1.0.0-newerself.txt new file mode 100644 index 0000000..7670f29 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_cmd_v1.0.0-newerself.txt @@ -0,0 +1,28 @@ +example.com/cmd contains main packages. + +-- .info -- +{"Version":"v1.0.0-newerself"} +-- .mod -- +module example.com/cmd + +go 1.16 + +require example.com/cmd v1.0.0 +-- go.mod -- +module example.com/cmd + +go 1.16 + +require example.com/cmd v1.0.0 +-- a/a.go -- +package main + +func main() {} +-- b/b.go -- +package main + +func main() {} +-- err/err.go -- +package err + +var X = DoesNotCompile diff --git a/src/cmd/go/testdata/mod/example.com_cmd_v1.0.0-replace.txt b/src/cmd/go/testdata/mod/example.com_cmd_v1.0.0-replace.txt new file mode 100644 index 0000000..581a496 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_cmd_v1.0.0-replace.txt @@ -0,0 +1,28 @@ +example.com/cmd contains main packages. + +-- .info -- +{"Version":"v1.0.0-replace"} +-- .mod -- +module example.com/cmd + +go 1.16 + +replace rsc.io/quote => rsc.io/quote v1.5.2 +-- go.mod -- +module example.com/cmd + +go 1.16 + +replace rsc.io/quote => rsc.io/quote v1.5.2 +-- a/a.go -- +package main + +func main() {} +-- b/b.go -- +package main + +func main() {} +-- err/err.go -- +package err + +var X = DoesNotCompile diff --git a/src/cmd/go/testdata/mod/example.com_cmd_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_cmd_v1.0.0.txt new file mode 100644 index 0000000..ee43938 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_cmd_v1.0.0.txt @@ -0,0 +1,27 @@ +example.com/cmd contains main packages. + +v1.0.0 is the latest non-retracted version. Other versions contain errors or +detectable problems. + +-- .info -- +{"Version":"v1.0.0"} +-- .mod -- +module example.com/cmd + +go 1.16 +-- go.mod -- +module example.com/cmd + +go 1.16 +-- a/a.go -- +package main + +func main() {} +-- b/b.go -- +package main + +func main() {} +-- err/err.go -- +package err + +var X = DoesNotCompile diff --git a/src/cmd/go/testdata/mod/example.com_cmd_v1.9.0.txt b/src/cmd/go/testdata/mod/example.com_cmd_v1.9.0.txt new file mode 100644 index 0000000..9298afb --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_cmd_v1.9.0.txt @@ -0,0 +1,30 @@ +example.com/cmd contains main packages. + +-- .info -- +{"Version":"v1.9.0"} +-- .mod -- +module example.com/cmd + +go 1.16 + +// this is a bad version +retract v1.9.0 +-- go.mod -- +module example.com/cmd + +go 1.16 + +// this is a bad version +retract v1.9.0 +-- a/a.go -- +package main + +func main() {} +-- b/b.go -- +package main + +func main() {} +-- err/err.go -- +package err + +var X = DoesNotCompile diff --git a/src/cmd/go/testdata/mod/example.com_dotgo.go_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_dotgo.go_v1.0.0.txt new file mode 100644 index 0000000..4f7f4d7 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_dotgo.go_v1.0.0.txt @@ -0,0 +1,16 @@ +This module's path ends with ".go". +Based on github.com/nats-io/nats.go. +Used in regression tests for golang.org/issue/32483. + +-- .mod -- +module example.com/dotgo.go + +go 1.13 +-- .info -- +{"Version":"v1.0.0"} +-- go.mod -- +module example.com/dotgo.go + +go 1.13 +-- dotgo.go -- +package dotgo diff --git a/src/cmd/go/testdata/mod/example.com_downgrade_v2.0.0.txt b/src/cmd/go/testdata/mod/example.com_downgrade_v2.0.0.txt new file mode 100644 index 0000000..88d50e5 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_downgrade_v2.0.0.txt @@ -0,0 +1,9 @@ +example.com/downgrade v2.0.0 +written by hand + +-- .mod -- +module example.com/downgrade + +require rsc.io/quote v1.5.2 +-- .info -- +{"Version":"v2.0.0"} diff --git a/src/cmd/go/testdata/mod/example.com_downgrade_v2_v2.0.1.txt b/src/cmd/go/testdata/mod/example.com_downgrade_v2_v2.0.1.txt new file mode 100644 index 0000000..a4d665f --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_downgrade_v2_v2.0.1.txt @@ -0,0 +1,13 @@ +example.com/downgrade/v2 v2.0.1 +written by hand + +-- .mod -- +module example.com/downgrade/v2 + +require rsc.io/quote v1.5.2 +-- .info -- +{"Version":"v2.0.1"} +-- go.mod -- +module example.com/downgrade/v2 + +require rsc.io/quote v1.5.2 diff --git a/src/cmd/go/testdata/mod/example.com_incompatiblewithsub_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_incompatiblewithsub_v1.0.0.txt new file mode 100644 index 0000000..435578d --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_incompatiblewithsub_v1.0.0.txt @@ -0,0 +1,8 @@ +Module example.com/incompatiblewithsub has an incompatible version +and a package in a subdirectory. +-- .info -- +{"Version":"v1.0.0"} +-- .mod -- +module example.com/incompatiblewithsub +-- sub/sub.go -- +package sub diff --git a/src/cmd/go/testdata/mod/example.com_incompatiblewithsub_v2.0.0+incompatible.txt b/src/cmd/go/testdata/mod/example.com_incompatiblewithsub_v2.0.0+incompatible.txt new file mode 100644 index 0000000..198ec17 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_incompatiblewithsub_v2.0.0+incompatible.txt @@ -0,0 +1,8 @@ +Module example.com/incompatiblewithsub has an incompatible version +and a package in a subdirectory. +-- .info -- +{"Version":"v2.0.0+incompatible"} +-- .mod -- +module example.com/incompatiblewithsub +-- sub/sub.go -- +package sub diff --git a/src/cmd/go/testdata/mod/example.com_invalidpath_v1_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_invalidpath_v1_v1.0.0.txt new file mode 100644 index 0000000..7d9d130 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_invalidpath_v1_v1.0.0.txt @@ -0,0 +1,13 @@ +example.com/invalidpath/v1 v1.0.0 +written by hand + +-- .mod -- +module example.com/invalidpath/v1 +-- .info -- +{"Version":"v1.0.0"} +-- go.mod -- +module example.com/invalidpath/v1 +-- version.go -- +package version + +const V = "v1.0.0" diff --git a/src/cmd/go/testdata/mod/example.com_join_subpkg_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_join_subpkg_v1.0.0.txt new file mode 100644 index 0000000..1ecfa0b --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/example.com_join_subpkg_v1.1.0.txt b/src/cmd/go/testdata/mod/example.com_join_subpkg_v1.1.0.txt new file mode 100644 index 0000000..9eb823a --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/example.com_join_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_join_v1.0.0.txt new file mode 100644 index 0000000..84c68b1 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/example.com_join_v1.1.0.txt b/src/cmd/go/testdata/mod/example.com_join_v1.1.0.txt new file mode 100644 index 0000000..5f92036 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/example.com_latemigrate_v2_v2.0.0.txt b/src/cmd/go/testdata/mod/example.com_latemigrate_v2_v2.0.0.txt new file mode 100644 index 0000000..25bd3d9 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_latemigrate_v2_v2.0.0.txt @@ -0,0 +1,14 @@ +example.com/latemigrate/v2 v2.0.0 +written by hand + +This repository migrated to modules in v2.0.1 after v2.0.0 was already tagged. +All versions require rsc.io/quote so we can test downgrades. + +v2.0.0 is technically part of example.com/latemigrate as v2.0.0+incompatible. +Proxies may serve it as part of the version list for example.com/latemigrate/v2. +'go get' must be able to ignore these versions. + +-- .mod -- +module example.com/latemigrate +-- .info -- +{"Version":"v2.0.0"} diff --git a/src/cmd/go/testdata/mod/example.com_latemigrate_v2_v2.0.1.txt b/src/cmd/go/testdata/mod/example.com_latemigrate_v2_v2.0.1.txt new file mode 100644 index 0000000..be427a3 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_latemigrate_v2_v2.0.1.txt @@ -0,0 +1,20 @@ +example.com/latemigrate/v2 v2.0.1 +written by hand + +This repository migrated to modules in v2.0.1 after v2.0.0 was already tagged. +All versions require rsc.io/quote so we can test downgrades. + +v2.0.1 belongs to example.com/latemigrate/v2. + +-- .mod -- +module example.com/latemigrate/v2 + +require rsc.io/quote v1.3.0 +-- .info -- +{"Version":"v2.0.1"} +-- go.mod -- +module example.com/latemigrate/v2 + +require rsc.io/quote v1.3.0 +-- late.go -- +package late diff --git a/src/cmd/go/testdata/mod/example.com_missingpkg_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_missingpkg_v1.0.0.txt new file mode 100644 index 0000000..15f3f69 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_missingpkg_v1.0.0.txt @@ -0,0 +1,11 @@ +The deprecated package is present in this version (which is @latest) but +is deleted in a newer prerelease version. + +-- .mod -- +module example.com/missingpkg +-- .info -- +{"Version":"v1.0.0"} +-- lib.go -- +package lib +-- deprecated/deprecated.go -- +package deprecated diff --git a/src/cmd/go/testdata/mod/example.com_missingpkg_v1.0.1-beta.txt b/src/cmd/go/testdata/mod/example.com_missingpkg_v1.0.1-beta.txt new file mode 100644 index 0000000..44580fe --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_missingpkg_v1.0.1-beta.txt @@ -0,0 +1,8 @@ +The deprecated package is deleted in this version. + +-- .mod -- +module example.com/missingpkg +-- .info -- +{"Version":"v1.0.1-beta"} +-- lib.go -- +package lib diff --git a/src/cmd/go/testdata/mod/example.com_nest_sub_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_nest_sub_v1.0.0.txt new file mode 100644 index 0000000..90f1459 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_nest_sub_v1.0.0.txt @@ -0,0 +1,12 @@ +Written by hand. +Test case for nested modules without an explicit relationship. +This is nested below the top-level module. + +-- .mod -- +module example.com/nest/sub +-- .info -- +{"Version": "v1.0.0"} +-- go.mod -- +module example.com/nest/sub +-- y/y.go -- +package y diff --git a/src/cmd/go/testdata/mod/example.com_nest_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_nest_v1.0.0.txt new file mode 100644 index 0000000..593caf1 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_nest_v1.0.0.txt @@ -0,0 +1,12 @@ +Written by hand. +Test case for nested modules without an explicit relationship. +This is the top-level module. + +-- .mod -- +module example.com/nest +-- .info -- +{"Version": "v1.0.0"} +-- go.mod -- +module example.com/nest +-- sub/x/x.go -- +package x diff --git a/src/cmd/go/testdata/mod/example.com_nest_v1.1.0.txt b/src/cmd/go/testdata/mod/example.com_nest_v1.1.0.txt new file mode 100644 index 0000000..5a01550 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_nest_v1.1.0.txt @@ -0,0 +1,12 @@ +Written by hand. +Test case for nested modules without an explicit relationship. +This is the top-level module. + +-- .mod -- +module example.com/nest +-- .info -- +{"Version": "v1.1.0"} +-- go.mod -- +module example.com/nest +-- sub/x/x.go -- +package x diff --git a/src/cmd/go/testdata/mod/example.com_newcycle_a_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_newcycle_a_v1.0.0.txt new file mode 100644 index 0000000..829065d --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_newcycle_a_v1.0.0.txt @@ -0,0 +1,10 @@ +example.com/newcycle/a v1.0.0 + +Transitively requires v1.0.1 of itself via example.com/newcycle/b + +-- .mod -- +module example.com/newcycle/a + +require example.com/newcycle/b v1.0.0 +-- .info -- +{"Version":"v1.0.0"} diff --git a/src/cmd/go/testdata/mod/example.com_newcycle_a_v1.0.1.txt b/src/cmd/go/testdata/mod/example.com_newcycle_a_v1.0.1.txt new file mode 100644 index 0000000..a03f4b4 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_newcycle_a_v1.0.1.txt @@ -0,0 +1,10 @@ +example.com/newcycle/a v1.0.1 + +Transitively requires itself via example.com/newcycle/b + +-- .mod -- +module example.com/newcycle/a + +require example.com/newcycle/b v1.0.0 +-- .info -- +{"Version":"v1.0.1"} diff --git a/src/cmd/go/testdata/mod/example.com_newcycle_b_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_newcycle_b_v1.0.0.txt new file mode 100644 index 0000000..ff9e1f5 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_newcycle_b_v1.0.0.txt @@ -0,0 +1,8 @@ +example.com/newcycle/b v1.0.0 + +-- .mod -- +module example.com/newcycle/b + +require example.com/newcycle/a v1.0.1 +-- .info -- +{"Version":"v1.0.0"} diff --git a/src/cmd/go/testdata/mod/example.com_noroot_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_noroot_v1.0.0.txt new file mode 100644 index 0000000..aa5febf --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_noroot_v1.0.0.txt @@ -0,0 +1,8 @@ +A module which has no root package. + +-- .mod -- +module example.com/noroot +-- .info -- +{"Version":"v1.0.0"} +-- pkg/pkg.go -- +package pkg diff --git a/src/cmd/go/testdata/mod/example.com_noroot_v1.0.1.txt b/src/cmd/go/testdata/mod/example.com_noroot_v1.0.1.txt new file mode 100644 index 0000000..9b93717 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_noroot_v1.0.1.txt @@ -0,0 +1,8 @@ +A module which has no root package. + +-- .mod -- +module example.com/noroot +-- .info -- +{"Version":"v1.0.1"} +-- pkg/pkg.go -- +package pkg diff --git a/src/cmd/go/testdata/mod/example.com_notags_v0.0.0-20190507143103-cc8cbe209b64.txt b/src/cmd/go/testdata/mod/example.com_notags_v0.0.0-20190507143103-cc8cbe209b64.txt new file mode 100644 index 0000000..259774d --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_notags_v0.0.0-20190507143103-cc8cbe209b64.txt @@ -0,0 +1,9 @@ +Written by hand. +The "latest" version of a module without any tags. + +-- .mod -- +module example.com/notags +-- .info -- +{"Version":"v0.0.0-20190507143103-cc8cbe209b64","Time":"2019-05-07T07:31:03-07:00"} +-- notags.go -- +package notags diff --git a/src/cmd/go/testdata/mod/example.com_printversion_v0.1.0.txt b/src/cmd/go/testdata/mod/example.com_printversion_v0.1.0.txt new file mode 100644 index 0000000..606322a --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_printversion_v0.1.0.txt @@ -0,0 +1,33 @@ +example.com/printversion v0.1.0 + +-- .mod -- +module example.com/printversion +-- .info -- +{"Version":"v0.1.0"} +-- README.txt -- +There is no go.mod file for this version of the module. +-- printversion.go -- +package main + +import ( + "fmt" + "os" + "runtime/debug" + + _ "example.com/version" +) + +func main() { + info, _ := debug.ReadBuildInfo() + fmt.Fprintf(os.Stdout, "path is %s\n", info.Path) + fmt.Fprintf(os.Stdout, "main is %s %s\n", info.Main.Path, info.Main.Version) + if r := info.Main.Replace; r != nil { + fmt.Fprintf(os.Stdout, "\t(replaced by %s %s)\n", r.Path, r.Version) + } + for _, m := range info.Deps { + fmt.Fprintf(os.Stdout, "using %s %s\n", m.Path, m.Version) + if r := m.Replace; r != nil { + fmt.Fprintf(os.Stdout, "\t(replaced by %s %s)\n", r.Path, r.Version) + } + } +} diff --git a/src/cmd/go/testdata/mod/example.com_printversion_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_printversion_v1.0.0.txt new file mode 100644 index 0000000..b9b71e9 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_printversion_v1.0.0.txt @@ -0,0 +1,41 @@ +example.com/printversion v1.0.0 + +-- .mod -- +module example.com/printversion + +require example.com/version v1.0.0 +replace example.com/version v1.0.0 => ../oops v0.0.0 +exclude example.com/version v1.1.0 +-- .info -- +{"Version":"v1.0.0"} +-- go.mod -- +module example.com/printversion + +require example.com/version v1.0.0 +replace example.com/version v1.0.0 => ../oops v0.0.0 +exclude example.com/version v1.0.1 +-- printversion.go -- +package main + +import ( + "fmt" + "os" + "runtime/debug" + + _ "example.com/version" +) + +func main() { + info, _ := debug.ReadBuildInfo() + fmt.Fprintf(os.Stdout, "path is %s\n", info.Path) + fmt.Fprintf(os.Stdout, "main is %s %s\n", info.Main.Path, info.Main.Version) + if r := info.Main.Replace; r != nil { + fmt.Fprintf(os.Stdout, "\t(replaced by %s %s)\n", r.Path, r.Version) + } + for _, m := range info.Deps { + fmt.Fprintf(os.Stdout, "using %s %s\n", m.Path, m.Version) + if r := m.Replace; r != nil { + fmt.Fprintf(os.Stdout, "\t(replaced by %s %s)\n", r.Path, r.Version) + } + } +} diff --git a/src/cmd/go/testdata/mod/example.com_pseudoupgrade_v0.0.0-20190430073000-30950c05d534.txt b/src/cmd/go/testdata/mod/example.com_pseudoupgrade_v0.0.0-20190430073000-30950c05d534.txt new file mode 100644 index 0000000..047ceb6 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_pseudoupgrade_v0.0.0-20190430073000-30950c05d534.txt @@ -0,0 +1,13 @@ +example.com/pseudoupgrade v0.0.0-20190429073000-30950c05d534 +written by hand + +-- .mod -- +module example.com/pseudoupgrade + +-- .info -- +{"Version":"v0.0.0-20190430073000-30950c05d534","Name":"v0.0.0-20190430073000-30950c05d534","Short":"30950c05d534","Time":"2019-04-30T07:30:00Z"} + +-- pseudoupgrade.go -- +package pseudoupgrade + +const X = 1 diff --git a/src/cmd/go/testdata/mod/example.com_pseudoupgrade_v0.1.0.txt b/src/cmd/go/testdata/mod/example.com_pseudoupgrade_v0.1.0.txt new file mode 100644 index 0000000..7ddb0dc --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_pseudoupgrade_v0.1.0.txt @@ -0,0 +1,13 @@ +example.com/pseudoupgrade v0.1.0 +written by hand + +-- .mod -- +module example.com/pseudoupgrade + +-- .info -- +{"Version":"v0.1.0","Name":"","Short":"","Time":"2019-04-29T07:30:30Z"} + +-- pseudoupgrade.go -- +package pseudoupgrade + +const X = 1 diff --git a/src/cmd/go/testdata/mod/example.com_pseudoupgrade_v0.1.1-0.20190429073117-b5426c86b553.txt b/src/cmd/go/testdata/mod/example.com_pseudoupgrade_v0.1.1-0.20190429073117-b5426c86b553.txt new file mode 100644 index 0000000..b3f48bb --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_pseudoupgrade_v0.1.1-0.20190429073117-b5426c86b553.txt @@ -0,0 +1,13 @@ +example.com/pseudoupgrade v0.1.1-0.20190429073117-b5426c86b553 +written by hand + +-- .mod -- +module example.com/pseudoupgrade + +-- .info -- +{"Version":"v0.1.1-0.20190429073117-b5426c86b553","Name":"v0.1.1-0.20190429073117-b5426c86b553","Short":"b5426c86b553","Time":"2019-04-29T07:31:00Z"} + +-- pseudoupgrade.go -- +package pseudoupgrade + +const X = 1 diff --git a/src/cmd/go/testdata/mod/example.com_quote_v1.5.2.txt b/src/cmd/go/testdata/mod/example.com_quote_v1.5.2.txt new file mode 100644 index 0000000..05f7ae2 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_quote_v1.5.2.txt @@ -0,0 +1,9 @@ +This module is a replacement for rsc.io/quote, but its go.mod file declares +a module path different from its location and the original module. + +-- .mod -- +module rsc.io/Quote + +go 1.14 +-- .info -- +{"Version":"v1.5.2"} diff --git a/src/cmd/go/testdata/mod/example.com_retract_ambiguous_nested_v1.9.0-bad.txt b/src/cmd/go/testdata/mod/example.com_retract_ambiguous_nested_v1.9.0-bad.txt new file mode 100644 index 0000000..f8e623d --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_ambiguous_nested_v1.9.0-bad.txt @@ -0,0 +1,10 @@ +-- .mod -- +module example.com/retract/ambiguous/nested + +go 1.16 + +retract v1.9.0-bad // nested modules are bad +-- .info -- +{"Version":"v1.9.0-bad"} +-- nested.go -- +package nested diff --git a/src/cmd/go/testdata/mod/example.com_retract_ambiguous_other_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_retract_ambiguous_other_v1.0.0.txt new file mode 100644 index 0000000..5ee0139 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_ambiguous_other_v1.0.0.txt @@ -0,0 +1,12 @@ +-- .mod -- +module example.com/retract/ambiguous/other + +go 1.16 + +require example.com/retract/ambiguous v1.0.0 +-- .info -- +{"Version":"v1.0.0"} +-- other.go -- +package other + +import _ "example.com/retract/ambiguous/nested" diff --git a/src/cmd/go/testdata/mod/example.com_retract_ambiguous_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_retract_ambiguous_v1.0.0.txt new file mode 100644 index 0000000..c8eeb16 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_ambiguous_v1.0.0.txt @@ -0,0 +1,9 @@ +-- .mod -- +module example.com/retract/ambiguous + +go 1.16 +-- .info -- +{"Version":"v1.0.0"} +-- nested/nested.go -- +package nested + diff --git a/src/cmd/go/testdata/mod/example.com_retract_incompatible_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_retract_incompatible_v1.0.0.txt new file mode 100644 index 0000000..a987685 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_incompatible_v1.0.0.txt @@ -0,0 +1,19 @@ +The v1.0.0 release of example.com/retract/incompatible retracts +v2.0.0+incompatible. + +-- .mod -- +module example.com/retract/incompatible + +go 1.16 + +retract v2.0.0+incompatible +-- .info -- +{"Version":"v1.0.0"} +-- go.mod -- +module example.com/retract/incompatible + +go 1.16 + +retract v2.0.0+incompatible +-- incompatible.go -- +package incompatible diff --git a/src/cmd/go/testdata/mod/example.com_retract_incompatible_v2.0.0+incompatible.txt b/src/cmd/go/testdata/mod/example.com_retract_incompatible_v2.0.0+incompatible.txt new file mode 100644 index 0000000..c668dbb --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_incompatible_v2.0.0+incompatible.txt @@ -0,0 +1,9 @@ +The v1.0.0 release of example.com/retract/incompatible retracts +v2.0.0+incompatible. + +-- .mod -- +module example.com/retract/incompatible +-- .info -- +{"Version":"v2.0.0+incompatible"} +-- incompatible.go -- +package incompatible diff --git a/src/cmd/go/testdata/mod/example.com_retract_missingmod_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_retract_missingmod_v1.0.0.txt new file mode 100644 index 0000000..1d8d810 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_missingmod_v1.0.0.txt @@ -0,0 +1,10 @@ +This version should be retracted, but the go.mod file for the version that would +contain the retraction is not available. +-- .mod -- +module example.com/retract/missingmod + +go 1.14 +-- .info -- +{"Version":"v1.0.0"} +-- missingmod.go -- +package missingmod diff --git a/src/cmd/go/testdata/mod/example.com_retract_missingmod_v1.9.0.txt b/src/cmd/go/testdata/mod/example.com_retract_missingmod_v1.9.0.txt new file mode 100644 index 0000000..bba919e --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_missingmod_v1.9.0.txt @@ -0,0 +1,4 @@ +The go.mod file at this version will be loaded to check for retractions +of earlier versions. However, the .mod file is not available. +-- .info -- +{"Version":"v1.9.0"} diff --git a/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-block.txt b/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-block.txt new file mode 100644 index 0000000..c4a53e1 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-block.txt @@ -0,0 +1,6 @@ +-- .mod -- +module example.com/retract/rationale + +go 1.14 +-- .info -- +{"Version":"v1.0.0-block"} diff --git a/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-blockwithcomment.txt b/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-blockwithcomment.txt new file mode 100644 index 0000000..92573b6 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-blockwithcomment.txt @@ -0,0 +1,6 @@ +-- .mod -- +module example.com/retract/rationale + +go 1.14 +-- .info -- +{"Version":"v1.0.0-blockwithcomment"} diff --git a/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-empty.txt b/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-empty.txt new file mode 100644 index 0000000..1f0894a --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-empty.txt @@ -0,0 +1,8 @@ +-- .mod -- +module example.com/retract/rationale + +go 1.14 +-- .info -- +{"Version":"v1.0.0-empty"} +-- empty.go -- +package empty diff --git a/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-long.txt b/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-long.txt new file mode 100644 index 0000000..1b5e753 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-long.txt @@ -0,0 +1,8 @@ +-- .mod -- +module example.com/retract/rationale + +go 1.14 +-- .info -- +{"Version":"v1.0.0-long"} +-- empty.go -- +package empty diff --git a/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-multiline1.txt b/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-multiline1.txt new file mode 100644 index 0000000..b1ffe27 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-multiline1.txt @@ -0,0 +1,8 @@ +-- .mod -- +module example.com/retract/rationale + +go 1.14 +-- .info -- +{"Version":"v1.0.0-multiline1"} +-- empty.go -- +package empty diff --git a/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-multiline2.txt b/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-multiline2.txt new file mode 100644 index 0000000..72f80b3 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-multiline2.txt @@ -0,0 +1,8 @@ +-- .mod -- +module example.com/retract/rationale + +go 1.14 +-- .info -- +{"Version":"v1.0.0-multiline2"} +-- empty.go -- +package empty diff --git a/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-order.txt b/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-order.txt new file mode 100644 index 0000000..1b04504 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-order.txt @@ -0,0 +1,6 @@ +-- .mod -- +module example.com/retract/rationale + +go 1.14 +-- .info -- +{"Version":"v1.0.0-order"} diff --git a/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-unprintable.txt b/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-unprintable.txt new file mode 100644 index 0000000..9496124 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.0-unprintable.txt @@ -0,0 +1,8 @@ +-- .mod -- +module example.com/retract/rationale + +go 1.14 +-- .info -- +{"Version":"v1.0.0-unprintable"} +-- empty.go -- +package empty diff --git a/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.1-order.txt b/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.1-order.txt new file mode 100644 index 0000000..3be7d5b --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.0.1-order.txt @@ -0,0 +1,6 @@ +-- .mod -- +module example.com/retract/rationale + +go 1.14 +-- .info -- +{"Version":"v1.0.1-order"} diff --git a/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.9.0.txt b/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.9.0.txt new file mode 100644 index 0000000..6975d4e --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_rationale_v1.9.0.txt @@ -0,0 +1,48 @@ +Module example.com/retract/description retracts all versions of itself. +The rationale comments have various problems. + +-- .mod -- +module example.com/retract/rationale + +go 1.14 + +retract ( + v1.0.0-empty + + // short description + // more + // + // detail + v1.0.0-multiline1 // suffix + // after not included +) + +// short description +// more +// +// detail +retract v1.0.0-multiline2 // suffix + +// loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong +retract v1.0.0-long + +// Ends with a BEL character. Beep! +retract v1.0.0-unprintable + +// block comment +retract ( + v1.0.0-block + + // inner comment + v1.0.0-blockwithcomment +) + +retract ( + [v1.0.0-order, v1.0.0-order] // degenerate range + v1.0.0-order // single version + + v1.0.1-order // single version + [v1.0.1-order, v1.0.1-order] // degenerate range +) +-- .info -- +{"Version":"v1.9.0"} diff --git a/src/cmd/go/testdata/mod/example.com_retract_rename_v1.0.0-bad.txt b/src/cmd/go/testdata/mod/example.com_retract_rename_v1.0.0-bad.txt new file mode 100644 index 0000000..25c4ff1 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_rename_v1.0.0-bad.txt @@ -0,0 +1,16 @@ +Module example.com/retract/rename is renamed in a later version. + +This happens frequently when a repository is renamed or when a go.mod file +is added for the first time with a custom module path. +-- .info -- +{"Version":"v1.0.0-bad"} +-- .mod -- +module example.com/retract/rename + +go 1.16 +-- go.mod -- +module example.com/retract/rename + +go 1.16 +-- rename.go -- +package rename diff --git a/src/cmd/go/testdata/mod/example.com_retract_rename_v1.9.0-new.txt b/src/cmd/go/testdata/mod/example.com_retract_rename_v1.9.0-new.txt new file mode 100644 index 0000000..9c08f71 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_rename_v1.9.0-new.txt @@ -0,0 +1,22 @@ +Module example.com/retract/rename is renamed in this version. + +This happens frequently when a repository is renamed or when a go.mod file +is added for the first time with a custom module path. +-- .info -- +{"Version":"v1.9.0-new"} +-- .mod -- +module example.com/retract/newname + +go 1.16 + +// bad +retract v1.0.0-bad +-- go.mod -- +module example.com/retract/newname + +go 1.16 + +// bad +retract v1.0.0-bad +-- newname.go -- +package newname diff --git a/src/cmd/go/testdata/mod/example.com_retract_self_all_v1.9.0.txt b/src/cmd/go/testdata/mod/example.com_retract_self_all_v1.9.0.txt new file mode 100644 index 0000000..4dc486b --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_self_all_v1.9.0.txt @@ -0,0 +1,14 @@ +Module example.com/retract/self/prev is a module that retracts its own +latest version. + +No unretracted versions are available. + +-- .mod -- +module example.com/retract/self/all + +go 1.15 + +retract v1.9.0 // bad + +-- .info -- +{"Version":"v1.9.0"} diff --git a/src/cmd/go/testdata/mod/example.com_retract_self_prerelease_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_retract_self_prerelease_v1.0.0.txt new file mode 100644 index 0000000..04c2845 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_self_prerelease_v1.0.0.txt @@ -0,0 +1,16 @@ +Module example.com/retract/self/prerelease is a module that retracts its own +latest version and all other release version. + +A pre-release version higher than the highest release version is still +available, and that should be matched by @latest. + +-- .mod -- +module example.com/retract/self/prerelease + +go 1.15 + +-- .info -- +{"Version":"v1.0.0"} + +-- p.go -- +package p diff --git a/src/cmd/go/testdata/mod/example.com_retract_self_prerelease_v1.9.0.txt b/src/cmd/go/testdata/mod/example.com_retract_self_prerelease_v1.9.0.txt new file mode 100644 index 0000000..7c1c047 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_self_prerelease_v1.9.0.txt @@ -0,0 +1,19 @@ +Module example.com/retract/self/prerelease is a module that retracts its own +latest version and all other release version. + +A pre-release version higher than the highest release version is still +available, and that should be matched by @latest. + +-- .mod -- +module example.com/retract/self/prerelease + +go 1.15 + +retract v1.0.0 // bad +retract v1.9.0 // self + +-- .info -- +{"Version":"v1.9.0"} + +-- p.go -- +package p diff --git a/src/cmd/go/testdata/mod/example.com_retract_self_prerelease_v1.9.1-pre.txt b/src/cmd/go/testdata/mod/example.com_retract_self_prerelease_v1.9.1-pre.txt new file mode 100644 index 0000000..abf44fd --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_self_prerelease_v1.9.1-pre.txt @@ -0,0 +1,16 @@ +Module example.com/retract/self/prerelease is a module that retracts its own +latest version and all other release version. + +A pre-release version higher than the highest release version is still +available, and that should be matched by @latest. + +-- .mod -- +module example.com/retract/self/prerelease + +go 1.15 + +-- .info -- +{"Version":"v1.9.1-pre"} + +-- p.go -- +package p diff --git a/src/cmd/go/testdata/mod/example.com_retract_self_prev_v1.0.0-bad.txt b/src/cmd/go/testdata/mod/example.com_retract_self_prev_v1.0.0-bad.txt new file mode 100644 index 0000000..095063d --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_self_prev_v1.0.0-bad.txt @@ -0,0 +1,14 @@ +See example.com_retract_self_prev_v1.9.0.txt. + +This version is retracted. + +-- .mod -- +module example.com/retract/self/prev + +go 1.15 + +-- .info -- +{"Version":"v1.0.0-bad"} + +-- p.go -- +package p diff --git a/src/cmd/go/testdata/mod/example.com_retract_self_prev_v1.1.0.txt b/src/cmd/go/testdata/mod/example.com_retract_self_prev_v1.1.0.txt new file mode 100644 index 0000000..27c3a39 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_self_prev_v1.1.0.txt @@ -0,0 +1,14 @@ +See example.com_retract_self_pref_v1.9.0.txt. + +This version is the latest (only) non-retracted version. + +-- .mod -- +module example.com/retract/self/prev + +go 1.15 + +-- .info -- +{"Version":"v1.1.0"} + +-- p.go -- +package p diff --git a/src/cmd/go/testdata/mod/example.com_retract_self_prev_v1.9.0.txt b/src/cmd/go/testdata/mod/example.com_retract_self_prev_v1.9.0.txt new file mode 100644 index 0000000..03d6168 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_self_prev_v1.9.0.txt @@ -0,0 +1,18 @@ +Module example.com/retract/self/prev is a module that retracts its own +latest version, as well as an earlier version. + +A previous unretracted release version, v1.1.0, is still available. + +-- .mod -- +module example.com/retract/self/prev + +go 1.15 + +retract v1.0.0-bad // bad +retract v1.9.0 // self + +-- .info -- +{"Version":"v1.9.0"} + +-- p.go -- +package p diff --git a/src/cmd/go/testdata/mod/example.com_retract_self_pseudo_v0.0.0-20200325131415-0123456789ab b/src/cmd/go/testdata/mod/example.com_retract_self_pseudo_v0.0.0-20200325131415-0123456789ab new file mode 100644 index 0000000..f9ab41e --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_self_pseudo_v0.0.0-20200325131415-0123456789ab @@ -0,0 +1,20 @@ +See example.com_retract_self_pseudo_v1.9.0.txt. + +This version is not retracted. It should be returned by the proxy's +@latest endpoint. It should match the @latest version query. + +TODO(golang.org/issue/24031): the proxy and proxy.golang.org both return +the highest release version from the @latest endpoint, even if that +version is retracted, so there is no way for the go command to +discover an unretracted pseudo-version. + +-- .mod -- +module example.com/retract/self/pseudo + +go 1.15 + +-- .info -- +{"Version":"v0.0.0-20200325131415-01234567890ab"} + +-- p.go -- +package p diff --git a/src/cmd/go/testdata/mod/example.com_retract_self_pseudo_v1.0.0-bad.txt b/src/cmd/go/testdata/mod/example.com_retract_self_pseudo_v1.0.0-bad.txt new file mode 100644 index 0000000..d47eda0 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_self_pseudo_v1.0.0-bad.txt @@ -0,0 +1,14 @@ +See example.com_retract_self_pseudo_v1.9.0.txt. + +This version is retracted. + +-- .mod -- +module example.com/retract/self/pseudo + +go 1.15 + +-- .info -- +{"Version":"v1.0.0-bad"} + +-- p.go -- +package p diff --git a/src/cmd/go/testdata/mod/example.com_retract_self_pseudo_v1.9.0.txt b/src/cmd/go/testdata/mod/example.com_retract_self_pseudo_v1.9.0.txt new file mode 100644 index 0000000..db09cc6 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_self_pseudo_v1.9.0.txt @@ -0,0 +1,16 @@ +Module example.com/retract/self/pseudo is a module that retracts its own +latest version, as well as an earlier version. + +An unretracted pseudo-version is available. + +-- .mod -- +module example.com/retract/self/pseudo + +go 1.15 + +retract v1.0.0-bad // bad +retract v1.9.0 // self + +-- .info -- +{"Version":"v1.9.0"} + diff --git a/src/cmd/go/testdata/mod/example.com_retract_v1.0.0-bad.txt b/src/cmd/go/testdata/mod/example.com_retract_v1.0.0-bad.txt new file mode 100644 index 0000000..2f996cf --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_v1.0.0-bad.txt @@ -0,0 +1,10 @@ +-- .mod -- +module example.com/retract + +go 1.15 + +-- .info -- +{"Version":"v1.0.0-bad"} + +-- retract.go -- +package retract diff --git a/src/cmd/go/testdata/mod/example.com_retract_v1.0.0-good.txt b/src/cmd/go/testdata/mod/example.com_retract_v1.0.0-good.txt new file mode 100644 index 0000000..78152bb --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_v1.0.0-good.txt @@ -0,0 +1,10 @@ +-- .mod -- +module example.com/retract + +go 1.15 + +-- .info -- +{"Version":"v1.0.0-good"} + +-- retract.go -- +package retract diff --git a/src/cmd/go/testdata/mod/example.com_retract_v1.0.0-unused.txt b/src/cmd/go/testdata/mod/example.com_retract_v1.0.0-unused.txt new file mode 100644 index 0000000..3bc9e35 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_v1.0.0-unused.txt @@ -0,0 +1,10 @@ +-- .mod -- +module example.com/retract + +go 1.15 + +-- .info -- +{"Version":"v1.0.0-unused"} + +-- retract.go -- +package retract diff --git a/src/cmd/go/testdata/mod/example.com_retract_v1.1.0.txt b/src/cmd/go/testdata/mod/example.com_retract_v1.1.0.txt new file mode 100644 index 0000000..18d6d83 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_retract_v1.1.0.txt @@ -0,0 +1,13 @@ +-- .mod -- +module example.com/retract + +go 1.15 + +retract v1.0.0-bad // bad +retract v1.0.0-unused // bad + +-- .info -- +{"Version":"v1.1.0"} + +-- retract.go -- +package retract diff --git a/src/cmd/go/testdata/mod/example.com_split-incompatible_subpkg_v0.1.0.txt b/src/cmd/go/testdata/mod/example.com_split-incompatible_subpkg_v0.1.0.txt new file mode 100644 index 0000000..8f9e491 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_split-incompatible_subpkg_v0.1.0.txt @@ -0,0 +1,14 @@ +Written by hand. +Test case for getting a package that has been moved to a nested module, +with a +incompatible verison (and thus no go.mod file) at the root module. + +-- .mod -- +module example.com/split-incompatible/subpkg +-- .info -- +{"Version": "v0.1.0"} +-- go.mod -- +module example.com/split-incompatible/subpkg + +go 1.16 +-- subpkg.go -- +package subpkg diff --git a/src/cmd/go/testdata/mod/example.com_split-incompatible_v2.0.0+incompatible.txt b/src/cmd/go/testdata/mod/example.com_split-incompatible_v2.0.0+incompatible.txt new file mode 100644 index 0000000..35c3f27 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_split-incompatible_v2.0.0+incompatible.txt @@ -0,0 +1,10 @@ +Written by hand. +Test case for getting a package that has been moved to a nested module, +with a +incompatible verison (and thus no go.mod file) at the root module. + +-- .mod -- +module example.com/split-incompatible +-- .info -- +{"Version": "v2.0.0+incompatible"} +-- subpkg/subpkg.go -- +package subpkg diff --git a/src/cmd/go/testdata/mod/example.com_split-incompatible_v2.1.0-pre+incompatible.txt b/src/cmd/go/testdata/mod/example.com_split-incompatible_v2.1.0-pre+incompatible.txt new file mode 100644 index 0000000..917fc0f --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_split-incompatible_v2.1.0-pre+incompatible.txt @@ -0,0 +1,10 @@ +Written by hand. +Test case for getting a package that has been moved to a nested module, +with a +incompatible verison (and thus no go.mod file) at the root module. + +-- .mod -- +module example.com/split-incompatible +-- .info -- +{"Version": "v2.1.0-pre+incompatible"} +-- README.txt -- +subpkg has moved to module example.com/split-incompatible/subpkg diff --git a/src/cmd/go/testdata/mod/example.com_split_subpkg_v1.1.0.txt b/src/cmd/go/testdata/mod/example.com_split_subpkg_v1.1.0.txt new file mode 100644 index 0000000..b197b66 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/example.com_split_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_split_v1.0.0.txt new file mode 100644 index 0000000..b706e59 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/example.com_split_v1.1.0.txt b/src/cmd/go/testdata/mod/example.com_split_v1.1.0.txt new file mode 100644 index 0000000..d38971f --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/example.com_stack_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_stack_v1.0.0.txt new file mode 100644 index 0000000..787b7ae --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_stack_v1.0.0.txt @@ -0,0 +1,18 @@ +Module with a function that prints file name for the top stack frame. +Different versions of this module are identical, but they should return +different file names with -trimpath. +-- .mod -- +module example.com/stack + +go 1.14 +-- .info -- +{"Version":"v1.0.0"} +-- stack.go -- +package stack + +import "runtime" + +func TopFile() string { + _, file, _, _ := runtime.Caller(0) + return file +} diff --git a/src/cmd/go/testdata/mod/example.com_stack_v1.0.1.txt b/src/cmd/go/testdata/mod/example.com_stack_v1.0.1.txt new file mode 100644 index 0000000..c715dd2 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_stack_v1.0.1.txt @@ -0,0 +1,18 @@ +Module with a function that prints file name for the top stack frame. +Different versions of this module are identical, but they should return +different file names with -trimpath. +-- .mod -- +module example.com/stack + +go 1.14 +-- .info -- +{"Version":"v1.0.1"} +-- stack.go -- +package stack + +import "runtime" + +func TopFile() string { + _, file, _, _ := runtime.Caller(0) + return file +} diff --git a/src/cmd/go/testdata/mod/example.com_tools_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_tools_v1.0.0.txt new file mode 100644 index 0000000..22e36b9 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_tools_v1.0.0.txt @@ -0,0 +1,12 @@ +-- .info -- +{"Version": "v1.0.0"} +-- .mod -- +module example.com/tools +-- cmd/hello/hello.go -- +package main + +import "fmt" + +func main() { + fmt.Println("hello") +} diff --git a/src/cmd/go/testdata/mod/example.com_usemissingpre_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_usemissingpre_v1.0.0.txt new file mode 100644 index 0000000..5e1c5c8 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_usemissingpre_v1.0.0.txt @@ -0,0 +1,13 @@ +This module requires example.com/missingpkg at a prerelease version, which +is newer than @latest. + +-- .mod -- +module example.com/usemissingpre + +require example.com/missingpkg v1.0.1-beta +-- .info -- +{"Version":"v1.0.0"} +-- use.go -- +package use + +import _ "example.com/missingpkg" diff --git a/src/cmd/go/testdata/mod/example.com_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_v1.0.0.txt new file mode 100644 index 0000000..263287d --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/example.com_version_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_version_v1.0.0.txt new file mode 100644 index 0000000..d8c45b5 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_version_v1.0.0.txt @@ -0,0 +1,11 @@ +example.com/version v1.0.0 +written by hand + +-- .mod -- +module example.com/version +-- .info -- +{"Version":"v1.0.0"} +-- version.go -- +package version + +const V = "v1.0.0" diff --git a/src/cmd/go/testdata/mod/example.com_version_v1.0.1.txt b/src/cmd/go/testdata/mod/example.com_version_v1.0.1.txt new file mode 100644 index 0000000..3bfdb0e --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_version_v1.0.1.txt @@ -0,0 +1,11 @@ +example.com/version v1.0.1 +written by hand + +-- .mod -- +module example.com/version +-- .info -- +{"Version":"v1.0.1"} +-- version.go -- +package version + +const V = "v1.0.1" diff --git a/src/cmd/go/testdata/mod/example.com_version_v1.1.0.txt b/src/cmd/go/testdata/mod/example.com_version_v1.1.0.txt new file mode 100644 index 0000000..8109a9a --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_version_v1.1.0.txt @@ -0,0 +1,11 @@ +example.com/version v1.1.0 +written by hand + +-- .mod -- +module example.com/version +-- .info -- +{"Version":"v1.1.0"} +-- version.go -- +package version + +const V = "v1.1.0" diff --git a/src/cmd/go/testdata/mod/example.net_ambiguous_nested_v0.1.0.txt b/src/cmd/go/testdata/mod/example.net_ambiguous_nested_v0.1.0.txt new file mode 100644 index 0000000..8c9de7a --- /dev/null +++ b/src/cmd/go/testdata/mod/example.net_ambiguous_nested_v0.1.0.txt @@ -0,0 +1,19 @@ +Written by hand. + +Test module containing a package that is also provided by a nested module tagged +with the same version. + +-- .mod -- +module example.net/ambiguous/nested + +go 1.16 +-- .info -- +{"Version": "v0.1.0"} +-- go.mod -- +module example.net/ambiguous/nested + +go 1.16 +-- pkg/pkg.go -- +// Package pkg exists in both example.net/ambiguous v0.1.0 +// and example.net/ambiguous/nested v0.1.0 +package pkg diff --git a/src/cmd/go/testdata/mod/example.net_ambiguous_v0.1.0.txt b/src/cmd/go/testdata/mod/example.net_ambiguous_v0.1.0.txt new file mode 100644 index 0000000..8fa6d83 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.net_ambiguous_v0.1.0.txt @@ -0,0 +1,19 @@ +Written by hand. + +Test module containing a package that is also provided by a nested module tagged +with the same version. + +-- .mod -- +module example.net/ambiguous + +go 1.16 +-- .info -- +{"Version": "v0.1.0"} +-- go.mod -- +module example.net/ambiguous + +go 1.16 +-- nested/pkg/pkg.go -- +// Package pkg exists in both example.net/ambiguous v0.1.0 +// and example.net/ambiguous/nested v0.1.0 +package pkg diff --git a/src/cmd/go/testdata/mod/example.net_ambiguous_v0.2.0.txt b/src/cmd/go/testdata/mod/example.net_ambiguous_v0.2.0.txt new file mode 100644 index 0000000..7589ad7 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.net_ambiguous_v0.2.0.txt @@ -0,0 +1,18 @@ +Written by hand. + +Test module containing a package that is also provided by a nested module tagged +with the same version. + +-- .mod -- +module example.net/ambiguous + +go 1.16 +-- .info -- +{"Version": "v0.2.0"} +-- go.mod -- +module example.net/ambiguous + +go 1.16 +-- nested/pkg/README.txt -- +// Package pkg no longer exists in this module at v0.2.0. +// Find it in module example.net/ambiguous/nested instead. diff --git a/src/cmd/go/testdata/mod/example.net_pkgadded_v1.0.0.txt b/src/cmd/go/testdata/mod/example.net_pkgadded_v1.0.0.txt new file mode 100644 index 0000000..207e86a --- /dev/null +++ b/src/cmd/go/testdata/mod/example.net_pkgadded_v1.0.0.txt @@ -0,0 +1,17 @@ +Written by hand. +Test module with a root package added in v1.1.0 +and a subpackage added in v1.2.0. + +-- .mod -- +module example.net/pkgadded + +go 1.16 +-- .info -- +{"Version":"v1.0.0"} +-- go.mod -- +module example.net/pkgadded + +go 1.16 +-- README.txt -- +We will add the package example.net/pkgadded in v1.1.0, +and example.net/pkgadded/subpkg in v1.2.0. diff --git a/src/cmd/go/testdata/mod/example.net_pkgadded_v1.1.0.txt b/src/cmd/go/testdata/mod/example.net_pkgadded_v1.1.0.txt new file mode 100644 index 0000000..1c88de2 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.net_pkgadded_v1.1.0.txt @@ -0,0 +1,19 @@ +Written by hand. +Test module with a root package added in v1.1.0 +and a subpackage added in v1.2.0. + +-- .mod -- +module example.net/pkgadded + +go 1.16 +-- .info -- +{"Version":"v1.1.0"} +-- go.mod -- +module example.net/pkgadded + +go 1.16 +-- README.txt -- +We will add the package example.net/pkgadded/subpkg in v1.2.0. +-- pkgadded.go -- +// Package pkgadded was added in v1.1.0. +package pkgadded diff --git a/src/cmd/go/testdata/mod/example.net_pkgadded_v1.2.0.txt b/src/cmd/go/testdata/mod/example.net_pkgadded_v1.2.0.txt new file mode 100644 index 0000000..922951a --- /dev/null +++ b/src/cmd/go/testdata/mod/example.net_pkgadded_v1.2.0.txt @@ -0,0 +1,20 @@ +Written by hand. +Test module with a root package added in v1.1.0 +and a subpackage added in v1.2.0. + +-- .mod -- +module example.net/pkgadded + +go 1.16 +-- .info -- +{"Version":"v1.2.0"} +-- go.mod -- +module example.net/pkgadded + +go 1.16 +-- pkgadded.go -- +// Package pkgadded was added in v1.1.0. +package pkgadded +-- subpkg/subpkg.go -- +// Package subpkg was added in v1.2.0. +package subpkg diff --git a/src/cmd/go/testdata/mod/github.com_dmitshur-test_modtest5_v0.0.0-20190619020302-197a620e0c9a.txt b/src/cmd/go/testdata/mod/github.com_dmitshur-test_modtest5_v0.0.0-20190619020302-197a620e0c9a.txt new file mode 100644 index 0000000..c2709c1 --- /dev/null +++ b/src/cmd/go/testdata/mod/github.com_dmitshur-test_modtest5_v0.0.0-20190619020302-197a620e0c9a.txt @@ -0,0 +1,10 @@ +module github.com/dmitshur-test/modtest5@v0.0.0-20190619020302-197a620e0c9a + +-- .mod -- +module github.com/dmitshur-test/modtest5 +-- .info -- +{"Version":"v0.0.0-20190619020302-197a620e0c9a","Time":"2019-06-18T19:03:02-07:00"} +-- p.go -- +package p + +const v = 1 diff --git a/src/cmd/go/testdata/mod/github.com_dmitshur-test_modtest5_v0.5.0-alpha.0.20190619023908-3da23a9deb9e.txt b/src/cmd/go/testdata/mod/github.com_dmitshur-test_modtest5_v0.5.0-alpha.0.20190619023908-3da23a9deb9e.txt new file mode 100644 index 0000000..22e47f3 --- /dev/null +++ b/src/cmd/go/testdata/mod/github.com_dmitshur-test_modtest5_v0.5.0-alpha.0.20190619023908-3da23a9deb9e.txt @@ -0,0 +1,10 @@ +module github.com/dmitshur-test/modtest5@v0.5.0-alpha.0.20190619023908-3da23a9deb9e + +-- .mod -- +module github.com/dmitshur-test/modtest5 +-- .info -- +{"Version":"v0.5.0-alpha.0.20190619023908-3da23a9deb9e","Time":"2019-06-18T19:39:08-07:00"} +-- p.go -- +package p + +const v = 3 diff --git a/src/cmd/go/testdata/mod/github.com_dmitshur-test_modtest5_v0.5.0-alpha.txt b/src/cmd/go/testdata/mod/github.com_dmitshur-test_modtest5_v0.5.0-alpha.txt new file mode 100644 index 0000000..4f088cc --- /dev/null +++ b/src/cmd/go/testdata/mod/github.com_dmitshur-test_modtest5_v0.5.0-alpha.txt @@ -0,0 +1,10 @@ +module github.com/dmitshur-test/modtest5@v0.5.0-alpha + +-- .mod -- +module github.com/dmitshur-test/modtest5 +-- .info -- +{"Version":"v0.5.0-alpha","Time":"2019-06-18T19:04:46-07:00"} +-- p.go -- +package p + +const v = 2 diff --git a/src/cmd/go/testdata/mod/golang.org_notx_useinternal_v0.1.0.txt b/src/cmd/go/testdata/mod/golang.org_notx_useinternal_v0.1.0.txt new file mode 100644 index 0000000..0420a1a --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/golang.org_x_internal_v0.1.0.txt b/src/cmd/go/testdata/mod/golang.org_x_internal_v0.1.0.txt new file mode 100644 index 0000000..5737e95 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/golang.org_x_text_v0.0.0-20170915032832-14c0d48ead0c.txt b/src/cmd/go/testdata/mod/golang.org_x_text_v0.0.0-20170915032832-14c0d48ead0c.txt new file mode 100644 index 0000000..f4f50cd --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/golang.org_x_text_v0.3.0.txt b/src/cmd/go/testdata/mod/golang.org_x_text_v0.3.0.txt new file mode 100644 index 0000000..5561afa --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/golang.org_x_useinternal_v0.1.0.txt b/src/cmd/go/testdata/mod/golang.org_x_useinternal_v0.1.0.txt new file mode 100644 index 0000000..3fcba44 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/gopkg.in_dummy.v2-unstable_v2.0.0.txt b/src/cmd/go/testdata/mod/gopkg.in_dummy.v2-unstable_v2.0.0.txt new file mode 100644 index 0000000..f174159 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/not-rsc.io_quote_v0.1.0-nomod.txt b/src/cmd/go/testdata/mod/not-rsc.io_quote_v0.1.0-nomod.txt new file mode 100644 index 0000000..efff088 --- /dev/null +++ b/src/cmd/go/testdata/mod/not-rsc.io_quote_v0.1.0-nomod.txt @@ -0,0 +1,59 @@ +Constructed by hand. +(derived from rsc.io/quote@e7a685a342, but without an explicit go.mod file.) + +-- .mod -- +module "not-rsc.io/quote" +-- .info -- +{"Version":"v0.1.0-nomod","Time":"2018-02-14T00:51:33Z"} +-- 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/src/cmd/go/testdata/mod/patch.example.com_depofdirectpatch_v1.0.0.txt b/src/cmd/go/testdata/mod/patch.example.com_depofdirectpatch_v1.0.0.txt new file mode 100644 index 0000000..40616c6 --- /dev/null +++ b/src/cmd/go/testdata/mod/patch.example.com_depofdirectpatch_v1.0.0.txt @@ -0,0 +1,11 @@ +patch.example.com/depofdirectpatch v1.0.0 +written by hand + +-- .mod -- +module patch.example.com/depofdirectpatch +-- .info -- +{"Version":"v1.0.0"} +-- go.mod -- +module patch.example.com/depofdirectpatch +-- depofdirectpatch.go -- +package depofdirectpatch diff --git a/src/cmd/go/testdata/mod/patch.example.com_depofdirectpatch_v1.0.1.txt b/src/cmd/go/testdata/mod/patch.example.com_depofdirectpatch_v1.0.1.txt new file mode 100644 index 0000000..e075028 --- /dev/null +++ b/src/cmd/go/testdata/mod/patch.example.com_depofdirectpatch_v1.0.1.txt @@ -0,0 +1,11 @@ +patch.example.com/depofdirectpatch v1.0.1 +written by hand + +-- .mod -- +module patch.example.com/depofdirectpatch +-- .info -- +{"Version":"v1.0.1"} +-- go.mod -- +module patch.example.com/depofdirectpatch +-- depofdirectpatch.go -- +package depofdirectpatch diff --git a/src/cmd/go/testdata/mod/patch.example.com_direct_v1.0.0.txt b/src/cmd/go/testdata/mod/patch.example.com_direct_v1.0.0.txt new file mode 100644 index 0000000..1e775fb --- /dev/null +++ b/src/cmd/go/testdata/mod/patch.example.com_direct_v1.0.0.txt @@ -0,0 +1,21 @@ +patch.example.com/direct v1.0.0 +written by hand + +-- .mod -- +module patch.example.com/direct + +require ( + patch.example.com/indirect v1.0.0 +) +-- .info -- +{"Version":"v1.0.0"} +-- go.mod -- +module patch.example.com/direct + +require ( + patch.example.com/indirect v1.0.0 +) +-- direct.go -- +package direct + +import _ "patch.example.com/indirect" diff --git a/src/cmd/go/testdata/mod/patch.example.com_direct_v1.0.1.txt b/src/cmd/go/testdata/mod/patch.example.com_direct_v1.0.1.txt new file mode 100644 index 0000000..64912b7 --- /dev/null +++ b/src/cmd/go/testdata/mod/patch.example.com_direct_v1.0.1.txt @@ -0,0 +1,27 @@ +patch.example.com/direct v1.0.1 +written by hand + +-- .mod -- +module patch.example.com/direct + +require ( + patch.example.com/indirect v1.0.0 + patch.example.com/depofdirectpatch v1.0.0 +) +-- .info -- +{"Version":"v1.0.1"} +-- go.mod -- +module patch.example.com/direct + +require ( + patch.example.com/indirect v1.0.0 + patch.example.com/depofdirectpatch v1.0.0 +) +-- direct.go -- +package direct + +import _ "patch.example.com/indirect" +-- usedepofdirectpatch/unused.go -- +package usedepofdirectpatch + +import _ "patch.example.com/depofdirectpatch" diff --git a/src/cmd/go/testdata/mod/patch.example.com_direct_v1.1.0.txt b/src/cmd/go/testdata/mod/patch.example.com_direct_v1.1.0.txt new file mode 100644 index 0000000..406e3b9 --- /dev/null +++ b/src/cmd/go/testdata/mod/patch.example.com_direct_v1.1.0.txt @@ -0,0 +1,21 @@ +patch.example.com/direct v1.1.0 +written by hand + +-- .mod -- +module patch.example.com/direct + +require ( + patch.example.com/indirect v1.0.0 +) +-- .info -- +{"Version":"v1.1.0"} +-- go.mod -- +module patch.example.com/direct + +require ( + patch.example.com/indirect v1.0.0 +) +-- direct.go -- +package direct + +import _ "patch.example.com/indirect" diff --git a/src/cmd/go/testdata/mod/patch.example.com_indirect_v1.0.0.txt b/src/cmd/go/testdata/mod/patch.example.com_indirect_v1.0.0.txt new file mode 100644 index 0000000..ea7f5e2 --- /dev/null +++ b/src/cmd/go/testdata/mod/patch.example.com_indirect_v1.0.0.txt @@ -0,0 +1,11 @@ +patch.example.com/indirect v1.0.0 +written by hand + +-- .mod -- +module patch.example.com/indirect +-- .info -- +{"Version":"v1.0.0"} +-- go.mod -- +module patch.example.com/indirect +-- direct.go -- +package indirect diff --git a/src/cmd/go/testdata/mod/patch.example.com_indirect_v1.0.1.txt b/src/cmd/go/testdata/mod/patch.example.com_indirect_v1.0.1.txt new file mode 100644 index 0000000..8c6cf8e --- /dev/null +++ b/src/cmd/go/testdata/mod/patch.example.com_indirect_v1.0.1.txt @@ -0,0 +1,11 @@ +patch.example.com/indirect v1.0.1 +written by hand + +-- .mod -- +module patch.example.com/indirect +-- .info -- +{"Version":"v1.0.1"} +-- go.mod -- +module patch.example.com/indirect +-- direct.go -- +package indirect diff --git a/src/cmd/go/testdata/mod/patch.example.com_indirect_v1.1.0.txt b/src/cmd/go/testdata/mod/patch.example.com_indirect_v1.1.0.txt new file mode 100644 index 0000000..f7229d4 --- /dev/null +++ b/src/cmd/go/testdata/mod/patch.example.com_indirect_v1.1.0.txt @@ -0,0 +1,11 @@ +patch.example.com/indirect v1.1.0 +written by hand + +-- .mod -- +module patch.example.com/indirect +-- .info -- +{"Version":"v1.1.0"} +-- go.mod -- +module patch.example.com/indirect +-- direct.go -- +package indirect diff --git a/src/cmd/go/testdata/mod/rsc.io_!c!g!o_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_!c!g!o_v1.0.0.txt new file mode 100644 index 0000000..6276147 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_!q!u!o!t!e_v1.5.2.txt b/src/cmd/go/testdata/mod/rsc.io_!q!u!o!t!e_v1.5.2.txt new file mode 100644 index 0000000..21185c3 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_!q!u!o!t!e_v1.5.3-!p!r!e.txt b/src/cmd/go/testdata/mod/rsc.io_!q!u!o!t!e_v1.5.3-!p!r!e.txt new file mode 100644 index 0000000..54bac2d --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_badfile1_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_badfile1_v1.0.0.txt new file mode 100644 index 0000000..9d23e7d --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_badfile2_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_badfile2_v1.0.0.txt new file mode 100644 index 0000000..58e1e1c --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_badfile3_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_badfile3_v1.0.0.txt new file mode 100644 index 0000000..a008448 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_badfile4_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_badfile4_v1.0.0.txt new file mode 100644 index 0000000..e28844d --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_badfile5_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_badfile5_v1.0.0.txt new file mode 100644 index 0000000..3c7903a --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_badmod_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_badmod_v1.0.0.txt new file mode 100644 index 0000000..993ceb7 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_badsum_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_badsum_v1.0.0.txt new file mode 100644 index 0000000..d62db26 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_badsum_v1.0.0.txt @@ -0,0 +1,14 @@ +rsc.io/badsum@v1.0.0 + +This module would match the hard-coded hash for rsc.io/badsum v1.0.0 +in modfetch/notary.go if not for the "break hash" line. + +-- .mod -- +module "rsc.io/badsum" +-- .info -- +{"Version":"v1.0.0","Time":"2018-02-14T00:45:20Z"} +-- go.mod -- +module "rsc.io/badsum" +-- badsum.go -- +package badsum +// break hash diff --git a/src/cmd/go/testdata/mod/rsc.io_badsum_v1.0.1.txt b/src/cmd/go/testdata/mod/rsc.io_badsum_v1.0.1.txt new file mode 100644 index 0000000..5fea50a --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_badsum_v1.0.1.txt @@ -0,0 +1,14 @@ +rsc.io/badsum@v1.0.1 + +This module would match the hard-coded hash for rsc.io/badsum v1.0.1/go.mod +in modfetch/notary.go if not for the "break hash" line. + +-- .mod -- +module "rsc.io/badsum" +# break hash +-- .info -- +{"Version":"v1.0.1","Time":"2018-02-14T00:45:20Z"} +-- go.mod -- +module "rsc.io/badsum" +-- badsum.go -- +package badsum diff --git a/src/cmd/go/testdata/mod/rsc.io_badzip_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_badzip_v1.0.0.txt new file mode 100644 index 0000000..07a38fa --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_badzip_v1.0.0.txt @@ -0,0 +1,11 @@ +rsc.io/badzip v1.0.0 +written by hand + +-- .mod -- +module rsc.io/badzip +-- .info -- +{"Version":"v1.0.0"} +-- x.go -- +package x +-- /rsc.io/badzip@v1.0.0.txt -- +This file should not be here. diff --git a/src/cmd/go/testdata/mod/rsc.io_breaker_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_breaker_v1.0.0.txt new file mode 100644 index 0000000..a103e3f --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_breaker_v2.0.0+incompatible.txt b/src/cmd/go/testdata/mod/rsc.io_breaker_v2.0.0+incompatible.txt new file mode 100644 index 0000000..59d8bac --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_breaker_v2.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_breaker_v2.0.0.txt new file mode 100644 index 0000000..59d8bac --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_fortune_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_fortune_v1.0.0.txt new file mode 100644 index 0000000..d8a71f3 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_fortune_v2_v2.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_fortune_v2_v2.0.0.txt new file mode 100644 index 0000000..3acd637 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_fortune_v2_v2.0.0.txt @@ -0,0 +1,21 @@ +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()) +} +-- fortune_test.go -- +package main + +import "testing" + +func TestFortuneV2(t *testing.T) {} diff --git a/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180214005133-e7a685a342c0.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180214005133-e7a685a342c0.txt new file mode 100644 index 0000000..8ae173e --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180214005840-23179ee8a569.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180214005840-23179ee8a569.txt new file mode 100644 index 0000000..bc626ba --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180628003336-dd9747d19b04.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180628003336-dd9747d19b04.txt new file mode 100644 index 0000000..bbc8097 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709153244-fd906ed3b100.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709153244-fd906ed3b100.txt new file mode 100644 index 0000000..e461ed4 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709160352-0d003b9c4bfa.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709160352-0d003b9c4bfa.txt new file mode 100644 index 0000000..c1d511f --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162749-b44a0b17b2d1.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162749-b44a0b17b2d1.txt new file mode 100644 index 0000000..f7f794d --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162816-fe488b867524.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162816-fe488b867524.txt new file mode 100644 index 0000000..2d5d8b4 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162918-a91498bed0a7.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162918-a91498bed0a7.txt new file mode 100644 index 0000000..853a8c2 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180710144737-5d9f230bcfba.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180710144737-5d9f230bcfba.txt new file mode 100644 index 0000000..2ebeac3 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_quote_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v1.0.0.txt new file mode 100644 index 0000000..9a07937 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_quote_v1.1.0.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v1.1.0.txt new file mode 100644 index 0000000..0c41605 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_quote_v1.2.0.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v1.2.0.txt new file mode 100644 index 0000000..e714f0b --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_quote_v1.2.1.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v1.2.1.txt new file mode 100644 index 0000000..89d5191 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_quote_v1.3.0.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v1.3.0.txt new file mode 100644 index 0000000..d62766c --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_quote_v1.4.0.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v1.4.0.txt new file mode 100644 index 0000000..698ff8d --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_quote_v1.5.0.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v1.5.0.txt new file mode 100644 index 0000000..e7fcdbc --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_quote_v1.5.1.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v1.5.1.txt new file mode 100644 index 0000000..eed051b --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_quote_v1.5.2.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v1.5.2.txt new file mode 100644 index 0000000..8671f6f --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_quote_v1.5.3-pre1.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v1.5.3-pre1.txt new file mode 100644 index 0000000..212ef13 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_quote_v2.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v2.0.0.txt new file mode 100644 index 0000000..e461ed4 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_quote_v2_v2.0.1.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v2_v2.0.1.txt new file mode 100644 index 0000000..d51128c --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_quote_v3_v3.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v3_v3.0.0.txt new file mode 100644 index 0000000..0afe1f0 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_sampler_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_sampler_v1.0.0.txt new file mode 100644 index 0000000..c4b6a71 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_sampler_v1.2.0.txt b/src/cmd/go/testdata/mod/rsc.io_sampler_v1.2.0.txt new file mode 100644 index 0000000..98c35fa --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_sampler_v1.2.1.txt b/src/cmd/go/testdata/mod/rsc.io_sampler_v1.2.1.txt new file mode 100644 index 0000000..7982ccc --- /dev/null +++ b/src/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"} +-- 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/src/cmd/go/testdata/mod/rsc.io_sampler_v1.3.0.txt b/src/cmd/go/testdata/mod/rsc.io_sampler_v1.3.0.txt new file mode 100644 index 0000000..febe51f --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_sampler_v1.3.1.txt b/src/cmd/go/testdata/mod/rsc.io_sampler_v1.3.1.txt new file mode 100644 index 0000000..a293f10 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_sampler_v1.99.99.txt b/src/cmd/go/testdata/mod/rsc.io_sampler_v1.99.99.txt new file mode 100644 index 0000000..5036d20 --- /dev/null +++ b/src/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/src/cmd/go/testdata/mod/rsc.io_testonly_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_testonly_v1.0.0.txt new file mode 100644 index 0000000..dfb8ca2 --- /dev/null +++ b/src/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/src/cmd/go/testdata/modlegacy/src/new/go.mod b/src/cmd/go/testdata/modlegacy/src/new/go.mod new file mode 100644 index 0000000..d0dd46d --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/new/go.mod @@ -0,0 +1 @@ +module "new/v2" diff --git a/src/cmd/go/testdata/modlegacy/src/new/new.go b/src/cmd/go/testdata/modlegacy/src/new/new.go new file mode 100644 index 0000000..e99c47a --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/new/new.go @@ -0,0 +1,3 @@ +package new + +import _ "new/v2/p2" diff --git a/src/cmd/go/testdata/modlegacy/src/new/p1/p1.go b/src/cmd/go/testdata/modlegacy/src/new/p1/p1.go new file mode 100644 index 0000000..4539f40 --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/new/p1/p1.go @@ -0,0 +1,7 @@ +package p1 + +import _ "old/p2" +import _ "new/v2" +import _ "new/v2/p2" +import _ "new/sub/v2/x/v1/y" // v2 is module, v1 is directory in module +import _ "new/sub/inner/x" // new/sub/inner/go.mod overrides new/sub/go.mod diff --git a/src/cmd/go/testdata/modlegacy/src/new/p2/p2.go b/src/cmd/go/testdata/modlegacy/src/new/p2/p2.go new file mode 100644 index 0000000..9b9052f --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/new/p2/p2.go @@ -0,0 +1 @@ +package p2 diff --git a/src/cmd/go/testdata/modlegacy/src/new/sub/go.mod b/src/cmd/go/testdata/modlegacy/src/new/sub/go.mod new file mode 100644 index 0000000..484d20c --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/new/sub/go.mod @@ -0,0 +1 @@ +module new/sub/v2 diff --git a/src/cmd/go/testdata/modlegacy/src/new/sub/inner/go.mod b/src/cmd/go/testdata/modlegacy/src/new/sub/inner/go.mod new file mode 100644 index 0000000..ba39345 --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/new/sub/inner/go.mod @@ -0,0 +1 @@ +module new/sub/inner diff --git a/src/cmd/go/testdata/modlegacy/src/new/sub/inner/x/x.go b/src/cmd/go/testdata/modlegacy/src/new/sub/inner/x/x.go new file mode 100644 index 0000000..823aafd --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/new/sub/inner/x/x.go @@ -0,0 +1 @@ +package x diff --git a/src/cmd/go/testdata/modlegacy/src/new/sub/x/v1/y/y.go b/src/cmd/go/testdata/modlegacy/src/new/sub/x/v1/y/y.go new file mode 100644 index 0000000..789ca71 --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/new/sub/x/v1/y/y.go @@ -0,0 +1 @@ +package y diff --git a/src/cmd/go/testdata/modlegacy/src/old/p1/p1.go b/src/cmd/go/testdata/modlegacy/src/old/p1/p1.go new file mode 100644 index 0000000..9052748 --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/old/p1/p1.go @@ -0,0 +1,5 @@ +package p1 + +import _ "old/p2" +import _ "new/p1" +import _ "new" diff --git a/src/cmd/go/testdata/modlegacy/src/old/p2/p2.go b/src/cmd/go/testdata/modlegacy/src/old/p2/p2.go new file mode 100644 index 0000000..9b9052f --- /dev/null +++ b/src/cmd/go/testdata/modlegacy/src/old/p2/p2.go @@ -0,0 +1 @@ +package p2 diff --git a/src/cmd/go/testdata/savedir.go b/src/cmd/go/testdata/savedir.go new file mode 100644 index 0000000..d469c31 --- /dev/null +++ b/src/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/fs" + "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.WalkDir(dir, func(path string, info fs.DirEntry, 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.Type().IsRegular() { + return nil + } + data, err := os.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/src/cmd/go/testdata/script/README b/src/cmd/go/testdata/script/README new file mode 100644 index 0000000..d658ceb --- /dev/null +++ b/src/cmd/go/testdata/script/README @@ -0,0 +1,310 @@ +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= + GOCACHE= + GOEXE= + GOEXPSTRING= + GOOS= + GOPATH=$WORK/gopath + GOPROXY= + GOROOT= + GOROOT_FINAL= + TESTGO_GOROOT= + HOME=/no-home + PATH= + TMPDIR=$WORK/tmp + GODEBUG= + devnull= + goversion= + := + +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 ? indicates that the command on the rest of the line +may or may not succeed, but the test should continue regardless. +Commands that support this prefix are indicated by [?]. + +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() + - [root] for os.Geteuid() == 0 + - [symlink] for testenv.HasSymlink() + - [case-sensitive] for whether the file system is case-sensitive + - [exec:prog] for whether prog is available for execution (found by exec.LookPath) + - [GODEBUG:value] for whether value is one of the comma-separated entries in the GODEBUG variable + - [buildmode:value] for whether -buildmode=value is supported + +A condition can be negated: [!short] means to run the rest of the line +when testing.Short() is false. Multiple conditions may be given for a single +command, for example, '[linux] [amd64] skip'. The command will run if all conditions +are satisfied. + +The commands are: + +- [! | ?] cc args... [&] + Run the C compiler, the platform specific flags (i.e. `go env GOGCCFLAGS`) will be + added automatically before args. + +- cd dir + Change to the given directory for future commands. + +- chmod perm path... + Change the permissions of the files or directories named by the path arguments + to be equal to perm. Only numerical permissions are supported. + +- 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.) + +- cmpenv file1 file2 + Like cmp, but environment variables are substituted in the file contents + before the comparison. For example, $GOOS is replaced by the target GOOS. + +- [! | ?] cp src... dst + Copy the listed files to the target file or existing directory. + src can include "stdout" or "stderr" to use the standard output or standard error + from the most recent exec or go command. + +- env [-r] [key=value...] + With no arguments, print the environment to stdout + (useful for debugging and for verifying initial state). + Otherwise add the listed key=value pairs to the environment. + The -r flag causes the values to be escaped using regexp.QuoteMeta + before being recorded. + +- [! | ?] 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). + + If the last token is '&', the program executes in the background. The standard + output and standard error of the previous command is cleared, but the output + of the background process is buffered — and checking of its exit status is + delayed — until the next call to 'wait', 'skip', or 'stop' or the end of the + test. If any background processes remain at the end of the test, they + are terminated using os.Interrupt (if supported) or os.Kill and the test + must not depend upon their exit status. + +- [!] exists [-readonly] [-exec] file... + Each of the listed files or directories must (or must not) exist. + If -readonly is given, the files or directories must be unwritable. + If -exec is given, the files or directories must be executable. + +- [! | ?] go args... [&] + Run the (test copy of the) go command with the given arguments. + It must (or must not) succeed. + +- [!] grep [-count=N] [-q] 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. + The -q flag disables printing the file content on a mismatch. + +- 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, go, or wait command. + +- [!] stdout [-count=N] pattern + Apply the grep command (see above) to the standard output + from the most recent exec, go, wait, or env 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. + +- wait + Wait for all 'exec' and 'go' commands started in the background (with the '&' + token) to exit, and display success or failure status for them. + After a call to wait, the 'stderr' and 'stdout' commands will apply to the + concatenation of the corresponding streams of the background commands, + in the order in which those commands were started. + +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/src/cmd/go/testdata/script/bug.txt b/src/cmd/go/testdata/script/bug.txt new file mode 100644 index 0000000..b9bbaaa --- /dev/null +++ b/src/cmd/go/testdata/script/bug.txt @@ -0,0 +1,46 @@ +# Verify that go bug creates the appropriate URL issue body + +[!linux] skip + +go install +env BROWSER=$GOPATH/bin/browser +go bug +exists $TMPDIR/browser +grep '^go version' $TMPDIR/browser +grep '^GOROOT/bin/go version: go version' $TMPDIR/browser +grep '^GOROOT/bin/go tool compile -V: compile version' $TMPDIR/browser +grep '^uname -sr: Linux' $TMPDIR/browser + +-- go.mod -- +module browser + +-- main.go -- +package main + +import ( + "fmt" + "net/url" + "os" + "path/filepath" +) + +func main() { + u, err := url.Parse(os.Args[1]) + if err != nil { + panic(err) + } + body, err := url.PathUnescape(u.Query().Get("body")) + if err != nil { + panic(err) + } + out := filepath.Join(os.TempDir(), "browser") + f, err := os.Create(out) + if err != nil { + panic(err) + } + fmt.Fprintln(f, body) + if err := f.Close(); err != nil { + panic(err) + } +} + diff --git a/src/cmd/go/testdata/script/build_GOTMPDIR.txt b/src/cmd/go/testdata/script/build_GOTMPDIR.txt new file mode 100644 index 0000000..1073517 --- /dev/null +++ b/src/cmd/go/testdata/script/build_GOTMPDIR.txt @@ -0,0 +1,50 @@ +# Set GOCACHE to a clean directory to ensure that 'go build' has work to report. +[!windows] env GOCACHE=$WORK/gocache +[windows] env GOCACHE=$WORK\gocache + +# 'go build' should use GOTMPDIR if set. +[!windows] env GOTMPDIR=$WORK/my-favorite-tmpdir +[windows] env GOTMPDIR=$WORK\my-favorite-tmpdir +mkdir $GOTMPDIR +go build -x hello.go +stderr ^WORK=.*my-favorite-tmpdir + +# Make GOTMPDIR a regular file. This prevents the creation of work directories, +# so we can check that certain commands don't create them. +# This simulates running on a full disk or a read-only volume. +rm $GOTMPDIR +cp hello.go $GOTMPDIR # any file will do + +# 'go build' should fail if GOTMPDIR is read-only. +! go build -x . +stderr '^go: creating work dir: \w+ '$GOTMPDIR + +# 'go list' should only fail if it needs to build something. +go list -x . +! stderr 'creating work dir' +stdout m +go list -m all +stdout m +! go list -x -export . +stderr '^go: creating work dir: \w+ '$GOTMPDIR + +# 'go clean -cache' and 'go clean -modcache' should not fail. +go clean -x -cache +! stderr 'creating work dir' +go clean -x -modcache +! stderr 'creating work dir' + +# 'go env' should not fail for specific variables. +# Without arguments, it needs to initialize a builder to load cgo flags, and +# that uses a temporary directory. +! go env +stderr '^go: creating work dir: \w+ '$GOTMPDIR +go env GOROOT + +-- go.mod -- +module m + +go 1.15 +-- hello.go -- +package main +func main() { println("hello") } diff --git a/src/cmd/go/testdata/script/build_acl_windows.txt b/src/cmd/go/testdata/script/build_acl_windows.txt new file mode 100644 index 0000000..13a3ba2 --- /dev/null +++ b/src/cmd/go/testdata/script/build_acl_windows.txt @@ -0,0 +1,44 @@ +[!windows] stop +[!exec:icacls] skip +[!exec:powershell] skip + +# Create $WORK\guest and give the Guests group full access. +# Files created within that directory will have different security attributes by default. +mkdir $WORK\guest +exec icacls $WORK\guest /grant '*S-1-5-32-546:(oi)(ci)f' + +env TMP=$WORK\guest +env TEMP=$WORK\guest + +# Build a binary using the guest directory as an intermediate +cd TestACL +go build -o main.exe main.go +# Build the same binary, but write it to the guest directory. +go build -o $TMP\main.exe main.go + +# Read ACLs for the files. +exec powershell -Command 'Get-Acl main.exe | Select -expand AccessToString' +cp stdout $WORK\exe-acl.txt +exec powershell -Command 'Get-Acl main.go | Select -expand AccessToString' +cp stdout $WORK\src-acl.txt +cd $TMP +exec powershell -Command 'Get-Acl main.exe | Select -expand AccessToString' +cp stdout $WORK\guest-acl.txt + +cd $WORK + +# The executable written to the source directory should have the same ACL as the source file. +cmp $WORK\exe-acl.txt $WORK\src-acl.txt + +# The file written to the guest-allowed directory should give Guests control. +grep 'BUILTIN\\Guests\s+Allow' $WORK\guest-acl.txt + +# The file written to the ordinary directory should not. +! grep 'BUILTIN\\Guests\s+Allow' $WORK\exe-acl.txt + + +-- TestACL/go.mod -- +module TestACL +-- TestACL/main.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/build_arm.txt b/src/cmd/go/testdata/script/build_arm.txt new file mode 100644 index 0000000..ff2a364 --- /dev/null +++ b/src/cmd/go/testdata/script/build_arm.txt @@ -0,0 +1,13 @@ +[short] skip 'skipping cross-compile in short mode' + +env GOARCH=arm +env GOOS=linux +env GOARM=5 + +go build hello.go +! stderr 'unable to find math.a' + +-- hello.go -- +package main + +func main() {} \ No newline at end of file diff --git a/src/cmd/go/testdata/script/build_cache_arch_mode.txt b/src/cmd/go/testdata/script/build_cache_arch_mode.txt new file mode 100644 index 0000000..931827f --- /dev/null +++ b/src/cmd/go/testdata/script/build_cache_arch_mode.txt @@ -0,0 +1,21 @@ +# Issue 9737: verify that GOARM affects the computed build ID + +[short] skip + +# arm +env GOOS=linux +env GOARCH=arm +env GOARM=5 +go install mycmd +env GOARM=7 +stale mycmd + + +-- go.mod -- +module mycmd + +go 1.16 +-- x.go -- +package main + +func main() {} diff --git a/src/cmd/go/testdata/script/build_cache_compile.txt b/src/cmd/go/testdata/script/build_cache_compile.txt new file mode 100644 index 0000000..64b391f --- /dev/null +++ b/src/cmd/go/testdata/script/build_cache_compile.txt @@ -0,0 +1,21 @@ +env GO111MODULE=off +[short] skip + +# 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/src/cmd/go/testdata/script/build_cache_disabled.txt b/src/cmd/go/testdata/script/build_cache_disabled.txt new file mode 100644 index 0000000..8b005c8 --- /dev/null +++ b/src/cmd/go/testdata/script/build_cache_disabled.txt @@ -0,0 +1,50 @@ +# The build cache is required to build anything. It also may be needed to +# initialize the build system, which is needed for commands like 'go env'. +# However, there are lots of commands the cache is not needed for, and we +# shouldn't require it when it won't be used. +# +# TODO(golang.org/issue/39882): commands below should work, too. +# * go clean -modcache +# * go env +# * go fix +# * go fmt +# * go generate +# * go get -d +# * go list (without -export or -compiled) + +env GOCACHE=off + +# Commands that don't completely load packages should work. +go doc fmt +stdout Printf + +! go tool compile -h +stderr usage: + +go version +stdout '^go version' + + +# Module commands that don't load packages should work. +go mod init m +exists go.mod + +go mod edit -require rsc.io/quote@v1.5.2 + +go mod download rsc.io/quote + +go mod graph +stdout rsc.io/quote + +go mod verify + + +# Commands that load but don't build packages should work. +go fmt . + +go doc . + +-- main.go -- +package main + +func main() {} diff --git a/src/cmd/go/testdata/script/build_cache_gomips.txt b/src/cmd/go/testdata/script/build_cache_gomips.txt new file mode 100644 index 0000000..0cbf16a --- /dev/null +++ b/src/cmd/go/testdata/script/build_cache_gomips.txt @@ -0,0 +1,40 @@ +env GO111MODULE=off +[short] skip # rebuilds std for mips + +# Set up fresh GOCACHE. +env GOCACHE=$WORK/gocache +mkdir $GOCACHE + +# Building for mipsle without setting GOMIPS will use floating point registers. +env GOARCH=mipsle +env GOOS=linux +go build -gcflags=-S f.go +stderr ADDD.F[0-9]+,.F[0-9]+,.F[0-9]+ + +# Clean cache +go clean -cache + +# Building with GOMIPS=softfloat will not use floating point registers +env GOMIPS=softfloat +go build -gcflags=-S f.go +! stderr ADDD.F[0-9]+,.F[0-9]+,.F[0-9]+ + +# Clean cache +go clean -cache + +# Build without setting GOMIPS +env GOMIPS= +go build -gcflags=-S f.go +stderr ADDD.F[0-9]+,.F[0-9]+,.F[0-9]+ + +# Building with GOMIPS should still not use floating point registers. +env GOMIPS=softfloat +go build -gcflags=-S f.go +! stderr ADDD.F[0-9]+,.F[0-9]+,.F[0-9]+ + +-- f.go -- +package f + +func F(x float64) float64 { + return x + x +} diff --git a/src/cmd/go/testdata/script/build_cache_link.txt b/src/cmd/go/testdata/script/build_cache_link.txt new file mode 100644 index 0000000..b9c740a --- /dev/null +++ b/src/cmd/go/testdata/script/build_cache_link.txt @@ -0,0 +1,26 @@ +env GO111MODULE=off +[short] skip + +# 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$GOEXE -x main.go +stderr '(link|gccgo)( |\.exe)' +go build -o main$GOEXE -x main.go +! stderr '(link|gccgo)( |\.exe)' + +-- main.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/build_cache_output.txt b/src/cmd/go/testdata/script/build_cache_output.txt new file mode 100644 index 0000000..0d94bf6 --- /dev/null +++ b/src/cmd/go/testdata/script/build_cache_output.txt @@ -0,0 +1,67 @@ +env GO111MODULE=off +env GODEBUG=gocachetest=1 + +[!gc] skip +[short] skip # clears cache, rebuilds too much + +# 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 +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 +! 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/p_test.go -- +package p +import "testing" +func Test(t *testing.T) {println("TEST")} diff --git a/src/cmd/go/testdata/script/build_cache_trimpath.txt b/src/cmd/go/testdata/script/build_cache_trimpath.txt new file mode 100644 index 0000000..9a4b9d7 --- /dev/null +++ b/src/cmd/go/testdata/script/build_cache_trimpath.txt @@ -0,0 +1,47 @@ +[short] skip +env GO111MODULE=on + +# Set up fresh GOCACHE. +env GOCACHE=$WORK/gocache +mkdir $GOCACHE + +cd $WORK +go build -o a.out + +# Varying -trimpath should cause a rebuild. +go build -x -o a.out -trimpath +stderr '(compile|gccgo)( |\.exe)' +stderr 'link( |\.exe)' + +# Two distinct versions of the same module with identical content should +# still be cached separately. +# Verifies golang.org/issue/35412. +go get -d example.com/stack@v1.0.0 +go run -trimpath printstack.go +stdout '^example.com/stack@v1.0.0/stack.go$' +go get -d example.com/stack@v1.0.1 +go run -trimpath printstack.go +stdout '^example.com/stack@v1.0.1/stack.go$' + +-- $WORK/hello.go -- +package main +func main() { println("hello") } + +-- $WORK/printstack.go -- +// +build ignore + +package main + +import ( + "fmt" + + "example.com/stack" +) + +func main() { + fmt.Println(stack.TopFile()) +} +-- $WORK/go.mod -- +module m + +go 1.14 diff --git a/src/cmd/go/testdata/script/build_cd_gopath_different.txt b/src/cmd/go/testdata/script/build_cd_gopath_different.txt new file mode 100644 index 0000000..a7a4bf4 --- /dev/null +++ b/src/cmd/go/testdata/script/build_cd_gopath_different.txt @@ -0,0 +1,73 @@ +[gccgo] skip 'gccgo does not support -ldflags -X' +env GO111MODULE=off +go build run_go.go + +# Apply identity function to GOPATH +exec ./run_go$GOEXE $GOPATH/src/my.pkg/main $GOPATH IDENTITY build -o $WORK/tmp/a.exe -ldflags -X=my.pkg.Text=linkXworked +exec $WORK/tmp/a.exe +stderr 'linkXworked' +rm $WORK/tmp/a.exe + +[!windows] stop 'rest of the tests only apply to Windows' + +# Replace '\' with '/' in GOPATH +exec ./run_go$GOEXE $GOPATH/src/my.pkg/main $GOPATH REPLACE_SLASH build -o $WORK/tmp/a.exe -ldflags -X=my.pkg.Text=linkXworked +exec $WORK/tmp/a.exe +stderr 'linkXworked' +rm $WORK/tmp/a.exe + +# Apply identity function to GOPATH +exec ./run_go$GOEXE $GOPATH/src/my.pkg/main $GOPATH UPPER build -o $WORK/tmp/a.exe -ldflags -X=my.pkg.Text=linkXworked +exec $WORK/tmp/a.exe +stderr 'linkXworked' +rm $WORK/tmp/a.exe + +# Apply identity function to GOPATH +exec ./run_go$GOEXE $GOPATH/src/my.pkg/main $GOPATH LOWER build -o $WORK/tmp/a.exe -ldflags -X=my.pkg.Text=linkXworked +exec $WORK/tmp/a.exe +stderr 'linkXworked' +rm $WORK/tmp/a.exe + +-- run_go.go -- +package main + +import ( + "fmt" + "os" + "os/exec" + "strings" +) + +func main() { + dir := os.Args[1] + gopath := os.Args[2] + switch os.Args[3] { + case "IDENTITY": + case "REPLACE_SLASH": gopath = strings.ReplaceAll(gopath, `\`, `/`) + case "UPPER": gopath = strings.ToUpper(gopath) + case "LOWER": gopath = strings.ToLower(gopath) + default: fmt.Fprintln(os.Stderr, "bad op"); os.Exit(1) + } + cmd := exec.Command("go", os.Args[4:]...) + cmd.Dir = dir + cmd.Env = append(os.Environ(), "GOPATH="+gopath) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +-- my.pkg/main/main.go -- +package main + +import "my.pkg" + +func main() { + println(pkg.Text) +} +-- my.pkg/pkg.go -- +package pkg + +var Text = "unset" diff --git a/src/cmd/go/testdata/script/build_cgo_consistent_results.txt b/src/cmd/go/testdata/script/build_cgo_consistent_results.txt new file mode 100644 index 0000000..88a24de --- /dev/null +++ b/src/cmd/go/testdata/script/build_cgo_consistent_results.txt @@ -0,0 +1,23 @@ +[short] skip +[!cgo] skip + +[solaris] skip "skipping on Solaris; see golang.org/issue/13247" +[illumos] skip "skipping on Solaris; see golang.org/issue/13247" + +go build -o $WORK/exe1$GOEXE cgotest +go build -x -o $WORK/exe2$GOEXE cgotest + +# TODO(matloob): skip if stderr does not contain '-fdebug-prefix-map=\$WORK' + +cmp $WORK/exe1$GOEXE $WORK/exe2$GOEXE + +-- go.mod -- +module cgotest + +go 1.16 +-- m.go -- +package cgotest + +import "C" + +var _ C.int diff --git a/src/cmd/go/testdata/script/build_darwin_cc_arch.txt b/src/cmd/go/testdata/script/build_darwin_cc_arch.txt new file mode 100644 index 0000000..2b81b4c --- /dev/null +++ b/src/cmd/go/testdata/script/build_darwin_cc_arch.txt @@ -0,0 +1,24 @@ +# Test that we pass -arch flag to C compiler on Darwin (issue 43692). + +[!darwin] skip +[!cgo] skip + +# clear CC, in case user sets it +env CC= + +env CGO_ENABLED=1 + +env GOARCH=amd64 +go build -n -x c.go +stderr 'clang.*-arch x86_64' + +env GOARCH=arm64 +go build -n -x c.go +stderr 'clang.*-arch arm64' + +-- c.go -- +package main + +import "C" + +func main() {} diff --git a/src/cmd/go/testdata/script/build_dash_n_cgo.txt b/src/cmd/go/testdata/script/build_dash_n_cgo.txt new file mode 100644 index 0000000..3f49ef6 --- /dev/null +++ b/src/cmd/go/testdata/script/build_dash_n_cgo.txt @@ -0,0 +1,18 @@ +# Tests golang.org/issue/14944 + +[!cgo] skip + +go build -n foo.go +! stderr 'os.Stat .* no such file or directory' # there shouldn't be a stat of the archive file + +-- foo.go -- +package main + +/* +#include +*/ +import "C" + +func main() { + println(C.INT_MAX) +} \ No newline at end of file diff --git a/src/cmd/go/testdata/script/build_dash_o_dev_null.txt b/src/cmd/go/testdata/script/build_dash_o_dev_null.txt new file mode 100644 index 0000000..e415fc2 --- /dev/null +++ b/src/cmd/go/testdata/script/build_dash_o_dev_null.txt @@ -0,0 +1,13 @@ +# Issue #25579 + +[short] skip + +go build -o $devnull hello.go +! exists 'hello'$GOEXE + +-- hello.go -- +package main + +func main() { + println("hello, world") +} diff --git a/src/cmd/go/testdata/script/build_dash_x.txt b/src/cmd/go/testdata/script/build_dash_x.txt new file mode 100644 index 0000000..6fd5bbe --- /dev/null +++ b/src/cmd/go/testdata/script/build_dash_x.txt @@ -0,0 +1,49 @@ +[short] skip +[!cgo] skip + +[!exec:/usr/bin/env] skip +[!exec:bash] skip +[!exec:cat] skip + +mkdir $WORK/tmp/cache +env GOCACHE=$WORK/tmp/cache + +# Before building our test main.go, ensure that an up-to-date copy of +# runtime/cgo is present in the cache. If it isn't, the 'go build' step below +# will fail with "can't open import". See golang.org/issue/29004. +# +# (The fix in golang.org/issue/29004 didn't completely fix the underlying issue: +# cmd/go/internal/load adds a bunch of implicit dependencies +# based on various heuristics, and, due to a bug described in +# https://golang.org/issue/31544#issuecomment-490607180, +# those implicit dependencies are not added early enough during +# loading to properly affect the import graph.) +go build runtime/cgo + +go build -x -o main main.go +cp stderr commands.txt +exec cat header.txt commands.txt +cp stdout test.sh + +exec ./main +cmp stderr hello.txt +rm ./main + +exec /usr/bin/env bash -x test.sh +exec ./main +cmp stderr hello.txt + +grep '^WORK=(.*)\n' commands.txt + +-- main.go -- +package main + +import "C" + +func main() { + print("hello\n") +} +-- header.txt -- +set -e +-- hello.txt -- +hello diff --git a/src/cmd/go/testdata/script/build_exe.txt b/src/cmd/go/testdata/script/build_exe.txt new file mode 100644 index 0000000..a994d17 --- /dev/null +++ b/src/cmd/go/testdata/script/build_exe.txt @@ -0,0 +1,25 @@ +# go build with -o and -buildmode=exe should report an error on a non-main package. + +! go build -buildmode=exe -o out$GOEXE ./not_main +stderr '-buildmode=exe requires exactly one main package' +! exists out$GOEXE +! go build -buildmode=exe -o out$GOEXE ./main_one ./main_two +stderr '-buildmode=exe requires exactly one main package' +! exists out$GOEXE + +-- go.mod -- +module m + +go 1.16 +-- not_main/not_main.go -- +package not_main + +func F() {} +-- main_one/main_one.go -- +package main + +func main() {} +-- main_two/main_two.go -- +package main + +func main() {} diff --git a/src/cmd/go/testdata/script/build_gcflags.txt b/src/cmd/go/testdata/script/build_gcflags.txt new file mode 100644 index 0000000..b472374 --- /dev/null +++ b/src/cmd/go/testdata/script/build_gcflags.txt @@ -0,0 +1,22 @@ +env GO111MODULE=off + +# Test that the user can override default code generation flags. + +[gccgo] skip # gccgo does not use -gcflags +[!cgo] skip +[!linux] skip # test only works if c-archive implies -shared +[short] skip + +env GOCACHE=$WORK/gocache # Looking for compile commands, so need a clean cache. +go build -x -n -buildmode=c-archive -gcflags=all=-shared=false ./override.go +stderr '^.*/compile (.* )?-shared (.* )?-shared=false' + +-- override.go -- +package main + +import "C" + +//export GoFunc +func GoFunc() {} + +func main() {} diff --git a/src/cmd/go/testdata/script/build_gopath_order.txt b/src/cmd/go/testdata/script/build_gopath_order.txt new file mode 100644 index 0000000..caf2502 --- /dev/null +++ b/src/cmd/go/testdata/script/build_gopath_order.txt @@ -0,0 +1,36 @@ +# golang.org/issue/14176#issuecomment-179895769 +# golang.org/issue/14192 +# -I arguments to compiler could end up not in GOPATH order, +# leading to unexpected import resolution in the compiler. + +env GO111MODULE=off +env GOPATH=$WORK/p1${:}$WORK/p2 +mkdir $WORK/p1/src/foo $WORK/p2/src/baz +mkdir $WORK/p2/pkg/${GOOS}_${GOARCH} $WORK/p1/src/bar +cp foo.go $WORK/p1/src/foo/foo.go +cp baz.go $WORK/p2/src/baz/baz.go +cp foo.a $WORK/p2/pkg/${GOOS}_${GOARCH}/foo.a +cp bar.go $WORK/p1/src/bar/bar.go + +go install -x bar + +# add in baz.a to the mix +mkdir $WORK/p1/pkg/${GOOS}_${GOARCH} +cp baz.a $WORK/p1/pkg/${GOOS}_${GOARCH}/baz.a +env GOPATH=$WORK/p1${:}$WORK/p2 +go install -x bar +env GOPATH=$WORK/p2${:}$WORK/p1 +go install -x bar + +-- foo.go -- +package foo +-- baz.go -- +package baz +-- foo.a -- +bad +-- baz.a -- +bad +-- bar.go -- +package bar +import _ "baz" +import _ "foo" diff --git a/src/cmd/go/testdata/script/build_i.txt b/src/cmd/go/testdata/script/build_i.txt new file mode 100644 index 0000000..0e7ebed --- /dev/null +++ b/src/cmd/go/testdata/script/build_i.txt @@ -0,0 +1,41 @@ +env GO111MODULE=off + +# Test that 'go build -i' installs dependencies of the requested package. + +[short] skip + +# Since we are checking installation of dependencies, use a clean cache +# to ensure that multiple runs of the test do not interfere. +env GOCACHE=$WORK/cache + +# The initial 'go build -i' for bar should install its dependency foo. + +go build -v -i x/y/bar +stderr 'x/y/foo' # should be rebuilt +go build -v -i x/y/bar +! stderr 'x/y/foo' # should already be installed + +# After modifying the source files, both packages should be rebuild. + +cp x/y/foo/foo.go.next x/y/foo/foo.go +cp x/y/bar/bar.go.next x/y/bar/bar.go + +go build -v -i x/y/bar +stderr 'x/y/foo' # should be rebuilt +go build -v -i x/y/bar +! stderr 'x/y/foo' # should already be installed + +-- x/y/foo/foo.go -- +package foo +func F() {} +-- x/y/bar/bar.go -- +package bar +import "x/y/foo" +func F() { foo.F() } +-- x/y/foo/foo.go.next -- +package foo +func F() { F() } +-- x/y/bar/bar.go.next -- +package main +import "x/y/foo" +func main() { foo.F() } diff --git a/src/cmd/go/testdata/script/build_i_deprecate.txt b/src/cmd/go/testdata/script/build_i_deprecate.txt new file mode 100644 index 0000000..71356e5 --- /dev/null +++ b/src/cmd/go/testdata/script/build_i_deprecate.txt @@ -0,0 +1,24 @@ +# Check that deprecation warnings are printed when the -i flag is used. +# TODO(golang.org/issue/41696): remove the -i flag after Go 1.16, and this test. + +go build -n -i +stderr '^go build: -i flag is deprecated$' + +go install -n -i +stderr '^go install: -i flag is deprecated$' + +go test -n -i +stderr '^go test: -i flag is deprecated$' + + +# 'go clean -i' should not print a deprecation warning. +# It will continue working. +go clean -i . +! stderr . + +-- go.mod -- +module m + +go 1.16 +-- m.go -- +package m diff --git a/src/cmd/go/testdata/script/build_import_comment.txt b/src/cmd/go/testdata/script/build_import_comment.txt new file mode 100644 index 0000000..b500340 --- /dev/null +++ b/src/cmd/go/testdata/script/build_import_comment.txt @@ -0,0 +1,68 @@ +# Test in GOPATH mode first. +env GO111MODULE=off +cd m + +# Import comment matches +go build -n works.go + +# Import comment mismatch +! go build -n wrongplace.go +stderr 'wrongplace expects import "my/x"' + +# Import comment syntax error +! go build -n bad.go +stderr 'cannot parse import comment' + +# Import comment conflict +! go build -n conflict.go +stderr 'found import comments' + + +# Test in module mode. +# We ignore import comments, so these commands should succeed. +env GO111MODULE=on + +# Import comment matches +go build -n works.go + +# Import comment mismatch +go build -n wrongplace.go + +# Import comment syntax error +go build -n bad.go + +# Import comment conflict +go build -n conflict.go + +-- m/go.mod -- +module m + +go 1.16 +-- m/bad.go -- +package p + +import "m/bad" +-- m/conflict.go -- +package p + +import "m/conflict" +-- m/works.go -- +package p + +import _ "m/works/x" +-- m/wrongplace.go -- +package p + +import "m/wrongplace" +-- m/bad/bad.go -- +package bad // import +-- m/conflict/a.go -- +package conflict // import "a" +-- m/conflict/b.go -- +package conflict /* import "b" */ +-- m/works/x/x.go -- +package x // import "m/works/x" +-- m/works/x/x1.go -- +package x // important! not an import comment +-- m/wrongplace/x.go -- +package x // import "my/x" diff --git a/src/cmd/go/testdata/script/build_import_cycle.txt b/src/cmd/go/testdata/script/build_import_cycle.txt new file mode 100644 index 0000000..16e4e87 --- /dev/null +++ b/src/cmd/go/testdata/script/build_import_cycle.txt @@ -0,0 +1,13 @@ +# mod_import_cycle covers this error in module mode. +env GO111MODULE=off + +! go build selfimport +stderr -count=1 'import cycle not allowed' + +go list -e -f '{{.Error}}' selfimport # Don't hang forever +stdout -count=1 'import cycle not allowed' + +-- selfimport/selfimport.go -- +package selfimport + +import "selfimport" diff --git a/src/cmd/go/testdata/script/build_internal.txt b/src/cmd/go/testdata/script/build_internal.txt new file mode 100644 index 0000000..25aa18c --- /dev/null +++ b/src/cmd/go/testdata/script/build_internal.txt @@ -0,0 +1,63 @@ +# Test internal package errors are handled +cd testinternal3 +go list . +stdout 'testinternal3' + +# Test internal cache +cd ../testinternal4 +! go build testinternal4/p +stderr 'internal' + +# Test internal packages outside GOROOT are respected +cd ../testinternal2 +! go build -v . +stderr 'p\.go:3:8: use of internal package .*internal/w not allowed' + +[gccgo] skip # gccgo does not have GOROOT +cd ../testinternal +! go build -v . +stderr 'p\.go:3:8: use of internal package net/http/internal not allowed' + +-- testinternal/go.mod -- +module testinternal + +go 1.16 +-- testinternal/p.go -- +package p + +import _ "net/http/internal" +-- testinternal2/go.mod -- +module testinternal2 + +go 1.16 +-- testinternal2/p.go -- +package p + +import _ "./x/y/z/internal/w" +-- testinternal2/x/y/z/internal/w/w.go -- +package w +-- testinternal3/go.mod -- +module testinternal3 + +go 1.16 +-- testinternal3/t.go -- +package t + +import _ "internal/does-not-exist" +-- testinternal4/go.mod -- +module testinternal4 + +go 1.16 +-- testinternal4/p/p.go -- +package p + +import ( + _ "testinternal4/q/internal/x" + _ "testinternal4/q/j" +) +-- testinternal4/q/internal/x/x.go -- +package x +-- testinternal4/q/j/j.go -- +package j + +import _ "testinternal4/q/internal/x" diff --git a/src/cmd/go/testdata/script/build_issue6480.txt b/src/cmd/go/testdata/script/build_issue6480.txt new file mode 100644 index 0000000..cf1e9ea --- /dev/null +++ b/src/cmd/go/testdata/script/build_issue6480.txt @@ -0,0 +1,128 @@ +# "go test -c -test.bench=XXX errors" should not hang. +# "go test -c" should also produce reproducible binaries. +# "go test -c" should also appear to write a new binary every time, +# even if it's really just updating the mtime on an existing up-to-date binary. + +[gccgo] skip +[short] skip + +# Install some commands to compare mtimes +env GOBIN=$WORK/tmp/bin +go install m/now m/mtime m/before + +# Initial builds +go test -c -test.bench=XXX errors +go test -c -o errors2.test errors +cmp errors.test$GOEXE errors2.test # // errors2.test has no exeSuffix because -o above doesn't have it + +# Check errors.test mtime is updated +exec $GOBIN/now +cp stdout start_time.txt +go test -x -c -test.bench=XXX errors +! stderr '[\\/]link|gccgo' # make sure up-to-date test binary is not relinked +exec $GOBIN/mtime errors.test$GOEXE +cp stdout errors1_mod_time.txt +exec $GOBIN/before start_time.txt errors1_mod_time.txt +rm start_time.txt errors1_mod_time.txt + +# Check errors2.test mtime is updated +exec $GOBIN/now +cp stdout start_time.txt +go test -x -c -o errors2.test errors +! stderr '[\\/]link|gccgo' # make sure up-to-date test binary is not relinked +exec $GOBIN/mtime errors2.test +cp stdout errors2_mod_time.txt +exec $GOBIN/before start_time.txt errors2_mod_time.txt + +-- go.mod -- +module m + +go 1.16 +-- now/now.go -- +// Writes time.Now() to a file +package main + +import ( + "encoding/json" + "fmt" + "os" + "time" +) + +func main() { + if err := json.NewEncoder(os.Stdout).Encode(time.Now()); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} +-- mtime/mtime.go -- +package main + +import ( + "encoding/json" + "fmt" + "os" +) + +func main() { + info, err := os.Stat(os.Args[1]) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + if err := json.NewEncoder(os.Stdout).Encode(info.ModTime()); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} +-- before/before.go -- +package main + +import ( + "encoding/json" + "fmt" + "os" + "time" +) + +func truncateLike(t, p time.Time) time.Time { + nano := p.UnixNano() + d := 1 * time.Nanosecond + for nano%int64(d) == 0 && d < 1*time.Second { + d *= 10 + } + for nano%int64(d) == 0 && d < 2*time.Second { + d *= 2 + } + return t.Truncate(d) +} + +func main() { + var t1 time.Time + b1, err := os.ReadFile(os.Args[1]) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + if err := json.Unmarshal(b1, &t1); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + var t2 time.Time + b2, err := os.ReadFile(os.Args[2]) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + if err := json.Unmarshal(b2, &t2); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + t1 = truncateLike(t1, t2) + if !t1.Before(t2) { + fmt.Fprintf(os.Stderr, "time in %v (%v) is not before time in %v (%v)", os.Args[1], t1, os.Args[2], t2) + os.Exit(1) + } +} diff --git a/src/cmd/go/testdata/script/build_link_x_import_path_escape.txt b/src/cmd/go/testdata/script/build_link_x_import_path_escape.txt new file mode 100644 index 0000000..f1de1e4 --- /dev/null +++ b/src/cmd/go/testdata/script/build_link_x_import_path_escape.txt @@ -0,0 +1,22 @@ +[gccgo] skip 'gccgo does not support -ldflags -X' + +go build -o linkx$GOEXE -ldflags -X=my.pkg.Text=linkXworked my.pkg/main +exec ./linkx$GOEXE +stderr '^linkXworked$' + +-- go.mod -- +module my.pkg + +go 1.16 +-- main/main.go -- +package main + +import "my.pkg" + +func main() { + println(pkg.Text) +} +-- pkg.go -- +package pkg + +var Text = "unset" diff --git a/src/cmd/go/testdata/script/build_multi_main.txt b/src/cmd/go/testdata/script/build_multi_main.txt new file mode 100644 index 0000000..8afd8b8 --- /dev/null +++ b/src/cmd/go/testdata/script/build_multi_main.txt @@ -0,0 +1,43 @@ +# Verify build -o can output multiple executables to a directory. + +mkdir $WORK/bin +go build -o $WORK/bin ./cmd/c1 ./cmd/c2 +! stderr 'multiple packages' + +! go build -o $WORK/bin ./pkg1 ./pkg1 +stderr 'no main packages' + +! go build ./cmd/c1 +stderr 'already exists and is a directory' + +# Verify build -o output correctly local packages +mkdir $WORK/local +go build -o $WORK/local ./exec.go +exists $WORK/local/exec$GOEXE + +-- go.mod -- +module exmod + +-- cmd/c1/main.go -- +package main + +func main() {} + +-- cmd/c2/main.go -- +package main + +func main() {} + +-- pkg1/pkg1.go -- +package pkg1 + +-- pkg2/pkg2.go -- +package pkg2 + +-- exec.go -- +package main + +func main() {} + +-- c1$GOEXE/keep.txt -- +Create c1 directory. diff --git a/src/cmd/go/testdata/script/build_n_cgo.txt b/src/cmd/go/testdata/script/build_n_cgo.txt new file mode 100644 index 0000000..7aa77ae --- /dev/null +++ b/src/cmd/go/testdata/script/build_n_cgo.txt @@ -0,0 +1,17 @@ +[!cgo] skip + +# Test that nothing is prepended to $WORK path prefix. +# See issue golang.org/issue/37012. +go build -n +! stderr '[/\\]\$WORK' + +-- go.mod -- +module m + +go 1.16 +-- main.go -- +package main + +import "C" + +var _ C.int diff --git a/src/cmd/go/testdata/script/build_no_go.txt b/src/cmd/go/testdata/script/build_no_go.txt new file mode 100644 index 0000000..b61d752 --- /dev/null +++ b/src/cmd/go/testdata/script/build_no_go.txt @@ -0,0 +1,41 @@ +! go build ./empty/test +stderr 'no non-test Go files in ' + +! go build ./empty/xtest +stderr 'no non-test Go files in ' + +! go build ./empty/testxtest +stderr 'no non-test Go files in ' + +! go build ./exclude +stderr 'build constraints exclude all Go files in ' + +! go build ./exclude/ignore +stderr 'no Go files in ' + +! go build ./exclude/empty +stderr 'no Go files in ' + +-- go.mod -- +module m + +go 1.16 +-- empty/test/test_test.go -- +package p +-- empty/testxtest/test_test.go -- +package p +-- empty/testxtest/xtest_test.go -- +package p_test +-- empty/xtest/xtest_test.go -- +package p_test +-- exclude/empty/x.txt -- +-- exclude/ignore/_x.go -- +package x +-- exclude/x.go -- +// +build linux,!linux + +package x +-- exclude/x_linux.go -- +// +build windows + +package x diff --git a/src/cmd/go/testdata/script/build_nocache.txt b/src/cmd/go/testdata/script/build_nocache.txt new file mode 100644 index 0000000..1059cad --- /dev/null +++ b/src/cmd/go/testdata/script/build_nocache.txt @@ -0,0 +1,40 @@ +env GO111MODULE=off + +# As of Go 1.12, the module cache is required. + +# If none of the variables we use to locate GOCACHE are set, the cache is off +# and we cannot build. +env GOCACHE= +env XDG_CACHE_HOME= +env HOME= +[plan9] env home= +[windows] env LocalAppData= +! go build -o triv triv.go +stderr 'build cache is required, but could not be located: GOCACHE is not defined and .*' + +# If GOCACHE is set but is not an absolute path, and we cannot build. +env GOCACHE=test +! go build -o triv triv.go +stderr 'build cache is required, but could not be located: GOCACHE is not an absolute path' + +# An explicit GOCACHE=off also disables builds. +env GOCACHE=off +! go build -o triv triv.go +stderr 'build cache is disabled by GOCACHE=off' + +# If GOCACHE is set to an unwritable directory, we should diagnose it as such. +[windows] stop # Does not support unwritable directories. +[root] skip # Can write to unwritable directories. + +mkdir $WORK/unwritable/home +chmod 0555 $WORK/unwritable/home +[!plan9] env HOME=$WORK/unwritable/home +[plan9] env home=$WORK/unwritable/home + +env GOCACHE=$WORK/unwritable/home +! go build -o triv triv.go +stderr 'failed to initialize build cache.* permission denied' + +-- triv.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/build_output.txt b/src/cmd/go/testdata/script/build_output.txt new file mode 100644 index 0000000..1e82950 --- /dev/null +++ b/src/cmd/go/testdata/script/build_output.txt @@ -0,0 +1,117 @@ +[gccgo] skip 'gccgo has no standard packages' +[short] skip + +[!windows] env NONEXE='.exe' +[windows] env NONEXE='' + +env GOBIN=$WORK/tmp/bin +go install m/isarchive & + +go build x.go +exists -exec x$GOEXE +rm x$GOEXE +! exists x$NONEXE + +go build -o myprog x.go +! exists x +! exists x.exe +exists -exec myprog +! exists myprogr.exe + +! exists bin +go build -o bin/x x.go +exists -exec bin/x +rm bin + +! exists bin +go build -o bin/ x.go +exists -exec bin/x$GOEXE +rm bin + +[windows] ! exists bin +[windows] go build -o bin\x x.go +[windows] exists -exec bin\x +[windows] rm bin + +[windows] ! exists bin +[windows] go build -o bin\ x.go +[windows] exists -exec bin\x.exe +[windows] rm bin + +! exists bin +mkdir bin +go build -o bin x.go +exists -exec bin/x$GOEXE +rm bin + +go build p.go +! exists p +! exists p.a +! exists p.o +! exists p.exe + +wait # for isarchive + +go build -o p.a p.go +exists p.a +exec $GOBIN/isarchive p.a + +go build cmd/gofmt +exists -exec gofmt$GOEXE +rm gofmt$GOEXE +! exists gofmt$NONEXE + +go build -o mygofmt cmd/gofmt +exists -exec mygofmt +! exists mygofmt.exe +! exists gofmt +! exists gofmt.exe + +go build sync/atomic +! exists atomic +! exists atomic.exe + +go build -o myatomic.a sync/atomic +exists myatomic.a +exec $GOBIN/isarchive myatomic.a +! exists atomic +! exists atomic.a +! exists atomic.exe + +! go build -o whatever cmd/gofmt sync/atomic +stderr 'multiple packages' + +-- go.mod -- +module m + +go 1.16 +-- x.go -- +package main + +func main() {} +-- p.go -- +package p +-- isarchive/isarchive.go -- +package main + +import ( + "bytes" + "fmt" + "io" + "os" +) + +func main() { + f, err := os.Open(os.Args[1]) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + buf := make([]byte, 100) + io.ReadFull(f, buf) + f.Close() + if !bytes.HasPrefix(buf, []byte("!\n")) { + fmt.Fprintf(os.Stderr, "file %s exists but is not an archive\n", os.Args[1]) + os.Exit(1) + } +} diff --git a/src/cmd/go/testdata/script/build_overlay.txt b/src/cmd/go/testdata/script/build_overlay.txt new file mode 100644 index 0000000..b11cd96 --- /dev/null +++ b/src/cmd/go/testdata/script/build_overlay.txt @@ -0,0 +1,308 @@ +[short] skip + +# Test building in overlays. +# TODO(#39958): add a test case where the destination file in the replace map +# isn't a go file. Either completely exclude that case in fs.IsDirWithGoFiles +# if the compiler doesn't allow it, or test that it works all the way. +# TODO(#39958): add a test that both gc and gccgo assembly files can include .h +# files. + +# The main package (m) is contained in an overlay. It imports m/dir2 which has one +# file in an overlay and one file outside the overlay, which in turn imports m/dir, +# which only has source files in the overlay. + +cd m + +! go build . +go build -overlay overlay.json -o main$GOEXE . +exec ./main$goexe +stdout '^hello$' + +go build -overlay overlay.json -o print_abspath$GOEXE ./printpath +exec ./print_abspath$GOEXE +stdout $WORK[/\\]gopath[/\\]src[/\\]m[/\\]printpath[/\\]main.go + +go build -overlay overlay.json -o print_trimpath$GOEXE -trimpath ./printpath +exec ./print_trimpath$GOEXE +stdout ^m[/\\]printpath[/\\]main.go + +go build -overlay overlay.json -o print_trimpath_two_files$GOEXE printpath/main.go printpath/other.go +exec ./print_trimpath_two_files$GOEXE +stdout $WORK[/\\]gopath[/\\]src[/\\]m[/\\]printpath[/\\]main.go +stdout $WORK[/\\]gopath[/\\]src[/\\]m[/\\]printpath[/\\]other.go + +go build -overlay overlay.json -o main_cgo_replace$GOEXE ./cgo_hello_replace +exec ./main_cgo_replace$GOEXE +stdout '^hello cgo\r?\n' + +go build -overlay overlay.json -o main_cgo_quote$GOEXE ./cgo_hello_quote +exec ./main_cgo_quote$GOEXE +stdout '^hello cgo\r?\n' + +go build -overlay overlay.json -o main_cgo_angle$GOEXE ./cgo_hello_angle +exec ./main_cgo_angle$GOEXE +stdout '^hello cgo\r?\n' + +go build -overlay overlay.json -o main_call_asm$GOEXE ./call_asm +exec ./main_call_asm$GOEXE +! stdout . + +# Change the contents of a file in the overlay and ensure that makes the target stale +go install -overlay overlay.json ./test_cache +go list -overlay overlay.json -f '{{.Stale}}' ./test_cache +stdout '^false$' +cp overlay/test_cache_different.go overlay/test_cache.go +go list -overlay overlay.json -f '{{.Stale}}' ./test_cache +stdout '^true$' + +go list -compiled -overlay overlay.json -f '{{range .CompiledGoFiles}}{{. | printf "%s\n"}}{{end}}' ./cgo_hello_replace +cp stdout compiled_cgo_sources.txt +go run ../print_line_comments.go compiled_cgo_sources.txt +stdout $GOPATH[/\\]src[/\\]m[/\\]cgo_hello_replace[/\\]cgo_hello_replace.go +! stdout $GOPATH[/\\]src[/\\]m[/\\]overlay[/\\]hello.c + +# Run same tests but with gccgo. +env GO111MODULE=off +[!exec:gccgo] stop + +! go build -compiler=gccgo . +go build -compiler=gccgo -overlay overlay.json -o main_gccgo$GOEXE . +exec ./main_gccgo$goexe +stdout '^hello$' + +go build -compiler=gccgo -overlay overlay.json -o print_abspath_gccgo$GOEXE ./printpath +exec ./print_abspath_gccgo$GOEXE +stdout $WORK[/\\]gopath[/\\]src[/\\]m[/\\]printpath[/\\]main.go + +go build -compiler=gccgo -overlay overlay.json -o print_trimpath_gccgo$GOEXE -trimpath ./printpath +exec ./print_trimpath_gccgo$GOEXE +stdout ^\.[/\\]printpath[/\\]main.go + + +go build -compiler=gccgo -overlay overlay.json -o main_cgo_replace_gccgo$GOEXE ./cgo_hello_replace +exec ./main_cgo_replace_gccgo$GOEXE +stdout '^hello cgo\r?\n' + +go build -compiler=gccgo -overlay overlay.json -o main_cgo_quote_gccgo$GOEXE ./cgo_hello_quote +exec ./main_cgo_quote_gccgo$GOEXE +stdout '^hello cgo\r?\n' + +go build -compiler=gccgo -overlay overlay.json -o main_cgo_angle_gccgo$GOEXE ./cgo_hello_angle +exec ./main_cgo_angle_gccgo$GOEXE +stdout '^hello cgo\r?\n' + +go build -compiler=gccgo -overlay overlay.json -o main_call_asm_gccgo$GOEXE ./call_asm +exec ./main_call_asm_gccgo$GOEXE +! stdout . + + +-- m/go.mod -- +// TODO(matloob): how do overlays work with go.mod (especially if mod=readonly) +module m + +go 1.16 + +-- m/dir2/h.go -- +package dir2 + +func PrintMessage() { + printMessage() +} +-- m/dir/foo.txt -- +The build action code currently expects the package directory +to exist, so it can run the compiler in that directory. +TODO(matloob): Remove this requirement. +-- m/printpath/about.txt -- +the actual code is in the overlay +-- m/overlay.json -- +{ + "Replace": { + "f.go": "overlay/f.go", + "dir/g.go": "overlay/dir_g.go", + "dir2/i.go": "overlay/dir2_i.go", + "printpath/main.go": "overlay/printpath.go", + "printpath/other.go": "overlay2/printpath2.go", + "call_asm/asm_gc.s": "overlay/asm_gc.s", + "call_asm/asm_gccgo.s": "overlay/asm_gccgo.s", + "test_cache/main.go": "overlay/test_cache.go", + "cgo_hello_replace/cgo_header.h": "overlay/cgo_head.h", + "cgo_hello_replace/hello.c": "overlay/hello.c", + "cgo_hello_quote/cgo_hello.go": "overlay/cgo_hello_quote.go", + "cgo_hello_quote/cgo_header.h": "overlay/cgo_head.h", + "cgo_hello_angle/cgo_hello.go": "overlay/cgo_hello_angle.go", + "cgo_hello_angle/cgo_header.h": "overlay/cgo_head.h" + } +} +-- m/cgo_hello_replace/cgo_hello_replace.go -- +package main + +// #include "cgo_header.h" +import "C" + +func main() { + C.say_hello() +} +-- m/cgo_hello_replace/cgo_header.h -- + // Test that this header is replaced with one that has the proper declaration. +void say_goodbye(); + +-- m/cgo_hello_replace/hello.c -- +#include + +void say_goodbye() { puts("goodbye cgo\n"); fflush(stdout); } + +-- m/overlay/f.go -- +package main + +import "m/dir2" + +func main() { + dir2.PrintMessage() +} +-- m/call_asm/main.go -- +package main + +func foo() // There will be a "missing function body" error if the assembly file isn't found. + +func main() { + foo() +} +-- m/overlay/dir_g.go -- +package dir + +import "fmt" + +func PrintMessage() { + fmt.Println("hello") +} +-- m/overlay/printpath.go -- +package main + +import ( + "fmt" + "path/filepath" + "runtime" +) + +func main() { + _, file, _, _ := runtime.Caller(0) + + // Since https://golang.org/cl/214286, the runtime's debug paths are + // slash-separated regardless of platform, so normalize them to system file + // paths. + fmt.Println(filepath.FromSlash(file)) +} +-- m/overlay2/printpath2.go -- +package main + +import ( + "fmt" + "path/filepath" + "runtime" +) + +func init() { + _, file, _, _ := runtime.Caller(0) + fmt.Println(filepath.FromSlash(file)) +} +-- m/overlay/dir2_i.go -- +package dir2 + +import "m/dir" + +func printMessage() { + dir.PrintMessage() +} +-- m/overlay/cgo_hello_quote.go -- +package main + +// #include "cgo_header.h" +import "C" + +func main() { + C.say_hello() +} +-- m/overlay/cgo_hello_angle.go -- +package main + +// #include +import "C" + +func main() { + C.say_hello() +} +-- m/overlay/cgo_head.h -- +void say_hello(); +-- m/overlay/hello.c -- +#include + +void say_hello() { puts("hello cgo\n"); fflush(stdout); } +-- m/overlay/asm_gc.s -- +// +build !gccgo + +TEXT ·foo(SB),0,$0 + RET + +-- m/overlay/asm_gccgo.s -- +// +build gccgo + +.globl main.foo +.text +main.foo: + ret + +-- m/overlay/test_cache.go -- +package foo + +import "fmt" + +func bar() { + fmt.Println("something") +} +-- m/overlay/test_cache_different.go -- +package foo + +import "fmt" + +func bar() { + fmt.Println("different") +} +-- m/cgo_hello_quote/hello.c -- +#include + +void say_hello() { puts("hello cgo\n"); fflush(stdout); } +-- m/cgo_hello_angle/hello.c -- +#include + +void say_hello() { puts("hello cgo\n"); fflush(stdout); } + +-- print_line_comments.go -- +package main + +import ( + "fmt" + "io/ioutil" + "log" + "os" + "strings" +) + +func main() { + compiledGoFilesArg := os.Args[1] + b, err := ioutil.ReadFile(compiledGoFilesArg) + if err != nil { + log.Fatal(err) + } + compiledGoFiles := strings.Split(strings.TrimSpace(string(b)), "\n") + for _, f := range compiledGoFiles { + b, err := ioutil.ReadFile(f) + if err != nil { + log.Fatal(err) + } + for _, line := range strings.Split(string(b), "\n") { + if strings.HasPrefix(line, "#line") || strings.HasPrefix(line, "//line") { + fmt.Println(line) + } + } + } +} diff --git a/src/cmd/go/testdata/script/build_package_not_stale_trailing_slash.txt b/src/cmd/go/testdata/script/build_package_not_stale_trailing_slash.txt new file mode 100644 index 0000000..38a151e --- /dev/null +++ b/src/cmd/go/testdata/script/build_package_not_stale_trailing_slash.txt @@ -0,0 +1,13 @@ +# Tests Issue #12690 + +[gccgo] skip 'gccgo does not have GOROOT' + +! stale runtime +! stale os +! stale io + +env GOROOT=$GOROOT'/' + +! stale runtime +! stale os +! stale io \ No newline at end of file diff --git a/src/cmd/go/testdata/script/build_patterns_outside_gopath.txt b/src/cmd/go/testdata/script/build_patterns_outside_gopath.txt new file mode 100644 index 0000000..6a600cf --- /dev/null +++ b/src/cmd/go/testdata/script/build_patterns_outside_gopath.txt @@ -0,0 +1,36 @@ +# Tests issue #18778 +[short] skip + +cd pkgs + +env GO111MODULE=off +go build ./... +! stdout . +go test ./... +stdout '^ok' +go list ./... +stdout 'pkgs$' +stdout 'pkgs/a' + +-- pkgs/go.mod -- +module pkgs + +go 1.16 +-- pkgs/a.go -- +package x +-- pkgs/a_test.go -- +package x_test + +import "testing" + +func TestX(t *testing.T) { +} +-- pkgs/a/a.go -- +package a +-- pkgs/a/a_test.go -- +package a_test + +import "testing" + +func TestA(t *testing.T) { +} diff --git a/src/cmd/go/testdata/script/build_plugin_non_main.txt b/src/cmd/go/testdata/script/build_plugin_non_main.txt new file mode 100644 index 0000000..e0bbbef --- /dev/null +++ b/src/cmd/go/testdata/script/build_plugin_non_main.txt @@ -0,0 +1,13 @@ +# Plugins are not supported on all platforms. +[!buildmode:plugin] skip + +go build -n testdep +! go build -buildmode=plugin testdep +stderr '-buildmode=plugin requires exactly one main package' + +-- go.mod -- +module testdep + +go 1.16 +-- testdep.go -- +package p diff --git a/src/cmd/go/testdata/script/build_relative_pkgdir.txt b/src/cmd/go/testdata/script/build_relative_pkgdir.txt new file mode 100644 index 0000000..0716bcd --- /dev/null +++ b/src/cmd/go/testdata/script/build_relative_pkgdir.txt @@ -0,0 +1,9 @@ +env GO111MODULE=off + +# Regression test for golang.org/issue/21309: accept relative -pkgdir argument. + +[short] skip + +mkdir $WORK/gocache +env GOCACHE=$WORK/gocache +go build -i -pkgdir=. runtime diff --git a/src/cmd/go/testdata/script/build_relative_tmpdir.txt b/src/cmd/go/testdata/script/build_relative_tmpdir.txt new file mode 100644 index 0000000..3e98a67 --- /dev/null +++ b/src/cmd/go/testdata/script/build_relative_tmpdir.txt @@ -0,0 +1,18 @@ +env GO111MODULE=off + +# If GOTMPDIR is relative, 'go build' should derive an absolute $WORK directory. +cd $WORK +mkdir tmp +env GOTMPDIR=tmp +go build -work a +stderr 'WORK=\$WORK' # the test script itself converts the absolute directory back to $WORK + +# Similarly if TMP/TMPDIR is relative. +env GOTMPDIR= +env TMP=tmp # Windows +env TMPDIR=tmp # Unix +go build -work a +stderr 'WORK=\$WORK' + +-- a/a.go -- +package a diff --git a/src/cmd/go/testdata/script/build_runtime_gcflags.txt b/src/cmd/go/testdata/script/build_runtime_gcflags.txt new file mode 100644 index 0000000..da1b65f --- /dev/null +++ b/src/cmd/go/testdata/script/build_runtime_gcflags.txt @@ -0,0 +1,11 @@ +env GO111MODULE=off +[short] skip # rebuilds all of std + +# Set up fresh GOCACHE. +env GOCACHE=$WORK/gocache +mkdir $GOCACHE + +# Verify the standard library (specifically runtime/internal/atomic) can be +# built with -gcflags when -n is given. See golang.org/issue/29346. +go build -n -gcflags=all='-l' std +stderr 'compile.* -l .* runtime/internal/atomic' diff --git a/src/cmd/go/testdata/script/build_tag_goexperiment.txt b/src/cmd/go/testdata/script/build_tag_goexperiment.txt new file mode 100644 index 0000000..26ad029 --- /dev/null +++ b/src/cmd/go/testdata/script/build_tag_goexperiment.txt @@ -0,0 +1,104 @@ +# compile_ext will fail if the buildtags that are enabled (or not enabled) for the +# framepointer and fieldtrack experiments are not consistent with the value of +# GOEXPSTRING (which comes from objabi.Expstring()). + +[short] skip +go run m + +-- expt_main.go -- +package main + +import ( + "os" + "strings" +) + +func main() { + fp() + ft() +} + +func hasExpEntry(s string) bool { + // script_test.go defines GOEXPSTRING to be the value of + // objabi.Expstring(), which gives the enabled experiments baked into the + // toolchain. + g := os.Getenv("GOEXPSTRING") + for _, f := range strings.Split(g, ",") { + if f == s { + return true + } + } + return false +} + +-- fp_off.go -- +// +build !goexperiment.framepointer + +package main + +import ( + "fmt" + "os" +) + +func fp() { + if hasExpEntry("framepointer") { + fmt.Println("in !framepointer build, but objabi.Expstring() has 'framepointer'") + os.Exit(1) + } +} + +-- fp_on.go -- +// +build goexperiment.framepointer + +package main + +import ( + "fmt" + "os" +) + +func fp() { + if !hasExpEntry("framepointer") { + fmt.Println("in framepointer build, but objabi.Expstring() does not have 'framepointer', is", os.Getenv("GOEXPSTRING")) + os.Exit(1) + } +} + +-- ft_off.go -- +// +build !goexperiment.fieldtrack + +package main + +import ( + "fmt" + "os" +) + +func ft() { + if hasExpEntry("fieldtrack") { + fmt.Println("in !fieldtrack build, but objabi.Expstring() has 'fieldtrack'") + os.Exit(1) + } +} + +-- ft_on.go -- +// +build goexperiment.fieldtrack + +package main + +import ( + "fmt" + "os" +) + +func ft() { + if !hasExpEntry("fieldtrack") { + fmt.Println("in fieldtrack build, but objabi.Expstring() does not have 'fieldtrack', is", os.Getenv("GOEXPSTRING")) + os.Exit(1) + } +} + +-- go.mod -- +module m +go 1.14 diff --git a/src/cmd/go/testdata/script/build_tags_no_comma.txt b/src/cmd/go/testdata/script/build_tags_no_comma.txt new file mode 100644 index 0000000..f3eb282 --- /dev/null +++ b/src/cmd/go/testdata/script/build_tags_no_comma.txt @@ -0,0 +1,4 @@ +[gccgo] skip 'gccgo has no standard packages' +go build -tags 'tag1 tag2' math +! go build -tags 'tag1,tag2 tag3' math +stderr 'space-separated list contains comma' \ No newline at end of file diff --git a/src/cmd/go/testdata/script/build_test_only.txt b/src/cmd/go/testdata/script/build_test_only.txt new file mode 100644 index 0000000..8693a80 --- /dev/null +++ b/src/cmd/go/testdata/script/build_test_only.txt @@ -0,0 +1,19 @@ +# Named explicitly, test-only packages should be reported as +# unbuildable/uninstallable, even if there is a wildcard also matching. +! go build m/testonly m/testonly... +stderr 'no non-test Go files in' +! go install ./testonly +stderr 'no non-test Go files in' + +# Named through a wildcard, the test-only packages should be silently ignored. +go build m/testonly... +go install ./testonly... + +-- go.mod -- +module m + +go 1.16 +-- testonly/t_test.go -- +package testonly +-- testonly2/t.go -- +package testonly2 diff --git a/src/cmd/go/testdata/script/build_trimpath.txt b/src/cmd/go/testdata/script/build_trimpath.txt new file mode 100644 index 0000000..2c3bee8 --- /dev/null +++ b/src/cmd/go/testdata/script/build_trimpath.txt @@ -0,0 +1,162 @@ +[short] skip + +# If GOROOT_FINAL is set, 'go build -trimpath' bakes that into the resulting +# binary instead of GOROOT. Explicitly unset it here. +env GOROOT_FINAL= + +# Set up two identical directories that can be used as GOPATH. +env GO111MODULE=on +mkdir $WORK/a/src/paths $WORK/b/src/paths +cp paths.go $WORK/a/src/paths +cp paths.go $WORK/b/src/paths +cp overlay.json $WORK/a/src/paths +cp overlay.json $WORK/b/src/paths +cp go.mod $WORK/a/src/paths/ +cp go.mod $WORK/b/src/paths/ + + +# A binary built without -trimpath should contain the module root dir +# and GOROOT for debugging and stack traces. +cd $WORK/a/src/paths +go build -o $WORK/paths-dbg.exe . +exec $WORK/paths-dbg.exe $WORK/paths-dbg.exe +stdout 'binary contains module root: true' +stdout 'binary contains GOROOT: true' + +# A binary built with -trimpath should not contain the current workspace +# or GOROOT. +go build -trimpath -o $WORK/paths-a.exe . +exec $WORK/paths-a.exe $WORK/paths-a.exe +stdout 'binary contains module root: false' +stdout 'binary contains GOROOT: false' + +# A binary from an external module built with -trimpath should not contain +# the current workspace or GOROOT. +go get -trimpath rsc.io/fortune +exec $WORK/paths-a.exe $GOPATH/bin/fortune$GOEXE +stdout 'binary contains module root: false' +stdout 'binary contains GOROOT: false' +go mod edit -droprequire rsc.io/fortune + +# Two binaries built from identical packages in different directories +# should be identical. +cd $WORK/b/src/paths +go build -trimpath -o $WORK/paths-b.exe +cmp -q $WORK/paths-a.exe $WORK/paths-b.exe + + +# Same sequence of tests but with overlays. +# A binary built without -trimpath should contain the module root dir +# and GOROOT for debugging and stack traces. +cd $WORK/a/src/paths +go build -overlay overlay.json -o $WORK/paths-dbg.exe ./overlaydir +exec $WORK/paths-dbg.exe $WORK/paths-dbg.exe +stdout 'binary contains module root: true' +stdout 'binary contains GOROOT: true' + +# A binary built with -trimpath should not contain the current workspace +# or GOROOT. +go build -overlay overlay.json -trimpath -o $WORK/paths-a.exe ./overlaydir +exec $WORK/paths-a.exe $WORK/paths-a.exe +stdout 'binary contains module root: false' +stdout 'binary contains GOROOT: false' + +# Two binaries built from identical packages in different directories +# should be identical. +cd $WORK/b/src/paths +go build -overlay overlay.json -trimpath -o $WORK/paths-b.exe ./overlaydir +cmp -q $WORK/paths-a.exe $WORK/paths-b.exe + + +# Same sequence of tests but in GOPATH mode. +# A binary built without -trimpath should contain GOPATH and GOROOT. +env GO111MODULE=off +cd $WORK +env GOPATH=$WORK/a +go build -o paths-dbg.exe paths +exec ./paths-dbg.exe paths-dbg.exe +stdout 'binary contains GOPATH: true' +stdout 'binary contains GOROOT: true' + +# A binary built with -trimpath should not contain GOPATH or GOROOT. +go build -trimpath -o paths-a.exe paths +exec ./paths-a.exe paths-a.exe +stdout 'binary contains GOPATH: false' +stdout 'binary contains GOROOT: false' + +# Two binaries built from identical packages in different GOPATH roots +# should be identical. +env GOPATH=$WORK/b +go build -trimpath -o paths-b.exe paths +cmp -q paths-a.exe paths-b.exe + + +# Same sequence of tests but with gccgo. +# gccgo does not support builds in module mode. +[!exec:gccgo] stop +env GOPATH=$WORK/a + +# A binary built with gccgo without -trimpath should contain the current +# GOPATH and GOROOT. +go build -compiler=gccgo -o paths-dbg.exe paths +exec ./paths-dbg.exe paths-dbg.exe +stdout 'binary contains GOPATH: true' +stdout 'binary contains GOROOT: false' # gccgo doesn't load std from GOROOT. + +# A binary built with gccgo with -trimpath should not contain GOPATH or GOROOT. +go build -compiler=gccgo -trimpath -o paths-a.exe paths +exec ./paths-a.exe paths-a.exe +stdout 'binary contains GOPATH: false' +stdout 'binary contains GOROOT: false' + +# Two binaries built from identical packages in different directories +# should be identical. +env GOPATH=$WORK/b +go build -compiler=gccgo -trimpath -o paths-b.exe paths +cmp -q paths-a.exe paths-b.exe + +-- paths.go -- +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "log" + "os" + "os/exec" + "path/filepath" + "strings" +) + +func main() { + exe := os.Args[1] + data, err := ioutil.ReadFile(exe) + if err != nil { + log.Fatal(err) + } + + if os.Getenv("GO111MODULE") == "on" { + out, err := exec.Command("go", "env", "GOMOD").Output() + if err != nil { + log.Fatal(err) + } + modRoot := filepath.Dir(strings.TrimSpace(string(out))) + check(data, "module root", modRoot) + } else { + check(data, "GOPATH", os.Getenv("GOPATH")) + } + check(data, "GOROOT", os.Getenv("GOROOT")) +} + +func check(data []byte, desc, dir string) { + containsDir := bytes.Contains(data, []byte(dir)) + containsSlashDir := bytes.Contains(data, []byte(filepath.ToSlash(dir))) + fmt.Printf("binary contains %s: %v\n", desc, containsDir || containsSlashDir) +} +-- overlay.json -- +{ "Replace": { "overlaydir/paths.go": "paths.go" } } +-- go.mod -- +module paths + +go 1.14 diff --git a/src/cmd/go/testdata/script/build_trimpath_cgo.txt b/src/cmd/go/testdata/script/build_trimpath_cgo.txt new file mode 100644 index 0000000..3187b4d --- /dev/null +++ b/src/cmd/go/testdata/script/build_trimpath_cgo.txt @@ -0,0 +1,184 @@ +# This test builds a cgo binary and verifies the source directory path +# does not appear in the binary, either literally or in compressed DWARF. +# TODO(golang.org/issue/36072): ideally we should build a binary from identical +# sources in different directories and verify the binary and all intermediate +# files are identical. + +[short] skip +[!cgo] skip + +# Check that the source path appears when -trimpath is not used. +go build -o hello.exe . +grep -q gopath[/\\]src hello.exe +go run ./list-dwarf hello.exe +stdout gopath[/\\]src + +# Check that the source path does not appear when -trimpath is used. +[aix] stop # can't inspect XCOFF binaries +go build -trimpath -o hello.exe . +! grep -q gopath[/\\]src hello.exe +go run ./list-dwarf hello.exe +! stdout gopath/src + + +# Do the above, with the cgo (but not .c) sources in an overlay +# Check that the source path appears when -trimpath is not used. +mkdir $WORK/overlay +cp hello.go $WORK/overlay/hello.go +mkdir hello_overlay +cp hello.c hello_overlay/hello.c +go build -overlay overlay.json -o hello_overlay.exe ./hello_overlay +grep -q gopath[/\\]src hello_overlay.exe +! grep -q $WORK[/\\]overlay hello_overlay.exe +go run ./list-dwarf hello_overlay.exe +stdout gopath[/\\]src +! stdout $WORK[/\\]overlay + +# Check that the source path does not appear when -trimpath is used. +go build -overlay overlay.json -trimpath -o hello_overlay.exe ./hello_overlay +! grep -q gopath[/\\]src hello_overlay.exe +! grep -q $WORK[/\\]overlay hello_overlay.exe +go run ./list-dwarf hello_overlay.exe +! stdout gopath/src +! stdout $WORK[/\\]overlay + +-- go.mod -- +module m + +go 1.14 +-- overlay.json -- +{ + "Replace": { + "hello_overlay/hello.go": "../../overlay/hello.go" + } +} +-- hello.c -- +#include + +void say_hello() { puts("Hello, world!\n"); } + +-- hello.go -- +package main + +// void say_hello(); +import "C" + +func main() { + C.say_hello() +} + +-- list-dwarf/list-dwarf.go -- +package main + +import ( + "debug/dwarf" + "fmt" + "io" + "log" + "os" + "sort" +) + +func main() { + files, err := run(os.Args[1]) + if err != nil { + log.Fatal(err) + } + for _, file := range files { + fmt.Println(file) + } +} + +func run(exePath string) ([]string, error) { + dwarfData, err := readDWARF(exePath) + if err != nil { + return nil, err + } + + dwarfReader := dwarfData.Reader() + files := make(map[string]bool) + for { + e, err := dwarfReader.Next() + if err != nil { + return nil, err + } + if e == nil { + break + } + lr, err := dwarfData.LineReader(e) + if err != nil { + return nil, err + } + if lr == nil { + continue + } + + var le dwarf.LineEntry + for { + if err := lr.Next(&le); err != nil { + if err == io.EOF { + break + } + return nil, err + } + files[le.File.Name] = true + } + } + + sortedFiles := make([]string, 0, len(files)) + for file := range files { + sortedFiles = append(sortedFiles, file) + } + sort.Strings(sortedFiles) + return sortedFiles, nil +} +-- list-dwarf/read_darwin.go -- +package main + +import ( + "debug/dwarf" + "debug/macho" +) + +func readDWARF(exePath string) (*dwarf.Data, error) { + machoFile, err := macho.Open(exePath) + if err != nil { + return nil, err + } + defer machoFile.Close() + return machoFile.DWARF() +} +-- list-dwarf/read_elf.go -- +// +build android dragonfly freebsd illumos linux netbsd openbsd solaris + +package main + +import ( + "debug/dwarf" + "debug/elf" +) + +func readDWARF(exePath string) (*dwarf.Data, error) { + elfFile, err := elf.Open(exePath) + if err != nil { + return nil, err + } + defer elfFile.Close() + return elfFile.DWARF() +} +-- list-dwarf/read_windows.go -- +package main + +import ( + "debug/dwarf" + "debug/pe" +) + +func readDWARF(exePath string) (*dwarf.Data, error) { + peFile, err := pe.Open(exePath) + if err != nil { + return nil, err + } + defer peFile.Close() + return peFile.DWARF() +} diff --git a/src/cmd/go/testdata/script/build_unsupported_goos.txt b/src/cmd/go/testdata/script/build_unsupported_goos.txt new file mode 100644 index 0000000..d61e420 --- /dev/null +++ b/src/cmd/go/testdata/script/build_unsupported_goos.txt @@ -0,0 +1,6 @@ +[gccgo] skip # gccgo assumes cross-compilation is always possible + +env GOOS=windwos + +! go build -n exclude +stderr 'unsupported GOOS/GOARCH pair' \ No newline at end of file diff --git a/src/cmd/go/testdata/script/build_vendor.txt b/src/cmd/go/testdata/script/build_vendor.txt new file mode 100644 index 0000000..f430ff2 --- /dev/null +++ b/src/cmd/go/testdata/script/build_vendor.txt @@ -0,0 +1,42 @@ +# Build +env GO111MODULE=off +go build vend/x +! stdout . +! stderr . + +-- vend/dir1/dir1.go -- +package dir1 +-- vend/subdir/bad.go -- +package subdir + +import _ "r" +-- vend/subdir/good.go -- +package subdir + +import _ "p" +-- vend/vendor/p/p.go -- +package p +-- vend/vendor/q/q.go -- +package q +-- vend/vendor/vend/dir1/dir2/dir2.go -- +package dir2 +-- vend/x/invalid/invalid.go -- +package invalid + +import "vend/x/invalid/vendor/foo" +-- vend/x/vendor/p/p/p.go -- +package p + +import _ "notfound" +-- vend/x/vendor/p/p.go -- +package p +-- vend/x/vendor/r/r.go -- +package r +-- vend/x/x.go -- +package x + +import _ "p" +import _ "q" +import _ "r" +import _ "vend/dir1" // not vendored +import _ "vend/dir1/dir2" // vendored diff --git a/src/cmd/go/testdata/script/cache_unix.txt b/src/cmd/go/testdata/script/cache_unix.txt new file mode 100644 index 0000000..0e07ba6 --- /dev/null +++ b/src/cmd/go/testdata/script/cache_unix.txt @@ -0,0 +1,36 @@ +env GO111MODULE=off + +# Integration test for cache directory calculation (cmd/go/internal/cache). + +[windows] skip +[darwin] skip +[plan9] skip + +mkdir $WORK/gocache +mkdir $WORK/xdg +mkdir $WORK/home + +# Set GOCACHE, XDG_CACHE_HOME, and HOME. +env GOCACHE=$WORK/gocache +env XDG_CACHE_HOME=$WORK/xdg +env HOME=$WORK/home + +# With all three set, we should prefer GOCACHE. +go env GOCACHE +stdout '\$WORK/gocache$' + +# Without GOCACHE, we should prefer XDG_CACHE_HOME over HOME. +env GOCACHE= +go env GOCACHE +stdout '\$WORK/xdg/go-build$$' + +# With only HOME set, we should use $HOME/.cache. +env XDG_CACHE_HOME= +go env GOCACHE +stdout '\$WORK/home/.cache/go-build$' + +# With no guidance from the environment, we must disable the cache, but that +# should not cause commands that do not write to the cache to fail. +env HOME= +go env GOCACHE +stdout 'off' diff --git a/src/cmd/go/testdata/script/cache_vet.txt b/src/cmd/go/testdata/script/cache_vet.txt new file mode 100644 index 0000000..928024e --- /dev/null +++ b/src/cmd/go/testdata/script/cache_vet.txt @@ -0,0 +1,22 @@ +env GO111MODULE=off + +[short] skip +[GODEBUG:gocacheverify=1] skip +[gccgo] skip # gccgo has no standard packages + +# Start with a clean build cache: +# test failures may be masked if the cache has just the right entries already. +env GOCACHE=$WORK/cache + +# Run 'go vet os/user' once to warm up the cache. +go vet os/user + +# 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. + +go vet -x os/user +! stderr '^(clang|gcc)' # should not have run compiler +! stderr '[\\/]cgo ' # should not have run cgo diff --git a/src/cmd/go/testdata/script/cgo_asm_error.txt b/src/cmd/go/testdata/script/cgo_asm_error.txt new file mode 100644 index 0000000..7aaa713 --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_asm_error.txt @@ -0,0 +1,25 @@ +[!cgo] skip + +# Test that cgo package can't contain a go assembly file. + +# Ensure the build fails and reports that the package has a Go assembly file. +! go build cgoasm +stderr 'package using cgo has Go assembly file' + +-- go.mod -- +module cgoasm + +go 1.16 +-- p.go -- +package p + +/* +// hi +*/ +import "C" + +func F() {} +-- p.s -- +TEXT asm(SB),$0 + RET + diff --git a/src/cmd/go/testdata/script/cgo_bad_directives.txt b/src/cmd/go/testdata/script/cgo_bad_directives.txt new file mode 100644 index 0000000..6bf3beb --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_bad_directives.txt @@ -0,0 +1,129 @@ +[!cgo] skip +[short] skip + +cp x.go.txt x.go + +# Only allow //go:cgo_ldflag .* in cgo-generated code +[gc] cp x_gc.go.txt x.go +[gc] ! go build x +[gc] stderr '//go:cgo_ldflag .* only allowed in cgo-generated code' + +# Ignore _* files +rm x.go +! go build . +stderr 'no Go files' +cp cgo_yy.go.txt _cgo_yy.go +! go build . +stderr 'no Go files' #_* files are ignored... + +[gc] ! go build _cgo_yy.go # ... but if forced, the comment is rejected +# Actually, today there is a separate issue that _ files named +# on the command line are ignored. Once that is fixed, +# we want to see the cgo_ldflag error. +[gc] stderr '//go:cgo_ldflag only allowed in cgo-generated code|no Go files' + +rm _cgo_yy.go + +# Reject #cgo CFLAGS: -fplugin=foo.so +cp x.go.txt x.go +cp y_fplugin.go.txt y.go +! go build x +stderr 'invalid flag in #cgo CFLAGS: -fplugin=foo.so' + +# Reject #cgo CFLAGS: -lbar -fplugin=foo.so +cp y_lbar_fplugin.go.txt y.go +! go build x +stderr 'invalid flag in #cgo CFLAGS: -fplugin=foo.so' + +# Reject #cgo pkg-config: -foo +cp y_pkgconfig_dash_foo.txt y.go +! go build x +stderr 'invalid pkg-config package name: -foo' + +# Reject #cgo pkg-config: @foo +cp y_pkgconfig_at_foo.txt y.go +! go build x +stderr 'invalid pkg-config package name: @foo' + +# Reject #cgo CFLAGS: @foo +cp y_cflags_at_foo.txt y.go +! go build x +stderr 'invalid flag in #cgo CFLAGS: @foo' + +# Reject #cgo CFLAGS: -D +cp y_cflags_dash_d.txt y.go +! go build x +stderr 'invalid flag in #cgo CFLAGS: -D without argument' + +# Note that -I @foo is allowed because we rewrite it into -I /path/to/src/@foo +# before the check is applied. There's no such rewrite for -D. + +# Reject #cgo CFLAGS: -D @foo +cp y_cflags_dash_d_space_at_foo.txt y.go +! go build x +stderr 'invalid flag in #cgo CFLAGS: -D @foo' + +# Reject #cgo CFLAGS -D@foo +cp y_cflags_dash_d_at_foo.txt y.go +! go build x +stderr 'invalid flag in #cgo CFLAGS: -D@foo' + +# Check for CFLAGS in commands +env CGO_CFLAGS=-D@foo +cp y_no_cflags.txt y.go +go build -n x +stderr '-D@foo' + +-- go.mod -- +module x + +go 1.16 +-- x_gc.go.txt -- +package x + +//go:cgo_ldflag "-fplugin=foo.so" + +import "C" +-- cgo_yy.go.txt -- +package x + +//go:cgo_ldflag "-fplugin=foo.so" + +import "C" +-- x.go.txt -- +package x +-- y_fplugin.go.txt -- +package x +// #cgo CFLAGS: -fplugin=foo.so +import "C" +-- y_lbar_fplugin.go.txt -- +package x +// #cgo CFLAGS: -Ibar -fplugin=foo.so +import "C" +-- y_pkgconfig_dash_foo.txt -- +package x +// #cgo pkg-config: -foo +import "C" +-- y_pkgconfig_at_foo.txt -- +package x +// #cgo pkg-config: @foo +import "C" +-- y_cflags_at_foo.txt -- +package x +// #cgo CFLAGS: @foo +import "C" +-- y_cflags_dash_d.txt -- +package x +// #cgo CFLAGS: -D +import "C" +-- y_cflags_dash_d_space_at_foo.txt -- +package x +// #cgo CFLAGS: -D @foo +import "C" +-- y_cflags_dash_d_at_foo.txt -- +package x +// #cgo CFLAGS: -D@foo +import "C" +-- y_no_cflags.txt -- +package x +import "C" diff --git a/src/cmd/go/testdata/script/cgo_depends_on_syscall.txt b/src/cmd/go/testdata/script/cgo_depends_on_syscall.txt new file mode 100644 index 0000000..bd4777c --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_depends_on_syscall.txt @@ -0,0 +1,15 @@ +[!cgo] skip +[!race] skip + +go list -race -deps foo +stdout syscall + +-- go.mod -- +module foo + +go 1.16 +-- foo.go -- +package foo + +// #include +import "C" diff --git a/src/cmd/go/testdata/script/cgo_flag_contains_space.txt b/src/cmd/go/testdata/script/cgo_flag_contains_space.txt new file mode 100644 index 0000000..a3372bb --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_flag_contains_space.txt @@ -0,0 +1,16 @@ +[short] skip +[!cgo] skip + +env GOCACHE=$WORK/gocache # Looking for compile flags, so need a clean cache. +go build -x -n main.go +stderr '"-I[^"]+c flags"' # find quoted c flags +! stderr '"-I[^"]+c flags".*"-I[^"]+c flags"' # don't find too many quoted c flags per line +stderr '"-L[^"]+ld flags"' # find quoted ld flags +! stderr '"-L[^"]+c flags".*"-L[^"]+c flags"' # don't find too many quoted ld flags per line + +-- main.go -- +package main +// #cgo CFLAGS: -I"c flags" +// #cgo LDFLAGS: -L"ld flags" +import "C" +func main() {} diff --git a/src/cmd/go/testdata/script/cgo_path.txt b/src/cmd/go/testdata/script/cgo_path.txt new file mode 100644 index 0000000..be9609e --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_path.txt @@ -0,0 +1,43 @@ +[!cgo] skip + +# Set CC explicitly to something that requires a PATH lookup. +# Normally, the default is gcc or clang, but if CC was set during make.bash, +# that becomes the default. +[exec:clang] env CC=clang +[exec:gcc] env CC=gcc +[!exec:clang] [!exec:gcc] skip 'Unknown C compiler' + +env GOCACHE=$WORK/gocache # Looking for compile flags, so need a clean cache. +[!windows] env PATH=.:$PATH +[!windows] chmod 0755 p/gcc p/clang +[!windows] exists -exec p/gcc p/clang +[windows] exists -exec p/gcc.bat p/clang.bat +! exists p/bug.txt +! go build -x +stderr '^cgo: exec (clang|gcc): (clang|gcc) resolves to executable relative to current directory \(.[/\\](clang|gcc)(.bat)?\)$' +! exists p/bug.txt + +-- go.mod -- +module m + +-- m.go -- +package m + +import _ "m/p" + +-- p/p.go -- +package p + +// #define X 1 +import "C" + +-- p/gcc -- +#!/bin/sh +echo ran gcc >bug.txt +-- p/clang -- +#!/bin/sh +echo ran clang >bug.txt +-- p/gcc.bat -- +echo ran gcc >bug.txt +-- p/clang.bat -- +echo ran clang >bug.txt diff --git a/src/cmd/go/testdata/script/cgo_path_space.txt b/src/cmd/go/testdata/script/cgo_path_space.txt new file mode 100644 index 0000000..654295d --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_path_space.txt @@ -0,0 +1,56 @@ +# Check that if the PATH directory containing the C compiler has a space, +# we can still use that compiler with cgo. +# Verifies #43808. +[!cgo] skip + +# Set CC explicitly to something that requires a PATH lookup. +# Normally, the default is gcc or clang, but if CC was set during make.bash, +# that becomes the default. +[exec:clang] env CC=clang +[exec:gcc] env CC=gcc +[!exec:clang] [!exec:gcc] skip 'Unknown C compiler' + +[!windows] chmod 0755 $WORK/'program files'/clang +[!windows] chmod 0755 $WORK/'program files'/gcc +[!windows] exists -exec $WORK/'program files'/clang +[!windows] exists -exec $WORK/'program files'/gcc +[!windows] env PATH=$WORK/'program files':$PATH +[windows] exists -exec $WORK/'program files'/gcc.bat +[windows] exists -exec $WORK/'program files'/clang.bat +[windows] env PATH=$WORK\'program files';%PATH% + +! exists $WORK/log.txt +? go build -x +exists $WORK/log.txt +rm $WORK/log.txt + +# TODO(#41400, #43078): when CC is set explicitly, it should be allowed to +# contain spaces separating arguments, and it should be possible to quote +# arguments with spaces (including the path), as in CGO_CFLAGS and other +# variables. For now, this doesn't work. +[!windows] env CC=$WORK/'program files'/gcc +[windows] env CC=$WORK\'program files'\gcc.bat +! go build -x +! exists $WORK/log.txt + +-- go.mod -- +module m + +-- m.go -- +package m + +// #define X 1 +import "C" + +-- $WORK/program files/gcc -- +#!/bin/sh + +echo ok >$WORK/log.txt +-- $WORK/program files/clang -- +#!/bin/sh + +echo ok >$WORK/log.txt +-- $WORK/program files/gcc.bat -- +echo ok >%WORK%\log.txt +-- $WORK/program files/clang.bat -- +echo ok >%WORK%\log.txt diff --git a/src/cmd/go/testdata/script/cgo_syso_issue29253.txt b/src/cmd/go/testdata/script/cgo_syso_issue29253.txt new file mode 100644 index 0000000..4fb5cca --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_syso_issue29253.txt @@ -0,0 +1,31 @@ +env GO111MODULE=off +[short] skip + +# This test tests that we can link in-package syso files that provides symbols +# for cgo. See issue 29253. +[!cgo] stop +[!gc] stop +cc -c -o pkg/o.syso ext.c +go build main.go + +-- ext.c -- +// +build ignore + +int f() { return 42; } +-- pkg/pkg.go -- +package pkg + +// extern int f(void); +import "C" + +func init() { + if v := C.f(); v != 42 { + panic(v) + } +} +-- main.go -- +package main + +import _ "pkg" + +func main() {} diff --git a/src/cmd/go/testdata/script/clean_binary.txt b/src/cmd/go/testdata/script/clean_binary.txt new file mode 100644 index 0000000..7335f8a --- /dev/null +++ b/src/cmd/go/testdata/script/clean_binary.txt @@ -0,0 +1,78 @@ +# Build something to create the executable, including several cases +[short] skip + +# --------------------- clean executables ------------------------- + +# case1: test file-named executable 'main' +env GO111MODULE=on + +! exists main$GOEXE +go build main.go +exists -exec main$GOEXE +go clean +! exists main$GOEXE + +# case2: test module-named executable 'a.b.c' +! exists a.b.c$GOEXE +go build +exists -exec a.b.c$GOEXE +go clean +! exists a.b.c$GOEXE + +# case3: directory-named executable 'src' +env GO111MODULE=off + +! exists src$GOEXE +go build +exists -exec src$GOEXE +go clean +! exists src$GOEXE + +# --------------------- clean test files ------------------------- + +# case1: test file-named test file +env GO111MODULE=on + +! exists main.test$GOEXE +go test -c main_test.go +exists -exec main.test$GOEXE +go clean +! exists main.test$GOEXE + +# case2: test module-named test file +! exists a.b.c.test$GOEXE +go test -c +exists -exec a.b.c.test$GOEXE +go clean +! exists a.b.c.test$GOEXE + +# case3: test directory-based test file +env GO111MODULE=off + +! exists src.test$GOEXE +go test -c +exists -exec src.test$GOEXE +go clean +! exists src.test$GOEXE + +-- main.go -- +package main + +import "fmt" + +func main() { + fmt.Println("hello!") +} + +-- main_test.go -- +package main + +import "testing" + +func TestSomething(t *testing.T) { +} + +-- go.mod -- +module example.com/a.b.c/v2 + +go 1.12 \ No newline at end of file diff --git a/src/cmd/go/testdata/script/clean_cache_n.txt b/src/cmd/go/testdata/script/clean_cache_n.txt new file mode 100644 index 0000000..4497b36 --- /dev/null +++ b/src/cmd/go/testdata/script/clean_cache_n.txt @@ -0,0 +1,25 @@ +# We're testing cache behavior, so start with a clean GOCACHE. +env GOCACHE=$WORK/cache + +# Build something so that the cache gets populates +go build main.go + +# Check that cache contains directories before running +exists $GOCACHE/00 + +# Run go clean -cache -n and ensure that directories weren't deleted +go clean -cache -n +exists $GOCACHE/00 + +# Re-run go clean cache without the -n flag go ensure that directories were properly removed +go clean -cache +! exists $GOCACHE/00 + +-- main.go -- +package main + +import "fmt" + +func main() { + fmt.Println("hello!") +} diff --git a/src/cmd/go/testdata/script/clean_testcache.txt b/src/cmd/go/testdata/script/clean_testcache.txt new file mode 100644 index 0000000..b3f32fe --- /dev/null +++ b/src/cmd/go/testdata/script/clean_testcache.txt @@ -0,0 +1,26 @@ +env GO111MODULE=off +[short] skip + +# go clean -testcache +# should work (see golang.org/issue/29757). +cd x +go test x_test.go +go clean -testcache +go test x_test.go +! stdout 'cached' + +# golang.org/issue/29100: 'go clean -testcache' should succeed +# if the cache directory doesn't exist at all. +# It should not write a testexpire.txt file, since there are no +# test results that need to be invalidated in the first place. +env GOCACHE=$WORK/nonexistent +go clean -testcache +! exists $WORK/nonexistent + +-- x/x_test.go -- +package x_test +import ( + "testing" +) +func TestMain(t *testing.T) { +} diff --git a/src/cmd/go/testdata/script/cmd_import_error.txt b/src/cmd/go/testdata/script/cmd_import_error.txt new file mode 100644 index 0000000..dea76f4 --- /dev/null +++ b/src/cmd/go/testdata/script/cmd_import_error.txt @@ -0,0 +1,16 @@ +env GO111MODULE=on + +# Regression test for golang.org/issue/31031: +# Importing or loading a non-existent package in cmd/ should print +# a clear error in module mode. + +! go list cmd/unknown +stderr '^package cmd/unknown is not in GOROOT \('$GOROOT'[/\\]src[/\\]cmd[/\\]unknown\)$' + +go list -f '{{range .DepsErrors}}{{.Err}}{{end}}' x.go +stdout '^package cmd/unknown is not in GOROOT \('$GOROOT'[/\\]src[/\\]cmd[/\\]unknown\)$' + +-- x.go -- +package x + +import _ "cmd/unknown" diff --git a/src/cmd/go/testdata/script/cover_asm.txt b/src/cmd/go/testdata/script/cover_asm.txt new file mode 100644 index 0000000..57f76d6 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_asm.txt @@ -0,0 +1,33 @@ +[short] skip +[gccgo] skip # gccgo has no cover tool + +# Test cover for a package that has an assembly function. + +go test -outputdir=$WORK -coverprofile=cover.out coverasm +go tool cover -func=$WORK/cover.out +stdout '\tg\t*100.0%' # Check g is 100% covered. +! stdout '\tf\t*[0-9]' # Check for no coverage on the assembly function + +-- go.mod -- +module coverasm + +go 1.16 +-- p.go -- +package p + +func f() + +func g() { + println("g") +} +-- p.s -- +// empty asm file, +// so go test doesn't complain about declaration of f in p.go. +-- p_test.go -- +package p + +import "testing" + +func Test(t *testing.T) { + g() +} diff --git a/src/cmd/go/testdata/script/cover_atomic_pkgall.txt b/src/cmd/go/testdata/script/cover_atomic_pkgall.txt new file mode 100644 index 0000000..c3bc67d --- /dev/null +++ b/src/cmd/go/testdata/script/cover_atomic_pkgall.txt @@ -0,0 +1,25 @@ +env GO111MODULE=off + +[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/src/cmd/go/testdata/script/cover_blank_func_decl.txt b/src/cmd/go/testdata/script/cover_blank_func_decl.txt new file mode 100644 index 0000000..e7d5250 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_blank_func_decl.txt @@ -0,0 +1,35 @@ +[short] skip +go test -cover coverblank +stdout 'coverage: 100.0% of statements' + + +-- go.mod -- +module coverblank + +go 1.16 +-- a.go -- +package coverblank + +func _() { + println("unreachable") +} + +type X int + +func (x X) Print() { + println(x) +} + +func (x X) _() { + println("unreachable") +} + +-- a_test.go -- +package coverblank + +import "testing" + +func TestX(t *testing.T) { + var x X + x.Print() +} diff --git a/src/cmd/go/testdata/script/cover_cgo.txt b/src/cmd/go/testdata/script/cover_cgo.txt new file mode 100644 index 0000000..9cf78f7 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_cgo.txt @@ -0,0 +1,42 @@ +[short] skip +[!cgo] skip +[gccgo] skip # gccgo has no cover tool + +# Test coverage on cgo code. + +go test -short -cover cgocover +stdout 'coverage:.*[1-9][0-9.]+%' +! stderr '[^0-9]0\.0%' + +-- go.mod -- +module cgocover + +go 1.16 +-- p.go -- +package p + +/* +void +f(void) +{ +} +*/ +import "C" + +var b bool + +func F() { + if b { + for { + } + } + C.f() +} +-- p_test.go -- +package p + +import "testing" + +func TestF(t *testing.T) { + F() +} diff --git a/src/cmd/go/testdata/script/cover_cgo_extra_file.txt b/src/cmd/go/testdata/script/cover_cgo_extra_file.txt new file mode 100644 index 0000000..c53b979 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_cgo_extra_file.txt @@ -0,0 +1,48 @@ +[short] skip +[!cgo] skip +[gccgo] skip # gccgo has no cover tool + +# Test coverage on cgo code. This test case includes an +# extra empty non-cgo file in the package being checked. + +go test -short -cover cgocover4 +stdout 'coverage:.*[1-9][0-9.]+%' +! stderr '[^0-9]0\.0%' + +-- go.mod -- +module cgocover4 + +go 1.16 +-- notcgo.go -- +package p +-- p.go -- +package p + +/* +void +f(void) +{ +} +*/ +import "C" + +var b bool + +func F() { + if b { + for { + } + } + C.f() +} +-- x_test.go -- +package p_test + +import ( + . "cgocover4" + "testing" +) + +func TestF(t *testing.T) { + F() +} diff --git a/src/cmd/go/testdata/script/cover_cgo_extra_test.txt b/src/cmd/go/testdata/script/cover_cgo_extra_test.txt new file mode 100644 index 0000000..b501ab0 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_cgo_extra_test.txt @@ -0,0 +1,49 @@ +[short] skip +[!cgo] skip +[gccgo] skip # gccgo has no cover tool + +# Test coverage on cgo code. This test case has an external +# test that tests the code and an in-package test file with +# no test cases. + +go test -short -cover cgocover3 +stdout 'coverage:.*[1-9][0-9.]+%' +! stderr '[^0-9]0\.0%' + +-- go.mod -- +module cgocover3 + +go 1.16 +-- p.go -- +package p + +/* +void +f(void) +{ +} +*/ +import "C" + +var b bool + +func F() { + if b { + for { + } + } + C.f() +} +-- p_test.go -- +package p +-- x_test.go -- +package p_test + +import ( + . "cgocover3" + "testing" +) + +func TestF(t *testing.T) { + F() +} diff --git a/src/cmd/go/testdata/script/cover_cgo_xtest.txt b/src/cmd/go/testdata/script/cover_cgo_xtest.txt new file mode 100644 index 0000000..79cc08c --- /dev/null +++ b/src/cmd/go/testdata/script/cover_cgo_xtest.txt @@ -0,0 +1,45 @@ +[short] skip +[!cgo] skip +[gccgo] skip # gccgo has no cover tool + +# Test cgo coverage with an external test. + +go test -short -cover cgocover2 +stdout 'coverage:.*[1-9][0-9.]+%' +! stderr '[^0-9]0\.0%' + +-- go.mod -- +module cgocover2 + +go 1.16 +-- p.go -- +package p + +/* +void +f(void) +{ +} +*/ +import "C" + +var b bool + +func F() { + if b { + for { + } + } + C.f() +} +-- x_test.go -- +package p_test + +import ( + . "cgocover2" + "testing" +) + +func TestF(t *testing.T) { + F() +} diff --git a/src/cmd/go/testdata/script/cover_dash_c.txt b/src/cmd/go/testdata/script/cover_dash_c.txt new file mode 100644 index 0000000..8950f8d --- /dev/null +++ b/src/cmd/go/testdata/script/cover_dash_c.txt @@ -0,0 +1,31 @@ +[short] skip +[gccgo] skip + +# Test for issue 24588 + +go test -c -o $WORK/coverdep -coverprofile=$WORK/no/such/dir/cover.out coverdep +exists -exec $WORK/coverdep + +-- go.mod -- +module coverdep + +go 1.16 +-- p.go -- +package p + +import _ "coverdep/p1" + +func F() { +} +-- p1/p1.go -- +package p1 + +import _ "errors" +-- p_test.go -- +package p + +import "testing" + +func Test(t *testing.T) { + F() +} diff --git a/src/cmd/go/testdata/script/cover_dep_loop.txt b/src/cmd/go/testdata/script/cover_dep_loop.txt new file mode 100644 index 0000000..36ea6e0 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_dep_loop.txt @@ -0,0 +1,36 @@ +[short] skip +[gccgo] skip + +# coverdep2/p1's xtest imports coverdep2/p2 which imports coverdep2/p1. +# Make sure that coverage on coverdep2/p2 recompiles coverdep2/p2. + +go test -short -cover coverdep2/p1 +stdout 'coverage: 100.0% of statements' # expect 100.0% coverage + +-- go.mod -- +module coverdep2 + +go 1.16 +-- p1/p.go -- +package p1 + +func F() int { return 1 } +-- p1/p_test.go -- +package p1_test + +import ( + "coverdep2/p2" + "testing" +) + +func Test(t *testing.T) { + p2.F() +} +-- p2/p2.go -- +package p2 + +import "coverdep2/p1" + +func F() { + p1.F() +} diff --git a/src/cmd/go/testdata/script/cover_dot_import.txt b/src/cmd/go/testdata/script/cover_dot_import.txt new file mode 100644 index 0000000..d492e42 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_dot_import.txt @@ -0,0 +1,29 @@ +[short] skip +[gccgo] skip # gccgo has no cover tool + +go test -coverpkg=coverdot/a,coverdot/b coverdot/b +! stderr '[^0-9]0\.0%' +! stdout '[^0-9]0\.0%' + +-- go.mod -- +module coverdot + +go 1.16 +-- a/a.go -- +package a + +func F() {} +-- b/b.go -- +package b + +import . "coverdot/a" + +func G() { F() } +-- b/b_test.go -- +package b + +import "testing" + +func TestG(t *testing.T) { + G() +} diff --git a/src/cmd/go/testdata/script/cover_error.txt b/src/cmd/go/testdata/script/cover_error.txt new file mode 100644 index 0000000..583a664 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_error.txt @@ -0,0 +1,74 @@ +[short] skip +[gccgo] skip + +# Test line numbers in cover errors. + +# Get errors from a go test into stderr.txt +! go test coverbad +stderr 'p\.go:4' # look for error at coverbad/p.go:4 +[cgo] stderr 'p1\.go:6' # look for error at coverbad/p.go:6 +! stderr $WORK # make sure temporary directory isn't in error + +cp stderr $WORK/stderr.txt + +# Clean out character positions from stderr.txt +# It's OK that stderr2 drops the character position in the error, +# because of the //line directive (see golang.org/issue/22662). +go run clean_charpos.go $WORK/stderr.txt & + +# Get errors from coverage into stderr2.txt +! go test -cover coverbad +cp stderr $WORK/stderr2.txt + +wait # for go run above + +cmp $WORK/stderr.txt $WORK/stderr2.txt + +-- go.mod -- +module coverbad + +go 1.16 +-- p.go -- +package p + +func f() { + g() +} +-- p1.go -- +package p + +import "C" + +func h() { + j() +} +-- p_test.go -- +package p + +import "testing" + +func Test(t *testing.T) {} +-- clean_charpos.go -- +// +build ignore + +package main + +import ( + "log" + "os" + "strings" +) + +func main() { + log.SetFlags(0) + b, err := os.ReadFile(os.Args[1]) + if err != nil { + log.Fatal(err) + } + s := strings.ReplaceAll(string(b), "p.go:4:2:", "p.go:4:") + s = strings.ReplaceAll(s, "p1.go:6:2:", "p1.go:6:") + os.WriteFile(os.Args[1], []byte(s), 0644) + if err != nil { + log.Fatal(err) + } +} diff --git a/src/cmd/go/testdata/script/cover_import_main_loop.txt b/src/cmd/go/testdata/script/cover_import_main_loop.txt new file mode 100644 index 0000000..eb6de67 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_import_main_loop.txt @@ -0,0 +1,26 @@ +[gccgo] skip # gccgo has no cover tool + +! go test -n importmain/test +stderr 'not an importable package' # check that import main was detected +! go test -n -cover importmain/test +stderr 'not an importable package' # check that import main was detected + +-- go.mod -- +module importmain + +go 1.16 +-- ismain/main.go -- +package main + +import _ "importmain/test" + +func main() {} +-- test/test.go -- +package test +-- test/test_test.go -- +package test_test + +import "testing" +import _ "importmain/ismain" + +func TestCase(t *testing.T) {} diff --git a/src/cmd/go/testdata/script/cover_mod_empty.txt b/src/cmd/go/testdata/script/cover_mod_empty.txt new file mode 100644 index 0000000..3c45243 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_mod_empty.txt @@ -0,0 +1,9 @@ +go tool cover -func=cover.out +stdout total.*statements.*0.0% + +go mod init golang.org/issue/33855 + +go tool cover -func=cover.out +stdout total.*statements.*0.0% + +-- cover.out -- diff --git a/src/cmd/go/testdata/script/cover_modes.txt b/src/cmd/go/testdata/script/cover_modes.txt new file mode 100644 index 0000000..f8a399d --- /dev/null +++ b/src/cmd/go/testdata/script/cover_modes.txt @@ -0,0 +1,25 @@ +env GO111MODULE=off + +# Coverage analysis should use 'set' mode by default, +# and should merge coverage profiles correctly. + +[short] skip +[gccgo] skip # gccgo has no cover tool + +go test -short -cover encoding/binary errors -coverprofile=$WORK/cover.out +! stderr '[^0-9]0\.0%' +! stdout '[^0-9]0\.0%' + +grep -count=1 '^mode: set$' $WORK/cover.out +grep 'errors\.go' $WORK/cover.out +grep 'binary\.go' $WORK/cover.out + +[!race] stop + +go test -short -race -cover encoding/binary errors -coverprofile=$WORK/cover.out +! stderr '[^0-9]0\.0%' +! stdout '[^0-9]0\.0%' + +grep -count=1 '^mode: atomic$' $WORK/cover.out +grep 'errors\.go' $WORK/cover.out +grep 'binary\.go' $WORK/cover.out diff --git a/src/cmd/go/testdata/script/cover_pattern.txt b/src/cmd/go/testdata/script/cover_pattern.txt new file mode 100644 index 0000000..ec0850c --- /dev/null +++ b/src/cmd/go/testdata/script/cover_pattern.txt @@ -0,0 +1,41 @@ +[gccgo] skip + +# If coverpkg=m/sleepy... expands by package loading +# (as opposed to pattern matching on deps) +# then it will try to load sleepybad, which does not compile, +# and the test command will fail. +! go list m/sleepy... +go test -c -n -coverprofile=$TMPDIR/cover.out -coverpkg=m/sleepy... -run=^$ m/sleepy1 + +-- go.mod -- +module m + +go 1.16 +-- sleepy1/p_test.go -- +package p + +import ( + "testing" + "time" +) + +func Test1(t *testing.T) { + time.Sleep(200 * time.Millisecond) +} +-- sleepy2/p_test.go -- +package p + +import ( + "testing" + "time" +) + +func Test1(t *testing.T) { + time.Sleep(200 * time.Millisecond) +} +-- sleepybad/p.go -- +package p + +import ^ + +var _ = io.DoesNotExist diff --git a/src/cmd/go/testdata/script/cover_pkgall_multiple_mains.txt b/src/cmd/go/testdata/script/cover_pkgall_multiple_mains.txt new file mode 100644 index 0000000..f21cd8b --- /dev/null +++ b/src/cmd/go/testdata/script/cover_pkgall_multiple_mains.txt @@ -0,0 +1,46 @@ +# This test checks that multiple main packages can be tested +# with -coverpkg=all without duplicate symbol errors. +# Verifies golang.org/issue/30374, golang.org/issue/34114. + +[short] skip +cd $GOPATH/src/example.com/cov + +env GO111MODULE=on +go test -coverpkg=all ./... + +env GO111MODULE=off +go test -coverpkg=all ./... + +-- $GOPATH/src/example.com/cov/go.mod -- +module example.com/cov + +-- $GOPATH/src/example.com/cov/mainonly/mainonly.go -- +package main + +func main() {} + +-- $GOPATH/src/example.com/cov/mainwithtest/mainwithtest.go -- +package main + +func main() {} + +func Foo() {} + +-- $GOPATH/src/example.com/cov/mainwithtest/mainwithtest_test.go -- +package main + +import "testing" + +func TestFoo(t *testing.T) { + Foo() +} + +-- $GOPATH/src/example.com/cov/xtest/x.go -- +package x + +-- $GOPATH/src/example.com/cov/xtest/x_test.go -- +package x_test + +import "testing" + +func TestX(t *testing.T) {} diff --git a/src/cmd/go/testdata/script/cover_pkgall_runtime.txt b/src/cmd/go/testdata/script/cover_pkgall_runtime.txt new file mode 100644 index 0000000..9927c30 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_pkgall_runtime.txt @@ -0,0 +1,23 @@ +env GO111MODULE=off + +# 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/src/cmd/go/testdata/script/cover_runs.txt b/src/cmd/go/testdata/script/cover_runs.txt new file mode 100644 index 0000000..38a7bb7 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_runs.txt @@ -0,0 +1,13 @@ +[gccgo] skip 'gccgo has no cover tool' +[short] skip + +go test -short -coverpkg=strings strings regexp +! stdout '[^0-9]0\.0%' +stdout 'strings.*coverage:.*[1-9][0-9.]+%' +stdout 'regexp.*coverage:.*[1-9][0-9.]+%' + +go test -short -cover strings math regexp +! stdout '[^0-9]0\.0%' +stdout 'strings.*coverage:.*[1-9][0-9.]+%' +stdout 'math.*coverage:.*[1-9][0-9.]+%' +stdout 'regexp.*coverage:.*[1-9][0-9.]+%' \ No newline at end of file diff --git a/src/cmd/go/testdata/script/cover_statements.txt b/src/cmd/go/testdata/script/cover_statements.txt new file mode 100644 index 0000000..4f3c9ca --- /dev/null +++ b/src/cmd/go/testdata/script/cover_statements.txt @@ -0,0 +1,61 @@ +[short] skip +go test -cover ./pkg1 ./pkg2 ./pkg3 ./pkg4 +stdout 'pkg1 \[no test files\]' +stdout 'pkg2 \S+ coverage: 0.0% of statements \[no tests to run\]' +stdout 'pkg3 \S+ coverage: 100.0% of statements' +stdout 'pkg4 \S+ coverage: \[no statements\]' + +-- go.mod -- +module m + +go 1.16 +-- pkg1/a.go -- +package pkg1 + +import "fmt" + +func F() { + fmt.Println("pkg1") +} +-- pkg2/a.go -- +package pkg2 + +import "fmt" + +func F() { + fmt.Println("pkg2") +} +-- pkg2/a_test.go -- +package pkg2 +-- pkg3/a.go -- +package pkg3 + +import "fmt" + +func F() { + fmt.Println("pkg3") +} +-- pkg3/a_test.go -- +package pkg3 + +import "testing" + +func TestF(t *testing.T) { + F() +} +-- pkg4/a.go -- +package pkg4 + +type T struct { + X bool +} +-- pkg4/a_test.go -- +package pkg4 + +import ( + "testing" +) + +func TestT(t *testing.T) { + _ = T{} +} diff --git a/src/cmd/go/testdata/script/cover_sync_atomic_import.txt b/src/cmd/go/testdata/script/cover_sync_atomic_import.txt new file mode 100644 index 0000000..433af9a --- /dev/null +++ b/src/cmd/go/testdata/script/cover_sync_atomic_import.txt @@ -0,0 +1,28 @@ +[short] skip +[gccgo] skip # gccgo has no cover tool + +go test -short -cover -covermode=atomic -coverpkg=coverdep/p1 coverdep + +-- go.mod -- +module coverdep + +go 1.16 +-- p.go -- +package p + +import _ "coverdep/p1" + +func F() { +} +-- p1/p1.go -- +package p1 + +import _ "errors" +-- p_test.go -- +package p + +import "testing" + +func Test(t *testing.T) { + F() +} diff --git a/src/cmd/go/testdata/script/cpu_profile_twice.txt b/src/cmd/go/testdata/script/cpu_profile_twice.txt new file mode 100644 index 0000000..38d6439 --- /dev/null +++ b/src/cmd/go/testdata/script/cpu_profile_twice.txt @@ -0,0 +1,22 @@ +env GO111MODULE=off + +# 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/src/cmd/go/testdata/script/devnull.txt b/src/cmd/go/testdata/script/devnull.txt new file mode 100644 index 0000000..ccb866a --- /dev/null +++ b/src/cmd/go/testdata/script/devnull.txt @@ -0,0 +1,26 @@ +env GO111MODULE=off + +# Issue 28035: go test -c -o NUL should work. +# Issue 28549: go test -c -o /dev/null should not overwrite /dev/null when run as root. +cd x +cmp $devnull $WORK/empty.txt +go test -o=$devnull -c +! exists x.test$GOEXE +cmp $devnull $WORK/empty.txt + +# Issue 12407: go build -o /dev/null should succeed. +cd .. +go build -o $devnull y +cmp $devnull $WORK/empty.txt + +-- x/x_test.go -- +package x_test +import ( + "testing" +) +func TestNUL(t *testing.T) { +} +-- y/y.go -- +package y +func main() {} +-- $WORK/empty.txt -- diff --git a/src/cmd/go/testdata/script/doc.txt b/src/cmd/go/testdata/script/doc.txt new file mode 100644 index 0000000..3ff1aab --- /dev/null +++ b/src/cmd/go/testdata/script/doc.txt @@ -0,0 +1,75 @@ +# go doc --help +! go doc --help +stderr 'go doc' +stderr 'go doc ' +stderr 'go doc \[\.\]' +stderr 'go doc \[\.\]\[\.\]' +stderr 'go doc \[\.\]\[\.\]' +stderr 'go doc \[\.\]' + +# go help doc +go help doc +stdout 'go doc' +stdout 'go doc ' +stdout 'go doc \[\.\]' +stdout 'go doc \[\.\]\[\.\]' +stdout 'go doc \[\.\]\[\.\]' +stdout 'go doc \[\.\]' + +# go doc +go doc p/v2 +stdout . + +# go doc +go doc p/v2 Symbol +stdout . + +# go doc +! go doc p/v2 Symbol Method +stderr . + +# go doc . +go doc p/v2.Symbol +stdout . + +# go doc .. +go doc p/v2.Symbol.Method +stdout . + +# go doc +go doc Symbol +stdout . + +# go doc +! go doc Symbol Method +stderr . + +# go doc . +go doc Symbol.Method +stdout . + +# go doc . +go doc p/v2.Method +stdout . + +# go doc +go doc p/v2 Method +stdout . + +# go doc +go doc Method +stdout . + +-- go.mod -- +module p/v2 + +go 1.13 + +-- p.go -- +package p + +type Symbol struct{} + +func (Symbol) Method() error { + return nil +} diff --git a/src/cmd/go/testdata/script/embed.txt b/src/cmd/go/testdata/script/embed.txt new file mode 100644 index 0000000..6ad42e9 --- /dev/null +++ b/src/cmd/go/testdata/script/embed.txt @@ -0,0 +1,109 @@ +# go list shows patterns and files +go list -f '{{.EmbedPatterns}}' +stdout '\[x\*t\*t\]' +go list -f '{{.EmbedFiles}}' +stdout '\[x.txt\]' +go list -test -f '{{.TestEmbedPatterns}}' +stdout '\[y\*t\*t\]' +go list -test -f '{{.TestEmbedFiles}}' +stdout '\[y.txt\]' +go list -test -f '{{.XTestEmbedPatterns}}' +stdout '\[z\*t\*t\]' +go list -test -f '{{.XTestEmbedFiles}}' +stdout '\[z.txt\]' + +# build embeds x.txt +go build -x +stderr 'x.txt' + +# build uses cache correctly +go build -x +! stderr 'x.txt' +cp x.txt2 x.txt +go build -x +stderr 'x.txt' + +# build rejects invalid names +cp x.go2 x.go +go build -x +cp x.txt .git +! go build -x +stderr '^x.go:5:12: pattern [*]t: cannot embed file [.]git: invalid name [.]git$' +rm .git + +# build rejects symlinks +[symlink] symlink x.tzt -> x.txt +[symlink] ! go build -x +[symlink] stderr 'pattern [*]t: cannot embed irregular file x.tzt' +[symlink] rm x.tzt + +# build rejects empty directories +mkdir t +! go build -x +stderr '^x.go:5:12: pattern [*]t: cannot embed directory t: contains no embeddable files$' + +# build ignores symlinks and invalid names in directories +cp x.txt t/.git +! go build -x +stderr '^x.go:5:12: pattern [*]t: cannot embed directory t: contains no embeddable files$' +go list -e -f '{{.Incomplete}}' +stdout 'true' +[symlink] symlink t/x.link -> ../x.txt +[symlink] ! go build -x +[symlink] stderr '^x.go:5:12: pattern [*]t: cannot embed directory t: contains no embeddable files$' + +cp x.txt t/x.txt +go build -x + +# build reports errors with positions in imported packages +rm t/x.txt +! go build m/use +stderr '^x.go:5:12: pattern [*]t: cannot embed directory t: contains no embeddable files$' + +-- x.go -- +package p + +import "embed" + +//go:embed x*t*t +var X embed.FS + +-- x_test.go -- +package p + +import "embed" + +//go:embed y*t*t +var Y string + +-- x_x_test.go -- +package p_test + +import "embed" + +//go:embed z*t*t +var Z string + +-- x.go2 -- +package p + +import "embed" + +//go:embed *t +var X embed.FS + +-- x.txt -- +hello + +-- y.txt -- +-- z.txt -- +-- x.txt2 -- +not hello + +-- use/use.go -- +package use + +import _ "m" +-- go.mod -- +module m + diff --git a/src/cmd/go/testdata/script/embed_fmt.txt b/src/cmd/go/testdata/script/embed_fmt.txt new file mode 100644 index 0000000..8a16afe --- /dev/null +++ b/src/cmd/go/testdata/script/embed_fmt.txt @@ -0,0 +1,22 @@ +# go fmt ignores file not found +go fmt xnofmt.go +cmp xnofmt.go xfmt.ref +! go build xnofmt.go +stderr 'xnofmt.go:5:12: pattern missing.txt: no matching files found' + +-- xnofmt.go -- +package p + +import "embed" + +//go:embed missing.txt +var X embed.FS +-- xfmt.ref -- +package p + +import "embed" + +//go:embed missing.txt +var X embed.FS +-- go.mod -- +module m diff --git a/src/cmd/go/testdata/script/env_write.txt b/src/cmd/go/testdata/script/env_write.txt new file mode 100644 index 0000000..bda1e57 --- /dev/null +++ b/src/cmd/go/testdata/script/env_write.txt @@ -0,0 +1,175 @@ +env GO111MODULE=off + +# go env should default to the right places +env AppData=$HOME/windowsappdata +env home=$HOME/plan9home +go env GOENV +[aix] stdout $HOME/.config/go/env +[darwin] stdout $HOME'/Library/Application Support/go/env' +[freebsd] stdout $HOME/.config/go/env +[linux] stdout $HOME/.config/go/env +[netbsd] stdout $HOME/.config/go/env +[openbsd] stdout $HOME/.config/go/env +[plan9] stdout $HOME/plan9home/lib/go/env +[windows] stdout $HOME\\windowsappdata\\go\\env + +# Now override it to something writable. +env GOENV=$WORK/envdir/go/env +go env GOENV +stdout envdir[\\/]go[\\/]env + +# go env shows all variables +go env +stdout GOARCH= +stdout GOOS= +stdout GOROOT= + +# go env ignores invalid flag in GOFLAGS environment variable +env GOFLAGS='=true' +go env + +# checking errors +! go env -w +stderr 'go env -w: no KEY=VALUE arguments given' +! go env -u +stderr 'go env -u: no arguments given' + +# go env -w changes default setting +env root= +[windows] env root=c: +env GOPATH= +go env -w GOPATH=$root/non-exist/gopath +! stderr .+ +grep GOPATH=$root/non-exist/gopath $WORK/envdir/go/env +go env GOPATH +stdout /non-exist/gopath + +# go env -w does not override OS environment, and warns about that +env GOPATH=$root/other +go env -w GOPATH=$root/non-exist/gopath2 +stderr 'warning: go env -w GOPATH=... does not override conflicting OS environment variable' +go env GOPATH +stdout $root/other + +# but go env -w does do the update, and unsetting the env var exposes the change +env GOPATH= +go env GOPATH +stdout $root/non-exist/gopath2 + +# unsetting with go env -u does not warn about OS environment overrides, +# nor does it warn about variables that haven't been set by go env -w. +env GOPATH=$root/other +go env -u GOPATH +! stderr .+ +go env -u GOPATH +! stderr .+ + +# go env -w rejects unknown or bad variables +! go env -w GODEBUG=gctrace=1 +stderr 'unknown go command variable GODEBUG' +! go env -w GOEXE=.bat +stderr 'GOEXE cannot be modified' +! go env -w GOVERSION=customversion +stderr 'GOVERSION cannot be modified' +! go env -w GOENV=/env +stderr 'GOENV can only be set using the OS environment' + +# go env -w can set multiple variables +env CC= +go env CC +! stdout ^xyc$ +go env -w GOOS=$GOOS CC=xyc +grep CC=xyc $GOENV +# file is maintained in sorted order +grep 'CC=xyc\nGOOS=' $GOENV +go env CC +stdout ^xyc$ + +# go env -u unsets effect of go env -w. +go env -u CC +go env CC +! stdout ^xyc$ + +# go env -w rejects double-set variables +! go env -w GOOS=$GOOS GOOS=$GOOS +stderr 'multiple values for key: GOOS' + +# go env -w rejects missing variables +! go env -w GOOS +stderr 'arguments must be KEY=VALUE: invalid argument: GOOS' + +# go env -w rejects invalid GO111MODULE values, as otherwise cmd/go would break +! go env -w GO111MODULE=badvalue +stderr 'invalid GO111MODULE value "badvalue"' + +# go env -w rejects invalid GOPATH values +! go env -w GOPATH=~/go +stderr 'GOPATH entry cannot start with shell metacharacter' + +! go env -w GOPATH=./go +stderr 'GOPATH entry is relative; must be absolute path' + +# go env -w rejects invalid GOTMPDIR values +! go env -w GOTMPDIR=x +stderr 'go env -w: GOTMPDIR must be an absolute path' + +# go env -w should accept absolute GOTMPDIR value +# and should not create it +[windows] go env -w GOTMPDIR=$WORK\x\y\z +[!windows] go env -w GOTMPDIR=$WORK/x/y/z +! exists $WORK/x/y/z +# we should be able to clear an env +go env -u GOTMPDIR +go env GOTMPDIR +stdout ^$ + +[windows] go env -w GOTMPDIR=$WORK\x\y\z +[!windows] go env -w GOTMPDIR=$WORK/x/y/z +go env -w GOTMPDIR= +go env GOTMPDIR +stdout ^$ + +# go env -w rejects relative CC values +[!windows] go env -w CC=/usr/bin/clang +go env -w CC=clang +[!windows] ! go env -w CC=./clang +[!windows] ! go env -w CC=bin/clang +[!windows] stderr 'go env -w: CC entry is relative; must be absolute path' + +[windows] go env -w CC=$WORK\bin\clang +[windows] ! go env -w CC=.\clang +[windows] ! go env -w CC=bin\clang +[windows] stderr 'go env -w: CC entry is relative; must be absolute path' + +# go env -w rejects relative CXX values +[!windows] go env -w CC=/usr/bin/cpp +go env -w CXX=cpp +[!windows] ! go env -w CXX=./cpp +[!windows] ! go env -w CXX=bin/cpp +[!windows] stderr 'go env -w: CXX entry is relative; must be absolute path' + +[windows] go env -w CXX=$WORK\bin\cpp +[windows] ! go env -w CXX=.\cpp +[windows] ! go env -w CXX=bin\cpp +[windows] stderr 'go env -w: CXX entry is relative; must be absolute path' + +# go env -w/-u checks validity of GOOS/ARCH combinations +env GOOS= +env GOARCH= +# check -w doesn't allow invalid GOOS +! go env -w GOOS=linuxx +stderr 'unsupported GOOS/GOARCH pair linuxx' +# check -w doesn't allow invalid GOARCH +! go env -w GOARCH=amd644 +stderr 'unsupported GOOS/GOARCH.*/amd644$' +# check -w doesn't allow invalid GOOS with valid GOARCH +! go env -w GOOS=linuxx GOARCH=amd64 +stderr 'unsupported GOOS/GOARCH pair linuxx' +# check a valid GOOS and GOARCH values but an incompatible combinations +! go env -w GOOS=android GOARCH=s390x +stderr 'unsupported GOOS/GOARCH pair android/s390x' +# check that -u considers explicit envs +go env -w GOOS=linux GOARCH=mips +env GOOS=windows +! go env -u GOOS +stderr 'unsupported GOOS/GOARCH.*windows/mips$' diff --git a/src/cmd/go/testdata/script/fileline.txt b/src/cmd/go/testdata/script/fileline.txt new file mode 100644 index 0000000..5cb35f0 --- /dev/null +++ b/src/cmd/go/testdata/script/fileline.txt @@ -0,0 +1,8 @@ +env GO111MODULE=off + +# 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/src/cmd/go/testdata/script/fmt_load_errors.txt b/src/cmd/go/testdata/script/fmt_load_errors.txt new file mode 100644 index 0000000..297ec0f --- /dev/null +++ b/src/cmd/go/testdata/script/fmt_load_errors.txt @@ -0,0 +1,19 @@ +env GO111MODULE=off + +! go fmt does-not-exist + +go fmt -n exclude +stdout 'exclude[/\\]x\.go' +stdout 'exclude[/\\]x_linux\.go' + +-- exclude/empty/x.txt -- +-- exclude/ignore/_x.go -- +package x +-- exclude/x.go -- +// +build linux,!linux + +package x +-- exclude/x_linux.go -- +// +build windows + +package x diff --git a/src/cmd/go/testdata/script/gccgo_link_c.txt b/src/cmd/go/testdata/script/gccgo_link_c.txt new file mode 100644 index 0000000..422adea --- /dev/null +++ b/src/cmd/go/testdata/script/gccgo_link_c.txt @@ -0,0 +1,16 @@ +# Issue #7573 +# cmd/cgo: undefined reference when linking a C-library using gccgo + +[!cgo] skip +[!gccgo] skip + +go build -r -compiler gccgo cgoref +stderr 'gccgo.*\-L [^ ]*alibpath \-lalib' # make sure that Go-inline "#cgo LDFLAGS:" ("-L alibpath -lalib") passed to gccgo linking stage + +-- cgoref/cgoref.go -- +package main +// #cgo LDFLAGS: -L alibpath -lalib +// void f(void) {} +import "C" + +func main() { C.f() } \ No newline at end of file diff --git a/src/cmd/go/testdata/script/gccgo_m.txt b/src/cmd/go/testdata/script/gccgo_m.txt new file mode 100644 index 0000000..b63ba46 --- /dev/null +++ b/src/cmd/go/testdata/script/gccgo_m.txt @@ -0,0 +1,19 @@ +# It's absurd, but builds with -compiler=gccgo used to fail to build module m. +# golang.org/issue/34358 + +env GO111MODULE=off + +[short] skip + +cd m +go build +exists m$GOEXE +rm m$GOEXE +[exec:gccgo] go build -compiler=gccgo +[exec:gccgo] exists m$GOEXE + +-- m/go.mod -- +module m +-- m/main.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/gccgo_mangle.txt b/src/cmd/go/testdata/script/gccgo_mangle.txt new file mode 100644 index 0000000..7a09a80 --- /dev/null +++ b/src/cmd/go/testdata/script/gccgo_mangle.txt @@ -0,0 +1,15 @@ +# Issue 33871. + +cd m/a.0 +go build + +-- m/go.mod -- +module m +-- m/a.0/a.go -- +package a + +type T int + +func (t T) M() int { + return int(t) +} diff --git a/src/cmd/go/testdata/script/gcflags_patterns.txt b/src/cmd/go/testdata/script/gcflags_patterns.txt new file mode 100644 index 0000000..f23cece --- /dev/null +++ b/src/cmd/go/testdata/script/gcflags_patterns.txt @@ -0,0 +1,92 @@ +env GO111MODULE=off + +[!gc] skip 'using -gcflags and -ldflags' +[short] skip + +env GOCACHE=$WORK/gocache # Looking for compile commands, so need a clean cache. + +# -gcflags=-e applies to named packages, not dependencies +go build -n -v -gcflags=-e z1 z2 +stderr 'compile.* -e.* -p z1' +stderr 'compile.* -e.* -p z2' +stderr 'compile.* -p y' +! stderr 'compile.* -e.* -p [^z]' + +# -gcflags can specify package=flags, and can be repeated; last match wins +go build -n -v -gcflags=-e -gcflags=z1=-N z1 z2 +stderr 'compile.* -N.* -p z1' +! stderr 'compile.* -e.* -p z1' +! stderr 'compile.* -N.* -p z2' +stderr 'compile.* -e.* -p z2' +stderr 'compile.* -p y' +! stderr 'compile.* -e.* -p [^z]' +! stderr 'compile.* -N.* -p [^z]' + +# -gcflags can have arbitrary spaces around the flags +go build -n -v -gcflags=' z1 = -e ' z1 +stderr 'compile.* -e.* -p z1' + +# -gcflags='all=-e' should apply to all packages, even with go test +go test -c -n -gcflags='all=-e' z1 +stderr 'compile.* -e.* -p z3 ' + +# this particular -gcflags argument made the compiler crash +! go build -gcflags=-d=ssa/ z1 +stderr 'PhaseOptions usage' + +# -ldflags for implicit test package applies to test binary +go test -c -n -gcflags=-N -ldflags=-X=x.y=z z1 +stderr 'compile.* -N .*z_test.go' +stderr 'link.* -X=x.y=z' + +# -ldflags for explicit test package applies to test binary +go test -c -n -gcflags=z1=-N -ldflags=z1=-X=x.y=z z1 +stderr 'compile.* -N .*z_test.go' +stderr 'link.* -X=x.y=z' + +# -ldflags applies to link of command +go build -n -ldflags=-X=math.pi=3 my/cmd/prog +stderr 'link.* -X=math.pi=3' + +# -ldflags applies to link of command even with strange directory name +go build -n -ldflags=-X=math.pi=3 my/cmd/prog/ +stderr 'link.* -X=math.pi=3' + +# -ldflags applies to current directory +cd my/cmd/prog +go build -n -ldflags=-X=math.pi=3 +stderr 'link.* -X=math.pi=3' + +# -ldflags applies to current directory even if GOPATH is funny +[windows] cd $WORK/GoPath/src/my/cmd/prog +[darwin] cd $WORK/GoPath/src/my/cmd/prog +go build -n -ldflags=-X=math.pi=3 +stderr 'link.* -X=math.pi=3' + +# cgo.a should not be a dependency of internally-linked go package +go build -ldflags='-linkmode=external -linkmode=internal' -n prog.go +! stderr 'packagefile .*runtime/cgo.a' + +-- z1/z.go -- +package z1 +import _ "y" +import _ "z2" + +-- z1/z_test.go -- +package z1_test +import "testing" +import _ "z3" +func Test(t *testing.T) {} + +-- z2/z.go -- +package z2 + +-- z3/z.go -- +package z3 + +-- y/y.go -- +package y + +-- my/cmd/prog/prog.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/generate.txt b/src/cmd/go/testdata/script/generate.txt new file mode 100644 index 0000000..c3c563e --- /dev/null +++ b/src/cmd/go/testdata/script/generate.txt @@ -0,0 +1,91 @@ +[short] skip + +# Install an echo command because Windows doesn't have it. +env GOBIN=$WORK/tmp/bin +go install echo.go +env PATH=$GOBIN${:}$PATH + +# Test go generate handles a simple command +go generate ./generate/simple.go +stdout 'Success' + +# Test go generate handles a command alias +go generate './generate/alias.go' +stdout 'Now is the time for all good men' + +# Test go generate's variable substitution +go generate './generate/substitution.go' +stdout $GOARCH' substitution.go:7 pabc xyzp/substitution.go/123' + +# Test go generate's run flag +go generate -run y.s './generate/flag.go' +stdout 'yes' # flag.go should select yes +! stdout 'no' # flag.go should not select no + +# Test go generate provides the right "$GOPACKAGE" name in an x_test +go generate './generate/env_test.go' +stdout 'main_test' + +-- echo.go -- +package main + +import ( + "fmt" + "os" + "strings" +) + +func main() { + fmt.Println(strings.Join(os.Args[1:], " ")) + fmt.Println() +} +-- generate/simple.go -- +// Copyright 2014 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. + +// Simple test for go generate. + +// We include a build tag that go generate should ignore. + +// +build ignore + +//go:generate echo Success + +package p +-- generate/alias.go -- +// Copyright 2014 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. + +// Test that go generate handles command aliases. + +//go:generate -command run echo Now is the time +//go:generate run for all good men + +package p +-- generate/substitution.go -- +// Copyright 2014 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. + +// Test go generate variable substitution. + +//go:generate echo $GOARCH $GOFILE:$GOLINE ${GOPACKAGE}abc xyz$GOPACKAGE/$GOFILE/123 + +package p +-- generate/flag.go -- +// Copyright 2015 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. + +// Test -run flag + +//go:generate echo oh yes my man +//go:generate echo no, no, a thousand times no + +package p +-- generate/env_test.go -- +package main_test + +//go:generate echo $GOPACKAGE \ No newline at end of file diff --git a/src/cmd/go/testdata/script/generate_bad_imports.txt b/src/cmd/go/testdata/script/generate_bad_imports.txt new file mode 100644 index 0000000..4d31573 --- /dev/null +++ b/src/cmd/go/testdata/script/generate_bad_imports.txt @@ -0,0 +1,15 @@ +[windows] skip # skip because windows has no echo command + +go generate gencycle +stdout 'hello world' # check go generate gencycle ran the generator + +-- go.mod -- +module gencycle + +go 1.16 +-- gencycle.go -- +//go:generate echo hello world + +package gencycle + +import _ "gencycle" diff --git a/src/cmd/go/testdata/script/generate_env.txt b/src/cmd/go/testdata/script/generate_env.txt new file mode 100644 index 0000000..2df1663 --- /dev/null +++ b/src/cmd/go/testdata/script/generate_env.txt @@ -0,0 +1,32 @@ +# Install an env command because Windows and plan9 don't have it. +env GOBIN=$WORK/tmp/bin +go install env.go +[plan9] env path=$GOBIN${:}$path +[!plan9] env PATH=$GOBIN${:}$PATH + +# Test generators have access to the environment +go generate ./printenv.go +stdout '^GOARCH='$GOARCH +stdout '^GOOS='$GOOS +stdout '^GOFILE=' +stdout '^GOLINE=' +stdout '^GOPACKAGE=' +stdout '^DOLLAR=' + +-- env.go -- +package main + +import ( + "fmt" + "os" +) + +func main() { + for _, v := range os.Environ() { + fmt.Println(v) + } +} +-- printenv.go -- +package main + +//go:generate env \ No newline at end of file diff --git a/src/cmd/go/testdata/script/generate_invalid.txt b/src/cmd/go/testdata/script/generate_invalid.txt new file mode 100644 index 0000000..e18e62c --- /dev/null +++ b/src/cmd/go/testdata/script/generate_invalid.txt @@ -0,0 +1,203 @@ +[short] skip + +# Install an echo command because Windows doesn't have it. +env GOBIN=$WORK/tmp/bin +go install echo.go +env PATH=$GOBIN${:}$PATH + +# Test go generate for directory with no go files +go generate ./nogo +! stdout 'Fail' + +# Test go generate for package where all .go files are excluded by build +# constraints +go generate -v ./excluded +! stdout 'Fail' +! stderr 'go' # -v shouldn't list any files + +# Test go generate for "package" with no package clause in any file +go generate ./nopkg +stdout 'Success a' +! stdout 'Fail' + +# Test go generate for package with inconsistent package clauses +# $GOPACKAGE should depend on each file's package clause +go generate ./inconsistent +stdout 'Success a' +stdout 'Success b' +stdout -count=2 'Success c' +! stdout 'Fail' + +# Test go generate for syntax errors before and after package clauses +go generate ./syntax +stdout 'Success a' +stdout 'Success b' +! stdout 'Fail' + +# Test go generate for files importing non-existent packages +go generate ./importerr +stdout 'Success a' +stdout 'Success b' +stdout 'Success c' + +-- echo.go -- +package main + +import ( + "fmt" + "os" + "strings" +) + +func main() { + fmt.Println(strings.Join(os.Args[1:], " ")) + fmt.Println() +} + +-- go.mod -- +module m + +go 1.16 +-- nogo/foo.txt -- +Text file in a directory without go files. +Go generate should ignore this directory. +//go:generate echo Fail nogo + +-- excluded/a.go -- +// Include a build tag that go generate should exclude. +// Go generate should ignore this file. + +// +build a + +//go:generate echo Fail a + +package excluded + +-- excluded/b.go -- +// Include a build tag that go generate should exclude. +// Go generate should ignore this file. + +//go:generate echo Fail b + +// +build b + +package excluded + + +-- nopkg/a.go -- +// Go file with package clause after comment. +// Go generate should process this file. + +/* Pre-comment */ package nopkg +//go:generate echo Success a + +-- nopkg/b.go -- +// Go file with commented package clause. +// Go generate should ignore this file. + +//package nopkg + +//go:generate echo Fail b + +-- nopkg/c.go -- +// Go file with package clause inside multiline comment. +// Go generate should ignore this file. + +/* +package nopkg +*/ + +//go:generate echo Fail c + +-- nopkg/d.go -- +// Go file with package clause inside raw string literal. +// Go generate should ignore this file. + +const foo = ` +package nopkg +` +//go:generate echo Fail d + +-- nopkg/e.go -- +// Go file without package clause. +// Go generate should ignore this file. + +//go:generate echo Fail e + +-- inconsistent/a.go -- +// Valid go file with inconsistent package name. +// Go generate should process this file with GOPACKAGE=a + +package a +//go:generate echo Success $GOPACKAGE + +-- inconsistent/b.go -- +// Valid go file with inconsistent package name. +// Go generate should process this file with GOPACKAGE=b + +//go:generate echo Success $GOPACKAGE +package b + +-- inconsistent/c.go -- +// Go file with two package clauses. +// Go generate should process this file with GOPACKAGE=c + +//go:generate echo Success $GOPACKAGE +package c +// Invalid package clause, should be ignored: +package cinvalid +//go:generate echo Success $GOPACKAGE + +-- inconsistent/d.go -- +// Go file with invalid package name. +// Go generate should ignore this file. + +package +d+ +//go:generate echo Fail $GOPACKAGE + +-- syntax/a.go -- +// Go file with syntax error after package clause. +// Go generate should process this file. + +package syntax +123 +//go:generate echo Success a + +-- syntax/b.go -- +// Go file with syntax error after package clause. +// Go generate should process this file. + +package syntax; 123 +//go:generate echo Success b + +-- syntax/c.go -- +// Go file with syntax error before package clause. +// Go generate should ignore this file. + +foo +package syntax +//go:generate echo Fail c + +-- importerr/a.go -- +// Go file which imports non-existing package. +// Go generate should process this file. + +package importerr +//go:generate echo Success a +import "foo" + +-- importerr/b.go -- +// Go file which imports non-existing package. +// Go generate should process this file. + +//go:generate echo Success b +package importerr +import "bar" + +-- importerr/c.go -- +// Go file which imports non-existing package. +// Go generate should process this file. + +package importerr +import "moo" +//go:generate echo Success c diff --git a/src/cmd/go/testdata/script/get_404_meta.txt b/src/cmd/go/testdata/script/get_404_meta.txt new file mode 100644 index 0000000..b71cc7f --- /dev/null +++ b/src/cmd/go/testdata/script/get_404_meta.txt @@ -0,0 +1,11 @@ +# golang.org/issue/13037: 'go get' was not parsing tags in 404 served over HTTPS. + +[!net] skip +[!exec:git] skip + +env GO111MODULE=off +go get -d -insecure bazil.org/fuse/fs/fstestutil + +env GO111MODULE=on +env GOPROXY=direct +go get -d -insecure bazil.org/fuse/fs/fstestutil diff --git a/src/cmd/go/testdata/script/get_brace.txt b/src/cmd/go/testdata/script/get_brace.txt new file mode 100644 index 0000000..3449a0c --- /dev/null +++ b/src/cmd/go/testdata/script/get_brace.txt @@ -0,0 +1,51 @@ +env GO111MODULE=off + +[!exec:git] skip + +# Set up some empty repositories. +cd $WORK/_origin/foo +exec git init +exec git config user.name 'Nameless Gopher' +exec git config user.email 'nobody@golang.org' +exec git commit --allow-empty -m 'create master branch' + +cd $WORK +cd '_origin/{confusing}' +exec git init +exec git config user.name 'Nameless Gopher' +exec git config user.email 'nobody@golang.org' +exec git commit --allow-empty -m 'create master branch' + +# Clone the empty repositories into GOPATH. +# This tells the Go command where to find them: it takes the place of a user's meta-tag redirector. +mkdir $GOPATH/src/example.com +cd $GOPATH/src/example.com +exec git clone $WORK/_origin/foo +exec git clone $WORK/_origin/{confusing} + +# Commit contents to the repositories. +cd $WORK/_origin/foo +exec git add main.go +exec git commit -m 'add main' + +cd $WORK +cd '_origin/{confusing}' +exec git add confusing.go +exec git commit -m 'just try to delete this!' + +# 'go get' should refuse to download or update the confusingly-named repo. +cd $GOPATH/src/example.com/foo +! go get -u 'example.com/{confusing}' +stderr 'invalid char' +! go get -u example.com/foo +stderr 'invalid import path' +! exists example.com/{confusing} + +-- $WORK/_origin/foo/main.go -- +package main +import _ "example.com/{confusing}" + +func main() {} + +-- $WORK/_origin/{confusing}/confusing.go -- +package confusing diff --git a/src/cmd/go/testdata/script/get_custom_domain_wildcard.txt b/src/cmd/go/testdata/script/get_custom_domain_wildcard.txt new file mode 100644 index 0000000..cda25e1 --- /dev/null +++ b/src/cmd/go/testdata/script/get_custom_domain_wildcard.txt @@ -0,0 +1,6 @@ +[!net] skip +[!exec:git] skip +env GO111MODULE=off + +go get -u rsc.io/pdf/... +exists $GOPATH/bin/pdfpasswd$GOEXE diff --git a/src/cmd/go/testdata/script/get_dash_t.txt b/src/cmd/go/testdata/script/get_dash_t.txt new file mode 100644 index 0000000..baac916 --- /dev/null +++ b/src/cmd/go/testdata/script/get_dash_t.txt @@ -0,0 +1,9 @@ +# Tests issue 8181 + +[!net] skip +[!exec:git] skip +env GO111MODULE=off + +go get -v -t github.com/rsc/go-get-issue-8181/a github.com/rsc/go-get-issue-8181/b +go list ... +stdout 'x/build/gerrit' diff --git a/src/cmd/go/testdata/script/get_domain_root.txt b/src/cmd/go/testdata/script/get_domain_root.txt new file mode 100644 index 0000000..9187848 --- /dev/null +++ b/src/cmd/go/testdata/script/get_domain_root.txt @@ -0,0 +1,20 @@ +# Tests issue #9357 +# go get foo.io (not foo.io/subdir) was not working consistently. + +[!net] skip +[!exec:git] skip +env GO111MODULE=off + +# go-get-issue-9357.appspot.com is running +# the code at github.com/rsc/go-get-issue-9357, +# a trivial Go on App Engine app that serves a +# tag for the domain root. +go get -d go-get-issue-9357.appspot.com +go get go-get-issue-9357.appspot.com +go get -u go-get-issue-9357.appspot.com + +rm $GOPATH/src/go-get-issue-9357.appspot.com +go get go-get-issue-9357.appspot.com + +rm $GOPATH/src/go-get-issue-9357.appspot.com +go get -u go-get-issue-9357.appspot.com diff --git a/src/cmd/go/testdata/script/get_dot_slash_download.txt b/src/cmd/go/testdata/script/get_dot_slash_download.txt new file mode 100644 index 0000000..dbaf46c --- /dev/null +++ b/src/cmd/go/testdata/script/get_dot_slash_download.txt @@ -0,0 +1,10 @@ +[!net] skip +[!exec:git] skip +env GO111MODULE=off + +# Tests Issues #9797 and #19769 + +mkdir $WORK/tmp/src/rsc.io +env GOPATH=$WORK/tmp +cd $WORK/tmp/src/rsc.io +go get ./pprof_mac_fix diff --git a/src/cmd/go/testdata/script/get_dotfiles.txt b/src/cmd/go/testdata/script/get_dotfiles.txt new file mode 100644 index 0000000..6757f9d --- /dev/null +++ b/src/cmd/go/testdata/script/get_dotfiles.txt @@ -0,0 +1,64 @@ +env GO111MODULE=off +[short] skip + +[!exec:git] skip + +# Set up a benign repository and a repository with a dotfile name. +cd $WORK/_origin/foo +exec git init +exec git config user.name 'Nameless Gopher' +exec git config user.email 'nobody@golang.org' +exec git commit --allow-empty -m 'create master branch' + +cd $WORK/_origin/.hidden +exec git init +exec git config user.name 'Nameless Gopher' +exec git config user.email 'nobody@golang.org' +exec git commit --allow-empty -m 'create master branch' + +# Clone the empty repositories into GOPATH. +# This tells the Go command where to find them: it takes the place of a user's meta-tag redirector. +mkdir $GOPATH/src/example.com +cd $GOPATH/src/example.com +exec git clone $WORK/_origin/foo +exec git clone $WORK/_origin/.hidden + +# Add a benign commit. +cd $WORK/_origin/foo +cp _ok/main.go main.go +exec git add main.go +exec git commit -m 'add ok' + +# 'go get' should install the benign commit. +cd $GOPATH +go get -u example.com/foo + +# Now sneak in an import of a dotfile path. +cd $WORK/_origin/.hidden +exec git add hidden.go +exec git commit -m 'nothing to see here, move along' + +cd $WORK/_origin/foo +cp _sneaky/main.go main.go +exec git add main.go +exec git commit -m 'fix typo (heh heh heh)' + +# 'go get -u' should refuse to download or update the dotfile-named repo. +cd $GOPATH/src/example.com/foo +! go get -u example.com/foo +stderr 'leading dot' +! exists example.com/.hidden/hidden.go + +-- $WORK/_origin/foo/_ok/main.go -- +package main + +func main() {} + +-- $WORK/_origin/foo/_sneaky/main.go -- +package main +import _ "example.com/.hidden" + +func main() {} + +-- $WORK/_origin/.hidden/hidden.go -- +package hidden diff --git a/src/cmd/go/testdata/script/get_go_file.txt b/src/cmd/go/testdata/script/get_go_file.txt new file mode 100644 index 0000000..bed8720 --- /dev/null +++ b/src/cmd/go/testdata/script/get_go_file.txt @@ -0,0 +1,60 @@ +# Tests Issue #38478 +# Tests that go get in GOPATH mode returns a specific error if the argument +# ends with '.go', and either has no slash or refers to an existing file. + +env GO111MODULE=off + +# argument doesn't have .go suffix +go get -d test + +# argument has .go suffix, is a file and exists +! go get -d test.go +stderr 'go get test.go: arguments must be package or module paths' + +# argument has .go suffix, doesn't exist and has no slashes +! go get -d test_missing.go +stderr 'go get test_missing.go: arguments must be package or module paths' + +# argument has .go suffix, is a file and exists in sub-directory +! go get -d test/test.go +stderr 'go get: test/test.go exists as a file, but ''go get'' requires package arguments' + +# argument has .go suffix, doesn't exist and has slashes +! go get -d test/test_missing.go +! stderr 'arguments must be package or module paths' +! stderr 'exists as a file, but ''go get'' requires package arguments' + +# argument has .go suffix, is a symlink and exists +[symlink] symlink test_sym.go -> test.go +[symlink] ! go get -d test_sym.go +[symlink] stderr 'go get test_sym.go: arguments must be package or module paths' +[symlink] rm test_sym.go + +# argument has .go suffix, is a symlink and exists in sub-directory +[symlink] symlink test/test_sym.go -> test.go +[symlink] ! go get -d test/test_sym.go +[symlink] stderr 'go get: test/test_sym.go exists as a file, but ''go get'' requires package arguments' +[symlink] rm test_sym.go + +# argument has .go suffix, is a directory and exists +mkdir test_dir.go +! go get -d test_dir.go +stderr 'go get test_dir.go: arguments must be package or module paths' +rm test_dir.go + +# argument has .go suffix, is a directory and exists in sub-directory +mkdir test/test_dir.go +! go get -d test/test_dir.go +! stderr 'arguments must be package or module paths' +! stderr 'exists as a file, but ''go get'' requires package arguments' +rm test/test_dir.go + + +-- test.go -- +package main +func main() {println("test")} + + +-- test/test.go -- +package main +func main() {println("test")} diff --git a/src/cmd/go/testdata/script/get_goroot.txt b/src/cmd/go/testdata/script/get_goroot.txt new file mode 100644 index 0000000..929435a --- /dev/null +++ b/src/cmd/go/testdata/script/get_goroot.txt @@ -0,0 +1,53 @@ +[!net] skip +env GO111MODULE=off + +# Issue 4186. go get cannot be used to download packages to $GOROOT. +# Test that without GOPATH set, go get should fail. + +# Fails because GOROOT=GOPATH +env GOPATH=$WORK/tmp +env GOROOT=$WORK/tmp +! go get -d github.com/golang/example/hello +stderr 'warning: GOPATH set to GOROOT' +stderr '\$GOPATH must not be set to \$GOROOT' + +# Fails because GOROOT=GOPATH after cleaning. +env GOPATH=$WORK/tmp/ +env GOROOT=$WORK/tmp +! go get -d github.com/golang/example/hello +stderr 'warning: GOPATH set to GOROOT' +stderr '\$GOPATH must not be set to \$GOROOT' + +env GOPATH=$WORK/tmp +env GOROOT=$WORK/tmp/ +! go get -d github.com/golang/example/hello +stderr 'warning: GOPATH set to GOROOT' +stderr '\$GOPATH must not be set to \$GOROOT' + +# Make a home directory +mkdir $WORK/home/go + +# Fails because GOROOT=$HOME/go so default GOPATH unset. +[windows] env USERPROFILE=$WORK/home +[plan9] env home=$WORK/home +[!windows] [!plan9] env HOME=$WORK/home +env GOPATH= +env GOROOT=$WORK/home/go +! go get -d github.com/golang/example/hello +stderr '\$GOPATH not set' + +[windows] env USERPROFILE=$WORK/home/ +[plan9] env home=$WORK/home/ +[!windows] [!plan9] env HOME=$WORK/home/ +env GOPATH= +env GOROOT=$WORK/home/go +! go get -d github.com/golang/example/hello +stderr '\$GOPATH not set' + +[windows] env USERPROFILE=$WORK/home +[plan9] env home=$WORK/home +[!windows] [!plan9] env HOME=$WORK/home +env GOPATH= +env GOROOT=$WORK/home/go/ +! go get -d github.com/golang/example/hello +stderr '\$GOPATH not set' diff --git a/src/cmd/go/testdata/script/get_insecure.txt b/src/cmd/go/testdata/script/get_insecure.txt new file mode 100644 index 0000000..36ad2c0 --- /dev/null +++ b/src/cmd/go/testdata/script/get_insecure.txt @@ -0,0 +1,51 @@ +# TODO(matloob): Split this test into two? It's one of the slowest tests we have. + +[!net] skip +[!exec:git] skip + +env PATH=$WORK/tmp/bin${:}$PATH +go build -o $WORK/tmp/bin/ssh ssh.go + +# GOPATH: Set up +env GO111MODULE=off + +# GOPATH: Try go get -d of HTTP-only repo (should fail). +! go get -d insecure.go-get-issue-15410.appspot.com/pkg/p + +# GOPATH: Try again with -insecure (should succeed). +go get -d -insecure insecure.go-get-issue-15410.appspot.com/pkg/p + +# GOPATH: Try updating without -insecure (should fail). +! go get -d -u -f insecure.go-get-issue-15410.appspot.com/pkg/p + +# Modules: Set up +env GOPATH=$WORK/m/gp +mkdir $WORK/m +cp module_file $WORK/m/go.mod +cd $WORK/m +env GO111MODULE=on +env GOPROXY='' + +# Modules: Try go get -d of HTTP-only repo (should fail). +! go get -d insecure.go-get-issue-15410.appspot.com/pkg/p + +# Modules: Try again with -insecure (should succeed). +go get -d -insecure insecure.go-get-issue-15410.appspot.com/pkg/p + +# Modules: Try updating without -insecure (should fail). +! go get -d -u -f insecure.go-get-issue-15410.appspot.com/pkg/p + +go list -m ... +stdout 'insecure.go-get-issue' + +-- ssh.go -- +// stub out uses of ssh by go get +package main + +import "os" + +func main() { + os.Exit(1) +} +-- module_file -- +module m \ No newline at end of file diff --git a/src/cmd/go/testdata/script/get_insecure_custom_domain.txt b/src/cmd/go/testdata/script/get_insecure_custom_domain.txt new file mode 100644 index 0000000..a4a6fd4 --- /dev/null +++ b/src/cmd/go/testdata/script/get_insecure_custom_domain.txt @@ -0,0 +1,6 @@ +[!net] skip +[!exec:git] skip +env GO111MODULE=off + +! go get -d insecure.go-get-issue-15410.appspot.com/pkg/p +go get -d -insecure insecure.go-get-issue-15410.appspot.com/pkg/p diff --git a/src/cmd/go/testdata/script/get_insecure_deprecated.txt b/src/cmd/go/testdata/script/get_insecure_deprecated.txt new file mode 100644 index 0000000..7f5f5c7 --- /dev/null +++ b/src/cmd/go/testdata/script/get_insecure_deprecated.txt @@ -0,0 +1,21 @@ +# GOPATH: Set up +env GO111MODULE=off + +# GOPATH: Fetch without insecure, no warning +! go get test +! stderr 'go get: -insecure flag is deprecated; see ''go help get'' for details' + +# GOPATH: Fetch with insecure, should warn +! go get -insecure test +stderr 'go get: -insecure flag is deprecated; see ''go help get'' for details' + +# Modules: Set up +env GO111MODULE=on + +# Modules: Fetch without insecure, no warning +! go get test +! stderr 'go get: -insecure flag is deprecated; see ''go help get'' for details' + +# Modules: Fetch with insecure, should warn +! go get -insecure test +stderr 'go get: -insecure flag is deprecated; see ''go help get'' for details' diff --git a/src/cmd/go/testdata/script/get_insecure_env.txt b/src/cmd/go/testdata/script/get_insecure_env.txt new file mode 100644 index 0000000..8d88427 --- /dev/null +++ b/src/cmd/go/testdata/script/get_insecure_env.txt @@ -0,0 +1,29 @@ +[!net] skip +[!exec:git] skip + +# GOPATH: Set up +env GO111MODULE=off + +# GOPATH: Try go get -d of HTTP-only repo (should fail). +! go get -d insecure.go-get-issue-15410.appspot.com/pkg/p + +# GOPATH: Try again with invalid GOINSECURE (should fail). +env GOINSECURE=insecure.go-get-issue-15410.appspot.com/pkg/q +! go get -d insecure.go-get-issue-15410.appspot.com/pkg/p + +# GOPATH: Try with correct GOINSECURE (should succeed). +env GOINSECURE=insecure.go-get-issue-15410.appspot.com/pkg/p +go get -d insecure.go-get-issue-15410.appspot.com/pkg/p + +# GOPATH: Try updating without GOINSECURE (should fail). +env GOINSECURE= +! go get -d -u -f insecure.go-get-issue-15410.appspot.com/pkg/p + +# GOPATH: Try updating with GOINSECURE glob (should succeed). +env GOINSECURE=*.go-get-*.appspot.com +go get -d -u -f insecure.go-get-issue-15410.appspot.com/pkg/p + +# GOPATH: Try updating with GOINSECURE base URL (should succeed). +env GOINSECURE=insecure.go-get-issue-15410.appspot.com +go get -d -u -f insecure.go-get-issue-15410.appspot.com/pkg/p + diff --git a/src/cmd/go/testdata/script/get_insecure_redirect.txt b/src/cmd/go/testdata/script/get_insecure_redirect.txt new file mode 100644 index 0000000..0478d1f --- /dev/null +++ b/src/cmd/go/testdata/script/get_insecure_redirect.txt @@ -0,0 +1,12 @@ +# golang.org/issue/29591: 'go get' was following plain-HTTP redirects even without -insecure. +# golang.org/issue/34049: 'go get' would panic in case of an insecure redirect in GOPATH mode + +[!net] skip +[!exec:git] skip + +env GO111MODULE=off + +! go get -d vcs-test.golang.org/insecure/go/insecure +stderr 'redirected .* to insecure URL' + +go get -d -insecure vcs-test.golang.org/insecure/go/insecure diff --git a/src/cmd/go/testdata/script/get_insecure_update.txt b/src/cmd/go/testdata/script/get_insecure_update.txt new file mode 100644 index 0000000..4511c98 --- /dev/null +++ b/src/cmd/go/testdata/script/get_insecure_update.txt @@ -0,0 +1,12 @@ +[!net] skip +[!exec:git] skip +env GO111MODULE=off + +# Clone the repo via HTTP manually. +exec git clone -q http://github.com/golang/example github.com/golang/example + +# Update without -insecure should fail. +# Update with -insecure should succeed. +# We need -f to ignore import comments. +! go get -d -u -f github.com/golang/example/hello +go get -d -u -f -insecure github.com/golang/example/hello diff --git a/src/cmd/go/testdata/script/get_internal_wildcard.txt b/src/cmd/go/testdata/script/get_internal_wildcard.txt new file mode 100644 index 0000000..ff20d4b --- /dev/null +++ b/src/cmd/go/testdata/script/get_internal_wildcard.txt @@ -0,0 +1,6 @@ +[!net] skip +[!exec:git] skip +env GO111MODULE=off + +# This used to fail with errors about internal packages +go get github.com/rsc/go-get-issue-11960/... diff --git a/src/cmd/go/testdata/script/get_issue11307.txt b/src/cmd/go/testdata/script/get_issue11307.txt new file mode 100644 index 0000000..9d6b7dd --- /dev/null +++ b/src/cmd/go/testdata/script/get_issue11307.txt @@ -0,0 +1,9 @@ +# go get -u was not working except in checkout directory + +[!net] skip +[!exec:git] skip +env GO111MODULE=off + +env GOPATH=$WORK/tmp/gopath +go get github.com/rsc/go-get-issue-11307 +go get -u github.com/rsc/go-get-issue-11307 # was failing diff --git a/src/cmd/go/testdata/script/get_legacy.txt b/src/cmd/go/testdata/script/get_legacy.txt new file mode 100644 index 0000000..938d428 --- /dev/null +++ b/src/cmd/go/testdata/script/get_legacy.txt @@ -0,0 +1,58 @@ +# This test was converted from a test in vendor_test.go (which no longer exists). +# That seems to imply that it's about vendoring semantics, but the test doesn't +# use 'go -mod=vendor' (and none of the fetched repos have vendor folders). +# The test still seems to be useful as a test of direct-mode go get. + +[short] skip +[!exec:git] skip +env GO111MODULE=off + +env GOPATH=$WORK/tmp/d1 +go get vcs-test.golang.org/git/modlegacy1-old.git/p1 +go list -f '{{.Deps}}' vcs-test.golang.org/git/modlegacy1-old.git/p1 +stdout 'new.git/p2' # old/p1 should depend on new/p2 +! stdout new.git/v2/p2 # old/p1 should NOT depend on new/v2/p2 +go build vcs-test.golang.org/git/modlegacy1-old.git/p1 vcs-test.golang.org/git/modlegacy1-new.git/p1 +! stdout . + +env GOPATH=$WORK/tmp/d2 + +rm $GOPATH +go get github.com/rsc/vgotest5 +go get github.com/rsc/vgotest4 +go get github.com/myitcv/vgo_example_compat + +rm $GOPATH +go get github.com/rsc/vgotest4 +go get github.com/rsc/vgotest5 +go get github.com/myitcv/vgo_example_compat + +rm $GOPATH +go get github.com/rsc/vgotest4 github.com/rsc/vgotest5 +go get github.com/myitcv/vgo_example_compat + +rm $GOPATH +go get github.com/rsc/vgotest5 github.com/rsc/vgotest4 +go get github.com/myitcv/vgo_example_compat + +rm $GOPATH +go get github.com/myitcv/vgo_example_compat +go get github.com/rsc/vgotest5 github.com/rsc/vgotest4 + +rm $GOPATH +go get github.com/myitcv/vgo_example_compat github.com/rsc/vgotest4 github.com/rsc/vgotest5 + +rm $GOPATH +go get github.com/myitcv/vgo_example_compat github.com/rsc/vgotest5 github.com/rsc/vgotest4 + +rm $GOPATH +go get github.com/rsc/vgotest4 github.com/myitcv/vgo_example_compat github.com/rsc/vgotest5 + +rm $GOPATH +go get github.com/rsc/vgotest4 github.com/rsc/vgotest5 github.com/myitcv/vgo_example_compat + +rm $GOPATH +go get github.com/rsc/vgotest5 github.com/myitcv/vgo_example_compat github.com/rsc/vgotest4 + +rm $GOPATH +go get github.com/rsc/vgotest5 github.com/rsc/vgotest4 github.com/myitcv/vgo_example_compat diff --git a/src/cmd/go/testdata/script/get_non_pkg.txt b/src/cmd/go/testdata/script/get_non_pkg.txt new file mode 100644 index 0000000..a878530 --- /dev/null +++ b/src/cmd/go/testdata/script/get_non_pkg.txt @@ -0,0 +1,14 @@ +[!net] skip +[!exec:git] skip + +env GOBIN=$WORK/tmp/gobin +env GO111MODULE=off + +! go get -d golang.org/x/tools +stderr 'golang.org/x/tools: no Go files' + +! go get -d -u golang.org/x/tools +stderr 'golang.org/x/tools: no Go files' + +! go get -d golang.org/x/tools +stderr 'golang.org/x/tools: no Go files' \ No newline at end of file diff --git a/src/cmd/go/testdata/script/get_race.txt b/src/cmd/go/testdata/script/get_race.txt new file mode 100644 index 0000000..16a560a --- /dev/null +++ b/src/cmd/go/testdata/script/get_race.txt @@ -0,0 +1,8 @@ +# Tests issue #20502 + +[!net] skip +[!exec:git] skip +[!race] skip +env GO111MODULE=off + +go get -race github.com/rsc/go-get-issue-9224-cmd diff --git a/src/cmd/go/testdata/script/get_test_only.txt b/src/cmd/go/testdata/script/get_test_only.txt new file mode 100644 index 0000000..a3f38dd --- /dev/null +++ b/src/cmd/go/testdata/script/get_test_only.txt @@ -0,0 +1,6 @@ +[!net] skip +[!exec:git] skip +env GO111MODULE=off + +go get golang.org/x/tour/content... +go get -t golang.org/x/tour/content... diff --git a/src/cmd/go/testdata/script/get_tilde.txt b/src/cmd/go/testdata/script/get_tilde.txt new file mode 100644 index 0000000..e520957 --- /dev/null +++ b/src/cmd/go/testdata/script/get_tilde.txt @@ -0,0 +1,24 @@ +env GO111MODULE=off +[short] skip + +# Paths containing windows short names should be rejected before attempting to fetch. +! go get example.com/longna~1.dir/thing +stderr 'trailing tilde and digits' +! go get example.com/longna~1/thing +stderr 'trailing tilde and digits' +! go get example.com/~9999999/thing +stderr 'trailing tilde and digits' + +# A path containing an element that is just a tilde, or a tilde followed by non-digits, +# should attempt to resolve. +! go get example.com/~glenda/notfound +! stderr 'trailing tilde and digits' +stderr 'unrecognized import path' + +! go get example.com/~glenda2/notfound +! stderr 'trailing tilde and digits' +stderr 'unrecognized import path' + +! go get example.com/~/notfound +! stderr 'trailing tilde and digits' +stderr 'unrecognized import path' diff --git a/src/cmd/go/testdata/script/get_update.txt b/src/cmd/go/testdata/script/get_update.txt new file mode 100644 index 0000000..9afce6a --- /dev/null +++ b/src/cmd/go/testdata/script/get_update.txt @@ -0,0 +1,25 @@ +# Tests Issue #9224 +# The recursive updating was trying to walk to +# former dependencies, not current ones. + +[!net] skip +[!exec:git] skip +env GO111MODULE=off + +# Rewind +go get github.com/rsc/go-get-issue-9224-cmd +cd $GOPATH/src/github.com/rsc/go-get-issue-9224-lib +exec git reset --hard HEAD~ +cd $GOPATH/src + +# Run get +go get -u 'github.com/rsc/go-get-issue-9224-cmd' + +# (Again with -d -u) Rewind +go get github.com/rsc/go-get-issue-9224-cmd +cd $GOPATH/src/github.com/rsc/go-get-issue-9224-lib +exec git reset --hard HEAD~ +cd $GOPATH/src + +# (Again with -d -u) Run get +go get -d -u 'github.com/rsc/go-get-issue-9224-cmd' diff --git a/src/cmd/go/testdata/script/get_update_all.txt b/src/cmd/go/testdata/script/get_update_all.txt new file mode 100644 index 0000000..2b75849 --- /dev/null +++ b/src/cmd/go/testdata/script/get_update_all.txt @@ -0,0 +1,9 @@ +# Issue 14444: go get -u .../ duplicate loads errors +# Check that go get update -u ... does not try to load duplicates + +[!net] skip + +env GO111MODULE=off + +go get -u -n .../ +! stderr 'duplicate loads of' # make sure old packages are removed from cache diff --git a/src/cmd/go/testdata/script/get_update_unknown_protocol.txt b/src/cmd/go/testdata/script/get_update_unknown_protocol.txt new file mode 100644 index 0000000..b00adea --- /dev/null +++ b/src/cmd/go/testdata/script/get_update_unknown_protocol.txt @@ -0,0 +1,14 @@ +[!net] skip +[!exec:git] skip +env GO111MODULE=off + +# Clone the repo via HTTPS manually. +exec git clone -q https://github.com/golang/example github.com/golang/example + +# Configure the repo to use a protocol unknown to cmd/go +# that still actually works. +cd github.com/golang/example +exec git remote set-url origin xyz://github.com/golang/example +exec git config --local url.https://github.com/.insteadOf xyz://github.com/ + +go get -d -u -f github.com/golang/example/hello diff --git a/src/cmd/go/testdata/script/get_update_wildcard.txt b/src/cmd/go/testdata/script/get_update_wildcard.txt new file mode 100644 index 0000000..4e66004 --- /dev/null +++ b/src/cmd/go/testdata/script/get_update_wildcard.txt @@ -0,0 +1,16 @@ +# Issue 14450: go get -u .../ tried to import not downloaded package + +[!net] skip +[!exec:git] skip +env GO111MODULE=off + +go get github.com/tmwh/go-get-issue-14450/a +! go get -u .../ +stderr 'cannot find package.*d-dependency/e' + +# Even though get -u failed, the source for others should be downloaded. +exists github.com/tmwh/go-get-issue-14450/b +exists github.com/tmwh/go-get-issue-14450-b-dependency/c +exists github.com/tmwh/go-get-issue-14450-b-dependency/d + +! exists github.com/tmwh/go-get-issue-14450-c-dependency/e diff --git a/src/cmd/go/testdata/script/get_vcs_error_message.txt b/src/cmd/go/testdata/script/get_vcs_error_message.txt new file mode 100644 index 0000000..8dc84fc --- /dev/null +++ b/src/cmd/go/testdata/script/get_vcs_error_message.txt @@ -0,0 +1,9 @@ +# Test that the Version Control error message includes the correct directory +env GO111MODULE=off +! go get -u foo +stderr gopath(\\\\|/)src(\\\\|/)foo + +-- foo/foo.go -- +package foo +-- math/math.go -- +package math diff --git a/src/cmd/go/testdata/script/get_vendor.txt b/src/cmd/go/testdata/script/get_vendor.txt new file mode 100644 index 0000000..4ebb8a2 --- /dev/null +++ b/src/cmd/go/testdata/script/get_vendor.txt @@ -0,0 +1,95 @@ +[short] skip +env GO111MODULE=off + +cd $GOPATH/src/v +go run m.go +go test +go list -f '{{.Imports}}' +stdout 'v/vendor/vendor.org/p' +go list -f '{{.TestImports}}' +stdout 'v/vendor/vendor.org/p' +go get -d +go get -t -d + +[!net] stop +[!exec:git] stop + +cd $GOPATH/src + +# Update +go get 'github.com/rsc/go-get-issue-11864' +go get -u 'github.com/rsc/go-get-issue-11864' +exists github.com/rsc/go-get-issue-11864/vendor + +# get -u +rm $GOPATH +mkdir $GOPATH/src +go get -u 'github.com/rsc/go-get-issue-11864' +exists github.com/rsc/go-get-issue-11864/vendor + +# get -t -u +rm $GOPATH +mkdir $GOPATH/src +go get -t -u 'github.com/rsc/go-get-issue-11864/...' +exists github.com/rsc/go-get-issue-11864/vendor + +# Submodules +rm $GOPATH +mkdir $GOPATH/src +go get -d 'github.com/rsc/go-get-issue-12612' +go get -u -d 'github.com/rsc/go-get-issue-12612' +exists github.com/rsc/go-get-issue-12612/vendor/golang.org/x/crypto/.git + +# Bad vendor (bad/imp) +rm $GOPATH +mkdir $GOPATH/src +! go get -t -u 'github.com/rsc/go-get-issue-18219/bad/imp' +stderr 'must be imported as' +! exists github.com/rsc/go-get-issue-11864/vendor + +# Bad vendor (bad/imp2) +rm $GOPATH +mkdir $GOPATH/src +! go get -t -u 'github.com/rsc/go-get-issue-18219/bad/imp2' +stderr 'must be imported as' +! exists github.com/rsc/go-get-issue-11864/vendor + +# Bad vendor (bad/imp3) +rm $GOPATH +mkdir $GOPATH/src +! go get -t -u 'github.com/rsc/go-get-issue-18219/bad/imp3' +stderr 'must be imported as' +! exists github.com/rsc/go-get-issue-11864/vendor + +# Bad vendor (bad/...) +rm $GOPATH +mkdir $GOPATH/src +! go get -t -u 'github.com/rsc/go-get-issue-18219/bad/...' +stderr 'must be imported as' +! exists github.com/rsc/go-get-issue-11864/vendor + +-- v/m.go -- +package main + +import ( + "fmt" + "vendor.org/p" +) + +func main() { + fmt.Println(p.C) +} +-- v/m_test.go -- +package main +import ( + "fmt" + "testing" + "vendor.org/p" +) + +func TestNothing(t *testing.T) { + fmt.Println(p.C) +} +-- v/vendor/vendor.org/p/p.go -- +package p +const C = 1 diff --git a/src/cmd/go/testdata/script/get_with_git_trace.txt b/src/cmd/go/testdata/script/get_with_git_trace.txt new file mode 100644 index 0000000..98854c7 --- /dev/null +++ b/src/cmd/go/testdata/script/get_with_git_trace.txt @@ -0,0 +1,9 @@ +env GO111MODULE=off + +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/src/cmd/go/testdata/script/goflags.txt b/src/cmd/go/testdata/script/goflags.txt new file mode 100644 index 0000000..686d113 --- /dev/null +++ b/src/cmd/go/testdata/script/goflags.txt @@ -0,0 +1,59 @@ +env GO111MODULE=off + +# 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 + +# Flags listed in GOFLAGS should be safe to duplicate on the command line. +env GOFLAGS=-tags=magic +go list -tags=magic +go test -tags=magic -c -o $devnull +go vet -tags=magic + +-- foo_test.go -- +package foo diff --git a/src/cmd/go/testdata/script/gopath_install.txt b/src/cmd/go/testdata/script/gopath_install.txt new file mode 100644 index 0000000..4b42fc5 --- /dev/null +++ b/src/cmd/go/testdata/script/gopath_install.txt @@ -0,0 +1,53 @@ +# Regression test for 'go install' locations in GOPATH mode. +env GO111MODULE=off +[short] skip + +# Without $GOBIN set, binaries should be installed into the GOPATH bin directory. +env GOBIN= +rm $GOPATH/bin/go-cmd-test$GOEXE +go install go-cmd-test +exists $GOPATH/bin/go-cmd-test$GOEXE + +# With $GOBIN set, binaries should be installed to $GOBIN. +env GOBIN=$WORK/bin1 +mkdir -p $GOBIN +go install go-cmd-test +exists $GOBIN/go-cmd-test$GOEXE + +# Issue 11065: installing to the current directory should create an executable. +cd go-cmd-test +env GOBIN=$PWD +go install +exists ./go-cmd-test$GOEXE +cd .. + +# Without $GOBIN set, installing a program outside $GOPATH should fail +# (there is nowhere to install it). +env GOPATH= # reset to default ($HOME/go, which does not exist) +env GOBIN= +! go install go-cmd-test/helloworld.go +stderr '^go install: no install location for \.go files listed on command line \(GOBIN not set\)$' + +# With $GOBIN set, should install there. +env GOBIN=$WORK/bin1 +go install go-cmd-test/helloworld.go +exists $GOBIN/helloworld$GOEXE + +# We can't assume that we can write to GOROOT, because it may not be writable. +# However, we can check its install location using 'go list'. +# cmd/fix should be installed to GOROOT/pkg, not GOPATH/bin. +env GOPATH=$PWD +go list -f '{{.Target}}' cmd/fix +stdout $GOROOT'[/\\]pkg[/\\]tool[/\\]'$GOOS'_'$GOARCH'[/\\]fix'$GOEXE'$' + +# GOBIN should not affect toolchain install locations. +env GOBIN=$WORK/bin1 +go list -f '{{.Target}}' cmd/fix +stdout $GOROOT'[/\\]pkg[/\\]tool[/\\]'$GOOS'_'$GOARCH'[/\\]fix'$GOEXE'$' + +-- go-cmd-test/helloworld.go -- +package main + +func main() { + println("hello world") +} diff --git a/src/cmd/go/testdata/script/gopath_local.txt b/src/cmd/go/testdata/script/gopath_local.txt new file mode 100644 index 0000000..7ee1f83 --- /dev/null +++ b/src/cmd/go/testdata/script/gopath_local.txt @@ -0,0 +1,117 @@ +env GO111MODULE=off # Relative imports only work in GOPATH mode. + +[short] skip + +# Imports should be resolved relative to the source file. +go build testdata/local/easy.go +exec ./easy$GOEXE +stdout '^easysub\.Hello' + +# Ignored files should be able to import the package built from +# non-ignored files in the same directory. +go build -o easysub$GOEXE testdata/local/easysub/main.go +exec ./easysub$GOEXE +stdout '^easysub\.Hello' + +# Files in relative-imported packages should be able to +# use relative imports themselves. +go build testdata/local/hard.go +exec ./hard$GOEXE +stdout '^sub\.Hello' + +# Explicit source files listed on the command line should not install without +# GOBIN set, since individual source files aren't part of the containing GOPATH. +! go install testdata/local/easy.go +stderr '^go install: no install location for \.go files listed on command line \(GOBIN not set\)$' + +[windows] stop # Windows does not allow the ridiculous directory name we're about to use. + +env BAD_DIR_NAME='#$%:, &()*;<=>?\^{}' + +mkdir -p testdata/$BAD_DIR_NAME/easysub +mkdir -p testdata/$BAD_DIR_NAME/sub/sub + +cp testdata/local/easy.go testdata/$BAD_DIR_NAME/easy.go +cp testdata/local/easysub/easysub.go testdata/$BAD_DIR_NAME/easysub/easysub.go +cp testdata/local/easysub/main.go testdata/$BAD_DIR_NAME/easysub/main.go +cp testdata/local/hard.go testdata/$BAD_DIR_NAME/hard.go +cp testdata/local/sub/sub.go testdata/$BAD_DIR_NAME/sub/sub.go +cp testdata/local/sub/sub/subsub.go testdata/$BAD_DIR_NAME/sub/sub/subsub.go + +# Imports should be resolved relative to the source file. +go build testdata/$BAD_DIR_NAME/easy.go +exec ./easy$GOEXE +stdout '^easysub\.Hello' + +# Ignored files should be able to import the package built from +# non-ignored files in the same directory. +go build -o easysub$GOEXE testdata/$BAD_DIR_NAME/easysub/main.go +exec ./easysub$GOEXE +stdout '^easysub\.Hello' + +# Files in relative-imported packages should be able to +# use relative imports themselves. +go build testdata/$BAD_DIR_NAME/hard.go +exec ./hard$GOEXE +stdout '^sub\.Hello' + +# Explicit source files listed on the command line should not install without +# GOBIN set, since individual source files aren't part of the containing GOPATH. +! go install testdata/$BAD_DIR_NAME/easy.go +stderr '^go install: no install location for \.go files listed on command line \(GOBIN not set\)$' + +-- testdata/local/easy.go -- +package main + +import "./easysub" + +func main() { + easysub.Hello() +} +-- testdata/local/easysub/easysub.go -- +package easysub + +import "fmt" + +func Hello() { + fmt.Println("easysub.Hello") +} +-- testdata/local/easysub/main.go -- +// +build ignore + +package main + +import "." + +func main() { + easysub.Hello() +} +-- testdata/local/hard.go -- +package main + +import "./sub" + +func main() { + sub.Hello() +} +-- testdata/local/sub/sub.go -- +package sub + +import ( + "fmt" + + subsub "./sub" +) + +func Hello() { + fmt.Println("sub.Hello") + subsub.Hello() +} +-- testdata/local/sub/sub/subsub.go -- +package subsub + +import "fmt" + +func Hello() { + fmt.Println("subsub.Hello") +} diff --git a/src/cmd/go/testdata/script/gopath_moved_repo.txt b/src/cmd/go/testdata/script/gopath_moved_repo.txt new file mode 100644 index 0000000..99d80bf --- /dev/null +++ b/src/cmd/go/testdata/script/gopath_moved_repo.txt @@ -0,0 +1,67 @@ +env GO111MODULE=off + +# Test that 'go get -u' reports packages whose VCS configurations do not +# match their import paths. + +[!net] skip +[short] skip + +# We need to execute a custom Go program to break the config files. +# +# git will ask for a username and password when we run 'go get -d -f -u', +# so we also need to set GIT_ASKPASS. Conveniently, a single binary can +# perform both tasks! + +go build -o replace.exe replace +env GIT_ASKPASS=$PWD/replace.exe + + +# Test that 'go get -u' reports moved git packages. + +[exec:git] go get -d rsc.io/pdf +[exec:git] go get -d -u rsc.io/pdf +[exec:git] exec ./replace.exe pdf rsc.io/pdf/.git/config + +[exec:git] ! go get -d -u rsc.io/pdf +[exec:git] stderr 'is a custom import path for' +[exec:git] ! go get -d -f -u rsc.io/pdf +[exec:git] stderr 'validating server certificate|[nN]ot [fF]ound' + + +# Test that 'go get -u' reports moved Mercurial packages. + +[exec:hg] go get -d vcs-test.golang.org/go/custom-hg-hello +[exec:hg] go get -d -u vcs-test.golang.org/go/custom-hg-hello +[exec:hg] exec ./replace.exe custom-hg-hello vcs-test.golang.org/go/custom-hg-hello/.hg/hgrc + +[exec:hg] ! go get -d -u vcs-test.golang.org/go/custom-hg-hello +[exec:hg] stderr 'is a custom import path for' +[exec:hg] ! go get -d -f -u vcs-test.golang.org/go/custom-hg-hello +[exec:hg] stderr 'validating server certificate|[nN]ot [fF]ound' + + +-- replace/replace.go -- +package main + +import ( + "bytes" + "log" + "os" +) + +func main() { + if len(os.Args) < 3 { + return + } + + base := []byte(os.Args[1]) + path := os.Args[2] + data, err := os.ReadFile(path) + if err != nil { + log.Fatal(err) + } + err = os.WriteFile(path, bytes.ReplaceAll(data, base, append(base, "XXX"...)), 0644) + if err != nil { + log.Fatal(err) + } +} diff --git a/src/cmd/go/testdata/script/gopath_paths.txt b/src/cmd/go/testdata/script/gopath_paths.txt new file mode 100644 index 0000000..04265b1 --- /dev/null +++ b/src/cmd/go/testdata/script/gopath_paths.txt @@ -0,0 +1,43 @@ +# Regression test for GOPATH validation in GOPATH mode. +env GO111MODULE=off + +env ORIG_GOPATH=$GOPATH + +# The literal path '.' in GOPATH should be rejected. +env GOPATH=. +! go build go-cmd-test/helloworld.go +stderr 'GOPATH entry is relative' + +# It should still be rejected if the requested package can be +# found using another entry. +env GOPATH=${:}$ORIG_GOPATH${:}. +! go build go-cmd-test +stderr 'GOPATH entry is relative' + +# GOPATH cannot be a relative subdirectory of the working directory. +env ORIG_GOPATH +stdout 'ORIG_GOPATH='$WORK[/\\]gopath +cd $WORK +env GOPATH=gopath +! go build gopath/src/go-cmd-test/helloworld.go +stderr 'GOPATH entry is relative' + +# Blank paths in GOPATH should be rejected as relative (issue 21928). +env GOPATH=' '${:}$ORIG_GOPATH +! go build go-cmd-test +stderr 'GOPATH entry is relative' + +[short] stop + +# Empty paths in GOPATH should be ignored (issue 21928). +env GOPATH=${:}$ORIG_GOPATH +env GOPATH +go install go-cmd-test +exists $ORIG_GOPATH/bin/go-cmd-test$GOEXE + +-- go-cmd-test/helloworld.go -- +package main + +func main() { + println("hello world") +} diff --git a/src/cmd/go/testdata/script/gopath_std_vendor.txt b/src/cmd/go/testdata/script/gopath_std_vendor.txt new file mode 100644 index 0000000..a0a41a5 --- /dev/null +++ b/src/cmd/go/testdata/script/gopath_std_vendor.txt @@ -0,0 +1,44 @@ +env GO111MODULE=off + +[!gc] skip + +go list -f '{{.Dir}}' vendor/golang.org/x/net/http2/hpack +stdout $GOPATH[/\\]src[/\\]vendor + +# A package importing 'net/http' should resolve its dependencies +# to the package 'vendor/golang.org/x/net/http2/hpack' within GOROOT. +cd importnethttp +go list -deps -f '{{.ImportPath}} {{.Dir}}' +stdout ^vendor/golang.org/x/net/http2/hpack +stdout $GOROOT[/\\]src[/\\]vendor[/\\]golang.org[/\\]x[/\\]net[/\\]http2[/\\]hpack +! stdout $GOPATH[/\\]src[/\\]vendor + +# In the presence of $GOPATH/src/vendor/golang.org/x/net/http2/hpack, +# a package in GOPATH importing 'golang.org/x/net/http2/hpack' should +# resolve its dependencies in GOPATH/src. +cd ../issue16333 +go build . + +go list -deps -f '{{.ImportPath}} {{.Dir}}' . +stdout $GOPATH[/\\]src[/\\]vendor[/\\]golang.org[/\\]x[/\\]net[/\\]http2[/\\]hpack +! stdout $GOROOT[/\\]src[/\\]vendor + +go list -test -deps -f '{{.ImportPath}} {{.Dir}}' . +stdout $GOPATH[/\\]src[/\\]vendor[/\\]golang.org[/\\]x[/\\]net[/\\]http2[/\\]hpack +! stdout $GOROOT[/\\]src[/\\]vendor + +-- issue16333/issue16333.go -- +package vendoring17 + +import _ "golang.org/x/net/http2/hpack" +-- issue16333/issue16333_test.go -- +package vendoring17 + +import _ "testing" +import _ "golang.org/x/net/http2/hpack" +-- importnethttp/http.go -- +package importnethttp + +import _ "net/http" +-- $GOPATH/src/vendor/golang.org/x/net/http2/hpack/hpack.go -- +package hpack diff --git a/src/cmd/go/testdata/script/gopath_vendor_dup_err.txt b/src/cmd/go/testdata/script/gopath_vendor_dup_err.txt new file mode 100644 index 0000000..22e6048 --- /dev/null +++ b/src/cmd/go/testdata/script/gopath_vendor_dup_err.txt @@ -0,0 +1,25 @@ +[!net] skip +env GO111MODULE=off + +# Issue 17119: Test more duplicate load errors. +! go build dupload +! stderr 'duplicate load|internal error' +stderr 'dupload/vendor/p must be imported as p' + +-- dupload/dupload.go -- +package main + +import ( + _ "dupload/p2" + _ "p" +) + +func main() {} +-- dupload/p/p.go -- +package p +-- dupload/p2/p2.go -- +package p2 + +import _ "dupload/vendor/p" +-- dupload/vendor/p/p.go -- +package p diff --git a/src/cmd/go/testdata/script/goroot_executable.txt b/src/cmd/go/testdata/script/goroot_executable.txt new file mode 100644 index 0000000..fdbcde0 --- /dev/null +++ b/src/cmd/go/testdata/script/goroot_executable.txt @@ -0,0 +1,111 @@ +[gccgo] skip + +mkdir $WORK/new/bin + +# In this test, we are specifically checking the logic for deriving +# the value of GOROOT from runtime.GOROOT. +# GOROOT_FINAL changes the default behavior of runtime.GOROOT, +# and will thus cause the test to fail if it is set when our +# new cmd/go is built. +env GOROOT_FINAL= + +go build -o $WORK/new/bin/go$GOEXE cmd/go & +go build -o $WORK/bin/check$GOEXE check.go & +wait + +env TESTGOROOT=$GOROOT +env GOROOT= + +# Relocated Executable +# cp $TESTGOROOT/bin/go$GOEXE $WORK/new/bin/go$GOEXE +exec $WORK/bin/check$GOEXE $WORK/new/bin/go$GOEXE $TESTGOROOT + +# Relocated Tree: +# If the binary is sitting in a bin dir next to ../pkg/tool, that counts as a GOROOT, +# so it should find the new tree. +mkdir $WORK/new/pkg/tool +exec $WORK/bin/check$GOEXE $WORK/new/bin/go$GOEXE $WORK/new + +[!symlink] stop 'The rest of the test cases require symlinks' + +# Symlinked Executable: +# With a symlink into go tree, we should still find the go tree. +mkdir $WORK/other/bin +symlink $WORK/other/bin/go$GOEXE -> $WORK/new/bin/go$GOEXE +exec $WORK/bin/check$GOEXE $WORK/new/bin/go$GOEXE $WORK/new + +rm $WORK/new/pkg + +# Runtime GOROOT: +# Binaries built in the new tree should report the +# new tree when they call runtime.GOROOT. +symlink $WORK/new/src -> $TESTGOROOT/src +symlink $WORK/new/pkg -> $TESTGOROOT/pkg +exec $WORK/new/bin/go$GOEXE run check_runtime_goroot.go $WORK/new + +-- check.go -- +package main + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" +) + +func main() { + exe := os.Args[1] + want := os.Args[2] + cmd := exec.Command(exe, "env", "GOROOT") + out, err := cmd.CombinedOutput() + if err != nil { + fmt.Fprintf(os.Stderr, "%s env GOROOT: %v, %s\n", exe, err, out) + os.Exit(1) + } + goroot, err := filepath.EvalSymlinks(strings.TrimSpace(string(out))) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + want, err = filepath.EvalSymlinks(want) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + if !strings.EqualFold(goroot, want) { + fmt.Fprintf(os.Stderr, "go env GOROOT:\nhave %s\nwant %s\n", goroot, want) + os.Exit(1) + } + fmt.Fprintf(os.Stderr, "go env GOROOT: %s\n", goroot) + +} +-- check_runtime_goroot.go -- +package main + +import ( + "fmt" + "os" + "path/filepath" + "runtime" + "strings" +) + +func main() { + goroot, err := filepath.EvalSymlinks(runtime.GOROOT()) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + want, err := filepath.EvalSymlinks(os.Args[1]) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + if !strings.EqualFold(goroot, want) { + fmt.Fprintf(os.Stderr, "go env GOROOT:\nhave %s\nwant %s\n", goroot, want) + os.Exit(1) + } + fmt.Fprintf(os.Stderr, "go env GOROOT: %s\n", goroot) + +} diff --git a/src/cmd/go/testdata/script/govcs.txt b/src/cmd/go/testdata/script/govcs.txt new file mode 100644 index 0000000..4180d7d --- /dev/null +++ b/src/cmd/go/testdata/script/govcs.txt @@ -0,0 +1,174 @@ +env GO111MODULE=on +env proxy=$GOPROXY +env GOPROXY=direct + +# GOVCS stops go get +env GOVCS='*:none' +! go get github.com/google/go-cmp +stderr '^go get: GOVCS disallows using git for public github.com/google/go-cmp; see ''go help vcs''$' +env GOPRIVATE='github.com/google' +! go get github.com/google/go-cmp +stderr '^go get: GOVCS disallows using git for private github.com/google/go-cmp; see ''go help vcs''$' + +# public pattern works +env GOPRIVATE='github.com/google' +env GOVCS='public:all,private:none' +! go get github.com/google/go-cmp +stderr '^go get: GOVCS disallows using git for private github.com/google/go-cmp; see ''go help vcs''$' + +# private pattern works +env GOPRIVATE='hubgit.com/google' +env GOVCS='private:all,public:none' +! go get github.com/google/go-cmp +stderr '^go get: GOVCS disallows using git for public github.com/google/go-cmp; see ''go help vcs''$' + +# other patterns work (for more patterns, see TestGOVCS) +env GOPRIVATE= +env GOVCS='github.com:svn|hg' +! go get github.com/google/go-cmp +stderr '^go get: GOVCS disallows using git for public github.com/google/go-cmp; see ''go help vcs''$' +env GOVCS='github.com/google/go-cmp/inner:git,github.com:svn|hg' +! go get github.com/google/go-cmp +stderr '^go get: GOVCS disallows using git for public github.com/google/go-cmp; see ''go help vcs''$' + +# bad patterns are reported (for more bad patterns, see TestGOVCSErrors) +env GOVCS='git' +! go get github.com/google/go-cmp +stderr '^go get github.com/google/go-cmp: malformed entry in GOVCS \(missing colon\): "git"$' + +env GOVCS=github.com:hg,github.com:git +! go get github.com/google/go-cmp +stderr '^go get github.com/google/go-cmp: unreachable pattern in GOVCS: "github.com:git" after "github.com:hg"$' + +# bad GOVCS patterns do not stop commands that do not need to check VCS +go list +env GOPROXY=$proxy +go get -d rsc.io/quote # ok because used proxy +env GOPROXY=direct + +# svn is disallowed by default +env GOPRIVATE= +env GOVCS= +! go get rsc.io/nonexist.svn/hello +stderr '^go get rsc.io/nonexist.svn/hello: GOVCS disallows using svn for public rsc.io/nonexist.svn; see ''go help vcs''$' + +# fossil is disallowed by default +env GOPRIVATE= +env GOVCS= +! go get rsc.io/nonexist.fossil/hello +stderr '^go get rsc.io/nonexist.fossil/hello: GOVCS disallows using fossil for public rsc.io/nonexist.fossil; see ''go help vcs''$' + +# bzr is disallowed by default +env GOPRIVATE= +env GOVCS= +! go get rsc.io/nonexist.bzr/hello +stderr '^go get rsc.io/nonexist.bzr/hello: GOVCS disallows using bzr for public rsc.io/nonexist.bzr; see ''go help vcs''$' + +# git is OK by default +env GOVCS= +env GONOSUMDB='*' +[net] [exec:git] [!short] go get rsc.io/sampler + +# hg is OK by default +env GOVCS= +env GONOSUMDB='*' +[net] [exec:hg] [!short] go get vcs-test.golang.org/go/custom-hg-hello + +# git can be disallowed +env GOVCS=public:hg +! go get rsc.io/nonexist.git/hello +stderr '^go get rsc.io/nonexist.git/hello: GOVCS disallows using git for public rsc.io/nonexist.git; see ''go help vcs''$' + +# hg can be disallowed +env GOVCS=public:git +! go get rsc.io/nonexist.hg/hello +stderr '^go get rsc.io/nonexist.hg/hello: GOVCS disallows using hg for public rsc.io/nonexist.hg; see ''go help vcs''$' + +# Repeat in GOPATH mode. Error texts slightly different. + +env GO111MODULE=off + +# GOVCS stops go get +env GOVCS='*:none' +! go get github.com/google/go-cmp +stderr '^package github.com/google/go-cmp: GOVCS disallows using git for public github.com/google/go-cmp; see ''go help vcs''$' +env GOPRIVATE='github.com/google' +! go get github.com/google/go-cmp +stderr '^package github.com/google/go-cmp: GOVCS disallows using git for private github.com/google/go-cmp; see ''go help vcs''$' + +# public pattern works +env GOPRIVATE='github.com/google' +env GOVCS='public:all,private:none' +! go get github.com/google/go-cmp +stderr '^package github.com/google/go-cmp: GOVCS disallows using git for private github.com/google/go-cmp; see ''go help vcs''$' + +# private pattern works +env GOPRIVATE='hubgit.com/google' +env GOVCS='private:all,public:none' +! go get github.com/google/go-cmp +stderr '^package github.com/google/go-cmp: GOVCS disallows using git for public github.com/google/go-cmp; see ''go help vcs''$' + +# other patterns work (for more patterns, see TestGOVCS) +env GOPRIVATE= +env GOVCS='github.com:svn|hg' +! go get github.com/google/go-cmp +stderr '^package github.com/google/go-cmp: GOVCS disallows using git for public github.com/google/go-cmp; see ''go help vcs''$' +env GOVCS='github.com/google/go-cmp/inner:git,github.com:svn|hg' +! go get github.com/google/go-cmp +stderr '^package github.com/google/go-cmp: GOVCS disallows using git for public github.com/google/go-cmp; see ''go help vcs''$' + +# bad patterns are reported (for more bad patterns, see TestGOVCSErrors) +env GOVCS='git' +! go get github.com/google/go-cmp +stderr '^package github.com/google/go-cmp: malformed entry in GOVCS \(missing colon\): "git"$' + +env GOVCS=github.com:hg,github.com:git +! go get github.com/google/go-cmp +stderr '^package github.com/google/go-cmp: unreachable pattern in GOVCS: "github.com:git" after "github.com:hg"$' + +# bad GOVCS patterns do not stop commands that do not need to check VCS +go list + +# svn is disallowed by default +env GOPRIVATE= +env GOVCS= +! go get rsc.io/nonexist.svn/hello +stderr '^package rsc.io/nonexist.svn/hello: GOVCS disallows using svn for public rsc.io/nonexist.svn; see ''go help vcs''$' + +# fossil is disallowed by default +env GOPRIVATE= +env GOVCS= +! go get rsc.io/nonexist.fossil/hello +stderr '^package rsc.io/nonexist.fossil/hello: GOVCS disallows using fossil for public rsc.io/nonexist.fossil; see ''go help vcs''$' + +# bzr is disallowed by default +env GOPRIVATE= +env GOVCS= +! go get rsc.io/nonexist.bzr/hello +stderr '^package rsc.io/nonexist.bzr/hello: GOVCS disallows using bzr for public rsc.io/nonexist.bzr; see ''go help vcs''$' + +# git is OK by default +env GOVCS= +env GONOSUMDB='*' +[net] [exec:git] [!short] go get rsc.io/sampler + +# hg is OK by default +env GOVCS= +env GONOSUMDB='*' +[net] [exec:hg] [!short] go get vcs-test.golang.org/go/custom-hg-hello + +# git can be disallowed +env GOVCS=public:hg +! go get rsc.io/nonexist.git/hello +stderr '^package rsc.io/nonexist.git/hello: GOVCS disallows using git for public rsc.io/nonexist.git; see ''go help vcs''$' + +# hg can be disallowed +env GOVCS=public:git +! go get rsc.io/nonexist.hg/hello +stderr '^package rsc.io/nonexist.hg/hello: GOVCS disallows using hg for public rsc.io/nonexist.hg; see ''go help vcs''$' + +-- go.mod -- +module m + +-- p.go -- +package p diff --git a/src/cmd/go/testdata/script/help.txt b/src/cmd/go/testdata/script/help.txt new file mode 100644 index 0000000..26a0194 --- /dev/null +++ b/src/cmd/go/testdata/script/help.txt @@ -0,0 +1,51 @@ +env GO111MODULE=off + +# 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 ' +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.' + +# Earlier versions of Go printed the same as 'go -h' here. +# Also make sure we print the short help line. +! go vet -h +stderr 'usage: go vet .*' +stderr 'Run ''go help vet'' for details.' +stderr 'Run ''go tool vet help'' for a full list of flags and analyzers.' +stderr 'Run ''go tool vet -help'' for an overview.' + +# Earlier versions of Go printed a large document here, instead of these two +# lines. +! go test -h +stderr 'usage: go test' +stderr 'Run ''go help test'' and ''go help testflag'' for details.' + +# go help get shows usage for get +go help get +stdout 'usage: go get' +stdout 'get when using GOPATH' diff --git a/src/cmd/go/testdata/script/import_cycle.txt b/src/cmd/go/testdata/script/import_cycle.txt new file mode 100644 index 0000000..901f43c --- /dev/null +++ b/src/cmd/go/testdata/script/import_cycle.txt @@ -0,0 +1,12 @@ +env GO111MODULE=off + +! go build selfimport +stderr -count=1 'import cycle not allowed' + +# 'go list' shouldn't hang forever. +go list -e -json selfimport + +-- $GOPATH/src/selfimport/selfimport.go -- +package selfimport + +import "selfimport" diff --git a/src/cmd/go/testdata/script/import_ignore.txt b/src/cmd/go/testdata/script/import_ignore.txt new file mode 100644 index 0000000..83a39a0 --- /dev/null +++ b/src/cmd/go/testdata/script/import_ignore.txt @@ -0,0 +1,11 @@ +cp go.mod go.mod.orig +go mod tidy +cmp go.mod go.mod.orig + +-- go.mod -- +module m.test + +go 1.16 +-- .ignore.go -- +package p +import _ "golang.org/x/mod/modfile" \ No newline at end of file diff --git a/src/cmd/go/testdata/script/import_main.txt b/src/cmd/go/testdata/script/import_main.txt new file mode 100644 index 0000000..bc2cc4d --- /dev/null +++ b/src/cmd/go/testdata/script/import_main.txt @@ -0,0 +1,114 @@ +env GO111MODULE=off + +# Test that you cannot import a main package. +# See golang.org/issue/4210 and golang.org/issue/17475. + +[short] skip +cd $WORK + +# Importing package main from that package main's test should work. +go build x +go test -c x + +# Importing package main from another package should fail. +! go build p1 +stderr 'import "x" is a program, not an importable package' + +# ... even in that package's test. +go build p2 +! go test -c p2 +stderr 'import "x" is a program, not an importable package' + +# ... even if that package's test is an xtest. +go build p3 +! go test p3 +stderr 'import "x" is a program, not an importable package' + +# ... even if that package is a package main +go build p4 +! go test -c p4 +stderr 'import "x" is a program, not an importable package' + +# ... even if that package is a package main using an xtest. +go build p5 +! go test -c p5 +stderr 'import "x" is a program, not an importable package' + +-- x/main.go -- +package main + +var X int + +func main() {} +-- x/main_test.go -- +package main_test + +import ( + "testing" + xmain "x" +) + +var _ = xmain.X + +func TestFoo(t *testing.T) {} +-- p1/p.go -- +package p1 + +import xmain "x" + +var _ = xmain.X +-- p2/p.go -- +package p2 +-- p2/p_test.go -- +package p2 + +import ( + "testing" + xmain "x" +) + +var _ = xmain.X + +func TestFoo(t *testing.T) {} +-- p3/p.go -- +package p +-- p3/p_test.go -- +package p_test + +import ( + "testing" + xmain "x" +) + +var _ = xmain.X + +func TestFoo(t *testing.T) {} +-- p4/p.go -- +package main + +func main() {} +-- p4/p_test.go -- +package main + +import ( + "testing" + xmain "x" +) + +var _ = xmain.X + +func TestFoo(t *testing.T) {} +-- p5/p.go -- +package main +func main() {} +-- p5/p_test.go -- +package main_test + +import ( + "testing" + xmain "x" +) + +var _ = xmain.X + +func TestFoo(t *testing.T) {} diff --git a/src/cmd/go/testdata/script/install_cgo_excluded.txt b/src/cmd/go/testdata/script/install_cgo_excluded.txt new file mode 100644 index 0000000..5a2b460 --- /dev/null +++ b/src/cmd/go/testdata/script/install_cgo_excluded.txt @@ -0,0 +1,15 @@ +env CGO_ENABLED=0 + +! go install cgotest +stderr 'build constraints exclude all Go files' + +-- go.mod -- +module cgotest + +go 1.16 +-- m.go -- +package cgotest + +import "C" + +var _ C.int diff --git a/src/cmd/go/testdata/script/install_cleans_build.txt b/src/cmd/go/testdata/script/install_cleans_build.txt new file mode 100644 index 0000000..dc85eb8 --- /dev/null +++ b/src/cmd/go/testdata/script/install_cleans_build.txt @@ -0,0 +1,25 @@ +env GO111MODULE=off +[short] skip + +# 'go install' with no arguments should clean up after go build +cd mycmd +go build +exists mycmd$GOEXE +go install +! exists mycmd$GOEXE + +# 'go install mycmd' does not clean up, even in the mycmd directory +go build +exists mycmd$GOEXE +go install mycmd +exists mycmd$GOEXE + +# 'go install mycmd' should not clean up in an unrelated current directory either +cd .. +cp mycmd/mycmd$GOEXE mycmd$GOEXE +go install mycmd +exists mycmd$GOEXE + +-- mycmd/main.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/install_cmd_gobin.txt b/src/cmd/go/testdata/script/install_cmd_gobin.txt new file mode 100644 index 0000000..38fd66c --- /dev/null +++ b/src/cmd/go/testdata/script/install_cmd_gobin.txt @@ -0,0 +1,10 @@ +# Check that commands in cmd are install to $GOROOT/bin, not $GOBIN. +# Verifies golang.org/issue/32674. +env GOBIN=gobin +mkdir gobin +go list -f '{{.Target}}' cmd/go +stdout $GOROOT[/\\]bin[/\\]go$GOEXE + +# Check that tools are installed to $GOTOOLDIR, not $GOBIN. +go list -f '{{.Target}}' cmd/compile +stdout $GOROOT[/\\]pkg[/\\]tool[/\\]${GOOS}_${GOARCH}[/\\]compile$GOEXE diff --git a/src/cmd/go/testdata/script/install_cross_gobin.txt b/src/cmd/go/testdata/script/install_cross_gobin.txt new file mode 100644 index 0000000..33d48fc --- /dev/null +++ b/src/cmd/go/testdata/script/install_cross_gobin.txt @@ -0,0 +1,25 @@ +env GO111MODULE=off +[short] skip # rebuilds std for alternate architecture + +cd mycmd +go build mycmd + +# 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 + +# The install directory for a cross-compiled standard command should include GOARCH. +go list -f '{{.Target}}' cmd/pack +stdout ${GOROOT}[/\\]pkg[/\\]tool[/\\]${GOOS}_${GOARCH}[/\\]pack$ + +-- mycmd/x.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/install_msan_and_race_require_cgo.txt b/src/cmd/go/testdata/script/install_msan_and_race_require_cgo.txt new file mode 100644 index 0000000..7985cd2 --- /dev/null +++ b/src/cmd/go/testdata/script/install_msan_and_race_require_cgo.txt @@ -0,0 +1,18 @@ +# Tests Issue #21895 + +[!msan] [!race] skip 'skipping because both msan and the race detector are not supported' + +env CGO_ENABLED=0 + +[race] ! go install -race triv.go +[race] stderr '-race requires cgo' +[race] ! stderr '-msan' + +[msan] ! go install -msan triv.go +[msan] stderr '-msan requires cgo' +[msan] ! stderr '-race' + +-- triv.go -- +package main + +func main() {} \ No newline at end of file diff --git a/src/cmd/go/testdata/script/install_rebuild_gopath.txt b/src/cmd/go/testdata/script/install_rebuild_gopath.txt new file mode 100644 index 0000000..14a6c86 --- /dev/null +++ b/src/cmd/go/testdata/script/install_rebuild_gopath.txt @@ -0,0 +1,30 @@ +env GO111MODULE=off + +# 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/src/cmd/go/testdata/script/install_rebuild_removed.txt b/src/cmd/go/testdata/script/install_rebuild_removed.txt new file mode 100644 index 0000000..5db3778 --- /dev/null +++ b/src/cmd/go/testdata/script/install_rebuild_removed.txt @@ -0,0 +1,44 @@ +env GO111MODULE=off + +# 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/src/cmd/go/testdata/script/install_relative_gobin_fail.txt b/src/cmd/go/testdata/script/install_relative_gobin_fail.txt new file mode 100644 index 0000000..aa14524 --- /dev/null +++ b/src/cmd/go/testdata/script/install_relative_gobin_fail.txt @@ -0,0 +1,12 @@ +env GOBIN=. +! go install +stderr 'cannot install, GOBIN must be an absolute path' + +-- go.mod -- +module triv + +go 1.16 +-- triv.go -- +package main + +func main() {} diff --git a/src/cmd/go/testdata/script/install_shadow_gopath.txt b/src/cmd/go/testdata/script/install_shadow_gopath.txt new file mode 100644 index 0000000..2039d9e --- /dev/null +++ b/src/cmd/go/testdata/script/install_shadow_gopath.txt @@ -0,0 +1,20 @@ +# Tests Issue #3562 +# go get foo.io (not foo.io/subdir) was not working consistently. + +[!net] skip + +env GO111MODULE=off +env GOPATH=$WORK/gopath1${:}$WORK/gopath2 + +mkdir $WORK/gopath1/src/test +mkdir $WORK/gopath2/src/test +cp main.go $WORK/gopath2/src/test/main.go +cd $WORK/gopath2/src/test + +! go install +stderr 'no install location for.*gopath2.src.test: hidden by .*gopath1.src.test' + +-- main.go -- +package main + +func main() {} diff --git a/src/cmd/go/testdata/script/issue36000.txt b/src/cmd/go/testdata/script/issue36000.txt new file mode 100644 index 0000000..4173275 --- /dev/null +++ b/src/cmd/go/testdata/script/issue36000.txt @@ -0,0 +1,6 @@ +# Tests golang.org/issue/36000 + +[!cgo] skip + +# go env with CGO flags should not make NUL file +go env CGO_CFLAGS diff --git a/src/cmd/go/testdata/script/ldflag.txt b/src/cmd/go/testdata/script/ldflag.txt new file mode 100644 index 0000000..6ceb33b --- /dev/null +++ b/src/cmd/go/testdata/script/ldflag.txt @@ -0,0 +1,44 @@ +# Issue #42565 + +[!cgo] skip + +# We can't build package bad, which uses #cgo LDFLAGS. +cd bad +! go build +stderr no-such-warning + +# We can build package ok with the same flags in CGO_LDFLAGS. +env CGO_LDFLAGS=-Wno-such-warning -Wno-unknown-warning-option +cd ../ok +go build + +# Build a main program that actually uses LDFLAGS. +cd .. +go build -ldflags=-v + +# Because we passed -v the Go linker should print the external linker +# command which should include the flag we passed in CGO_LDFLAGS. +stderr no-such-warning + +-- go.mod -- +module ldflag + +-- bad/bad.go -- +package bad + +// #cgo LDFLAGS: -Wno-such-warning -Wno-unknown-warning +import "C" + +func F() {} +-- ok/ok.go -- +package ok + +import "C" + +func F() {} +-- main.go -- +package main + +import _ "ldflag/ok" + +func main() {} diff --git a/src/cmd/go/testdata/script/link_matching_actionid.txt b/src/cmd/go/testdata/script/link_matching_actionid.txt new file mode 100644 index 0000000..b8d423d --- /dev/null +++ b/src/cmd/go/testdata/script/link_matching_actionid.txt @@ -0,0 +1,38 @@ +# Checks that an identical binary is built with -trimpath from the same +# source files, with GOROOT in two different locations. +# Verifies golang.org/issue/38989 + +[short] skip +[!symlink] skip + +# Symlink the compiler to a local path +env GOROOT=$WORK/goroot1 +symlink $GOROOT -> $TESTGO_GOROOT + +# Set up fresh GOCACHE +env GOCACHE=$WORK/gocache1 +mkdir $GOCACHE + +# Build a simple binary +go build -o binary1 -trimpath -x main.go + +# Now repeat the same process with the compiler at a different local path +env GOROOT=$WORK/goroot2 +symlink $GOROOT -> $TESTGO_GOROOT + +env GOCACHE=$WORK/gocache2 +mkdir $GOCACHE + +go build -o binary2 -trimpath -x main.go + +# Check that the binaries match exactly +go tool buildid binary1 +cp stdout buildid1 +go tool buildid binary2 +cp stdout buildid2 +cmp buildid1 buildid2 + + +-- main.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/link_syso_issue33139.txt b/src/cmd/go/testdata/script/link_syso_issue33139.txt new file mode 100644 index 0000000..8a8cb4a --- /dev/null +++ b/src/cmd/go/testdata/script/link_syso_issue33139.txt @@ -0,0 +1,43 @@ +# Test that we can use the external linker with a host syso file that is +# embedded in a package, that is referenced by a Go assembly function. +# See issue 33139. +[!gc] skip +[!cgo] skip + +# External linking is not supported on linux/ppc64. +# See: https://github.com/golang/go/issues/8912 +[linux] [ppc64] skip + +cc -c -o syso/objTestImpl.syso syso/src/objTestImpl.c +go build -ldflags='-linkmode=external' ./cmd/main.go + +-- go.mod -- +module m + +go 1.16 +-- syso/objTest.s -- +#include "textflag.h" + +TEXT ·ObjTest(SB), NOSPLIT, $0 + // We do not actually execute this function in the test above, thus + // there is no stack frame setup here. + // We only care about Go build and/or link errors when referencing + // the objTestImpl symbol in the syso file. + JMP objTestImpl(SB) + +-- syso/pkg.go -- +package syso + +func ObjTest() + +-- syso/src/objTestImpl.c -- +void objTestImpl() { /* Empty */ } + +-- cmd/main.go -- +package main + +import "m/syso" + +func main() { + syso.ObjTest() +} diff --git a/src/cmd/go/testdata/script/linkname.txt b/src/cmd/go/testdata/script/linkname.txt new file mode 100644 index 0000000..1133659 --- /dev/null +++ b/src/cmd/go/testdata/script/linkname.txt @@ -0,0 +1,9 @@ +env GO111MODULE=off + +# 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/src/cmd/go/testdata/script/list_ambiguous_path.txt b/src/cmd/go/testdata/script/list_ambiguous_path.txt new file mode 100644 index 0000000..82dde45 --- /dev/null +++ b/src/cmd/go/testdata/script/list_ambiguous_path.txt @@ -0,0 +1,38 @@ +# Ensures that we can correctly list package patterns ending in '.go'. +# See golang.org/issue/34653. + +# A single pattern for a package ending in '.go'. +go list ./foo.go +stdout '^test/foo.go$' + +# Multiple patterns for packages including one ending in '.go'. +go list ./bar ./foo.go +stdout '^test/bar$' +stdout '^test/foo.go$' + +# A single pattern for a Go file. +go list ./a.go +stdout '^command-line-arguments$' + +# A single typo-ed pattern for a Go file. This should +# treat the wrong pattern as if it were a package. +! go list ./foo.go/b.go +stderr '^stat .*[/\\]foo\.go[/\\]b\.go: directory not found$' + +# Multiple patterns for Go files with a typo. This should +# treat the wrong pattern as if it were a nonexistent file. +! go list ./foo.go/a.go ./foo.go/b.go +[plan9] stderr 'stat ./foo.go/b.go: ''./foo.go/b.go'' does not exist' +[windows] stderr './foo.go/b.go: The system cannot find the file specified' +[!plan9] [!windows] stderr './foo.go/b.go: no such file or directory' + +-- a.go -- +package main +-- bar/a.go -- +package bar +-- foo.go/a.go -- +package foo.go +-- go.mod -- +module "test" + +go 1.13 diff --git a/src/cmd/go/testdata/script/list_bad_import.txt b/src/cmd/go/testdata/script/list_bad_import.txt new file mode 100644 index 0000000..dbec350 --- /dev/null +++ b/src/cmd/go/testdata/script/list_bad_import.txt @@ -0,0 +1,72 @@ +env GO111MODULE=off +[short] skip + +# 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. +! go list -deps example.com/direct +stderr example.com[/\\]notfound + +# But -e -deps should succeed. +go list -e -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. +! go list -deps example.com/indirect +stderr example.com[/\\]notfound + +# But -deps -e should succeed. +go list -e -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 actually 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/src/cmd/go/testdata/script/list_case_collision.txt b/src/cmd/go/testdata/script/list_case_collision.txt new file mode 100644 index 0000000..181a202 --- /dev/null +++ b/src/cmd/go/testdata/script/list_case_collision.txt @@ -0,0 +1,41 @@ +# Tests golang.org/issue/4773 + +go list -json example/a +stdout 'case-insensitive import collision' + +! go build example/a +stderr 'case-insensitive import collision' + +# List files explicitly on command line, to encounter case-checking +# logic even on case-insensitive filesystems. +cp b/file.go b/FILE.go # no-op on case-insensitive filesystems +! go list b/file.go b/FILE.go +stderr 'case-insensitive file name collision' + +mkdir a/Pkg # no-op on case-insensitive filesystems +cp a/pkg/pkg.go a/Pkg/pkg.go # no-op on case-insensitive filesystems +! go list example/a/pkg example/a/Pkg + +# Test that the path reported with an indirect import is correct. +cp b/file.go b/FILE.go +[case-sensitive] ! go build example/c +[case-sensitive] stderr '^package example/c\n\timports example/b: case-insensitive file name collision: "FILE.go" and "file.go"$' + +-- go.mod -- +module example + +go 1.16 +-- a/a.go -- +package p +import ( + _ "example/a/pkg" + _ "example/a/Pkg" +) +-- a/pkg/pkg.go -- +package pkg +-- b/file.go -- +package b +-- c/c.go -- +package c + +import _ "example/b" diff --git a/src/cmd/go/testdata/script/list_compiled_imports.txt b/src/cmd/go/testdata/script/list_compiled_imports.txt new file mode 100644 index 0000000..7780b07 --- /dev/null +++ b/src/cmd/go/testdata/script/list_compiled_imports.txt @@ -0,0 +1,31 @@ +env GO111MODULE=off + +[!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}}' +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/src/cmd/go/testdata/script/list_constraints.txt b/src/cmd/go/testdata/script/list_constraints.txt new file mode 100644 index 0000000..7115c36 --- /dev/null +++ b/src/cmd/go/testdata/script/list_constraints.txt @@ -0,0 +1,86 @@ +# Check that files and their imports are not included in 'go list' output +# when they are excluded by build constraints. + +# Linux and cgo files should be included when building in that configuration. +env GOOS=linux +env GOARCH=amd64 +env CGO_ENABLED=1 +go list -f '{{range .GoFiles}}{{.}} {{end}}' +stdout '^cgotag.go empty.go suffix_linux.go tag.go $' +go list -f '{{range .CgoFiles}}{{.}} {{end}}' +stdout '^cgoimport.go $' +go list -f '{{range .Imports}}{{.}} {{end}}' +stdout '^C cgoimport cgotag suffix tag $' + +# Disabling cgo should exclude cgo files and their imports. +env CGO_ENABLED=0 +go list -f '{{range .GoFiles}}{{.}} {{end}}' +stdout 'empty.go suffix_linux.go tag.go' +go list -f '{{range .CgoFiles}}{{.}} {{end}}' +! stdout . +go list -f '{{range .Imports}}{{.}} {{end}}' +stdout '^suffix tag $' + +# Changing OS should exclude linux sources. +env GOOS=darwin +go list -f '{{range .GoFiles}}{{.}} {{end}}' +stdout '^empty.go $' +go list -f '{{range .Imports}}{{.}} {{end}}' +stdout '^$' + +# Enabling a tag should include files that require it. +go list -tags=extra -f '{{range .GoFiles}}{{.}} {{end}}' +stdout '^empty.go extra.go $' +go list -tags=extra -f '{{range .Imports}}{{.}} {{end}}' +stdout '^extra $' + +# Packages that require a tag should not be listed unless the tag is on. +! go list ./tagonly +go list -tags=extra ./tagonly +stdout m/tagonly + +-- go.mod -- +module m + +go 1.13 + +-- empty.go -- +package p + +-- extra.go -- +// +build extra + +package p + +import _ "extra" + +-- suffix_linux.go -- +package p + +import _ "suffix" + +-- tag.go -- +// +build linux + +package p + +import _ "tag" + +-- cgotag.go -- +// +build cgo + +package p + +import _ "cgotag" + +-- cgoimport.go -- +package p + +import "C" + +import _ "cgoimport" + +-- tagonly/tagonly.go -- +// +build extra + +package tagonly diff --git a/src/cmd/go/testdata/script/list_dedup_packages.txt b/src/cmd/go/testdata/script/list_dedup_packages.txt new file mode 100644 index 0000000..30c68dd --- /dev/null +++ b/src/cmd/go/testdata/script/list_dedup_packages.txt @@ -0,0 +1,31 @@ +# Setup +env GO111MODULE=off +mkdir $WORK/tmp/testdata/src/xtestonly +cp f.go $WORK/tmp/testdata/src/xtestonly/f.go +cp f_test.go $WORK/tmp/testdata/src/xtestonly/f_test.go +env GOPATH=$WORK/tmp/testdata +cd $WORK + +# Check output of go list to ensure no duplicates +go list xtestonly ./tmp/testdata/src/xtestonly/... +cmp stdout $WORK/gopath/src/wantstdout + +-- wantstdout -- +xtestonly +-- f.go -- +package xtestonly + +func F() int { return 42 } +-- f_test.go -- +package xtestonly_test + +import ( + "testing" + "xtestonly" +) + +func TestF(t *testing.T) { + if x := xtestonly.F(); x != 42 { + t.Errorf("f.F() = %d, want 42", x) + } +} diff --git a/src/cmd/go/testdata/script/list_err_cycle.txt b/src/cmd/go/testdata/script/list_err_cycle.txt new file mode 100644 index 0000000..44b82a6 --- /dev/null +++ b/src/cmd/go/testdata/script/list_err_cycle.txt @@ -0,0 +1,15 @@ +# Check that we don't get infinite recursion when loading a package with +# an import cycle and another error. Verifies #25830. +! go list +stderr 'found packages a \(a.go\) and b \(b.go\)' + +-- go.mod -- +module errcycle + +go 1.16 +-- a.go -- +package a + +import _ "errcycle" +-- b.go -- +package b \ No newline at end of file diff --git a/src/cmd/go/testdata/script/list_err_stack.txt b/src/cmd/go/testdata/script/list_err_stack.txt new file mode 100644 index 0000000..a7be9fd --- /dev/null +++ b/src/cmd/go/testdata/script/list_err_stack.txt @@ -0,0 +1,27 @@ + +# golang.org/issue/40544: regression in error stacks for parse errors + +env GO111MODULE=off +cd sandbox/foo +go list -e -json . +stdout '"sandbox/foo"' +stdout '"sandbox/bar"' +stdout '"Pos": "..(/|\\\\)bar(/|\\\\)bar.go:1:1"' +stdout '"Err": "expected ''package'', found ackage"' + +env GO111MODULE=on +go list -e -json . +stdout '"sandbox/foo"' +stdout '"sandbox/bar"' +stdout '"Pos": "..(/|\\\\)bar(/|\\\\)bar.go:1:1"' +stdout '"Err": "expected ''package'', found ackage"' + +-- sandbox/go.mod -- +module sandbox + +-- sandbox/foo/foo.go -- +package pkg + +import "sandbox/bar" +-- sandbox/bar/bar.go -- +ackage bar \ No newline at end of file diff --git a/src/cmd/go/testdata/script/list_find.txt b/src/cmd/go/testdata/script/list_find.txt new file mode 100644 index 0000000..d450fc9 --- /dev/null +++ b/src/cmd/go/testdata/script/list_find.txt @@ -0,0 +1,22 @@ +env GO111MODULE=off + +# 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 \[\]' + +# go list -find -compiled should use cached sources the second time it's run. +# It might not find the same cached sources as "go build", but the sources +# should be identical. "go build" derives action IDs (which are used as cache +# keys) from dependencies' action IDs. "go list -find" won't know what the +# dependencies are, so it's can't construct the same action IDs. +[short] skip +go list -find -compiled net +go list -find -compiled -x net +! stderr 'cgo' + +-- x/y/z/z.go -- +package z +import "does/not/exist" diff --git a/src/cmd/go/testdata/script/list_gofile_in_goroot.txt b/src/cmd/go/testdata/script/list_gofile_in_goroot.txt new file mode 100644 index 0000000..6e48d7b --- /dev/null +++ b/src/cmd/go/testdata/script/list_gofile_in_goroot.txt @@ -0,0 +1,76 @@ +# Return an error if the user tries to list a go source file directly in $GOROOT/src. +# Tests golang.org/issue/36587 + +env GOROOT=$WORK/goroot +env GOPATH=$WORK/gopath + +go env GOROOT +stdout $WORK[/\\]goroot + +# switch to GOROOT/src +cd $GOROOT/src + +# In module mode, 'go list ./...' should not treat .go files in GOROOT/src as an +# importable package, since that directory has no valid import path. +env GO111MODULE=on +go list ... +stdout -count=1 '^.+$' +stdout '^fmt$' +! stdout foo + +go list ./... +stdout -count=1 '^.+$' +stdout '^fmt$' +! stdout foo + +go list std +stdout -count=1 '^.+$' +stdout '^fmt$' + +! go list . +stderr '^GOROOT/src is not an importable package$' + +# In GOPATH mode, 'go list ./...' should synthesize a legacy GOPATH-mode path — +# not a standard-library or empty path — for the errant package. +env GO111MODULE=off +go list ./... +stdout -count=2 '^.+$' # Both 'fmt' and GOROOT/src should be listed. +stdout '^fmt$' +[!windows] stdout ^_$WORK/goroot/src$ +[windows] stdout goroot/src$ # On windows the ":" in the volume name is mangled + +go list ... +! stdout goroot/src + +go list std +! stdout goroot/src + +go list . +[!windows] stdout ^_$WORK/goroot/src$ +[windows] stdout goroot/src$ + +# switch to GOPATH/src +cd $GOPATH/src + +# GO111MODULE=off,GOPATH +env GO111MODULE=off +go list ./... +[!windows] stdout ^_$WORK/gopath/src$ +[windows] stdout gopath/src$ + +go list all +! stdout gopath/src + +-- $WORK/goroot/src/go.mod -- +module std + +go 1.14 +-- $WORK/goroot/src/foo.go -- +package foo +-- $WORK/goroot/src/fmt/fmt.go -- +package fmt +-- $WORK/goroot/src/cmd/README -- +This directory must exist in order for the 'cmd' pattern to have something to +match against. +-- $GOPATH/src/foo.go -- +package foo diff --git a/src/cmd/go/testdata/script/list_importmap.txt b/src/cmd/go/testdata/script/list_importmap.txt new file mode 100644 index 0000000..f424b98 --- /dev/null +++ b/src/cmd/go/testdata/script/list_importmap.txt @@ -0,0 +1,27 @@ +env GO111MODULE=off + +# gccgo does not have standard packages. +[gccgo] skip + +# fmt should have no rewritten imports. +# The import from a/b should map c/d to a's vendor directory. +go list -f '{{.ImportPath}}: {{.ImportMap}}' fmt a/b +stdout 'fmt: map\[\]' +stdout 'a/b: map\[c/d:a/vendor/c/d\]' + +# flag [fmt.test] should import fmt [fmt.test] as fmt +# fmt.test should import testing [fmt.test] as testing +# fmt.test should not import a modified os +go list -deps -test -f '{{.ImportPath}} MAP: {{.ImportMap}}{{"\n"}}{{.ImportPath}} IMPORT: {{.Imports}}' fmt +stdout '^flag \[fmt\.test\] MAP: map\[fmt:fmt \[fmt\.test\]\]' +stdout '^fmt\.test MAP: map\[(.* )?testing:testing \[fmt\.test\]' +! stdout '^fmt\.test MAP: map\[(.* )?os:' +stdout '^fmt\.test IMPORT: \[fmt \[fmt\.test\] fmt_test \[fmt\.test\] os reflect testing \[fmt\.test\] testing/internal/testdeps \[fmt\.test\]\]' + + +-- a/b/b.go -- +package b + +import _ "c/d" +-- a/vendor/c/d/d.go -- +package d diff --git a/src/cmd/go/testdata/script/list_linkshared.txt b/src/cmd/go/testdata/script/list_linkshared.txt new file mode 100644 index 0000000..baae1e2 --- /dev/null +++ b/src/cmd/go/testdata/script/list_linkshared.txt @@ -0,0 +1,16 @@ +env GO111MODULE=on + +# golang.org/issue/35759: 'go list -linkshared' +# panicked if invoked on a test-only package. + +[!buildmode:shared] skip + +go list -f '{{.ImportPath}}: {{.Target}} {{.Shlib}}' -linkshared . +stdout '^example.com: $' + +-- go.mod -- +module example.com + +go 1.14 +-- x.go -- +package x diff --git a/src/cmd/go/testdata/script/list_load_err.txt b/src/cmd/go/testdata/script/list_load_err.txt new file mode 100644 index 0000000..b3b7271 --- /dev/null +++ b/src/cmd/go/testdata/script/list_load_err.txt @@ -0,0 +1,79 @@ +# go list -e -deps should list imports from any file it can read, even if +# other files in the same package cause go/build.Import to return an error. +# Verfifies golang.org/issue/38568 + + +go list -e -deps ./scan +stdout m/want + + +go list -e -deps ./multi +stdout m/want + + +go list -e -deps ./constraint +stdout m/want + + +[cgo] go list -e -test -deps ./cgotest +[cgo] stdout m/want + + +[cgo] go list -e -deps ./cgoflag +[cgo] stdout m/want + +-- go.mod -- +module m + +go 1.14 + +-- want/want.go -- +package want + +-- scan/scan.go -- +// scan error +ʕ◔ϖ◔ʔ + +-- scan/good.go -- +package scan + +import _ "m/want" + +-- multi/a.go -- +package a + +-- multi/b.go -- +package b + +import _ "m/want" + +-- constraint/constraint.go -- +// +build !!nope + +package constraint + +-- constraint/good.go -- +package constraint + +import _ "m/want" + +-- cgotest/cgo_test.go -- +package cgo_test + +// cgo is not allowed in tests. +// See golang.org/issue/18647 + +import "C" +import ( + "testing" + _ "m/want" +) + +func Test(t *testing.T) {} + +-- cgoflag/cgoflag.go -- +package cgoflag + +// #cgo ʕ◔ϖ◔ʔ: + +import _ "m/want" diff --git a/src/cmd/go/testdata/script/list_overlay.txt b/src/cmd/go/testdata/script/list_overlay.txt new file mode 100644 index 0000000..1153975 --- /dev/null +++ b/src/cmd/go/testdata/script/list_overlay.txt @@ -0,0 +1,63 @@ +# Test listing with overlays + +# Overlay in an existing directory +go list -overlay overlay.json -f '{{.GoFiles}}' . +stdout '^\[f.go\]$' + +# Overlays in a non-existing directory +go list -overlay overlay.json -f '{{.GoFiles}}' ./dir +stdout '^\[g.go\]$' + +# Overlays in an existing directory with already existing files +go list -overlay overlay.json -f '{{.GoFiles}}' ./dir2 +stdout '^\[h.go i.go\]$' + +# Overlay that removes a file from a directory +! go list ./dir3 # contains a file without a package statement +go list -overlay overlay.json -f '{{.GoFiles}}' ./dir3 # overlay removes that file + +# Walking through an overlay +go list -overlay overlay.json ./... +cmp stdout want-list.txt + +# TODO(#39958): assembly files, C files, files that require cgo preprocessing + +-- want-list.txt -- +m +m/dir +m/dir2 +m/dir3 +-- go.mod -- +// TODO(#39958): Support and test overlays including go.mod itself (especially if mod=readonly) +module m + +go 1.16 + +-- dir2/h.go -- +package dir2 + +-- dir3/good.go -- +package dir3 +-- dir3/bad.go -- +// no package statement +-- overlay.json -- +{ + "Replace": { + "f.go": "overlay/f_go", + "dir/g.go": "overlay/dir_g_go", + "dir2/i.go": "overlay/dir2_i_go", + "dir3/bad.go": "" + } +} +-- overlay/f_go -- +package m + +func f() { +} +-- overlay/dir_g_go -- +package m + +func g() { +} +-- overlay/dir2_i_go -- +package dir2 diff --git a/src/cmd/go/testdata/script/list_parse_err.txt b/src/cmd/go/testdata/script/list_parse_err.txt new file mode 100644 index 0000000..3c53458 --- /dev/null +++ b/src/cmd/go/testdata/script/list_parse_err.txt @@ -0,0 +1,45 @@ +# 'go list' without -e should fail and print errors on stderr. +! go list ./p +stderr '^p[/\\]b.go:2:2: expected ''package'', found ''EOF''$' +! go list -f '{{range .Imports}}{{.}} {{end}}' ./p +stderr '^p[/\\]b.go:2:2: expected ''package'', found ''EOF''$' +! go list -test ./t +stderr '^can''t load test package: t[/\\]t_test.go:8:1: expected declaration, found ʕ' +! go list -test -f '{{range .Imports}}{{.}} {{end}}' ./t +stderr '^can''t load test package: t[/\\]t_test.go:8:1: expected declaration, found ʕ' + +# 'go list -e' should report imports, even if some files have parse errors +# before the import block. +go list -e -f '{{range .Imports}}{{.}} {{end}}' ./p +stdout '^fmt ' + +# 'go list' should report the position of the error if there's only one. +go list -e -f '{{.Error.Pos}} => {{.Error.Err}}' ./p +stdout 'b.go:[0-9:]+ => expected ''package'', found ''EOF''' + +# 'go test' should report the position of the error if there's only one. +go list -e -test -f '{{if .Error}}{{.Error.Pos}} => {{.Error.Err}}{{end}}' ./t +stdout 't_test.go:[0-9:]+ => expected declaration, found ʕ' + +-- go.mod -- +module m + +go 1.13 + +-- p/a.go -- +package a + +import "fmt" + +-- p/b.go -- +// no package statement + +-- t/t_test.go -- +package t + +import "testing" + +func Test(t *testing.T) {} + +// scan error +ʕ◔ϖ◔ʔ diff --git a/src/cmd/go/testdata/script/list_permissions.txt b/src/cmd/go/testdata/script/list_permissions.txt new file mode 100644 index 0000000..f65896c --- /dev/null +++ b/src/cmd/go/testdata/script/list_permissions.txt @@ -0,0 +1,84 @@ +env GO111MODULE=on + +# Establish baseline behavior, before mucking with file permissions. + +go list ./noread/... +stdout '^example.com/noread$' + +go list example.com/noread/... +stdout '^example.com/noread$' + +go list ./empty/... +stderr 'matched no packages' + +[root] stop # Root typically ignores file permissions. + +# Make the directory ./noread unreadable, and verify that 'go list' reports an +# explicit error for a pattern that should match it (rather than treating it as +# equivalent to an empty directory). + +[windows] skip # Does not have Unix-style directory permissions. +[plan9] skip # Might not have Unix-style directory permissions. + +chmod 000 noread + +# Check explicit paths. + +! go list ./noread +! stdout '^example.com/noread$' +! stderr 'matched no packages' + +! go list example.com/noread +! stdout '^example.com/noread$' +! stderr 'matched no packages' + +# Check filesystem-relative patterns. + +! go list ./... +! stdout '^example.com/noread$' +! stderr 'matched no packages' +stderr '^pattern ./...: ' + +! go list ./noread/... +! stdout '^example.com/noread$' +! stderr 'matched no packages' +stderr '^pattern ./noread/...: ' + + +# Check module-prefix patterns. + +! go list example.com/... +! stdout '^example.com/noread$' +! stderr 'matched no packages' +stderr '^pattern example.com/...: ' + +! go list example.com/noread/... +! stdout '^example.com/noread$' +! stderr 'matched no packages' +stderr '^pattern example.com/noread/...: ' + + +[short] stop + +# Check global patterns, which should still +# fail due to errors in the local module. + +! go list all +! stdout '^example.com/noread$' +! stderr 'matched no packages' +stderr '^pattern all: ' + +! go list ... +! stdout '^example.com/noread$' +! stderr 'matched no packages' +stderr '^pattern ...: ' + + +-- go.mod -- +module example.com +go 1.15 +-- noread/noread.go -- +// Package noread exists, but will be made unreadable. +package noread +-- empty/README.txt -- +This directory intentionally left empty. diff --git a/src/cmd/go/testdata/script/list_shadow.txt b/src/cmd/go/testdata/script/list_shadow.txt new file mode 100644 index 0000000..7b24d93 --- /dev/null +++ b/src/cmd/go/testdata/script/list_shadow.txt @@ -0,0 +1,25 @@ +env GO111MODULE=off +env GOPATH=$WORK/gopath/src/shadow/root1${:}$WORK/gopath/src/shadow/root2 + +# The math in root1 is not "math" because the standard math is. +go list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./shadow/root1/src/math +stdout '^\(.*(\\|/)src(\\|/)shadow(\\|/)root1(\\|/)src(\\|/)math\) \('$GOROOT'(\\|/)?src(\\|/)math\)$' + +# The foo in root1 is "foo". +go list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./shadow/root1/src/foo +stdout '^\(foo\) \(\)$' + +# The foo in root2 is not "foo" because the foo in root1 got there first. +go list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./shadow/root2/src/foo +stdout '^\(.*gopath(\\|/)src(\\|/)shadow(\\|/)root2(\\|/)src(\\|/)foo\) \('$WORK'(\\|/)?gopath(\\|/)src(\\|/)shadow(\\|/)root1(\\|/)src(\\|/)foo\)$' + +# The error for go install should mention the conflicting directory. +! go install -n ./shadow/root2/src/foo +stderr 'go install: no install location for '$WORK'(\\|/)?gopath(\\|/)src(\\|/)shadow(\\|/)root2(\\|/)src(\\|/)foo: hidden by '$WORK'(\\|/)?gopath(\\|/)src(\\|/)shadow(\\|/)root1(\\|/)src(\\|/)foo' + +-- shadow/root1/src/foo/foo.go -- +package foo +-- shadow/root1/src/math/math.go -- +package math +-- shadow/root2/src/foo/foo.go -- +package foo \ No newline at end of file diff --git a/src/cmd/go/testdata/script/list_split_main.txt b/src/cmd/go/testdata/script/list_split_main.txt new file mode 100644 index 0000000..74e7d5d --- /dev/null +++ b/src/cmd/go/testdata/script/list_split_main.txt @@ -0,0 +1,25 @@ +# This test checks that a "main" package with an external test package +# is recompiled only once. +# Verifies golang.org/issue/34321. + +env GO111MODULE=off + +go list -e -test -deps -f '{{if not .Standard}}{{.ImportPath}}{{end}}' pkg +cmp stdout want + +-- $GOPATH/src/pkg/pkg.go -- +package main + +func main() {} + +-- $GOPATH/src/pkg/pkg_test.go -- +package main + +import "testing" + +func Test(t *testing.T) {} + +-- want -- +pkg +pkg [pkg.test] +pkg.test diff --git a/src/cmd/go/testdata/script/list_std.txt b/src/cmd/go/testdata/script/list_std.txt new file mode 100644 index 0000000..6ab1bd1 --- /dev/null +++ b/src/cmd/go/testdata/script/list_std.txt @@ -0,0 +1,25 @@ +env GO111MODULE=off + +[!gc] skip +[short] skip + +# Listing GOROOT should only find standard packages. +cd $GOROOT/src +go list -f '{{if not .Standard}}{{.ImportPath}}{{end}}' ./... +! stdout . + +# Standard packages should include cmd, but not cmd/vendor. +go list ./... +stdout cmd/compile +! stdout vendor/golang.org +! stdout cmd/vendor + +# In GOPATH mode, packages vendored into GOROOT should be reported as standard. +go list -f '{{if .Standard}}{{.ImportPath}}{{end}}' std cmd +stdout golang.org/x/net/http2/hpack +stdout cmd/vendor/golang\.org/x/arch/x86/x86asm + +# However, vendored packages should not match wildcard patterns beginning with cmd. +go list cmd/... +stdout cmd/compile +! stdout cmd/vendor diff --git a/src/cmd/go/testdata/script/list_symlink.txt b/src/cmd/go/testdata/script/list_symlink.txt new file mode 100644 index 0000000..f74ca86 --- /dev/null +++ b/src/cmd/go/testdata/script/list_symlink.txt @@ -0,0 +1,12 @@ +[!symlink] skip +env GO111MODULE=off + +mkdir $WORK/tmp/src +symlink $WORK/tmp/src/dir1 -> $WORK/tmp +cp p.go $WORK/tmp/src/dir1/p.go +env GOPATH=$WORK/tmp +go list -f '{{.Root}}' dir1 +stdout '^'$WORK/tmp'$' + +-- p.go -- +package p diff --git a/src/cmd/go/testdata/script/list_symlink_internal.txt b/src/cmd/go/testdata/script/list_symlink_internal.txt new file mode 100644 index 0000000..f756a56 --- /dev/null +++ b/src/cmd/go/testdata/script/list_symlink_internal.txt @@ -0,0 +1,27 @@ +[!symlink] skip +env GO111MODULE=off + +mkdir $WORK/tmp/gopath/src/dir1/internal/v +cp p.go $WORK/tmp/gopath/src/dir1/p.go +cp v.go $WORK/tmp/gopath/src/dir1/internal/v/v.go +symlink $WORK/tmp/symdir1 -> $WORK/tmp/gopath/src/dir1 +env GOPATH=$WORK/tmp/gopath +cd $WORK/tmp/symdir1 +go list -f '{{.Root}}' . +stdout '^'$WORK/tmp/gopath'$' + +# All of these should succeed, not die in internal-handling code. +go run p.go & +go build & +go install & + +wait + +-- p.go -- +package main + +import _ `dir1/internal/v` + +func main() {} +-- v.go -- +package v diff --git a/src/cmd/go/testdata/script/list_symlink_vendor_issue14054.txt b/src/cmd/go/testdata/script/list_symlink_vendor_issue14054.txt new file mode 100644 index 0000000..8e63a5a --- /dev/null +++ b/src/cmd/go/testdata/script/list_symlink_vendor_issue14054.txt @@ -0,0 +1,28 @@ +[!symlink] skip +env GO111MODULE=off + +mkdir $WORK/tmp/gopath/src/dir1/vendor/v +cp p.go $WORK/tmp/gopath/src/dir1/p.go +cp v.go $WORK/tmp/gopath/src/dir1/vendor/v/v.go +symlink $WORK/tmp/symdir1 -> $WORK/tmp/gopath/src/dir1 +env GOPATH=$WORK/tmp/gopath +cd $WORK/tmp/symdir1 + +go list -f '{{.Root}}' . +stdout '^'$WORK/tmp/gopath'$' + +# All of these should succeed, not die in vendor-handling code. +go run p.go & +go build & +go install & + +wait + +-- p.go -- +package main + +import _ `v` + +func main () {} +-- v.go -- +package v diff --git a/src/cmd/go/testdata/script/list_symlink_vendor_issue15201.txt b/src/cmd/go/testdata/script/list_symlink_vendor_issue15201.txt new file mode 100644 index 0000000..19f2138 --- /dev/null +++ b/src/cmd/go/testdata/script/list_symlink_vendor_issue15201.txt @@ -0,0 +1,21 @@ +[!symlink] skip +env GO111MODULE=off + +mkdir $WORK/tmp/gopath/src/x/y/_vendor/src/x +symlink $WORK/tmp/gopath/src/x/y/_vendor/src/x/y -> ../../.. +mkdir $WORK/tmp/gopath/src/x/y/_vendor/src/x/y/w +cp w.go $WORK/tmp/gopath/src/x/y/w/w.go +symlink $WORK/tmp/gopath/src/x/y/w/vendor -> ../_vendor/src +mkdir $WORK/tmp/gopath/src/x/y/_vendor/src/x/y/z +cp z.go $WORK/tmp/gopath/src/x/y/z/z.go + +env GOPATH=$WORK/tmp/gopath/src/x/y/_vendor${:}$WORK/tmp/gopath +cd $WORK/tmp/gopath/src +go list ./... + +-- w.go -- +package w + +import "x/y/z" +-- z.go -- +package z diff --git a/src/cmd/go/testdata/script/list_test_e.txt b/src/cmd/go/testdata/script/list_test_e.txt new file mode 100644 index 0000000..263892b --- /dev/null +++ b/src/cmd/go/testdata/script/list_test_e.txt @@ -0,0 +1,11 @@ +env GO111MODULE=off + +# issue 25980: crash in go list -e -test +go list -e -test -deps -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/src/cmd/go/testdata/script/list_test_err.txt b/src/cmd/go/testdata/script/list_test_err.txt new file mode 100644 index 0000000..c6f1ecf --- /dev/null +++ b/src/cmd/go/testdata/script/list_test_err.txt @@ -0,0 +1,129 @@ +env GO111MODULE=off + +# issue 28491: errors in test source files should not prevent +# "go list -test" from returning useful information. + +# go list prints information for package, internal test, +# external test, but not testmain package when there is a +# syntax error in test sources. +! go list -test -deps syntaxerr +stdout pkgdep +stdout testdep_a +stdout testdep_b +stdout ^syntaxerr$ +stdout '^syntaxerr \[syntaxerr.test\]' +stdout '^syntaxerr_test \[syntaxerr.test\]' +! stdout '^syntaxerr\.test' +stderr 'expected declaration' + +# go list -e prints information for all test packages. +# The syntax error is shown in the package error field. +go list -e -test -deps -f '{{.ImportPath}} {{.Error | printf "%q"}}' syntaxerr +stdout 'pkgdep ' +stdout 'testdep_a ' +stdout 'testdep_b ' +stdout 'syntaxerr ' +stdout 'syntaxerr \[syntaxerr.test\] ' +stdout 'syntaxerr_test \[syntaxerr.test\] ' +stdout 'syntaxerr\.test "[^"]*expected declaration' +! stderr 'expected declaration' + +[short] stop + +# go list prints partial information with test naming error +! go list -test -deps nameerr +stdout pkgdep +stdout testdep_a +stdout testdep_b +stderr 'wrong signature for TestBad' + +go list -e -test -deps -f '{{.ImportPath}} {{.Error | printf "%q"}}' nameerr +stdout 'pkgdep ' +stdout 'testdep_a ' +stdout 'testdep_b ' +stdout 'nameerr\.test "[^"]*wrong signature for TestBad' +! stderr 'wrong signature for TestBad' + +# go list prints partial information with error if test has cyclic import +! go list -test -deps cycleerr +stdout cycleerr +stderr 'import cycle not allowed in test' + +go list -e -test -deps -f '{{.ImportPath}} {{.Error | printf "%q"}}' cycleerr +stdout 'cycleerr ' +stdout 'testdep_a ' +stdout 'testdep_cycle ' +stdout 'cycleerr \[cycleerr.test\] "[^"]*import cycle not allowed in test' +! stderr 'import cycle not allowed in test' + +-- syntaxerr/syntaxerr.go -- +package syntaxerr + +import _ "pkgdep" + +-- syntaxerr/syntaxerr_ie_test.go -- +package syntaxerr + +!!!syntax error + +-- syntaxerr/syntaxerr_xe_test.go -- +package syntaxerr_test + +!!!syntax error + +-- syntaxerr/syntaxerr_i_test.go -- +package syntaxerr + +import _ "testdep_a" + +-- syntaxerr/syntaxerr_x_test.go -- +package syntaxerr + +import _ "testdep_b" + +-- nameerr/nameerr.go -- +package nameerr + +import _ "pkgdep" + +-- nameerr/nameerr_i_test.go -- +package nameerr + +import ( + _ "testdep_a" + "testing" +) + +func TestBad(t *testing.B) {} + +-- nameerr/nameerr_x_test.go -- +package nameerr_test + +import ( + _ "testdep_b" + "testing" +) + +func TestBad(t *testing.B) {} + +-- cycleerr/cycleerr_test.go -- +package cycleerr + +import ( + _ "testdep_a" + _ "testdep_cycle" +) + +-- pkgdep/pkgdep.go -- +package pkgdep + +-- testdep_a/testdep_a.go -- +package testdep_a + +-- testdep_b/testdep_b.go -- +package testdep_b + +-- testdep_cycle/testdep_cycle.go -- +package testdep_cycle + +import _ "cycleerr" diff --git a/src/cmd/go/testdata/script/list_test_imports.txt b/src/cmd/go/testdata/script/list_test_imports.txt new file mode 100644 index 0000000..0342eba --- /dev/null +++ b/src/cmd/go/testdata/script/list_test_imports.txt @@ -0,0 +1,21 @@ +env GO111MODULE=off + +# 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, reflect, testing, testing/internal/testdeps +b [b.test]: +b_test [b.test]: a [b.test] diff --git a/src/cmd/go/testdata/script/list_test_non_go_files.txt b/src/cmd/go/testdata/script/list_test_non_go_files.txt new file mode 100644 index 0000000..6b2b633 --- /dev/null +++ b/src/cmd/go/testdata/script/list_test_non_go_files.txt @@ -0,0 +1,13 @@ +env GO111MODULE=off + +# issue 29899: handling files with non-Go extension +go list -e -test -json -- c.c x.go +stdout '"Err": "named files must be .go files: c.c"' + +! go list -test -json -- c.c x.go +stderr '^named files must be \.go files: c\.c$' + +-- x.go -- +package main +-- c.c -- +package c diff --git a/src/cmd/go/testdata/script/list_test_simple.txt b/src/cmd/go/testdata/script/list_test_simple.txt new file mode 100644 index 0000000..954897c --- /dev/null +++ b/src/cmd/go/testdata/script/list_test_simple.txt @@ -0,0 +1,67 @@ +[short] skip + +# Test +go test -list=Test +stdout TestSimple + +# Benchmark +go test -list=Benchmark +stdout BenchmarkSimple + +# Examples +go test -list=Example +stdout ExampleSimple +stdout ExampleWithEmptyOutput + +-- go.mod -- +module m + +go 1.16 +-- bench_test.go -- +package testlist + +import ( + "fmt" + "testing" +) + +func BenchmarkSimplefunc(b *testing.B) { + b.StopTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + _ = fmt.Sprint("Test for bench") + } +} +-- example_test.go -- +package testlist + +import ( + "fmt" +) + +func ExampleSimple() { + fmt.Println("Test with Output.") + + // Output: Test with Output. +} + +func ExampleWithEmptyOutput() { + fmt.Println("") + + // Output: +} + +func ExampleNoOutput() { + _ = fmt.Sprint("Test with no output") +} +-- test_test.go -- +package testlist + +import ( + "fmt" + "testing" +) + +func TestSimple(t *testing.T) { + _ = fmt.Sprint("Test simple") +} diff --git a/src/cmd/go/testdata/script/list_wildcard_skip_nonmatching.txt b/src/cmd/go/testdata/script/list_wildcard_skip_nonmatching.txt new file mode 100644 index 0000000..02b1088 --- /dev/null +++ b/src/cmd/go/testdata/script/list_wildcard_skip_nonmatching.txt @@ -0,0 +1,17 @@ +# Test that wildcards don't look in useless directories. + +# First make sure that badpkg fails the list of '...'. +! go list ./... +stderr badpkg + +# Check that the list of './goodpkg...' succeeds. That implies badpkg was skipped. +go list ./goodpkg... + +-- go.mod -- +module m + +go 1.16 +-- goodpkg/x.go -- +package goodpkg +-- badpkg/x.go -- +pkg badpkg diff --git a/src/cmd/go/testdata/script/load_test_pkg_err.txt b/src/cmd/go/testdata/script/load_test_pkg_err.txt new file mode 100644 index 0000000..d088ee4 --- /dev/null +++ b/src/cmd/go/testdata/script/load_test_pkg_err.txt @@ -0,0 +1,30 @@ +# Tests issue 37971. Check that tests are still loaded even when the package has an error. + +go list -e -test d +cmp stdout want_stdout + +go list -e -test -deps d +stdout golang.org/fake/d + +-- want_stdout -- +d +d.test +d_test [d.test] +-- go.mod -- +module d + +go 1.16 +-- d.go -- +package d + +import "net/http" + +const d = http.MethodGet +func Get() string { return d; } +-- d2.go -- +-- d_test.go -- +package d_test + +import "testing" +import "golang.org/fake/d" +func TestD(t *testing.T) { d.Get(); } diff --git a/src/cmd/go/testdata/script/mod_all.txt b/src/cmd/go/testdata/script/mod_all.txt new file mode 100644 index 0000000..aac6629 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_all.txt @@ -0,0 +1,444 @@ +# This test illustrates the relationship between the 'all' pattern and +# the dependencies of the main module. + +# The package import graph used in this test looks like: +# +# main --------- a --------- b +# | | +# | a_test ---- c +# | | +# | c_test ---- d +# | +# main_test ---- t --------- u +# | +# t_test ---- w +# | +# w_test ---- x +# +# main/testonly_test ---- q --------- r +# | +# q_test ---- s +# +# And the module dependency graph looks like: +# +# main --- a.1 ---- b.1 +# \ \ \ +# \ \ c.1 -- d.1 +# \ \ +# \ t.1 ---- u.1 +# \ \ +# \ w.1 -- x.1 +# \ +# q.1 ---- r.1 +# \ +# s.1 + +env PKGFMT='{{if .Module}}{{.ImportPath}}{{end}}' +env MODFMT='{{.Path}}' + + +# 'go list -deps' lists packages and tests in the main module, +# along with their transitive dependencies. + +go list -f $PKGFMT -deps ./... +stdout -count=4 '^.' +stdout '^example.com/a$' +stdout '^example.com/b$' +stdout '^example.com/main$' +stdout '^example.com/main/testonly' + + +# 'go list -deps -test' lists transitive imports of tests and non-tests in the +# main module. + +go list -f $PKGFMT -deps -test ./... +stdout -count=13 '^.' +stdout '^example.com/a$' +stdout '^example.com/b$' +stdout '^example.com/main$' +stdout '^example.com/main.test$' +stdout '^example.com/main \[example.com/main.test\]$' +stdout '^example.com/main_test \[example.com/main.test\]$' +stdout '^example.com/main/testonly$' +stdout '^example.com/main/testonly.test$' +stdout '^example.com/main/testonly_test \[example.com/main/testonly.test\]$' +stdout '^example.com/q$' +stdout '^example.com/r$' +stdout '^example.com/t$' +stdout '^example.com/u$' + + +# 'go list all' lists the fixpoint of iterating 'go list -deps -test' starting +# with the packages in the main module, then reducing to only the non-test +# variants of those packages. + +go list -f $PKGFMT all +stdout -count=13 '^.' +stdout '^example.com/a$' +stdout '^example.com/b$' +stdout '^example.com/c$' +stdout '^example.com/d$' +stdout '^example.com/main$' +stdout '^example.com/main/testonly$' +stdout '^example.com/q$' +stdout '^example.com/r$' +stdout '^example.com/s$' +stdout '^example.com/t$' +stdout '^example.com/u$' +stdout '^example.com/w$' +stdout '^example.com/x$' + + +# 'go list -test all' is equivalent to 'go list -test $(go list all)' +# and both should include tests for every package in 'all'. + +go list -test -f $PKGFMT example.com/a example.com/b example.com/c example.com/d example.com/main example.com/main/testonly example.com/q example.com/r example.com/s example.com/t example.com/u example.com/w example.com/x +cp stdout list-test-explicit.txt + +go list -test -f $PKGFMT all +cmp stdout list-test-explicit.txt +stdout -count=36 '^.' +stdout '^example.com/a$' +stdout '^example.com/b$' +stdout '^example.com/c$' +stdout '^example.com/d$' +stdout '^example.com/main$' +stdout '^example.com/main/testonly$' +stdout '^example.com/q$' +stdout '^example.com/r$' +stdout '^example.com/s$' +stdout '^example.com/t$' +stdout '^example.com/u$' +stdout '^example.com/w$' +stdout '^example.com/x$' +stdout '^example.com/a.test$' +stdout '^example.com/a_test \[example.com/a.test\]$' +stdout '^example.com/b.test$' +stdout '^example.com/b_test \[example.com/b.test\]$' +stdout '^example.com/c.test$' +stdout '^example.com/c_test \[example.com/c.test\]$' +stdout '^example.com/main.test$' +stdout '^example.com/main \[example.com/main.test\]$' +stdout '^example.com/main_test \[example.com/main.test\]$' +stdout '^example.com/main/testonly.test$' +stdout '^example.com/main/testonly_test \[example.com/main/testonly.test\]$' +stdout '^example.com/q.test$' +stdout '^example.com/q_test \[example.com/q.test\]$' +stdout '^example.com/r.test$' +stdout '^example.com/r_test \[example.com/r.test\]$' +stdout '^example.com/s.test$' +stdout '^example.com/s_test \[example.com/s.test\]$' +stdout '^example.com/t.test$' +stdout '^example.com/t_test \[example.com/t.test\]$' +stdout '^example.com/u.test$' +stdout '^example.com/u_test \[example.com/u.test\]$' +stdout '^example.com/w.test$' +stdout '^example.com/w_test \[example.com/w.test\]$' + + +# 'go list -m all' covers the packages in 'go list -test -deps all'. + +go list -m -f $MODFMT all +stdout -count=12 '^.' +stdout '^example.com/a$' +stdout '^example.com/b$' +stdout '^example.com/c$' +stdout '^example.com/d$' +stdout '^example.com/main$' +stdout '^example.com/q$' +stdout '^example.com/r$' +stdout '^example.com/s$' +stdout '^example.com/t$' +stdout '^example.com/u$' +stdout '^example.com/w$' +stdout '^example.com/x$' + + +# 'go mod vendor' copies in only the packages transitively imported by the main +# module, and omits their tests. As a result, the 'all' and '...' patterns +# report fewer packages when using '-mod=vendor'. + +go mod vendor + +go list -f $PKGFMT -mod=vendor all +stdout -count=8 '^.' +stdout '^example.com/a$' +stdout '^example.com/b$' +stdout '^example.com/main$' +stdout '^example.com/main/testonly$' +stdout '^example.com/q$' +stdout '^example.com/r$' +stdout '^example.com/t$' +stdout '^example.com/u$' + +go list -test -f $PKGFMT -mod=vendor all +stdout -count=13 '^.' +stdout '^example.com/a$' +stdout '^example.com/b$' +stdout '^example.com/main$' +stdout '^example.com/main/testonly$' +stdout '^example.com/q$' +stdout '^example.com/r$' +stdout '^example.com/t$' +stdout '^example.com/u$' +stdout '^example.com/main.test$' +stdout '^example.com/main \[example.com/main.test\]$' +stdout '^example.com/main_test \[example.com/main.test\]$' +stdout '^example.com/main/testonly.test$' +stdout '^example.com/main/testonly_test \[example.com/main/testonly.test\]$' + +rm vendor + +# Convert all modules to go 1.16 to enable lazy loading. +go mod edit -go=1.16 a/go.mod +go mod edit -go=1.16 b/go.mod +go mod edit -go=1.16 c/go.mod +go mod edit -go=1.16 d/go.mod +go mod edit -go=1.16 q/go.mod +go mod edit -go=1.16 r/go.mod +go mod edit -go=1.16 s/go.mod +go mod edit -go=1.16 t/go.mod +go mod edit -go=1.16 u/go.mod +go mod edit -go=1.16 w/go.mod +go mod edit -go=1.16 x/go.mod +go mod edit -go=1.16 + +# With lazy loading, 'go list all' with neither -mod=vendor nor -test should +# match -mod=vendor without -test in 1.15. + +go list -f $PKGFMT all +stdout -count=8 '^.' +stdout '^example.com/a$' +stdout '^example.com/b$' +stdout '^example.com/main$' +stdout '^example.com/main/testonly$' +stdout '^example.com/q$' +stdout '^example.com/r$' +stdout '^example.com/t$' +stdout '^example.com/u$' + +# 'go list -test all' should expand that to include the test variants of the +# packages in 'all', but not the dependencies of outside tests. + +go list -test -f $PKGFMT all +stdout -count=25 '^.' +stdout '^example.com/a$' +stdout '^example.com/b$' +stdout '^example.com/main$' +stdout '^example.com/main/testonly$' +stdout '^example.com/q$' +stdout '^example.com/r$' +stdout '^example.com/t$' +stdout '^example.com/u$' +stdout '^example.com/a.test$' +stdout '^example.com/a_test \[example.com/a.test\]$' +stdout '^example.com/b.test$' +stdout '^example.com/b_test \[example.com/b.test\]$' +stdout '^example.com/main.test$' +stdout '^example.com/main \[example.com/main.test\]$' +stdout '^example.com/main_test \[example.com/main.test\]$' +stdout '^example.com/main/testonly.test$' +stdout '^example.com/main/testonly_test \[example.com/main/testonly.test\]$' +stdout '^example.com/q.test$' +stdout '^example.com/q_test \[example.com/q.test\]$' +stdout '^example.com/r.test$' +stdout '^example.com/r_test \[example.com/r.test\]$' +stdout '^example.com/t.test$' +stdout '^example.com/t_test \[example.com/t.test\]$' +stdout '^example.com/u.test$' +stdout '^example.com/u_test \[example.com/u.test\]$' + +# 'go list -test -deps all' should include the dependencies of those tests, +# but not the tests of the dependencies of outside tests. + +go list -test -deps -f $PKGFMT all +stdout -count=28 '^.' +stdout '^example.com/a$' +stdout '^example.com/b$' +stdout '^example.com/c$' +stdout '^example.com/main$' +stdout '^example.com/main/testonly$' +stdout '^example.com/q$' +stdout '^example.com/r$' +stdout '^example.com/s$' +stdout '^example.com/t$' +stdout '^example.com/u$' +stdout '^example.com/w$' +stdout '^example.com/a.test$' +stdout '^example.com/a_test \[example.com/a.test\]$' +stdout '^example.com/b.test$' +stdout '^example.com/b_test \[example.com/b.test\]$' +stdout '^example.com/main.test$' +stdout '^example.com/main \[example.com/main.test\]$' +stdout '^example.com/main_test \[example.com/main.test\]$' +stdout '^example.com/main/testonly.test$' +stdout '^example.com/main/testonly_test \[example.com/main/testonly.test\]$' +stdout '^example.com/q.test$' +stdout '^example.com/q_test \[example.com/q.test\]$' +stdout '^example.com/r.test$' +stdout '^example.com/r_test \[example.com/r.test\]$' +stdout '^example.com/t.test$' +stdout '^example.com/t_test \[example.com/t.test\]$' +stdout '^example.com/u.test$' +stdout '^example.com/u_test \[example.com/u.test\]$' + + +# TODO(#36460): +# 'go list -m all' should exactly cover the packages in 'go list -test all'. + +-- go.mod -- +module example.com/main + +go 1.15 + +require ( + example.com/a v0.1.0 + example.com/b v0.1.0 + example.com/q v0.1.0 + example.com/t v0.1.0 +) + +replace ( + example.com/a v0.1.0 => ./a + example.com/b v0.1.0 => ./b + example.com/c v0.1.0 => ./c + example.com/d v0.1.0 => ./d + example.com/q v0.1.0 => ./q + example.com/r v0.1.0 => ./r + example.com/s v0.1.0 => ./s + example.com/t v0.1.0 => ./t + example.com/u v0.1.0 => ./u + example.com/w v0.1.0 => ./w + example.com/x v0.1.0 => ./x +) +-- main.go -- +package main + +import _ "example.com/a" + +func main() {} +-- main_test.go -- +package main_test + +import _ "example.com/t" +-- testonly/testonly_test.go -- +package testonly_test + +import _ "example.com/q" +-- a/go.mod -- +module example.com/a + +go 1.15 + +require ( + example.com/b v0.1.0 + example.com/c v0.1.0 +) +-- a/a.go -- +package a + +import _ "example.com/b" +-- a/a_test.go -- +package a_test + +import _ "example.com/c" +-- b/go.mod -- +module example.com/b + +go 1.15 +-- b/b.go -- +package b +-- b/b_test.go -- +package b_test +-- c/go.mod -- +module example.com/c + +go 1.15 + +require example.com/d v0.1.0 +-- c/c.go -- +package c +-- c/c_test.go -- +package c_test + +import _ "example.com/d" +-- d/go.mod -- +module example.com/d + +go 1.15 +-- d/d.go -- +package d +-- q/go.mod -- +module example.com/q + +go 1.15 + +require ( + example.com/r v0.1.0 + example.com/s v0.1.0 +) +-- q/q.go -- +package q +import _ "example.com/r" +-- q/q_test.go -- +package q_test +import _ "example.com/s" +-- r/go.mod -- +module example.com/r + +go 1.15 +-- r/r.go -- +package r +-- r/r_test.go -- +package r_test +-- s/go.mod -- +module example.com/s + +go 1.15 +-- s/s.go -- +package s +-- s/s_test.go -- +package s_test +-- t/go.mod -- +module example.com/t + +go 1.15 + +require ( + example.com/u v0.1.0 + example.com/w v0.1.0 +) +-- t/t.go -- +package t + +import _ "example.com/u" +-- t/t_test.go -- +package t_test + +import _ "example.com/w" +-- u/go.mod -- +module example.com/u + +go 1.15 +-- u/u.go -- +package u +-- u/u_test.go -- +package u_test +-- w/go.mod -- +module example.com/w + +go 1.15 + +require example.com/x v0.1.0 +-- w/w.go -- +package w +-- w/w_test.go -- +package w_test + +import _ "example.com/x" +-- x/go.mod -- +module example.com/x + +go 1.15 +-- x/x.go -- +package x diff --git a/src/cmd/go/testdata/script/mod_alt_goroot.txt b/src/cmd/go/testdata/script/mod_alt_goroot.txt new file mode 100644 index 0000000..32f94c5 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_alt_goroot.txt @@ -0,0 +1,20 @@ +env GO111MODULE=on + +# If the working directory is a different GOROOT, then the 'std' module should be +# treated as an ordinary module (with an ordinary module prefix). +# It should not override packages in GOROOT, but should not fail the command. +# See golang.org/issue/30756. +go list -e -deps -f '{{.ImportPath}} {{.Dir}}' ./bytes +stdout ^std/bytes.*$PWD[/\\]bytes +stdout '^bytes/modified' + +-- go.mod -- +module std + +go 1.12 +-- bytes/bytes.go -- +package bytes + +import _"bytes/modified" +-- bytes/modified/modified.go -- +package modified diff --git a/src/cmd/go/testdata/script/mod_ambiguous_import.txt b/src/cmd/go/testdata/script/mod_ambiguous_import.txt new file mode 100644 index 0000000..feaf5d2 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_ambiguous_import.txt @@ -0,0 +1,48 @@ +env GO111MODULE=on + +cd $WORK + +# An import provided by two different modules should be flagged as an error. +! go build ./importx +stderr '^importx[/\\]importx.go:2:8: ambiguous import: found package example.com/a/x in multiple modules:\n\texample.com/a v0.1.0 \('$WORK'[/\\]a[/\\]x\)\n\texample.com/a/x v0.1.0 \('$WORK'[/\\]ax\)$' + +# However, it should not be an error if that import is unused. +go build ./importy + +# An import provided by both the main module and the vendor directory +# should be flagged as an error only when -mod=vendor is set. +mkdir vendor/example.com/m/importy +cp $WORK/importy/importy.go vendor/example.com/m/importy/importy.go +go build example.com/m/importy +! go build -mod=vendor example.com/m/importy +stderr '^ambiguous import: found package example.com/m/importy in multiple directories:\n\t'$WORK'[/\\]importy\n\t'$WORK'[/\\]vendor[/\\]example.com[/\\]m[/\\]importy$' + +-- $WORK/go.mod -- +module example.com/m +go 1.13 +require ( + example.com/a v0.1.0 + example.com/a/x v0.1.0 +) +replace ( + example.com/a v0.1.0 => ./a + example.com/a/x v0.1.0 => ./ax +) +-- $WORK/importx/importx.go -- +package importx +import _ "example.com/a/x" +-- $WORK/importy/importy.go -- +package importy +import _ "example.com/a/y" +-- $WORK/a/go.mod -- +module example.com/a +go 1.14 +-- $WORK/a/x/x.go -- +package x +-- $WORK/a/y/y.go -- +package y +-- $WORK/ax/go.mod -- +module example.com/a/x +go 1.14 +-- $WORK/ax/x.go -- +package x diff --git a/src/cmd/go/testdata/script/mod_auth.txt b/src/cmd/go/testdata/script/mod_auth.txt new file mode 100644 index 0000000..d8ea586 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_auth.txt @@ -0,0 +1,35 @@ +[!net] skip + +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off +env GOVCS='*:off' + +# Without credentials, downloading a module from a path that requires HTTPS +# basic auth should fail. +env NETRC=$WORK/empty +! go mod tidy +stderr '^\tserver response: ACCESS DENIED, buddy$' +stderr '^\tserver response: File\? What file\?$' + +# With credentials from a netrc file, it should succeed. +env NETRC=$WORK/netrc +go mod tidy +go list all +stdout vcs-test.golang.org/auth/or401 +stdout vcs-test.golang.org/auth/or404 + +-- go.mod -- +module private.example.com +-- main.go -- +package useprivate + +import ( + _ "vcs-test.golang.org/auth/or401" + _ "vcs-test.golang.org/auth/or404" +) +-- $WORK/empty -- +-- $WORK/netrc -- +machine vcs-test.golang.org + login aladdin + password opensesame diff --git a/src/cmd/go/testdata/script/mod_bad_domain.txt b/src/cmd/go/testdata/script/mod_bad_domain.txt new file mode 100644 index 0000000..7a270d0 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_bad_domain.txt @@ -0,0 +1,47 @@ +env GO111MODULE=on + +# explicit get should report errors about bad names +! go get appengine +stderr '^go get: 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' + + +# 'go list -m' should report errors about module names, never GOROOT. +! go list -m -versions appengine +stderr 'malformed module path "appengine": missing dot in first path element' +! go list -m -versions 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 '^useappengine[/\\]x.go:2:8: cannot find package$' +! go build ./usenonexistent +stderr '^usenonexistent[/\\]x.go:2:8: no required module provides package nonexistent.rsc.io; to add it:\n\tgo get nonexistent.rsc.io$' + + +# 'get -d' should be similarly definitive + +go get -d ./useappengine # TODO(#41315): This should fail. + # stderr '^useappengine[/\\]x.go:2:8: cannot find package$' + +! go get -d ./usenonexistent +stderr '^x/usenonexistent imports\n\tnonexistent.rsc.io: 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/src/cmd/go/testdata/script/mod_bad_filenames.txt b/src/cmd/go/testdata/script/mod_bad_filenames.txt new file mode 100644 index 0000000..eb556f4 --- /dev/null +++ b/src/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: rsc.io[\\/]badfile3@v1.0.0[\\/]x\?y.go: malformed file path "x\?y.go": invalid char ''\?''' +stderr 'unzip.*badfile4[\\/]@v[\\/]v1.0.0.zip: rsc.io[\\/]badfile4@v1.0.0[\\/]x[\\/]y.go: case-insensitive file name collision: "x/Y.go" and "x/y.go"' +stderr 'unzip.*badfile5[\\/]@v[\\/]v1.0.0.zip: rsc.io[\\/]badfile5@v1.0.0[\\/]x[\\/]Y[\\/]zz[\\/]ww.go: case-insensitive file name collision: "x/y" and "x/Y"' + +-- go.mod -- +module x diff --git a/src/cmd/go/testdata/script/mod_build_info_err.txt b/src/cmd/go/testdata/script/mod_build_info_err.txt new file mode 100644 index 0000000..cee055e --- /dev/null +++ b/src/cmd/go/testdata/script/mod_build_info_err.txt @@ -0,0 +1,33 @@ +# This test verifies that line numbers are included in module import errors. +# Verifies golang.org/issue/34393. + +go list -e -mod=mod -deps -f '{{with .Error}}{{.Pos}}: {{.Err}}{{end}}' ./main +stdout '^bad[/\\]bad.go:3:8: malformed import path "🐧.example.com/string": invalid char ''🐧''$' + +# TODO(#26909): This should include an import stack. +# (Today it includes only a file and line.) +! go build ./main +stderr '^bad[/\\]bad.go:3:8: malformed import path "🐧.example.com/string": invalid char ''🐧''$' + +# TODO(#41688): This should include a file and line, and report the reason for the error.. +# (Today it includes only an import stack.) +! go get -d ./main +stderr '^m/main imports\n\tm/bad imports\n\t🐧.example.com/string: malformed import path "🐧.example.com/string": invalid char ''🐧''$' + + +-- go.mod -- +module m + +go 1.13 + +-- main/main.go -- +package main + +import _ "m/bad" + +func main() {} + +-- bad/bad.go -- +package bad + +import _ "🐧.example.com/string" diff --git a/src/cmd/go/testdata/script/mod_build_tags.txt b/src/cmd/go/testdata/script/mod_build_tags.txt new file mode 100644 index 0000000..ae1d605 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_build_tags.txt @@ -0,0 +1,33 @@ +# 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\]' + +go list -f {{.GoFiles}} -tags tag1,tag2 # commas allowed as of Go 1.13 +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/src/cmd/go/testdata/script/mod_build_versioned.txt b/src/cmd/go/testdata/script/mod_build_versioned.txt new file mode 100644 index 0000000..d1d74de --- /dev/null +++ b/src/cmd/go/testdata/script/mod_build_versioned.txt @@ -0,0 +1,17 @@ +env GO111MODULE=on +[short] skip + +go get -d rsc.io/fortune/v2 + +# The default executable name shouldn't be v2$GOEXE +go build rsc.io/fortune/v2 +! exists v2$GOEXE +exists fortune$GOEXE + +# The default test binary name shouldn't be v2.test$GOEXE +go test -c rsc.io/fortune/v2 +! exists v2.test$GOEXE +exists fortune.test$GOEXE + +-- go.mod -- +module scratch diff --git a/src/cmd/go/testdata/script/mod_cache_rw.txt b/src/cmd/go/testdata/script/mod_cache_rw.txt new file mode 100644 index 0000000..a541076 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_cache_rw.txt @@ -0,0 +1,49 @@ +# Regression test for golang.org/issue/31481. + +env GO111MODULE=on + +# golang.org/issue/31481: an explicit flag should make directories in the module +# cache writable in order to work around the historical inability of 'rm -rf' to +# forcibly remove files in unwritable directories. +go get -modcacherw -d rsc.io/quote@v1.5.2 +cp $WORK/extraneous.txt $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/extraneous_file.go + +# After adding an extraneous file, 'go mod verify' should fail. +! go mod verify + +# However, files within those directories should still be read-only to avoid +# accidental mutations. +[!root] ! cp $WORK/extraneous.txt $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod + +# If all 'go' commands ran with the flag, the system's 'rm' binary +# should be able to remove the module cache if the '-rf' flags are set. +[!windows] [exec:rm] exec rm -rf $GOPATH/pkg/mod +[!windows] [!exec:rm] go clean -modcache +[windows] [exec:cmd.exe] exec cmd.exe /c rmdir /s /q $GOPATH\pkg\mod +[windows] [!exec:cmd.exe] go clean -modcache +! exists $GOPATH/pkg/mod + +# The directories in the module cache should by default be unwritable, +# so that tests and tools will not accidentally add extraneous files to them. +# Windows does not respect FILE_ATTRIBUTE_READONLY on directories, according +# to MSDN, so there we disable testing whether the directory itself is +# unwritable. +go get -d rsc.io/quote@latest +[!root] ! cp $WORK/extraneous.txt $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod +[!windows] [!root] ! cp $WORK/extraneous.txt $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/extraneous_file.go +! exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/extraneous_file.go + + +# Repeat part of the test with 'go mod download' instead of 'go get' to verify +# -modcacherw is supported on 'go mod' subcommands. +go clean -modcache +go mod download -modcacherw rsc.io/quote +cp $WORK/extraneous.txt $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/extraneous_file.go +! go mod verify +[!root] ! cp $WORK/extraneous.txt $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod + + +-- $WORK/extraneous.txt -- +module oops +-- go.mod -- +module golang.org/issue/31481 diff --git a/src/cmd/go/testdata/script/mod_case.txt b/src/cmd/go/testdata/script/mod_case.txt new file mode 100644 index 0000000..4a46986 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_case.txt @@ -0,0 +1,25 @@ +env GO111MODULE=on + +go get -d +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 -d 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 + +-- use.go -- +package use + +import _ "rsc.io/QUOTE/QUOTE" diff --git a/src/cmd/go/testdata/script/mod_case_cgo.txt b/src/cmd/go/testdata/script/mod_case_cgo.txt new file mode 100644 index 0000000..f3d6aaa --- /dev/null +++ b/src/cmd/go/testdata/script/mod_case_cgo.txt @@ -0,0 +1,11 @@ +[!cgo] skip + +env GO111MODULE=on + +go get -d rsc.io/CGO +[short] stop + +go build rsc.io/CGO + +-- go.mod -- +module x diff --git a/src/cmd/go/testdata/script/mod_clean_cache.txt b/src/cmd/go/testdata/script/mod_clean_cache.txt new file mode 100644 index 0000000..01fbc38 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_clean_cache.txt @@ -0,0 +1,58 @@ +env GO111MODULE=on + +# 'mod download' should download the module to the cache. +go mod download rsc.io/quote@v1.5.0 +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 + +# '-n' should print commands but not actually execute them. +go clean -modcache -n +stdout '^rm -rf .*pkg.mod$' +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 + +# 'go clean -modcache' should actually delete the files. +go clean -modcache +! 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 + +# 'go clean -r -modcache' should clean only the dependencies that are within the +# main module. +# BUG(golang.org/issue/28680): Today, it cleans across module boundaries. +cd r +exists ./test.out +exists ../replaced/test.out +go clean -r -modcache +! exists ./test.out +! exists ../replaced/test.out # BUG: should still exist + +# 'go clean -modcache' should not download anything before cleaning. +go mod edit -require rsc.io/quote@v1.99999999.0-not-a-real-version +go clean -modcache +! stderr 'finding rsc.io' +go mod edit -droprequire rsc.io/quote + +-- go.mod -- +module m +-- m.go -- +package m + +-- r/go.mod -- +module example.com/r +require example.com/r/replaced v0.0.0 +replace example.com/r/replaced => ../replaced +-- r/r.go -- +package r +import _ "example.com/r/replaced" +-- r/test.out -- +DELETE ME + +-- replaced/go.mod -- +module example.com/r/replaced +-- replaced/replaced.go -- +package replaced +-- replaced/test.out -- +DO NOT DELETE diff --git a/src/cmd/go/testdata/script/mod_concurrent.txt b/src/cmd/go/testdata/script/mod_concurrent.txt new file mode 100644 index 0000000..8c21525 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_concurrent.txt @@ -0,0 +1,32 @@ +env GO111MODULE=on + +# Concurrent builds should succeed, even if they need to download modules. +go get -d ./x ./y +go build ./x & +go build ./y +wait + +# Concurrent builds should update go.sum to the union of the hashes for the +# modules they read. +cmp go.sum go.sum.want + +-- go.mod -- +module golang.org/issue/26794 + +require ( + golang.org/x/text v0.3.0 + rsc.io/sampler v1.0.0 +) +-- x/x.go -- +package x + +import _ "golang.org/x/text/language" +-- y/y.go -- +package y + +import _ "rsc.io/sampler" +-- go.sum.want -- +golang.org/x/text v0.3.0 h1:ivTorhoiROmZ1mcs15mO2czVF0uy0tnezXpBVNzgrmA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/sampler v1.0.0 h1:SRJnjyQ07sAtq6G4RcfJEmz8JxqLyj3PoGXG2VhbDWo= +rsc.io/sampler v1.0.0/go.mod h1:cqxpM3ZVz9VtirqxZPmrWzkQ+UkiNiGtkrN+B+i8kx8= diff --git a/src/cmd/go/testdata/script/mod_convert_dep.txt b/src/cmd/go/testdata/script/mod_convert_dep.txt new file mode 100644 index 0000000..875a836 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_convert_dep.txt @@ -0,0 +1,30 @@ +env GO111MODULE=on + +# We should not create a go.mod file unless the user ran 'go mod init' explicitly. +# However, we should suggest 'go mod init' if we can find an alternate config file. +cd $WORK/test/x +! go list . +stderr 'found Gopkg.lock in .*[/\\]test' +stderr '\s*cd \.\. && go mod init' + +# The command we suggested should succeed. +cd .. +go mod init +go list -m all +stdout '^m$' + +# In Plan 9, directories are automatically created in /n. +# For example, /n/Gopkg.lock always exists, but it's a directory. +# Test that we ignore directories when trying to find alternate config files. +cd $WORK/gopkgdir/x +! go list . +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' +! stderr 'Gopkg.lock' + +-- $WORK/test/Gopkg.lock -- +-- $WORK/test/x/x.go -- +package x // import "m/x" +-- $WORK/gopkgdir/Gopkg.lock/README.txt -- +../Gopkg.lock is a directory, not a file. +-- $WORK/gopkgdir/x/x.go -- +package x // import "m/x" diff --git a/src/cmd/go/testdata/script/mod_convert_git.txt b/src/cmd/go/testdata/script/mod_convert_git.txt new file mode 100644 index 0000000..6ff1eb5 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_convert_git.txt @@ -0,0 +1,40 @@ +env GO111MODULE=on + +# We should not create a go.mod file unless the user ran 'go mod init' explicitly. +# However, we should suggest 'go mod init' if we can find an alternate config file. +cd $WORK/test/x +! go list . +stderr 'found .git/config in .*[/\\]test' +stderr '\s*cd \.\. && go mod init' + +# The command we suggested should succeed. +cd .. +go mod init +go list -m all +stdout '^m$' + +# We should not suggest creating a go.mod file in $GOROOT, even though there may be a .git/config there. +cd $GOROOT +! go list . +! stderr 'go mod init' + +# We should also not suggest creating a go.mod file in $GOROOT if its own +# .git/config has been stripped away and we find one in a parent directory. +# (https://golang.org/issue/34191) +env GOROOT=$WORK/parent/goroot +cd $GOROOT +! go list . +! stderr 'go mod init' + +cd $GOROOT/doc +! go list . +! stderr 'go mod init' + +-- $WORK/test/.git/config -- +-- $WORK/test/x/x.go -- +package x // import "m/x" +-- $WORK/parent/.git/config -- +-- $WORK/parent/goroot/README -- +This directory isn't really a GOROOT, but let's pretend that it is. +-- $WORK/parent/goroot/doc/README -- +This is a subdirectory of our fake GOROOT. diff --git a/src/cmd/go/testdata/script/mod_convert_glide.txt b/src/cmd/go/testdata/script/mod_convert_glide.txt new file mode 100644 index 0000000..9f1fff5 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_convert_glide.txt @@ -0,0 +1,18 @@ +env GO111MODULE=on + +# We should not create a go.mod file unless the user ran 'go mod init' explicitly. +# However, we should suggest 'go mod init' if we can find an alternate config file. +cd $WORK/test/x +! go list . +stderr 'found glide.lock in .*[/\\]test' +stderr '\s*cd \.\. && go mod init' + +# The command we suggested should succeed. +cd .. +go mod init +go list -m all +stdout '^m$' + +-- $WORK/test/glide.lock -- +-- $WORK/test/x/x.go -- +package x // import "m/x" diff --git a/src/cmd/go/testdata/script/mod_convert_glockfile.txt b/src/cmd/go/testdata/script/mod_convert_glockfile.txt new file mode 100644 index 0000000..6aa0794 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_convert_glockfile.txt @@ -0,0 +1,18 @@ +env GO111MODULE=on + +# We should not create a go.mod file unless the user ran 'go mod init' explicitly. +# However, we should suggest 'go mod init' if we can find an alternate config file. +cd $WORK/test/x +! go list . +stderr 'found GLOCKFILE in .*[/\\]test' +stderr '\s*cd \.\. && go mod init' + +# The command we suggested should succeed. +cd .. +go mod init +go list -m all +stdout '^m$' + +-- $WORK/test/GLOCKFILE -- +-- $WORK/test/x/x.go -- +package x // import "m/x" diff --git a/src/cmd/go/testdata/script/mod_convert_godeps.txt b/src/cmd/go/testdata/script/mod_convert_godeps.txt new file mode 100644 index 0000000..da7b6c1 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_convert_godeps.txt @@ -0,0 +1,19 @@ +env GO111MODULE=on + +# We should not create a go.mod file unless the user ran 'go mod init' explicitly. +# However, we should suggest 'go mod init' if we can find an alternate config file. +cd $WORK/test/x +! go list . +stderr 'found Godeps/Godeps.json in .*[/\\]test' +stderr '\s*cd \.\. && go mod init' + +# The command we suggested should succeed. +cd .. +go mod init +go list -m all +stdout '^m$' + +-- $WORK/test/Godeps/Godeps.json -- +{} +-- $WORK/test/x/x.go -- +package x // import "m/x" diff --git a/src/cmd/go/testdata/script/mod_convert_tsv.txt b/src/cmd/go/testdata/script/mod_convert_tsv.txt new file mode 100644 index 0000000..6015ac8 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_convert_tsv.txt @@ -0,0 +1,18 @@ +env GO111MODULE=on + +# We should not create a go.mod file unless the user ran 'go mod init' explicitly. +# However, we should suggest 'go mod init' if we can find an alternate config file. +cd $WORK/test/x +! go list . +stderr 'found dependencies.tsv in .*[/\\]test' +stderr '\s*cd \.\. && go mod init' + +# The command we suggested should succeed. +cd .. +go mod init +go list -m all +stdout '^m$' + +-- $WORK/test/dependencies.tsv -- +-- $WORK/test/x/x.go -- +package x // import "m/x" diff --git a/src/cmd/go/testdata/script/mod_convert_tsv_insecure.txt b/src/cmd/go/testdata/script/mod_convert_tsv_insecure.txt new file mode 100644 index 0000000..ddb0c08 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_convert_tsv_insecure.txt @@ -0,0 +1,27 @@ +env GO111MODULE=on + +[!net] skip +[!exec:git] skip + +# secure fetch should report insecure warning +cd $WORK/test +go mod init +stderr 'redirected .* to insecure URL' + +# insecure fetch should not +env GOINSECURE=*.golang.org +rm go.mod +go mod init +! stderr 'redirected .* to insecure URL' + +# insecure fetch invalid path should report insecure warning +env GOINSECURE=foo.golang.org +rm go.mod +go mod init +stderr 'redirected .* to insecure URL' + +-- $WORK/test/dependencies.tsv -- +vcs-test.golang.org/insecure/go/insecure git 6fecd21f7c0c 2019-09-04T18:39:48Z + +-- $WORK/test/x.go -- +package x // import "m" diff --git a/src/cmd/go/testdata/script/mod_convert_vendor_conf.txt b/src/cmd/go/testdata/script/mod_convert_vendor_conf.txt new file mode 100644 index 0000000..57ec419 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_convert_vendor_conf.txt @@ -0,0 +1,18 @@ +env GO111MODULE=on + +# We should not create a go.mod file unless the user ran 'go mod init' explicitly. +# However, we should suggest 'go mod init' if we can find an alternate config file. +cd $WORK/test/x +! go list . +stderr 'found vendor.conf in .*[/\\]test' +stderr '\s*cd \.\. && go mod init' + +# The command we suggested should succeed. +cd .. +go mod init +go list -m all +stdout '^m$' + +-- $WORK/test/vendor.conf -- +-- $WORK/test/x/x.go -- +package x // import "m/x" diff --git a/src/cmd/go/testdata/script/mod_convert_vendor_json.txt b/src/cmd/go/testdata/script/mod_convert_vendor_json.txt new file mode 100644 index 0000000..df6db36 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_convert_vendor_json.txt @@ -0,0 +1,19 @@ +env GO111MODULE=on + +# We should not create a go.mod file unless the user ran 'go mod init' explicitly. +# However, we should suggest 'go mod init' if we can find an alternate config file. +cd $WORK/test/x +! go list . +stderr 'found vendor/vendor.json in .*[/\\]test' +stderr '\s*cd \.\. && go mod init' + +# The command we suggested should succeed. +cd .. +go mod init +go list -m +stdout '^m$' + +-- $WORK/test/vendor/vendor.json -- +{} +-- $WORK/test/x/x.go -- +package x // import "m/x" diff --git a/src/cmd/go/testdata/script/mod_convert_vendor_manifest.txt b/src/cmd/go/testdata/script/mod_convert_vendor_manifest.txt new file mode 100644 index 0000000..8b6a141 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_convert_vendor_manifest.txt @@ -0,0 +1,19 @@ +env GO111MODULE=on + +# We should not create a go.mod file unless the user ran 'go mod init' explicitly. +# However, we should suggest 'go mod init' if we can find an alternate config file. +cd $WORK/test/x +! go list . +stderr 'found vendor/manifest in .*[/\\]test' +stderr '\s*cd \.\. && go mod init' + +# The command we suggested should succeed. +cd .. +go mod init +go list -m +stdout '^m$' + +-- $WORK/test/vendor/manifest -- +{} +-- $WORK/test/x/x.go -- +package x // import "m/x" diff --git a/src/cmd/go/testdata/script/mod_convert_vendor_yml.txt b/src/cmd/go/testdata/script/mod_convert_vendor_yml.txt new file mode 100644 index 0000000..4ed140a --- /dev/null +++ b/src/cmd/go/testdata/script/mod_convert_vendor_yml.txt @@ -0,0 +1,18 @@ +env GO111MODULE=on + +# We should not create a go.mod file unless the user ran 'go mod init' explicitly. +# However, we should suggest 'go mod init' if we can find an alternate config file. +cd $WORK/test/x +! go list . +stderr 'found vendor.yml in .*[/\\]test' +stderr '\s*cd \.\. && go mod init' + +# The command we suggested should succeed. +cd .. +go mod init +go list -m all +stdout '^m$' + +-- $WORK/test/vendor.yml -- +-- $WORK/test/x/x.go -- +package x // import "m/x" diff --git a/src/cmd/go/testdata/script/mod_dir.txt b/src/cmd/go/testdata/script/mod_dir.txt new file mode 100644 index 0000000..05548f6 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_dir.txt @@ -0,0 +1,20 @@ +# The directory named go.mod should be ignored + +env GO111MODULE=on + +cd $WORK/sub + +go list . +stdout 'x/sub' + +mkdir go.mod +exists go.mod + +go list . +stdout 'x/sub' + +-- $WORK/go.mod -- +module x + +-- $WORK/sub/x.go -- +package x \ No newline at end of file diff --git a/src/cmd/go/testdata/script/mod_doc.txt b/src/cmd/go/testdata/script/mod_doc.txt new file mode 100644 index 0000000..595ad67 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_doc.txt @@ -0,0 +1,89 @@ +# go doc should find module documentation + +env GO111MODULE=on +env GOFLAGS=-mod=mod +[short] skip + +# Check when module x is inside GOPATH/src. +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 when module x is outside GOPATH/src. +env GOPATH=$WORK/emptygopath +go doc x/y +stdout 'Package y is.*alphabet' +go doc y +stdout 'Package y is.*alphabet' + +# Triple-check when module x is outside GOPATH/src, +# but other packages with same import paths are in GOPATH/src. +# Since go doc is running in module mode here, packages in active module +# should be preferred over packages in GOPATH. See golang.org/issue/28992. +env GOPATH=$WORK/gopath2 +go doc x/y +! stdout 'Package y is.*GOPATH' +stdout 'Package y is.*alphabet' +go doc rsc.io/quote +! stdout 'Package quote is located in a GOPATH workspace.' +stdout 'Package quote collects pithy sayings.' + +# Check that a sensible error message is printed when a package is not found. +env GOPROXY=off +! go doc example.com/hello +stderr '^doc: cannot find module providing package example.com/hello: module lookup disabled by GOPROXY=off$' + +# When in a module with a vendor directory, doc should use the vendored copies +# of the packages. 'std' and 'cmd' are convenient examples of such modules. +# +# When in those modules, the "// import" comment should refer to the same import +# path used in source code, not to the absolute path relative to GOROOT. + +cd $GOROOT/src +env GOFLAGS= +go doc cryptobyte +stdout '// import "golang.org/x/crypto/cryptobyte"' + +cd $GOROOT/src/cmd/go +go doc modfile +stdout '// import "golang.org/x/mod/modfile"' + +# When outside of the 'std' module, its vendored packages +# remain accessible using the 'vendor/' prefix, but report +# the correct "// import" comment as used within std. +cd $GOPATH +go doc vendor/golang.org/x/crypto/cryptobyte +stdout '// import "vendor/golang.org/x/crypto/cryptobyte"' + +go doc cmd/vendor/golang.org/x/mod/modfile +stdout '// import "cmd/vendor/golang.org/x/mod/modfile"' + +-- 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 + +-- $WORK/gopath2/src/x/y/y.go -- +// Package y is located in a GOPATH workspace. +package y +-- $WORK/gopath2/src/rsc.io/quote/quote.go -- +// Package quote is located in a GOPATH workspace. +package quote + +// Hello is located in a GOPATH workspace. +func Hello() string { return "" } diff --git a/src/cmd/go/testdata/script/mod_domain_root.txt b/src/cmd/go/testdata/script/mod_domain_root.txt new file mode 100644 index 0000000..14745b5 --- /dev/null +++ b/src/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 get -d + +-- go.mod -- +module x + +-- x.go -- +package x +import _ "example.com" diff --git a/src/cmd/go/testdata/script/mod_dot.txt b/src/cmd/go/testdata/script/mod_dot.txt new file mode 100644 index 0000000..ca8d5c6 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_dot.txt @@ -0,0 +1,131 @@ +env GO111MODULE=on + +# golang.org/issue/32917 and golang.org/issue/28459: 'go build' and 'go test' +# in an empty directory should refer to the path '.' and should not attempt +# to resolve an external module. +cd dir +! go get +stderr '^go get: no package in current directory$' +! go get . +stderr '^go get \.: no package in current directory$' +! go get ./subdir +stderr '^go get: \.[/\\]subdir \('$WORK'[/\\]gopath[/\\]src[/\\]dir[/\\]subdir\) is not a package in module rooted at '$WORK'[/\\]gopath[/\\]src[/\\]dir$' +! go list +! stderr 'cannot find module providing package' +stderr '^no Go files in '$WORK'[/\\]gopath[/\\]src[/\\]dir$' + +cd subdir +! go list +! stderr 'cannot find module providing package' +stderr '^no Go files in '$WORK'[/\\]gopath[/\\]src[/\\]dir[/\\]subdir$' +cd .. + +# golang.org/issue/30590: if a package is found in the filesystem +# but is not in the main module, the error message should not say +# "cannot find module providing package", and we shouldn't try +# to find a module providing the package. +! go list ./othermodule +! stderr 'cannot find module providing package' +stderr '^main module \(example\.com\) does not contain package example.com/othermodule$' + +# golang.org/issue/27122: 'go build' of a nonexistent directory should produce +# a helpful "no Go files" error message, not a generic "unknown import path". +! go list ./subdir +stderr '^no Go files in '$WORK'[/\\]gopath[/\\]src[/\\]dir[/\\]subdir$' + +# golang.org/issue/29280: 'go list -e' for a nonexistent directory should +# report a nonexistent package with an error. +go list -e -json ./subdir +stdout '"Incomplete": true' + +# golang.org/issue/28155: 'go list ./testdata' should not synthesize underscores. +go list ./testdata +stdout '^example.com/testdata' + +# golang.org/issue/32921: vendor directories should only be accepted as directories +# if the directory would actually be used to load the package. +! go list ./vendor/nonexist +stderr '^no Go files in '$WORK'[/\\]gopath[/\\]src[/\\]dir[/\\]vendor[/\\]nonexist$' + +! go list ./vendor/pkg +stderr '^without -mod=vendor, directory '$WORK'[/\\]gopath[/\\]src[/\\]dir[/\\]vendor[/\\]pkg has no package path$' + +! go list -mod=vendor ./vendor/nonexist +stderr '^no Go files in '$WORK'[/\\]gopath[/\\]src[/\\]dir[/\\]vendor[/\\]nonexist$' + +! go list -mod=vendor ./vendor/unlisted +stderr '^directory '$WORK'[/\\]gopath[/\\]src[/\\]dir[/\\]vendor[/\\]unlisted is not a package listed in vendor/modules.txt$' + +go list -mod=vendor ./vendor/pkg +stdout '^pkg$' + +# Packages within GOROOT should resolve as in any other module, +# except that -mod=vendor is implied by default. +cd $GOROOT/src +! go list . +stderr '^no Go files in '$GOROOT'[/\\]src$' + +! go list ./builtin +stderr '^"builtin" is a pseudo-package, not an importable package$' + +! go list ./debug +! stderr 'cannot find module providing package' +stderr '^no Go files in '$GOROOT'[/\\]src[/\\]debug$' + +! go list ./golang.org/x/tools/cmd/goimports +! stderr 'cannot find module providing package' +stderr '^stat '$GOROOT'[/\\]src[/\\]golang.org[/\\]x[/\\]tools[/\\]cmd[/\\]goimports: directory not found' + +go list ./vendor/golang.org/x/net/http2/hpack +stdout '^golang.org/x/net/http2/hpack$' + +# golang.org/issue/30756: packages in other GOROOTs should not get the special +# prefixless treatment of GOROOT itself. +cd $WORK/othergoroot/src +! go list . +stderr '^no Go files in '$WORK'[/\\]othergoroot[/\\]src$' + +go list ./builtin +stdout '^std/builtin$' # Only the "std" in actual $GOROOT is special, and only its "builtin" is special. + +! go list ./bytes +! stderr 'cannot find module providing package' +stderr '^no Go files in '$WORK'[/\\]othergoroot[/\\]src[/\\]bytes$' + +! go list ./vendor/golang.org/x/net/http2/hpack +stderr '^without -mod=vendor, directory '$WORK'[/\\]othergoroot[/\\]src[/\\]vendor[/\\]golang.org[/\\]x[/\\]net[/\\]http2[/\\]hpack has no package path$' + +-- dir/go.mod -- +module example.com +go 1.13 +-- dir/subdir/README -- +There are no Go source files in this directory. +-- dir/othermodule/go.mod -- +module example.com/othermodule +go 1.13 +-- dir/othermodule/om.go -- +package othermodule +-- dir/testdata/td.go -- +package testdata +-- dir/vendor/modules.txt -- +# pkg v0.0.0 +pkg +-- dir/vendor/nonexist/README -- +There are no Go source files here either. +-- dir/vendor/pkg/pkg.go -- +package pkg +-- dir/vendor/unlisted/unlisted.go -- +package unlisted +-- emptyroot/go.mod -- +module example.com/emptyroot +-- emptyroot/pkg/pkg.go -- +package pkg +-- $WORK/othergoroot/src/go.mod -- +module std +go 1.13 +-- $WORK/othergoroot/src/builtin/builtin.go -- +package builtin +-- $WORK/othergoroot/src/bytes/README -- +There are no Go source files in this directory. +-- $WORK/othergoroot/src/vendor/golang.org/x/net/http2/hpack -- +package hpack diff --git a/src/cmd/go/testdata/script/mod_download.txt b/src/cmd/go/testdata/script/mod_download.txt new file mode 100644 index 0000000..c2b72b2 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_download.txt @@ -0,0 +1,170 @@ +env GO111MODULE=on + +# download with version should print nothing. +# It should not load retractions from the .mod file from the latest version. +go mod download rsc.io/quote@v1.5.0 +! stdout . +! stderr . +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 +! 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 + +# download of an invalid path should report the error +[short] skip +! go mod download this.domain.is.invalid/somemodule@v1.0.0 +stderr 'this.domain.is.invalid' +! go mod download -json this.domain.is.invalid/somemodule@v1.0.0 +stdout '"Error": ".*this.domain.is.invalid.*"' + +# 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 + +# download query should have downloaded go.mod for the highest release version +# in order to find retractions when resolving the query '@<=v1.5.0'. +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 + +# add to go.mod so we can test non-query downloads +go mod edit -require rsc.io/quote@v1.5.3-pre1 +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.info +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.mod +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.zip + +# module loading will page in the info and mod files +go list -m -mod=mod all +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.info +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.mod +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.zip + +# download will fetch and unpack the zip file +go mod download +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.info +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.mod +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.zip +exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.3-pre1 + +# download repopulates deleted files and directories independently. +rm $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.info +go mod download +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.info +rm $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.mod +go mod download +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.mod +rm $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.zip +go mod download +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.zip +rm -r $GOPATH/pkg/mod/rsc.io/quote@v1.5.3-pre1 +go mod download +exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.3-pre1 + +# download reports the locations of downloaded files +go mod download -json +stdout '^\t"Path": "rsc.io/quote"' +stdout '^\t"Version": "v1.5.3-pre1"' +stdout '^\t"Info": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)cache(\\\\|/)download(\\\\|/)rsc.io(\\\\|/)quote(\\\\|/)@v(\\\\|/)v1.5.3-pre1.info"' +stdout '^\t"GoMod": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)cache(\\\\|/)download(\\\\|/)rsc.io(\\\\|/)quote(\\\\|/)@v(\\\\|/)v1.5.3-pre1.mod"' +stdout '^\t"Zip": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)cache(\\\\|/)download(\\\\|/)rsc.io(\\\\|/)quote(\\\\|/)@v(\\\\|/)v1.5.3-pre1.zip"' +stdout '^\t"Dir": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)rsc.io(\\\\|/)quote@v1.5.3-pre1"' + +# 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.2 +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.2.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 + +# download reports errors encountered when locating modules +! go mod download bad/path +stderr '^go mod download: module bad/path: not a known dependency$' +! go mod download bad/path@latest +stderr '^go mod download: bad/path@latest: malformed module path "bad/path": missing dot in first path element$' +! go mod download rsc.io/quote@v1.999.999 +stderr '^go mod download: rsc.io/quote@v1.999.999: reading .*/v1.999.999.info: 404 Not Found$' +! go mod download -json bad/path +stdout '^\t"Error": "module bad/path: not a known dependency"' + +# download main module produces a warning or error +go mod download m +stderr '^go mod download: skipping argument m that resolves to the main module\n' +! go mod download m@latest +stderr '^go mod download: m@latest: malformed module path "m": missing dot in first path element$' + +# download without arguments updates go.mod and go.sum after loading the +# build list, but does not save sums for downloaded zips. +cd update +cp go.mod.orig go.mod +! exists go.sum +go mod download +cmp go.mod.update go.mod +cmp go.sum.update go.sum +cp go.mod.orig go.mod +rm go.sum + +# download with arguments (even "all") does update go.mod and go.sum. +go mod download rsc.io/sampler +cmp go.mod.update go.mod +grep '^rsc.io/sampler v1.3.0 ' go.sum +cp go.mod.orig go.mod +rm go.sum + +go mod download all +cmp go.mod.update go.mod +grep '^rsc.io/sampler v1.3.0 ' go.sum +cd .. + +# allow go mod download without go.mod +env GO111MODULE=auto +rm go.mod +rm $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.2.1.zip +go mod download rsc.io/quote@v1.2.1 +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.2.1.zip + +# download -x with version should print +# the underlying commands such as contacting GOPROXY. +go mod download -x rsc.io/quote@v1.0.0 +! stdout . +stderr 'get '$GOPROXY + +-- go.mod -- +module m + +-- update/go.mod.orig -- +module m + +go 1.16 + +require ( + rsc.io/quote v1.5.2 + rsc.io/sampler v1.2.1 // older version than in build list +) +-- update/go.mod.update -- +module m + +go 1.16 + +require ( + rsc.io/quote v1.5.2 + rsc.io/sampler v1.3.0 // older version than in build list +) +-- update/go.sum.update -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/src/cmd/go/testdata/script/mod_download_concurrent_read.txt b/src/cmd/go/testdata/script/mod_download_concurrent_read.txt new file mode 100644 index 0000000..231babd --- /dev/null +++ b/src/cmd/go/testdata/script/mod_download_concurrent_read.txt @@ -0,0 +1,110 @@ +# This test simulates a process watching for changes and reading files in +# module cache as a module is extracted. +# +# Before Go 1.16, we extracted each module zip to a temporary directory with +# a random name, then renamed that into place with os.Rename. On Windows, +# this failed with ERROR_ACCESS_DENIED when another process (usually an +# anti-virus scanner) opened files in the temporary directory. This test +# simulates that behavior, verifying golang.org/issue/36568. +# +# Since 1.16, we extract to the final directory, but we create a .partial file +# so that if we crash, other processes know the directory is incomplete. + +[!windows] skip +[short] skip + +go run downloader.go + +-- go.mod -- +module example.com/m + +go 1.14 + +-- downloader.go -- +package main + +import ( + "fmt" + "log" + "os" + "os/exec" + "path/filepath" +) + +func main() { + if err := run(); err != nil { + log.Fatal(err) + } +} + +// run repeatedly downloads a module while opening files in the module cache +// in a background goroutine. +// +// run uses a different temporary module cache in each iteration so that we +// don't need to clean the cache or synchronize closing files after each +// iteration. +func run() (err error) { + tmpDir, err := os.MkdirTemp("", "") + if err != nil { + return err + } + defer func() { + if rmErr := os.RemoveAll(tmpDir); err == nil && rmErr != nil { + err = rmErr + } + }() + for i := 0; i < 10; i++ { + gopath := filepath.Join(tmpDir, fmt.Sprintf("gopath%d", i)) + var err error + done := make(chan struct{}) + go func() { + err = download(gopath) + close(done) + }() + readCache(gopath, done) + if err != nil { + return err + } + } + return nil +} + +// download downloads a module into the given cache using 'go mod download'. +func download(gopath string) error { + cmd := exec.Command("go", "mod", "download", "-modcacherw", "rsc.io/quote@v1.5.2") + cmd.Stderr = os.Stderr + cmd.Env = append(os.Environ(), "GOPATH="+gopath) + return cmd.Run() +} + +// readCache repeatedly globs for go.mod files in the given cache, then opens +// those files for reading. When the done chan is closed, readCache closes +// files and returns. +func readCache(gopath string, done <-chan struct{}) { + files := make(map[string]*os.File) + defer func() { + for _, f := range files { + f.Close() + } + }() + + pattern := filepath.Join(gopath, "pkg/mod/rsc.io/quote@v1.5.2*/go.mod") + for { + select { + case <-done: + return + default: + } + + names, _ := filepath.Glob(pattern) + for _, name := range names { + if files[name] != nil { + continue + } + f, _ := os.Open(name) + if f != nil { + files[name] = f + } + } + } +} diff --git a/src/cmd/go/testdata/script/mod_download_hash.txt b/src/cmd/go/testdata/script/mod_download_hash.txt new file mode 100644 index 0000000..5a42c4b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_download_hash.txt @@ -0,0 +1,24 @@ +env GO111MODULE=on + +# Testing mod download with non semantic versions; turn off proxy. +[!net] skip +[!exec:git] skip +env GOPROXY=direct +env GOSUMDB=off + +go mod download rsc.io/quote@a91498bed0a73d4bb9c1fb2597925f7883bc40a7 +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-0.20180709162918-a91498bed0a7.info +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-0.20180709162918-a91498bed0a7.mod +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-0.20180709162918-a91498bed0a7.zip + +go mod download rsc.io/quote@master +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-0.20180709162918-a91498bed0a7.info +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-0.20180709162918-a91498bed0a7.mod +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-0.20180709162918-a91498bed0a7.zip + + +-- go.mod -- +module m + +-- m.go -- +package m diff --git a/src/cmd/go/testdata/script/mod_download_json.txt b/src/cmd/go/testdata/script/mod_download_json.txt new file mode 100644 index 0000000..9555adf --- /dev/null +++ b/src/cmd/go/testdata/script/mod_download_json.txt @@ -0,0 +1,9 @@ +env GO111MODULE=on +env GOSUMDB=$sumdb' '$proxy/sumdb-wrong + +# download -json with version should print JSON on sumdb failure +! go mod download -json 'rsc.io/quote@<=v1.5.0' +stdout '"Error": ".*verifying (module|go.mod)' + +-- go.mod -- +module m diff --git a/src/cmd/go/testdata/script/mod_download_partial.txt b/src/cmd/go/testdata/script/mod_download_partial.txt new file mode 100644 index 0000000..0aab60d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_download_partial.txt @@ -0,0 +1,68 @@ +# Download modules and populate go.sum. +go get -d -modcacherw +exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod + +# 'go mod verify' should fail if we delete a file. +go mod verify +rm $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod +! go mod verify + +# Create a .partial file to simulate an failure extracting the zip file. +cp empty $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.partial + +# 'go mod verify' should not fail, since the module hasn't been completely +# ingested into the cache. +go mod verify + +# 'go list' should not load packages from the directory. +# NOTE: the message "directory $dir outside available modules" is reported +# for directories not in the main module, active modules in the module cache, +# or local replacements. In this case, the directory is in the right place, +# but it's incomplete, so 'go list' acts as if it's not an active module. +! go list $GOPATH/pkg/mod/rsc.io/quote@v1.5.2 +stderr 'outside available modules' + +# 'go list -m' should not print the directory. +go list -m -f '{{.Dir}}' rsc.io/quote +! stdout . + +# 'go mod download' should re-extract the module and remove the .partial file. +go mod download -modcacherw rsc.io/quote +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.partial +exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod + +# 'go list' should succeed. +go list $GOPATH/pkg/mod/rsc.io/quote@v1.5.2 +stdout '^rsc.io/quote$' + +# 'go list -m' should print the directory. +go list -m -f '{{.Dir}}' rsc.io/quote +stdout 'pkg[/\\]mod[/\\]rsc.io[/\\]quote@v1.5.2' + +# go mod verify should fail if we delete a file. +go mod verify +rm $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod +! go mod verify + +# 'go mod download' should not leave behind a directory or a .partial file +# if there is an error extracting the zip file. +rm $GOPATH/pkg/mod/rsc.io/quote@v1.5.2 +cp empty $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip +! go mod download +stderr 'not a valid zip file' +! exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.2 +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.partial + +-- go.mod -- +module m + +go 1.14 + +require rsc.io/quote v1.5.2 + +-- use.go -- +package use + +import _ "rsc.io/quote" + +-- empty -- diff --git a/src/cmd/go/testdata/script/mod_download_replace_file.txt b/src/cmd/go/testdata/script/mod_download_replace_file.txt new file mode 100644 index 0000000..f6ab4fe --- /dev/null +++ b/src/cmd/go/testdata/script/mod_download_replace_file.txt @@ -0,0 +1,16 @@ +# This test checks that 'go mod download' produces no output for +# the main module (when specified implicitly) and for a module replaced +# with a file path. +# Verifies golang.org/issue/35505. +go mod download -json all +cmp stdout no-output + +-- go.mod -- +module example.com/a + +require example.com/b v1.0.0 + +replace example.com/b => ./local/b +-- local/b/go.mod -- +module example.com/b +-- no-output -- diff --git a/src/cmd/go/testdata/script/mod_e.txt b/src/cmd/go/testdata/script/mod_e.txt new file mode 100644 index 0000000..3a0d18d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_e.txt @@ -0,0 +1,89 @@ +cp go.mod go.mod.orig + + +# If a dependency cannot be resolved, 'go mod tidy' fails with an error message +# explaining the problem and does not update the go.mod file. +# TODO(bcmills): Ideally, with less redundancy than these error messages! + +! go mod tidy + +stderr '^example.com/untidy imports\n\texample.net/directnotfound: cannot find module providing package example.net/directnotfound: module example.net/directnotfound: reading http://.*: 404 Not Found$' + +stderr '^example.com/untidy imports\n\texample.net/m imports\n\texample.net/indirectnotfound: cannot find module providing package example.net/indirectnotfound: module example.net/indirectnotfound: reading http://.*: 404 Not Found$' + +stderr '^example.com/untidy tested by\n\texample.com/untidy.test imports\n\texample.net/directtestnotfound: cannot find module providing package example.net/directtestnotfound: module example.net/directtestnotfound: reading http://.*: 404 Not Found$' + +stderr '^example.com/untidy imports\n\texample.net/m tested by\n\texample.net/m.test imports\n\texample.net/indirecttestnotfound: cannot find module providing package example.net/indirecttestnotfound: module example.net/indirecttestnotfound: reading http://.*: 404 Not Found$' + +cmp go.mod.orig go.mod + + +# If a dependency cannot be resolved, 'go mod vendor' fails with an error message +# explaining the problem, does not update the go.mod file, and does not create +# the vendor directory. + +! go mod vendor + +stderr '^example.com/untidy imports\n\texample.net/directnotfound: cannot find module providing package example.net/directnotfound: module example.net/directnotfound: reading http://.*: 404 Not Found$' + +stderr '^example.com/untidy imports\n\texample.net/m imports\n\texample.net/indirectnotfound: cannot find module providing package example.net/indirectnotfound: module example.net/indirectnotfound: reading http://.*: 404 Not Found$' + +stderr '^example.com/untidy tested by\n\texample.com/untidy.test imports\n\texample.net/directtestnotfound: cannot find module providing package example.net/directtestnotfound: module example.net/directtestnotfound: reading http://.*: 404 Not Found$' + +! stderr 'indirecttestnotfound' # Vendor prunes test dependencies. + +cmp go.mod.orig go.mod +! exists vendor + + +# 'go mod tidy' still logs the errors, but succeeds and updates go.mod. + +go mod tidy -e +stderr -count=4 'cannot find module providing package' +cmp go.mod.final go.mod + + +# 'go mod vendor -e' still logs the errors, but succeeds and updates go.mod. + +cp go.mod.orig go.mod +go mod vendor -e +stderr -count=3 'cannot find module providing package' +cmp go.mod.final go.mod +exists vendor/modules.txt +exists vendor/example.net/m/m.go + + +-- go.mod -- +module example.com/untidy +go 1.16 +replace example.net/m v0.1.0 => ./m +-- go.mod.final -- +module example.com/untidy + +go 1.16 + +replace example.net/m v0.1.0 => ./m + +require example.net/m v0.1.0 +-- untidy.go -- +package untidy + +import ( + _ "example.net/m" + _ "example.net/directnotfound" +) +-- untidy_test.go -- +package untidy_test + +import _ "example.net/directtestnotfound" +-- m/go.mod -- +module example.net/m +go 1.16 +-- m/m.go -- +package m + +import _ "example.net/indirectnotfound" +-- m/m_test.go -- +package m_test + +import _ "example.net/indirecttestnotfound" diff --git a/src/cmd/go/testdata/script/mod_edit.txt b/src/cmd/go/testdata/script/mod_edit.txt new file mode 100644 index 0000000..9da6930 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_edit.txt @@ -0,0 +1,303 @@ +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' +cmpenv go.mod $WORK/go.mod.init + +! go mod init +cmpenv 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 -exclude=x.1@v2.0.0+incompatible -replace=x.1@v1.3.0=y.1@v1.4.0 -replace='x.1@v1.4.0 = ../z' -retract=v1.6.0 -retract=[v1.1.0,v1.2.0] -retract=[v1.3.0,v1.4.0] -retract=v1.0.0 +cmpenv go.mod $WORK/go.mod.edit1 +go mod edit -droprequire=x.1 -dropexclude=x.1@v1.2.1 -dropexclude=x.1@v2.0.0+incompatible -dropreplace=x.1@v1.3.0 -require=x.3@v1.99.0 -dropretract=v1.0.0 -dropretract=[v1.1.0,v1.2.0] +cmpenv go.mod $WORK/go.mod.edit2 + +# -exclude and -retract reject invalid versions. +! go mod edit -exclude=example.com/m@bad +stderr '^go mod: -exclude=example.com/m@bad: version "bad" invalid: must be of the form v1.2.3$' +! go mod edit -retract=bad +stderr '^go mod: -retract=bad: version "bad" invalid: must be of the form v1.2.3$' + +! go mod edit -exclude=example.com/m@v2.0.0 +stderr '^go mod: -exclude=example.com/m@v2\.0\.0: version "v2\.0\.0" invalid: should be v2\.0\.0\+incompatible \(or module example\.com/m/v2\)$' + +! go mod edit -exclude=example.com/m/v2@v1.0.0 +stderr '^go mod: -exclude=example.com/m/v2@v1\.0\.0: version "v1\.0\.0" invalid: should be v2, not v1$' + +! go mod edit -exclude=gopkg.in/example.v1@v2.0.0 +stderr '^go mod: -exclude=gopkg\.in/example\.v1@v2\.0\.0: version "v2\.0\.0" invalid: should be v1, not v2$' + +cmpenv go.mod $WORK/go.mod.edit2 + +# go mod edit -json +go mod edit -json +cmpenv stdout $WORK/go.mod.json + +# go mod edit -json (retractions with rationales) +go mod edit -json $WORK/go.mod.retractrationale +cmp stdout $WORK/go.mod.retractrationale.json + +# go mod edit -json (empty mod file) +go mod edit -json $WORK/go.mod.empty +cmp stdout $WORK/go.mod.empty.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 +cmpenv go.mod $WORK/go.mod.edit3 +go mod edit -replace=x.1=y.1/v2@v2.3.6 +cmpenv go.mod $WORK/go.mod.edit4 +go mod edit -dropreplace=x.1 +cmpenv 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 +cmpenv stdout $WORK/go.mod.goodfmt +cmp go.mod $WORK/go.mod.badfmt +go mod edit -fmt # without -print, should write file (and nothing to stdout) +! stdout . +cmpenv go.mod $WORK/go.mod.goodfmt + +# go mod edit -module +cd $WORK/m +go mod init a.a/b/c +go mod edit -module x.x/y/z +cmpenv go.mod go.mod.edit + +# golang.org/issue/30513: don't require go-gettable module paths. +cd $WORK/local +go mod init foo +go mod edit -module local-only -require=other-local@v1.0.0 -replace other-local@v1.0.0=./other +cmpenv go.mod go.mod.edit + +-- x.go -- +package x + +-- w/w.go -- +package w + +-- $WORK/go.mod.init -- +module x.x/y/z + +go $goversion +-- $WORK/go.mod.edit1 -- +module x.x/y/z + +go $goversion + +require x.1 v1.0.0 + +exclude ( + x.1 v1.2.0 + x.1 v1.2.1 + x.1 v2.0.0+incompatible +) + +replace ( + x.1 v1.3.0 => y.1 v1.4.0 + x.1 v1.4.0 => ../z +) + +retract ( + v1.6.0 + [v1.3.0, v1.4.0] + [v1.1.0, v1.2.0] + v1.0.0 +) +-- $WORK/go.mod.edit2 -- +module x.x/y/z + +go $goversion + +exclude x.1 v1.2.0 + +replace x.1 v1.4.0 => ../z + +retract ( + v1.6.0 + [v1.3.0, v1.4.0] +) + +require x.3 v1.99.0 +-- $WORK/go.mod.json -- +{ + "Module": { + "Path": "x.x/y/z" + }, + "Go": "$goversion", + "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" + } + } + ], + "Retract": [ + { + "Low": "v1.6.0", + "High": "v1.6.0" + }, + { + "Low": "v1.3.0", + "High": "v1.4.0" + } + ] +} +-- $WORK/go.mod.edit3 -- +module x.x/y/z + +go $goversion + +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 +) + +retract ( + v1.6.0 + [v1.3.0, v1.4.0] +) + +require x.3 v1.99.0 +-- $WORK/go.mod.edit4 -- +module x.x/y/z + +go $goversion + +exclude x.1 v1.2.0 + +replace x.1 => y.1/v2 v2.3.6 + +retract ( + v1.6.0 + [v1.3.0, v1.4.0] +) + +require x.3 v1.99.0 +-- $WORK/go.mod.edit5 -- +module x.x/y/z + +go $goversion + +exclude x.1 v1.2.0 + +retract ( + v1.6.0 + [v1.3.0, v1.4.0] +) + +require x.3 v1.99.0 +-- $WORK/local/go.mod.edit -- +module local-only + +go $goversion + +require other-local v1.0.0 + +replace other-local v1.0.0 => ./other +-- $WORK/go.mod.badfmt -- +module x.x/y/z + +go 1.10 + +exclude x.1 v1.2.0 + +replace x.1 => y.1/v2 v2.3.6 + +require x.3 v1.99.0 + +retract [ "v1.8.1" , "v1.8.2" ] +-- $WORK/go.mod.goodfmt -- +module x.x/y/z + +go 1.10 + +exclude x.1 v1.2.0 + +replace x.1 => y.1/v2 v2.3.6 + +require x.3 v1.99.0 + +retract [v1.8.1, v1.8.2] +-- $WORK/m/go.mod.edit -- +module x.x/y/z + +go $goversion +-- $WORK/go.mod.retractrationale -- +module x.x/y/z + +go 1.15 + +// a +retract v1.0.0 + +// b +retract ( + v1.0.1 + v1.0.2 // c +) +-- $WORK/go.mod.retractrationale.json -- +{ + "Module": { + "Path": "x.x/y/z" + }, + "Go": "1.15", + "Require": null, + "Exclude": null, + "Replace": null, + "Retract": [ + { + "Low": "v1.0.0", + "High": "v1.0.0", + "Rationale": "a" + }, + { + "Low": "v1.0.1", + "High": "v1.0.1", + "Rationale": "b" + }, + { + "Low": "v1.0.2", + "High": "v1.0.2", + "Rationale": "c" + } + ] +} +-- $WORK/go.mod.empty -- +-- $WORK/go.mod.empty.json -- +{ + "Module": { + "Path": "" + }, + "Require": null, + "Exclude": null, + "Replace": null, + "Retract": null +} diff --git a/src/cmd/go/testdata/script/mod_edit_go.txt b/src/cmd/go/testdata/script/mod_edit_go.txt new file mode 100644 index 0000000..38321d0 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_edit_go.txt @@ -0,0 +1,23 @@ +# Test support for go mod -edit to set language version. + +env GO111MODULE=on +! go build +stderr 'type aliases only supported as of' +go mod edit -go=1.9 +grep 'go 1.9' go.mod +go build + +# Reverting the version should force a rebuild and error instead of using +# the cached 1.9 build. (https://golang.org/issue/37804) +go mod edit -go=1.8 +! go build +stderr 'type aliases only supported as of' + + +-- go.mod -- +module m +go 1.8 + +-- alias.go -- +package alias +type T = int diff --git a/src/cmd/go/testdata/script/mod_empty_err.txt b/src/cmd/go/testdata/script/mod_empty_err.txt new file mode 100644 index 0000000..982e6b2 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_empty_err.txt @@ -0,0 +1,36 @@ +# This test checks error messages for non-existant packages in module mode. +# Veries golang.org/issue/35414 +env GO111MODULE=on +cd $WORK + +go list -e -f {{.Error}} . +stdout 'no Go files in \$WORK' + +go list -e -f {{.Error}} ./empty +stdout 'no Go files in \$WORK[/\\]empty' + +go list -e -f {{.Error}} ./exclude +stdout 'build constraints exclude all Go files in \$WORK[/\\]exclude' + +go list -e -f {{.Error}} ./missing +stdout 'stat '$WORK'[/\\]missing: directory not found' + +# use 'go build -n' because 'go list' reports no error. +! go build -n ./testonly +stderr 'example.com/m/testonly: no non-test Go files in \$WORK[/\\]testonly' + +-- $WORK/go.mod -- +module example.com/m + +go 1.14 + +-- $WORK/empty/empty.txt -- +-- $WORK/exclude/exclude.go -- +// +build exclude + +package exclude +-- $WORK/testonly/testonly_test.go -- +package testonly_test +-- $WORK/excluded-stdout -- +package ./excluded: cannot find package "." in: + $WORK/excluded diff --git a/src/cmd/go/testdata/script/mod_enabled.txt b/src/cmd/go/testdata/script/mod_enabled.txt new file mode 100644 index 0000000..39f1ece --- /dev/null +++ b/src/cmd/go/testdata/script/mod_enabled.txt @@ -0,0 +1,93 @@ +# GO111MODULE=auto should trigger any time a go.mod exists in a parent directory. +env GO111MODULE=auto + +cd $GOPATH/src/x/y/z +go env GOMOD +stdout $GOPATH[/\\]src[/\\]x[/\\]y[/\\]z[/\\]go.mod +go list -m -f {{.GoMod}} +stdout $GOPATH[/\\]src[/\\]x[/\\]y[/\\]z[/\\]go.mod + +cd $GOPATH/src/x/y/z/w +go env GOMOD +stdout $GOPATH[/\\]src[/\\]x[/\\]y[/\\]z[/\\]go.mod + +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 unset should be equivalent to on. +env GO111MODULE= + +cd $GOPATH/src/x/y/z +go env GOMOD +stdout $GOPATH[/\\]src[/\\]x[/\\]y[/\\]z[/\\]go.mod + +cd $GOPATH/src/x/y +go env GOMOD +stdout 'NUL|/dev/null' + +# 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 'NUL|/dev/null' +go list -m +stdout '^command-line-arguments$' + +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/src/cmd/go/testdata/script/mod_file_proxy.txt b/src/cmd/go/testdata/script/mod_file_proxy.txt new file mode 100644 index 0000000..38d9fd2 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_file_proxy.txt @@ -0,0 +1,36 @@ +[short] skip + +# 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. +env GOPATH=$WORK/gopath2 +[windows] env GOPROXY=file:///C:/nonexist +[!windows] env GOPROXY=file:///nonexist +! go list +[windows] env GOPROXY=file:///$WORK/gopath1/pkg/mod/cache/download +[!windows] 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 +go 1.13 +require rsc.io/quote v1.5.1 +-- $WORK/x/x.go -- +package x +import _ "rsc.io/quote" +-- $WORK/x/go.sum -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.1 h1:ZE3OgnVGrhXtFkGw90HwW992ZRqcdli/33DLqEYsoxA= +rsc.io/quote v1.5.1/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/src/cmd/go/testdata/script/mod_find.txt b/src/cmd/go/testdata/script/mod_find.txt new file mode 100644 index 0000000..1e01973 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_find.txt @@ -0,0 +1,104 @@ +env GO111MODULE=on + +# 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' + +# Derive module path from location inside GOPATH. +# 'go mod init' should succeed if modules are not explicitly disabled. +cd $GOPATH/src/example.com/x/y +go mod init +stderr 'module example.com/x/y$' +rm go.mod + +# go mod init rejects a zero-length go.mod file +cp $devnull go.mod # can't use touch to create it because Windows +! go mod init +stderr 'go.mod already exists' + +# 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 + +# In Plan 9, directories are automatically created in /n. +# For example, /n/go.mod always exist, but it's a directory. +# Test that we ignore directories when trying to find go.mod. +cd $WORK/gomoddir +! go list . +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + +[!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"} + +-- $WORK/gomoddir/go.mod/README.txt -- +../go.mod is a directory, not a file. +-- $WORK/gomoddir/p.go -- +package p diff --git a/src/cmd/go/testdata/script/mod_fs_patterns.txt b/src/cmd/go/testdata/script/mod_fs_patterns.txt new file mode 100644 index 0000000..a20fefd --- /dev/null +++ b/src/cmd/go/testdata/script/mod_fs_patterns.txt @@ -0,0 +1,97 @@ +env GO111MODULE=on + +# File system pattern searches should skip sub-modules and vendor directories. +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 '^stat '$GOPATH'[/\\]src[/\\]x[/\\]nonexist: directory not found' + +! go build -mod=readonly ./go.mod +! stderr 'import lookup disabled' +stderr 'main module \(m\) does not contain package m/go.mod' + + +# File system paths and patterns should allow the '@' character. +cd ../@at +go list $PWD +stdout '^at$' +go list $PWD/... +stdout '^at$' + +# The '@' character is not allowed in directory paths that are part of +# a package path. +cd ../badat/bad@ +! go list . +stderr 'directory . outside available modules' +! go list $PWD +stderr 'directory . outside available modules' +! go list $PWD/... +stderr 'directory . outside available modules' + +-- 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 + +-- @at/go.mod -- +module at + +go 1.14 +-- @at/at.go -- +package at + +-- badat/go.mod -- +module badat + +go 1.14 +-- badat/bad@/bad.go -- +package bad diff --git a/src/cmd/go/testdata/script/mod_get_ambiguous_arg.txt b/src/cmd/go/testdata/script/mod_get_ambiguous_arg.txt new file mode 100644 index 0000000..daed03b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_ambiguous_arg.txt @@ -0,0 +1,107 @@ +go mod tidy +cp go.mod go.mod.orig + +# If there is no sensible *package* meaning for 'm/p', it should refer +# to *module* m/p. + +go get -d m/p # @latest +go list -m all +stdout '^m/p v0.3.0 ' +! stdout '^m ' + +cp go.mod.orig go.mod + +go get -d m/p@v0.1.0 +go list -m all +stdout '^m/p v0.1.0 ' +! stdout '^m ' + +# When feasible, the argument 'm/p' in 'go get m/p' refers to *package* m/p, +# which is in module m. +# +# (It only refers to *module* m/p if there is no such package at the +# requested version.) + +go get -d m/p@v0.2.0 +go list -m all +stdout '^m v0.2.0 ' +stdout '^m/p v0.1.0 ' # unchanged from the previous case + +# Repeating the above with module m/p already in the module graph does not +# change its meaning. + +go get -d m/p@v0.2.0 +go list -m all +stdout '^m v0.2.0 ' +stdout '^m/p v0.1.0 ' + +-- go.mod -- +module example.com + +go 1.16 + +replace ( + m v0.1.0 => ./m01 + m v0.2.0 => ./m02 + m v0.3.0 => ./m03 + m/p v0.1.0 => ./mp01 + m/p v0.2.0 => ./mp02 + m/p v0.3.0 => ./mp03 +) +-- m01/go.mod -- +module m + +go 1.16 +-- m01/README.txt -- +Module m at v0.1.0 does not yet contain package p. + +-- m02/go.mod -- +module m + +go 1.16 + +require m/p v0.1.0 +-- m02/p/p.go -- +// Package p is present in module m, but not module m/p. +package p + +-- m03/go.mod -- +module m + +go 1.16 + +require m/p v0.1.0 +-- m03/README.txt -- +Module m at v0.3.0 no longer contains package p. + +-- mv2/go.mod -- +module m/v2 + +go 1.16 +-- mv2/README.txt -- +This module is m/v2. It doesn't actually need to exist, +but it explains how module m could plausibly exist +and still contain package p at 'latest' even when module +m/p also exists. + +-- mp01/go.mod -- +module m/p + +go 1.16 +-- mp01/README.txt -- +This module is m/p. +Package m/p does not exist in this module. +-- mp02/go.mod -- +module m/p + +go 1.16 +-- mp02/README.txt -- +This module is m/p. +Package m/p does not exist in this module. +-- mp03/go.mod -- +module m/p + +go 1.16 +-- mp03/README.txt -- +This module is m/p. +Package m/p does not exist in this module. diff --git a/src/cmd/go/testdata/script/mod_get_ambiguous_import.txt b/src/cmd/go/testdata/script/mod_get_ambiguous_import.txt new file mode 100644 index 0000000..33605f5 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_ambiguous_import.txt @@ -0,0 +1,60 @@ +go list -m all +stdout '^example.net/m v0.1.0 ' +! stdout '^example.net/m/p ' +cp go.mod go.mod.orig + +# Upgrading example.net/m/p without also upgrading example.net/m +# causes the import of package example.net/m/p to be ambiguous. +# +# TODO(#27899): Should we automatically upgrade example.net/m to v0.2.0 +# to resolve the conflict? +! go get -d example.net/m/p@v1.0.0 +stderr '^example.net/m/p: ambiguous import: found package example.net/m/p in multiple modules:\n\texample.net/m v0.1.0 \(.*[/\\]m1[/\\]p\)\n\texample.net/m/p v1.0.0 \(.*[/\\]p0\)\n\z' +cmp go.mod go.mod.orig + +# Upgrading both modules simultaneously resolves the ambiguous upgrade. +# Note that this command line mixes a module path (example.net/m) +# and a package path (example.net/m/p) in the same command. +go get -d example.net/m@v0.2.0 example.net/m/p@v1.0.0 + +go list -m all +stdout '^example.net/m v0.2.0 ' +stdout '^example.net/m/p v1.0.0 ' + +-- go.mod -- +module example.net/importer + +go 1.16 + +require ( + example.net/m v0.1.0 +) + +replace ( + example.net/m v0.1.0 => ./m1 + example.net/m v0.2.0 => ./m2 + example.net/m/p v1.0.0 => ./p0 +) +-- importer.go -- +package importer +import _ "example.net/m/p" +-- m1/go.mod -- +module example.net/m + +go 1.16 +-- m1/p/p.go -- +package p +-- m2/go.mod -- +module example.net/m + +go 1.16 +-- m2/README.txt -- +Package p has been moved to module …/m/p. +Module …/m/p does not require any version of module …/m. + +-- p0/go.mod -- +module example.net/m/p + +go 1.16 +-- p0/p.go -- +package p diff --git a/src/cmd/go/testdata/script/mod_get_ambiguous_pkg.txt b/src/cmd/go/testdata/script/mod_get_ambiguous_pkg.txt new file mode 100644 index 0000000..0e7f93b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_ambiguous_pkg.txt @@ -0,0 +1,87 @@ +# Both example.net/ambiguous v0.1.0 and example.net/ambiguous/pkg v0.1.0 exist. +# 'go mod tidy' would arbitrarily choose the one with the longer path, +# but 'go mod tidy' also arbitrarily chooses the latest version. + +cp go.mod go.mod.orig + + +# From a clean slate, 'go get' currently does the same thing as 'go mod tidy': +# it resolves the package from the module with the longest matching prefix. + +go get -d example.net/ambiguous/nested/pkg@v0.1.0 +go list -m all +stdout '^example.net/ambiguous/nested v0.1.0$' +! stdout '^example.net/ambiguous ' + + +# From an initial state that already depends on the shorter path, +# the same 'go get' command should (somewhat arbitrarily) keep the +# existing path, since it is a valid interpretation of the command. + +cp go.mod.orig go.mod +go mod edit -require=example.net/ambiguous@v0.1.0 + +go get -d example.net/ambiguous/nested/pkg@v0.1.0 +go list -m all +stdout '^example.net/ambiguous v0.1.0$' +! stdout '^example.net/ambiguous/nested ' + + +# The user should be able to make the command unambiguous by explicitly +# upgrading the conflicting module... + +go get -d example.net/ambiguous@v0.2.0 example.net/ambiguous/nested/pkg@v0.1.0 +go list -m all +stdout '^example.net/ambiguous/nested v0.1.0$' +stdout '^example.net/ambiguous v0.2.0$' + + +# ...or by explicitly NOT adding the conflicting module. + +cp go.mod.orig go.mod +go mod edit -require=example.net/ambiguous@v0.1.0 + +go get -d example.net/ambiguous/nested/pkg@v0.1.0 example.net/ambiguous/nested@none +go list -m all +! stdout '^example.net/ambiguous/nested ' +stdout '^example.net/ambiguous v0.1.0$' + + +# The user should also be able to fix it by *downgrading* the conflicting module +# away. + +cp go.mod.orig go.mod +go mod edit -require=example.net/ambiguous@v0.1.0 + +go get -d example.net/ambiguous@none example.net/ambiguous/nested/pkg@v0.1.0 +go list -m all +stdout '^example.net/ambiguous/nested v0.1.0$' +! stdout '^example.net/ambiguous ' + + +# In contrast, if we do the same thing tacking a wildcard pattern ('/...') on +# the end of the package path, we get different behaviors depending on the +# initial state, and no error. (This seems to contradict the “same meaning +# regardless of the initial state” point above, but maybe that's ok?) + +cp go.mod.orig go.mod + +go get -d example.net/ambiguous/nested/pkg/...@v0.1.0 +go list -m all +stdout '^example.net/ambiguous/nested v0.1.0$' +! stdout '^example.net/ambiguous ' + + +cp go.mod.orig go.mod +go mod edit -require=example.net/ambiguous@v0.1.0 + +go get -d example.net/ambiguous/nested/pkg/...@v0.1.0 +go list -m all +! stdout '^example.net/ambiguous/nested ' +stdout '^example.net/ambiguous v0.1.0$' + + +-- go.mod -- +module test + +go 1.16 diff --git a/src/cmd/go/testdata/script/mod_get_changes.txt b/src/cmd/go/testdata/script/mod_get_changes.txt new file mode 100644 index 0000000..3287b2a --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_changes.txt @@ -0,0 +1,70 @@ +# When adding a requirement, 'go get' prints a message for the requirement +# and for changed explicit dependencies. 'go get' does not print messages +# for changed indirect dependencies. +go list -m all +! stdout golang.org/x/text +go get -d rsc.io/quote@v1.5.2 +stderr '^go get: added rsc.io/quote v1.5.2$' +stderr '^go get: upgraded rsc.io/sampler v1.0.0 => v1.3.0$' +! stderr '^go get.*golang.org/x/text' +go list -m all +stdout golang.org/x/text +cmp go.mod go.mod.upgrade + +# When removing a requirement, 'go get' prints a message for the requiremnent +# and for changed explicit dependencies. 'go get' does not print messages +# for changed indirect dependencies. +go get -d rsc.io/sampler@none +stderr '^go get: downgraded rsc.io/quote v1.5.2 => v1.3.0$' +stderr '^go get: removed rsc.io/sampler v1.3.0$' +! stderr '^go get.*golang.org/x/text' +cmp go.mod go.mod.downgrade + +# When removing or downgrading a requirement, 'go get' also prints a message +# for explicit dependencies removed as a consequence. +cp go.mod.usequote go.mod +go get -d rsc.io/quote@v1.5.1 +stderr '^go get: downgraded rsc.io/quote v1.5.2 => v1.5.1$' +stderr '^go get: removed usequote v0.0.0$' + +-- go.mod -- +module m + +go 1.16 + +require rsc.io/sampler v1.0.0 +-- go.sum -- +rsc.io/sampler v1.0.0 h1:SRJnjyQ07sAtq6G4RcfJEmz8JxqLyj3PoGXG2VhbDWo= +rsc.io/sampler v1.0.0/go.mod h1:cqxpM3ZVz9VtirqxZPmrWzkQ+UkiNiGtkrN+B+i8kx8= +-- go.mod.upgrade -- +module m + +go 1.16 + +require ( + rsc.io/quote v1.5.2 // indirect + rsc.io/sampler v1.3.0 +) +-- go.mod.downgrade -- +module m + +go 1.16 + +require ( + golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect + rsc.io/quote v1.3.0 // indirect +) +-- go.mod.usequote -- +module m + +go 1.16 + +require usequote v0.0.0 + +replace usequote => ./usequote +-- usequote/go.mod -- +module usequote + +go 1.16 + +require rsc.io/quote v1.5.2 diff --git a/src/cmd/go/testdata/script/mod_get_cmd.txt b/src/cmd/go/testdata/script/mod_get_cmd.txt new file mode 100644 index 0000000..d31cee1 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_cmd.txt @@ -0,0 +1,20 @@ +env GO111MODULE=on +[short] skip + +# Test that when 'go get' is run from $GOBIN, it does not delete binaries +# after it installs them. Verifies golang.org/issue/32766. + +go get example.com/tools/cmd/hello + +# 'go get' should not delete the command when run from $GOPATH/bin +cd $GOPATH/bin +exists hello$GOEXE +go get example.com/tools/cmd/hello +exists hello$GOEXE + +# 'go get' should not delete the command when run from a different $GOBIN +mkdir $WORK/bin +cd $WORK/bin +env GOBIN=$WORK/bin +go get example.com/tools/cmd/hello +exists hello$GOEXE diff --git a/src/cmd/go/testdata/script/mod_get_commit.txt b/src/cmd/go/testdata/script/mod_get_commit.txt new file mode 100644 index 0000000..4649491 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_commit.txt @@ -0,0 +1,51 @@ +env GO111MODULE=on +[short] skip + +# @commit should resolve + +# golang.org/x/text/language@commit should resolve. +# 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 -d golang.org/x/text@14c0d48 + +# dropping -d, we should see a build. +[short] skip + +env GOCACHE=$WORK/gocache # Looking for compile commands, so need a clean cache. + +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 -d 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 -d 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/src/cmd/go/testdata/script/mod_get_direct.txt b/src/cmd/go/testdata/script/mod_get_direct.txt new file mode 100644 index 0000000..42ccbcd --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_direct.txt @@ -0,0 +1,20 @@ +# Regression test for golang.org/issue/34092: with an empty module cache, +# 'GOPROXY=direct go get golang.org/x/tools/gopls@master' did not correctly +# resolve the pseudo-version for its dependency on golang.org/x/tools. + +[short] skip +[!net] skip +[!exec:git] skip + +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off + +go list -m cloud.google.com/go@master +! stdout 'v0.0.0-' + +-- go.mod -- +module example.com + +go 1.14 +-- go.sum -- diff --git a/src/cmd/go/testdata/script/mod_get_downgrade.txt b/src/cmd/go/testdata/script/mod_get_downgrade.txt new file mode 100644 index 0000000..a954c10 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_downgrade.txt @@ -0,0 +1,56 @@ +env GO111MODULE=on +[short] skip + +# downgrade sampler should downgrade quote +cp go.mod.orig go.mod +go get -d 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 -d 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 -d 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 -d rsc.io/sampler@v1.0.0 rsc.io/quote@v1.5.2 golang.org/x/text@none +stderr '^go get: rsc.io/quote@v1.5.2 requires rsc.io/sampler@v1.3.0, not rsc.io/sampler@v1.0.0$' +stderr '^go get: rsc.io/quote@v1.5.2 requires golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c, not golang.org/x/text@none$' + +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 -d -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 + +# downgrading away quote should also downgrade away latemigrate/v2, +# since there are no older versions. v2.0.0 is incompatible. +cp go.mod.orig go.mod +go list -m -versions example.com/latemigrate/v2 +stdout v2.0.0 # proxy may serve incompatible versions +go get -d rsc.io/quote@none +go list -m all +! stdout 'example.com/latemigrate/v2' + +-- go.mod.orig -- +module x +require ( + rsc.io/quote v1.5.1 + example.com/latemigrate/v2 v2.0.1 +) +-- go.mod.empty -- +module x +-- x.go -- +package x diff --git a/src/cmd/go/testdata/script/mod_get_downgrade_missing.txt b/src/cmd/go/testdata/script/mod_get_downgrade_missing.txt new file mode 100644 index 0000000..5b768fa --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_downgrade_missing.txt @@ -0,0 +1,43 @@ +cp go.mod go.mod.orig + +# getting a specific version of a module along with a pattern +# not yet present in that module should report the version mismatch +# rather than a "matched no packages" warning. + +! go get -d example.net/pkgadded@v1.1.0 example.net/pkgadded/subpkg/... +stderr '^go get: example.net/pkgadded@v1.1.0 conflicts with example.net/pkgadded/subpkg/...@upgrade \(v1.2.0\)$' +! stderr 'matched no packages' +cmp go.mod.orig go.mod + + +# A wildcard pattern should match the pattern with that path. + +go get -d example.net/pkgadded/...@v1.0.0 +go list -m all +stdout '^example.net/pkgadded v1.0.0' +cp go.mod.orig go.mod + + +# If we need to resolve a transitive dependency of a package, +# and another argument constrains away the version that provides that +# package, then 'go get' should fail with a useful error message. + +! go get -d example.net/pkgadded@v1.0.0 . +stderr '^example.com/m imports\n\texample.net/pkgadded/subpkg: cannot find module providing package example.net/pkgadded/subpkg$' +! stderr 'example.net/pkgadded v1\.2\.0' +cmp go.mod.orig go.mod + +go get -d example.net/pkgadded@v1.0.0 +! go list -deps -mod=readonly . +stderr '^m.go:3:8: cannot find module providing package example\.net/pkgadded/subpkg: ' + +-- go.mod -- +module example.com/m + +go 1.16 + +require example.net/pkgadded v1.2.0 +-- m.go -- +package m + +import _ "example.net/pkgadded/subpkg" diff --git a/src/cmd/go/testdata/script/mod_get_errors.txt b/src/cmd/go/testdata/script/mod_get_errors.txt new file mode 100644 index 0000000..5c37058 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_errors.txt @@ -0,0 +1,69 @@ +cp go.mod go.mod.orig + + +# Both 'go get' and 'go get -d' should fail, without updating go.mod, +# if the transitive dependencies of the requested package (by default, +# the package in the current directory) cannot be resolved. + +! go get +stderr '^example.com/m imports\n\texample.com/badimport imports\n\texample.net/oops: cannot find module providing package example.net/oops$' +cmp go.mod.orig go.mod + +! go get -d +stderr '^example.com/m imports\n\texample.com/badimport imports\n\texample.net/oops: cannot find module providing package example.net/oops$' +cmp go.mod.orig go.mod + +cd importsyntax + + +# If 'go get' fails due to a compile error (such as a syntax error), +# it should not update the go.mod file. + +! go get +stderr '^..[/\\]badimport[/\\]syntaxerror[/\\]syntaxerror.go:1:1: expected ''package'', found pack$' # TODO: An import stack would be nice. +cmp ../go.mod.orig ../go.mod + + +# A syntax error in a dependency prevents the compiler from needing that +# dependency's imports, so 'go get -d' should not report an error when those +# imports cannot be resolved: it has all of the dependencies that the compiler +# needs, and the user did not request to run the compiler. + +go get -d +cmp ../go.mod.syntax-d ../go.mod + + +-- go.mod -- +module example.com/m + +go 1.16 + +replace example.com/badimport v0.1.0 => ./badimport +-- go.mod.syntax-d -- +module example.com/m + +go 1.16 + +replace example.com/badimport v0.1.0 => ./badimport + +require example.com/badimport v0.1.0 +-- m.go -- +package m + +import _ "example.com/badimport" +-- importsyntax/importsyntax.go -- +package importsyntax + +import _ "example.com/badimport/syntaxerror" +-- badimport/go.mod -- +module example.com/badimport + +go 1.16 +-- badimport/badimport.go -- +package badimport + +import "example.net/oops" +-- badimport/syntaxerror/syntaxerror.go -- +pack-age syntaxerror // sic + +import "example.net/oops" diff --git a/src/cmd/go/testdata/script/mod_get_extra.txt b/src/cmd/go/testdata/script/mod_get_extra.txt new file mode 100644 index 0000000..7efa24e --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_extra.txt @@ -0,0 +1,69 @@ +cp go.mod go.mod.orig + +# The -u flag should not (even temporarily) upgrade modules whose versions are +# determined by explicit queries to any version other than the explicit one. +# Otherwise, 'go get -u' could introduce spurious dependencies. + +go get -d -u example.net/a@v0.1.0 example.net/b@v0.1.0 +go list -m all +stdout '^example.net/a v0.1.0 ' +stdout '^example.net/b v0.1.0 ' +! stdout '^example.net/c ' + + +# TODO(bcmills): This property does not yet hold for modules added for +# missing packages when the newly-added module matches a wildcard. + +cp go.mod.orig go.mod + +go get -d -u example.net/a@v0.1.0 example.net/b/...@v0.1.0 +go list -m all +stdout '^example.net/a v0.1.0 ' +stdout '^example.net/b v0.1.0 ' +stdout '^example.net/c ' # BUG, but a minor and rare one + + +-- go.mod -- +module example + +go 1.15 + +replace ( + example.net/a v0.1.0 => ./a1 + example.net/b v0.1.0 => ./b1 + example.net/b v0.2.0 => ./b2 + example.net/c v0.1.0 => ./c1 + example.net/c v0.2.0 => ./c1 +) + +-- a1/go.mod -- +module example.net/a + +go 1.15 + +// example.net/a needs a dependency on example.net/b, but lacks a requirement +// on it (perhaps due to a missed file in a VCS commit). +-- a1/a.go -- +package a +import _ "example.net/b" + +-- b1/go.mod -- +module example.net/b + +go 1.15 +-- b1/b.go -- +package b + +-- b2/go.mod -- +module example.net/b + +go 1.15 + +require example.net/c v0.1.0 +-- b2/b.go -- +package b + +-- c1/go.mod -- +module example.net/c + +go 1.15 diff --git a/src/cmd/go/testdata/script/mod_get_fallback.txt b/src/cmd/go/testdata/script/mod_get_fallback.txt new file mode 100644 index 0000000..9733fa3 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_fallback.txt @@ -0,0 +1,10 @@ +env GO111MODULE=on + +[!net] skip + +env GOPROXY=https://proxy.golang.org,direct +env GOSUMDB=off + +go get -x -v -d golang.org/x/tools/cmd/goimports +stderr '# get https://proxy.golang.org/golang.org/x/tools/@v/list' +! stderr '# get https://golang.org' diff --git a/src/cmd/go/testdata/script/mod_get_fossil.txt b/src/cmd/go/testdata/script/mod_get_fossil.txt new file mode 100644 index 0000000..baad544 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_fossil.txt @@ -0,0 +1,29 @@ +[!net] skip +[!exec:fossil] skip + +# Regression test for 'go get' to ensure repositories +# provided by fossil v2.12 and up are able to be fetched +# and parsed correctly. +# Verifies golang.org/issue/42323. + + +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off + +# 'go get' for the fossil repo will fail if fossil +# is unable to determine your fossil user. Easiest +# way to set it for use by 'go get' is specifying +# a any non-empty $USER; the value doesn't otherwise matter. +env USER=fossiluser +env FOSSIL_HOME=$WORK/home + +# Attempting to get the latest version of a fossil repo. +go get vcs-test.golang.org/fossil/hello.fossil +! stderr 'unexpected response from fossil info' +grep 'vcs-test.golang.org/fossil/hello.fossil' go.mod +exists $GOPATH/bin/hello.fossil$GOEXE + +-- go.mod -- +module x +-- $WORK/home/.fossil -- diff --git a/src/cmd/go/testdata/script/mod_get_go_file.txt b/src/cmd/go/testdata/script/mod_get_go_file.txt new file mode 100644 index 0000000..0c7b5dc --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_go_file.txt @@ -0,0 +1,68 @@ +# Tests Issue #38478 +# Tests that go get in GOMOD mode returns a specific error if the argument +# ends with '.go', has no version, and either has no slash or refers to an +# existing file. + +env GO111MODULE=on + +# argument doesn't have .go suffix and has no version +! go get test +! stderr 'arguments must be package or module paths' +! stderr 'exists as a file, but ''go get'' requires package arguments' + +# argument has .go suffix and has version +! go get test.go@v1.0.0 +! stderr 'arguments must be package or module paths' +! stderr 'exists as a file, but ''go get'' requires package arguments' + +# argument has .go suffix, is a file and exists +! go get test.go +stderr 'go get test.go: arguments must be package or module paths' + +# argument has .go suffix, doesn't exist and has no slashes +! go get test_missing.go +stderr 'arguments must be package or module paths' + +# argument has .go suffix, is a file and exists in sub-directory +! go get test/test.go +stderr 'go get: test/test.go exists as a file, but ''go get'' requires package arguments' + +# argument has .go suffix, doesn't exist and has slashes +! go get test/test_missing.go +! stderr 'arguments must be package or module paths' +! stderr 'exists as a file, but ''go get'' requires package arguments' + +# argument has .go suffix, is a symlink and exists +[symlink] symlink test_sym.go -> test.go +[symlink] ! go get test_sym.go +[symlink] stderr 'go get test_sym.go: arguments must be package or module paths' +[symlink] rm test_sym.go + +# argument has .go suffix, is a symlink and exists in sub-directory +[symlink] symlink test/test_sym.go -> test.go +[symlink] ! go get test/test_sym.go +[symlink] stderr 'go get: test/test_sym.go exists as a file, but ''go get'' requires package arguments' +[symlink] rm test_sym.go + +# argument has .go suffix, is a directory and exists +mkdir test_dir.go +! go get test_dir.go +stderr 'go get test_dir.go: arguments must be package or module paths' +rm test_dir.go + +# argument has .go suffix, is a directory and exists in sub-directory +mkdir test/test_dir.go +! go get test/test_dir.go +! stderr 'arguments must be package or module paths' +! stderr 'exists as a file, but ''go get'' requires package arguments' +rm test/test_dir.go + + +-- test.go -- +package main +func main() {println("test")} + + +-- test/test.go -- +package main +func main() {println("test")} diff --git a/src/cmd/go/testdata/script/mod_get_hash.txt b/src/cmd/go/testdata/script/mod_get_hash.txt new file mode 100644 index 0000000..3bb3ee7 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_hash.txt @@ -0,0 +1,19 @@ +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off +[!net] skip +[!exec:git] skip + +# fetch commit hash reachable from refs/heads/* and refs/tags/* is OK +go list -m golang.org/x/time@8be79e1e0910c292df4e79c241bb7e8f7e725959 # on master branch + +# fetch other commit hash, even with a non-standard ref, is not OK +! go list -m golang.org/x/time@334d83c35137ac2b376c1dc3e4c7733791855a3a # refs/changes/24/41624/3 +stderr 'unknown revision' +! go list -m golang.org/x/time@v0.0.0-20170424233410-334d83c35137 +stderr 'unknown revision' +! go list -m golang.org/x/time@334d83c35137 +stderr 'unknown revision' + +-- go.mod -- +module m diff --git a/src/cmd/go/testdata/script/mod_get_incompatible.txt b/src/cmd/go/testdata/script/mod_get_incompatible.txt new file mode 100644 index 0000000..8000ee6 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_incompatible.txt @@ -0,0 +1,26 @@ +env GO111MODULE=on + +go get -d x +go list -m all +stdout 'rsc.io/breaker v2.0.0\+incompatible' + +cp go.mod2 go.mod +go get -d rsc.io/breaker@7307b30 +go list -m all +stdout 'rsc.io/breaker v2.0.0\+incompatible' + +go get -d 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/src/cmd/go/testdata/script/mod_get_indirect.txt b/src/cmd/go/testdata/script/mod_get_indirect.txt new file mode 100644 index 0000000..e1cc1ab --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_indirect.txt @@ -0,0 +1,59 @@ +env GO111MODULE=on +[short] skip + +# get -u should not upgrade anything, since the package +# in the current directory doesn't import anything. +go get -u +go list -m all +stdout 'quote v1.5.1$' +grep 'rsc.io/quote v1.5.1$' go.mod + +# get -u should find quote v1.5.2 once there is a use. +cp $WORK/tmp/usequote.go x.go +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 does not remove indirect tag. +cp $WORK/tmp/usetext.go x.go +go list -e +grep 'golang.org/x/text v0.3.0 // indirect$' go.mod + +# indirect tag should be removed upon seeing direct import. +cp $WORK/tmp/uselang.go x.go +go get -d +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/src/cmd/go/testdata/script/mod_get_insecure_redirect.txt b/src/cmd/go/testdata/script/mod_get_insecure_redirect.txt new file mode 100644 index 0000000..3755f17 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_insecure_redirect.txt @@ -0,0 +1,34 @@ +# golang.org/issue/29591: 'go get' was following plain-HTTP redirects even without -insecure. + +[!net] skip +[!exec:git] skip + +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off + +! go get -d vcs-test.golang.org/insecure/go/insecure +stderr 'redirected .* to insecure URL' + +go get -d -insecure vcs-test.golang.org/insecure/go/insecure + +# insecure host +env GOINSECURE=vcs-test.golang.org +go clean -modcache +go get -d vcs-test.golang.org/insecure/go/insecure + +# insecure glob host +env GOINSECURE=*.golang.org +go clean -modcache +go get -d vcs-test.golang.org/insecure/go/insecure + +# insecure multiple host +env GOINSECURE=somewhere-else.com,*.golang.org +go clean -modcache +go get -d vcs-test.golang.org/insecure/go/insecure + +# different insecure host does not fetch +env GOINSECURE=somewhere-else.com +go clean -modcache +! go get -d vcs-test.golang.org/insecure/go/insecure +stderr 'redirected .* to insecure URL' diff --git a/src/cmd/go/testdata/script/mod_get_issue37438.txt b/src/cmd/go/testdata/script/mod_get_issue37438.txt new file mode 100644 index 0000000..38b2031 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_issue37438.txt @@ -0,0 +1,37 @@ +# Regression test for https://golang.org/issue/37438. +# +# If a path exists at the requested version, but does not exist at the +# version of the module that is already required and does not exist at +# the version that would be selected by 'go mod tidy', then +# 'go get foo@requested' should resolve the requested version, +# not error out on the (unrelated) latest one. + +go get -d example.net/a/p@v0.2.0 + +-- go.mod -- +module example + +go 1.15 + +require example.net/a v0.1.0 + +replace ( + example.net/a v0.1.0 => ./a1 + example.net/a v0.2.0 => ./a2 + example.net/a v0.3.0 => ./a1 +) + +-- a1/go.mod -- +module example.net/a + +go 1.15 +-- a1/README -- +package example.net/a/p does not exist at this version. + +-- a2/go.mod -- +module example.net/a + +go 1.15 +-- a2/p/p.go -- +// Package p exists only at v0.2.0. +package p diff --git a/src/cmd/go/testdata/script/mod_get_latest_pseudo.txt b/src/cmd/go/testdata/script/mod_get_latest_pseudo.txt new file mode 100644 index 0000000..241a0c2 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_latest_pseudo.txt @@ -0,0 +1,10 @@ +# Check that we can build a module with no tagged versions by querying +# "@latest" through a proxy. +# Verifies golang.org/issue/32636 + +env GO111MODULE=on + +go mod init m +go get -d example.com/notags +go list -m all +stdout '^example.com/notags v0.0.0-20190507143103-cc8cbe209b64$' diff --git a/src/cmd/go/testdata/script/mod_get_local.txt b/src/cmd/go/testdata/script/mod_get_local.txt new file mode 100644 index 0000000..eb09da5 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_local.txt @@ -0,0 +1,62 @@ +# Test 'go get' with a local module with a name that is not valid for network lookup. +[short] skip + +env GO111MODULE=on +go mod edit -fmt +cp go.mod go.mod.orig + +# 'go get -u' within the main module should work, even if it has a local-only name. +cp go.mod.orig go.mod +go get -d -u ./... +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 local/...' should be equivalent to 'go get -u ./...' +# (assuming no nested modules) +cp go.mod.orig go.mod +go get -d -u local/... +cmp go.mod go.mod.implicitmod + +# For the main module, @patch should be a no-op. +cp go.mod.orig go.mod +go get -d -u local/...@patch +cmp go.mod go.mod.implicitmod + +# 'go get -u -d' in the empty root of the main module should fail. +# 'go get -u -d .' should also fail. +cp go.mod.orig go.mod +! go get -u -d +! go get -u -d . + +# 'go get -u -d .' within a package in the main module updates the dependencies +# of that package. +cp go.mod.orig go.mod +cd uselang +go get -u -d . +cd .. +grep 'rsc.io/quote.*v1.3.0' 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 the +# dependencies of that package. +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/src/cmd/go/testdata/script/mod_get_main.txt b/src/cmd/go/testdata/script/mod_get_main.txt new file mode 100644 index 0000000..50b2fee --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_main.txt @@ -0,0 +1,51 @@ +env GO111MODULE=on +cp go.mod.orig go.mod + +# relative and absolute paths must be within the main module. +! go get -d .. +stderr '^go get: \.\. \('$WORK'[/\\]gopath\) is not within module rooted at '$WORK'[/\\]gopath[/\\]src$' +! go get -d $WORK +stderr '^go get: '$WORK' is not within module rooted at '$WORK'[/\\]gopath[/\\]src$' +! go get -d ../... +stderr '^go get: \.\./\.\.\. \('$WORK'[/\\]gopath([/\\]...)?\) is not within module rooted at '$WORK'[/\\]gopath[/\\]src$' +! go get -d $WORK/... +stderr '^go get: '$WORK'[/\\]\.\.\. is not within module rooted at '$WORK'[/\\]gopath[/\\]src$' + +# @patch and @latest within the main module refer to the current version. +# The main module won't be upgraded, but missing dependencies will be added. +go get -d rsc.io/x +grep 'rsc.io/quote v1.5.2' go.mod +go get -d rsc.io/x@upgrade +grep 'rsc.io/quote v1.5.2' go.mod +cp go.mod.orig go.mod +go get -d rsc.io/x@patch +grep 'rsc.io/quote v1.5.2' go.mod +cp go.mod.orig go.mod + + +# Upgrading a package pattern not contained in the main module should not +# attempt to upgrade the main module. +go get -d rsc.io/quote/...@v1.5.1 +grep 'rsc.io/quote v1.5.1' go.mod + + +# The main module cannot be updated to a specific version. +! go get -d rsc.io@v0.1.0 +stderr '^go get: can''t request version "v0.1.0" of the main module \(rsc.io\)$' + +# A package in the main module can't be upgraded either. +! go get -d rsc.io/x@v0.1.0 +stderr '^go get: package rsc.io/x is in the main module, so can''t request version v0.1.0$' + +# Nor can a pattern matching packages in the main module. +! go get -d rsc.io/x/...@latest +stderr '^go get: pattern rsc.io/x/... matches package rsc.io/x in the main module, so can''t request version latest$' + +-- go.mod.orig -- +module rsc.io + +go 1.13 +-- x/x.go -- +package x + +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_get_major.txt b/src/cmd/go/testdata/script/mod_get_major.txt new file mode 100644 index 0000000..367ede9 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_major.txt @@ -0,0 +1,23 @@ +[!net] skip +[!exec:git] skip + +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off + +# golang.org/issue/34383: if a module path ends in a major-version suffix, +# ensure that 'direct' mode can resolve the package to a module. + +go get -d vcs-test.golang.org/git/v3pkg.git/v3@v3.0.0 + +go list -m vcs-test.golang.org/git/v3pkg.git/v3 +stdout '^vcs-test.golang.org/git/v3pkg.git/v3 v3.0.0$' + +go get -d vcs-test.golang.org/git/empty-v2-without-v1.git/v2@v2.0.0 + +go list -m vcs-test.golang.org/git/empty-v2-without-v1.git/v2 +stdout '^vcs-test.golang.org/git/empty-v2-without-v1.git/v2 v2.0.0$' + +-- go.mod -- +module example.com +go 1.13 diff --git a/src/cmd/go/testdata/script/mod_get_missing_ziphash.txt b/src/cmd/go/testdata/script/mod_get_missing_ziphash.txt new file mode 100644 index 0000000..8f6793e --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_missing_ziphash.txt @@ -0,0 +1,55 @@ +# Test that if the module cache contains an extracted source directory but not +# a ziphash, 'go build' complains about a missing sum, and 'go get' adds +# the sum. Verifies #44749. + +# With a tidy go.sum, go build succeeds. This also populates the module cache. +cp go.sum.tidy go.sum +go build -n use +env GOPROXY=off +env GOSUMDB=off + +# Control case: if we delete the hash for rsc.io/quote v1.5.2, +# 'go build' reports an error. 'go get' adds the sum. +cp go.sum.bug go.sum +! go build -n use +stderr '^use.go:3:8: missing go.sum entry for module providing package rsc.io/quote \(imported by use\); to add:\n\tgo get use$' +go get -d use +cmp go.sum go.sum.tidy +go build -n use + +# If we delete the hash *and* the ziphash file, we should see the same behavior. +cp go.sum.bug go.sum +rm $WORK/gopath/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.ziphash +! go build -n use +stderr '^use.go:3:8: missing go.sum entry for module providing package rsc.io/quote \(imported by use\); to add:\n\tgo get use$' +go get -d use +cmp go.sum go.sum.tidy +go build -n use + +-- go.mod -- +module use + +go 1.17 + +require rsc.io/quote v1.5.2 +-- go.sum.tidy -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/testonly v1.0.0 h1:K/VWHdO+Jv7woUXG0GzVNx1czBXUt3Ib1deaMn+xk64= +rsc.io/testonly v1.0.0/go.mod h1:OqmGbIFOcF+XrFReLOGZ6BhMM7uMBiQwZsyNmh74SzY= +-- go.sum.bug -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/testonly v1.0.0 h1:K/VWHdO+Jv7woUXG0GzVNx1czBXUt3Ib1deaMn+xk64= +rsc.io/testonly v1.0.0/go.mod h1:OqmGbIFOcF+XrFReLOGZ6BhMM7uMBiQwZsyNmh74SzY= +-- use.go -- +package use + +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_get_moved.txt b/src/cmd/go/testdata/script/mod_get_moved.txt new file mode 100644 index 0000000..8430a73 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_moved.txt @@ -0,0 +1,40 @@ +env GO111MODULE=on +[short] skip + +# 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 -d 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. +# (A wildcard pattern applies to both packages and modules, +# because we define wildcard matching to apply after version resolution.) +go get -d 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/src/cmd/go/testdata/script/mod_get_newcycle.txt b/src/cmd/go/testdata/script/mod_get_newcycle.txt new file mode 100644 index 0000000..f71620c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_newcycle.txt @@ -0,0 +1,14 @@ +env GO111MODULE=on + +# Download modules to avoid stderr chatter +go mod download example.com@v1.0.0 +go mod download example.com/newcycle/a@v1.0.0 +go mod download example.com/newcycle/a@v1.0.1 +go mod download example.com/newcycle/b@v1.0.0 + +go mod init m +! go get example.com/newcycle/a@v1.0.0 +cmp stderr stderr-expected + +-- stderr-expected -- +go get: example.com/newcycle/a@v1.0.0 requires example.com/newcycle/a@v1.0.1, not example.com/newcycle/a@v1.0.0 diff --git a/src/cmd/go/testdata/script/mod_get_none.txt b/src/cmd/go/testdata/script/mod_get_none.txt new file mode 100644 index 0000000..b358f05 --- /dev/null +++ b/src/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 -d example.com/bar@none +go list -m all +! stdout example.com/bar + +go get -d example.com/bar@none +go list -m all +! stdout example.com/bar diff --git a/src/cmd/go/testdata/script/mod_get_nopkgs.txt b/src/cmd/go/testdata/script/mod_get_nopkgs.txt new file mode 100644 index 0000000..078e71a --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_nopkgs.txt @@ -0,0 +1,40 @@ +cd subdir + +# 'go get' on empty patterns that are necessarily local to the module +# should warn that the patterns are empty, exactly once. + +go get ./... +stderr -count=1 'matched no packages' + +go get -d ./... +stderr -count=1 'matched no packages' + +# 'go get' on patterns that could conceivably match nested modules +# should report a module resolution error. + +go get -d example.net/emptysubdir/... # control case + +! go get -d example.net/emptysubdir/subdir/... +! stderr 'matched no packages' +stderr '^go get example\.net/emptysubdir/subdir/\.\.\.: module example\.net/emptysubdir/subdir: reading http://.*: 404 Not Found\n\tserver response: 404 page not found\n\z' + +# It doesn't make sense to 'go get' a path in the standard library, +# since the standard library necessarily can't have unresolved imports. +# +# TODO(#30241): Maybe that won't always be the case? +# +# For that case, we emit a "malformed module path" error message, +# which isn't ideal either. + +! go get -d builtin/... # in GOROOT/src, but contains no packages +stderr '^go get builtin/...: malformed module path "builtin": missing dot in first path element$' + +-- go.mod -- +module example.net/emptysubdir + +go 1.16 +-- emptysubdir.go -- +// Package emptysubdir has a subdirectory containing no packages. +package emptysubdir +-- subdir/README.txt -- +This module intentionally does not contain any p diff --git a/src/cmd/go/testdata/script/mod_get_patch.txt b/src/cmd/go/testdata/script/mod_get_patch.txt new file mode 100644 index 0000000..053ef62 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_patch.txt @@ -0,0 +1,130 @@ +# This test examines the behavior of 'go get …@patch' +# See also mod_upgrade_patch.txt (focused on "-u=patch" specifically) +# and mod_get_patchmod.txt (focused on module/package ambiguities). + +cp go.mod go.mod.orig + +# example.net/b@patch refers to the patch for the version of b that was selected +# at the start of 'go get', not the version after applying other changes. + +! go get -d example.net/a@v0.2.0 example.net/b@patch +stderr '^go get: example.net/a@v0.2.0 requires example.net/b@v0.2.0, not example.net/b@patch \(v0.1.1\)$' +cmp go.mod go.mod.orig + + +# -u=patch changes the default version for other arguments to '@patch', +# but they continue to be resolved against the originally-selected version, +# not the updated one. +# +# TODO(#42360): Reconsider the change in defaults. + +! go get -d -u=patch example.net/a@v0.2.0 example.net/b +stderr '^go get: example.net/a@v0.2.0 requires example.net/b@v0.2.0, not example.net/b@patch \(v0.1.1\)$' +cmp go.mod go.mod.orig + + +# -u=patch refers to the patches for the selected versions of dependencies *after* +# applying other version changes, not the versions that were selected at the start. +# However, it should not patch versions determined by explicit arguments. + +go get -d -u=patch example.net/a@v0.2.0 +go list -m all +stdout '^example.net/a v0.2.0 ' +stdout '^example.net/b v0.2.1 ' + + +# "-u=patch all" should be equivalent to "all@patch", and should fail if the +# patched versions result in a higher-than-patch upgrade. + +cp go.mod.orig go.mod +! go get -u=patch all +stderr '^go get: example.net/a@v0.1.1 \(matching all@patch\) requires example.net/b@v0.2.0, not example.net/b@v0.1.1 \(matching all@patch\)$' +cmp go.mod go.mod.orig + + +# On the other hand, "-u=patch ./..." should patch-upgrade dependencies until +# they reach a fixed point, even if that results in higher-than-patch upgrades. + +go get -u=patch ./... +go list -m all +stdout '^example.net/a v0.1.1 ' +stdout '^example.net/b v0.2.1 ' + + +-- go.mod -- +module example + +go 1.16 + +require ( + example.net/a v0.1.0 + example.net/b v0.1.0 // indirect +) + +replace ( + example.net/a v0.1.0 => ./a10 + example.net/a v0.1.1 => ./a11 + example.net/a v0.2.0 => ./a20 + example.net/a v0.2.1 => ./a21 + example.net/b v0.1.0 => ./b + example.net/b v0.1.1 => ./b + example.net/b v0.2.0 => ./b + example.net/b v0.2.1 => ./b + example.net/b v0.3.0 => ./b + example.net/b v0.3.1 => ./b +) +-- example.go -- +package example + +import _ "example.net/a" + +-- a10/go.mod -- +module example.net/a + +go 1.16 + +require example.net/b v0.1.0 +-- a10/a.go -- +package a + +import _ "example.net/b" + +-- a11/go.mod -- +module example.net/a + +go 1.16 + +require example.net/b v0.2.0 // upgraded +-- a11/a.go -- +package a + +import _ "example.net/b" + +-- a20/go.mod -- +module example.net/a + +go 1.16 + +require example.net/b v0.2.0 +-- a20/a.go -- +package a + +import _ "example.net/b" + +-- a21/go.mod -- +module example.net/a + +go 1.16 + +require example.net/b v0.2.0 // not upgraded +-- a21/a.go -- +package a + +import _ "example.net/b" + +-- b/go.mod -- +module example.net/b + +go 1.16 +-- b/b.go -- +package b diff --git a/src/cmd/go/testdata/script/mod_get_patchbound.txt b/src/cmd/go/testdata/script/mod_get_patchbound.txt new file mode 100644 index 0000000..4fd1ec5 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_patchbound.txt @@ -0,0 +1,84 @@ +# -u=patch will patch dependencies as far as possible, but not so far that they +# conflict with other command-line arguments. + +go list -m all +stdout '^example.net/a v0.1.0 ' +stdout '^example.net/b v0.1.0 ' + +go get -d -u=patch example.net/a@v0.2.0 +go list -m all +stdout '^example.net/a v0.2.0 ' +stdout '^example.net/b v0.1.1 ' # not v0.1.2, which requires …/a v0.3.0. + +-- go.mod -- +module example + +go 1.16 + +require ( + example.net/a v0.1.0 + example.net/b v0.1.0 // indirect +) + +replace ( + example.net/a v0.1.0 => ./a + example.net/a v0.2.0 => ./a + example.net/a v0.3.0 => ./a + example.net/b v0.1.0 => ./b10 + example.net/b v0.1.1 => ./b11 + example.net/b v0.1.2 => ./b12 +) +-- example.go -- +package example + +import _ "example.net/a" + +-- a/go.mod -- +module example.net/a + +go 1.16 + +require example.net/b v0.1.0 +-- a/a.go -- +package a + +import _ "example.net/b" + +-- b10/go.mod -- +module example.net/b + +go 1.16 + +require example.net/a v0.1.0 +-- b10/b.go -- +package b +-- b10/b_test.go -- +package b_test + +import _ "example.net/a" + +-- b11/go.mod -- +module example.net/b + +go 1.16 + +require example.net/a v0.2.0 +-- b11/b.go -- +package b +-- b11/b_test.go -- +package b_test + +import _ "example.net/a" + +-- b12/go.mod -- +module example.net/b + +go 1.16 + +require example.net/a v0.3.0 +-- b12/b.go -- +package b +-- b12/b_test.go -- +package b_test + +import _ "example.net/a" diff --git a/src/cmd/go/testdata/script/mod_get_patchcycle.txt b/src/cmd/go/testdata/script/mod_get_patchcycle.txt new file mode 100644 index 0000000..d1db56f --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_patchcycle.txt @@ -0,0 +1,64 @@ +# If a patch of a module requires a higher version of itself, +# it should be reported as its own conflict. +# +# This case is weird and unlikely to occur often at all, but it should not +# spuriously succeed. +# (It used to print v0.1.1 but then silently upgrade to v0.2.0.) + +! go get example.net/a@patch +stderr '^go get: example.net/a@patch \(v0.1.1\) requires example.net/a@v0.2.0, not example.net/a@patch \(v0.1.1\)$' # TODO: A mention of b v0.1.0 would be nice. + +-- go.mod -- +module example + +go 1.16 + +require example.net/a v0.1.0 + +replace ( + example.net/a v0.1.0 => ./a10 + example.net/a v0.1.1 => ./a11 + example.net/a v0.2.0 => ./a20 + example.net/b v0.1.0 => ./b10 +) +-- example.go -- +package example + +import _ "example.net/a" + +-- a10/go.mod -- +module example.net/a + +go 1.16 +-- a10/a.go -- +package a + +-- a11/go.mod -- +module example.net/a + +go 1.16 + +require example.net/b v0.1.0 +-- a11/a.go -- +package a + +import _ "example.net/b" + +-- a20/go.mod -- +module example.net/a + +go 1.16 +-- a20/a.go -- +package a + + +-- b10/go.mod -- +module example.net/b + +go 1.16 + +require example.net/a v0.2.0 +-- b10/b.go -- +package b + +import _ "example.net/a" diff --git a/src/cmd/go/testdata/script/mod_get_patchmod.txt b/src/cmd/go/testdata/script/mod_get_patchmod.txt new file mode 100644 index 0000000..e39d13a --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_patchmod.txt @@ -0,0 +1,82 @@ +# example.net/pkgremoved@v0.1.0 refers to a package. +go get -d example.net/pkgremoved@v0.1.0 + +go list example.net/pkgremoved +stdout '^example.net/pkgremoved' + +cp go.mod go.mod.orig + + +# When we resolve a new dependency on example.net/other, +# it will change the meaning of the path "example.net/pkgremoved" +# from a package (at v0.1.0) to only a module (at v0.2.0). +# +# If we simultaneously 'get' that module at the query "patch", the module should +# be constrained to the latest patch of its originally-selected version (v0.1.0), +# not upgraded to the latest patch of the new transitive dependency. + +! go get -d example.net/pkgremoved@patch example.net/other@v0.1.0 +stderr '^go get: example.net/other@v0.1.0 requires example.net/pkgremoved@v0.2.0, not example.net/pkgremoved@patch \(v0.1.1\)$' +cmp go.mod.orig go.mod + + +# However, we should be able to patch from a package to a module and vice-versa. + +# Package to module ... + +go get -d example.net/pkgremoved@v0.3.0 +go list example.net/pkgremoved +stdout 'example.net/pkgremoved' + +go get -d example.net/pkgremoved@patch +! go list example.net/pkgremoved + +# ... and module to package. + +go get -d example.net/pkgremoved@v0.4.0 +! go list example.net/pkgremoved + +go get -d example.net/pkgremoved@patch +go list example.net/pkgremoved +stdout 'example.net/pkgremoved' + + +-- go.mod -- +module example + +go 1.16 + +replace ( + example.net/other v0.1.0 => ./other + + example.net/pkgremoved v0.1.0 => ./prpkg + example.net/pkgremoved v0.1.1 => ./prpkg + + example.net/pkgremoved v0.2.0 => ./prmod + example.net/pkgremoved v0.2.1 => ./prmod + + example.net/pkgremoved v0.3.0 => ./prpkg + example.net/pkgremoved v0.3.1 => ./prmod + + example.net/pkgremoved v0.4.0 => ./prmod + example.net/pkgremoved v0.4.1 => ./prpkg +) +-- other/go.mod -- +module example.net/other + +go 1.16 + +require example.net/pkgremoved v0.2.0 +-- other/other.go -- +package other +-- prpkg/go.mod -- +module example.net/pkgremoved + +go 1.16 +-- prpkg/pkgremoved.go -- +package pkgremoved +-- prmod/go.mod -- +module example.net/pkgremoved +-- prmod/README.txt -- +Package pkgremoved was removed in v0.2.0 and v0.3.1, +and added in v0.1.0 and v0.4.1. diff --git a/src/cmd/go/testdata/script/mod_get_patterns.txt b/src/cmd/go/testdata/script/mod_get_patterns.txt new file mode 100644 index 0000000..aee4374 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_patterns.txt @@ -0,0 +1,42 @@ +env GO111MODULE=on +[short] skip + +# If a pattern doesn't match any packages provided by modules +# in the build list, we assume the pattern matches a single module +# whose path is a prefix of the part of the pattern before "...". +cp go.mod.orig go.mod +go get -d rsc.io/quote/... +grep 'require rsc.io/quote' go.mod + +cp go.mod.orig go.mod +! go get -d rsc.io/quote/x... +stderr 'go get: module rsc.io/quote@upgrade found \(v1.5.2\), but does not contain packages matching rsc.io/quote/x...' +! grep 'require rsc.io/quote' go.mod + +! go get -d rsc.io/quote/x/... +stderr 'go get: module rsc.io/quote@upgrade found \(v1.5.2\), but does not contain packages matching rsc.io/quote/x/...' +! grep 'require rsc.io/quote' go.mod + +# If a pattern matches no packages within a module, the module should not +# be upgraded, even if the module path is a prefix of the pattern. +cp go.mod.orig go.mod +go mod edit -require example.com/nest@v1.0.0 +go get -d example.com/nest/sub/y... +grep 'example.com/nest/sub v1.0.0' go.mod +grep 'example.com/nest v1.0.0' go.mod + +# However, if the pattern matches the module path itself, the module +# should be upgraded even if it contains no matching packages. +go get -d example.com/n...t +grep 'example.com/nest v1.1.0' go.mod +grep 'example.com/nest/sub v1.0.0' go.mod + +-- go.mod.orig -- +module m + +go 1.13 + +-- use/use.go -- +package use + +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_get_pkgtags.txt b/src/cmd/go/testdata/script/mod_get_pkgtags.txt new file mode 100644 index 0000000..c0a57f3 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_pkgtags.txt @@ -0,0 +1,116 @@ +# https://golang.org/issue/44106 +# 'go get' should fetch the transitive dependencies of packages regardless of +# tags, but shouldn't error out if the package is missing tag-guarded +# dependencies. + +# Control case: just adding the top-level module to the go.mod file does not +# fetch its dependencies. + +go mod edit -require example.net/tools@v0.1.0 +! go list -deps example.net/cmd/tool +stderr '^module example\.net/cmd provides package example\.net/cmd/tool and is replaced but not required; to add it:\n\tgo get example\.net/cmd@v0\.1\.0$' +go mod edit -droprequire example.net/tools + + +# 'go get -d' makes a best effort to fetch those dependencies, but shouldn't +# error out if dependencies of tag-guarded files are missing. + +go get -d example.net/tools@v0.1.0 + +! go list example.net/tools +stderr '^package example.net/tools: build constraints exclude all Go files in .*[/\\]tools$' + +go list -tags=tools -e -deps example.net/tools +stdout '^example.net/cmd/tool$' +stdout '^example.net/missing$' + +go list -deps example.net/cmd/tool + +! go list example.net/missing +stderr '^no required module provides package example.net/missing; to add it:\n\tgo get example.net/missing$' + + +# https://golang.org/issue/29268 +# 'go get' should fetch modules whose roots contain test-only packages, but +# without the -t flag shouldn't error out if the test has missing dependencies. + +go get -d example.net/testonly@v0.1.0 + +# With the -t flag, the test dependencies must resolve successfully. +! go get -d -t example.net/testonly@v0.1.0 +stderr '^example.net/testonly tested by\n\texample.net/testonly\.test imports\n\texample.net/missing: cannot find module providing package example.net/missing$' + + +# 'go get -d' should succeed for a module path that does not contain a package, +# but fail for a non-package subdirectory of a module. + +! go get -d example.net/missing/subdir@v0.1.0 +stderr '^go get: module example.net/missing@v0.1.0 found \(replaced by ./missing\), but does not contain package example.net/missing/subdir$' + +go get -d example.net/missing@v0.1.0 + + +# Getting the subdirectory should continue to fail even if the corresponding +# module is already present in the build list. + +! go get -d example.net/missing/subdir@v0.1.0 +stderr '^go get: module example.net/missing@v0.1.0 found \(replaced by ./missing\), but does not contain package example.net/missing/subdir$' + + +-- go.mod -- +module example.net/m + +go 1.15 + +replace ( + example.net/tools v0.1.0 => ./tools + example.net/cmd v0.1.0 => ./cmd + example.net/testonly v0.1.0 => ./testonly + example.net/missing v0.1.0 => ./missing +) + +-- tools/go.mod -- +module example.net/tools + +go 1.15 + +// Requirements intentionally omitted. + +-- tools/tools.go -- +// +build tools + +package tools + +import ( + _ "example.net/cmd/tool" + _ "example.net/missing" +) + +-- cmd/go.mod -- +module example.net/cmd + +go 1.16 +-- cmd/tool/tool.go -- +package main + +func main() {} + +-- testonly/go.mod -- +module example.net/testonly + +go 1.15 +-- testonly/testonly_test.go -- +package testonly_test + +import _ "example.net/missing" + +func Test(t *testing.T) {} + +-- missing/go.mod -- +module example.net/missing + +go 1.15 +-- missing/README.txt -- +There are no Go source files here. +-- missing/subdir/README.txt -- +There are no Go source files here either. diff --git a/src/cmd/go/testdata/script/mod_get_prefer_incompatible.txt b/src/cmd/go/testdata/script/mod_get_prefer_incompatible.txt new file mode 100644 index 0000000..be3db42 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_prefer_incompatible.txt @@ -0,0 +1,29 @@ +# Verifies golang.org/issue/37574. + +# If we are already using an +incompatible version, we shouldn't look up +# a lower compatible version when upgrading. +cp go.mod go.mod.orig +go mod tidy +cmp go.mod.orig go.mod +grep '^example.com/incompatiblewithsub v2\.0\.0\+incompatible' go.sum +! grep '^example.com/incompatiblewithsub v1.0.0' go.sum + +go get -d example.com/incompatiblewithsub/sub +cmp go.mod.orig go.mod +! grep '^example.com/incompatiblewithsub v1.0.0' go.sum + +# TODO(golang.org/issue/31580): the 'go get' command above should not change +# go.sum. However, as part of the query above, we download example.com@v1.0.0, +# an unrelated module, since it's a possible prefix. The sum for that module +# should not be written to go.sum. + +-- go.mod -- +module m + +go 1.15 + +require example.com/incompatiblewithsub v2.0.0+incompatible +-- use.go -- +package use + +import _ "example.com/incompatiblewithsub/sub" diff --git a/src/cmd/go/testdata/script/mod_get_private_vcs.txt b/src/cmd/go/testdata/script/mod_get_private_vcs.txt new file mode 100644 index 0000000..514b0a7 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_private_vcs.txt @@ -0,0 +1,11 @@ +env GO111MODULE=on + +# Testing stderr for git ls-remote; turn off proxy. +[!net] skip +[!exec:git] skip +env GOPROXY=direct + +! go get github.com/golang/nonexist +stderr 'Confirm the import path was entered correctly.' +stderr 'If this is a private repository, see https://golang.org/doc/faq#git_https for additional information.' +! stdout . diff --git a/src/cmd/go/testdata/script/mod_get_promote_implicit.txt b/src/cmd/go/testdata/script/mod_get_promote_implicit.txt new file mode 100644 index 0000000..10ca659 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_promote_implicit.txt @@ -0,0 +1,92 @@ +cp go.mod.orig go.mod + +# If we list a package in an implicit dependency imported from the main module, +# we should get an error because the dependency should have an explicit +# requirement. +go list -m indirect-with-pkg +stdout '^indirect-with-pkg v1.0.0 => ./indirect-with-pkg$' +! go list ./use-indirect +stderr '^go: m/use-indirect: package indirect-with-pkg imported from implicitly required module; to add missing requirements, run:\n\tgo get indirect-with-pkg@v1.0.0$' + +# We can promote the implicit requirement by getting the importing package. +# NOTE: the hint recommends getting the imported package (tested below) since +# it's more obvious and doesn't require -d. However, that adds an '// indirect' +# comment on the requirement. +go get -d m/use-indirect +cmp go.mod go.mod.use +cp go.mod.orig go.mod + +# We can also promote implicit requirements using 'go get' on them, or their +# packages. This gives us "// indirect" requirements, since 'go get' doesn't +# know they're needed by the main module. See #43131 for the rationale. +# The hint above recommends this because it's more obvious usage and doesn't +# require the -d flag. +go get -d indirect-with-pkg indirect-without-pkg +cmp go.mod go.mod.indirect + +-- go.mod.orig -- +module m + +go 1.16 + +require direct v1.0.0 + +replace ( + direct v1.0.0 => ./direct + indirect-with-pkg v1.0.0 => ./indirect-with-pkg + indirect-without-pkg v1.0.0 => ./indirect-without-pkg +) +-- go.mod.use -- +module m + +go 1.16 + +require ( + direct v1.0.0 + indirect-with-pkg v1.0.0 +) + +replace ( + direct v1.0.0 => ./direct + indirect-with-pkg v1.0.0 => ./indirect-with-pkg + indirect-without-pkg v1.0.0 => ./indirect-without-pkg +) +-- go.mod.indirect -- +module m + +go 1.16 + +require ( + direct v1.0.0 + indirect-with-pkg v1.0.0 // indirect + indirect-without-pkg v1.0.0 // indirect +) + +replace ( + direct v1.0.0 => ./direct + indirect-with-pkg v1.0.0 => ./indirect-with-pkg + indirect-without-pkg v1.0.0 => ./indirect-without-pkg +) +-- use-indirect/use-indirect.go -- +package use + +import _ "indirect-with-pkg" +-- direct/go.mod -- +module direct + +go 1.16 + +require ( + indirect-with-pkg v1.0.0 + indirect-without-pkg v1.0.0 +) +-- indirect-with-pkg/go.mod -- +module indirect-with-pkg + +go 1.16 +-- indirect-with-pkg/p.go -- +package p +-- indirect-without-pkg/go.mod -- +module indirect-without-pkg + +go 1.16 diff --git a/src/cmd/go/testdata/script/mod_get_pseudo.txt b/src/cmd/go/testdata/script/mod_get_pseudo.txt new file mode 100644 index 0000000..582837a --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_pseudo.txt @@ -0,0 +1,82 @@ +env GO111MODULE=on + +# Testing git->module converter's generation of +incompatible tags; turn off proxy. +[!net] skip +[!exec:git] skip +env GOPROXY=direct +env GOSUMDB=off + +# 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 -d 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 mod edit -droprequire github.com/rsc/legacytest +go get -d 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 -d ...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 -d ...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 -d ...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 -d ...test@d7ae1e4 +go list -m all +stdout '^github.com/rsc/legacytest v2\.0\.0\+incompatible$' + +# v1.2.1-0.pseudo +go get -d ...test@d2d4c3e +go list -m all +stdout '^github.com/rsc/legacytest v1\.2\.1-0\.\d{14}-d2d4c3ea6623$' + +# v1.2.0 +go get -d ...test@9f6f860 +go list -m all +stdout '^github.com/rsc/legacytest v1\.2\.0$' + +# v1.1.0-pre.0.pseudo +go get -d ...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 -d ...test@731e3b1 +go list -m all +stdout '^github.com/rsc/legacytest v1\.1\.0-pre$' + +# v1.0.1-0.pseudo +go get -d ...test@fa4f5d6 +go list -m all +stdout '^github.com/rsc/legacytest v1\.0\.1-0\.\d{14}-fa4f5d6a71c6$' + +# v1.0.0 +go get -d ...test@7fff7f3 +go list -m all +stdout '^github.com/rsc/legacytest v1\.0\.0$' + +# v0.0.0-pseudo +go get -d ...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/src/cmd/go/testdata/script/mod_get_pseudo_other_branch.txt b/src/cmd/go/testdata/script/mod_get_pseudo_other_branch.txt new file mode 100644 index 0000000..0fbd041 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_pseudo_other_branch.txt @@ -0,0 +1,67 @@ +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off + +# Testing that a pseudo-version is based on the semantically-latest +# tag that appears in any commit that is a (transitive) parent of the commit +# supplied to 'go get', regardless of branches + +[!net] skip +[!exec:git] skip + +# For this test repository: +# tag v0.2.1 is most recent tag on master itself +# tag v0.2.2 is on branch2, which was then merged to master +# master is a merge commit with both tags as parents +# +# The pseudo-version hence sorts immediately after v0.2.2 rather +# than v0.2.1, even though the v0.2.2 tag is not on master. + +go get -d vcs-test.golang.org/git/tagtests.git@master +go list -m all +stdout '^vcs-test.golang.org/git/tagtests.git v0.2.3-0\.' + +-- go.mod -- +module x + +go 1.12 +-- x.go -- +package x + +import _ "vcs-test.golang.org/git/tagtests.git" +-- gen_testtags.sh -- +#!/bin/bash + +# This is not part of the test. +# Run this to generate and update the repository on vcs-test.golang.org. + +set -euo pipefail +cd "$(dirname "$0")" +rm -rf tagtests +mkdir tagtests +cd tagtests + +git init +echo module vcs-test.golang.org/git/tagtests.git >go.mod +echo package tagtests >tagtests.go +git add go.mod tagtests.go +git commit -m 'create module tagtests' + +git branch b + +echo v0.2.1 >v0.2.1 +git add v0.2.1 +git commit -m v0.2.1 +git tag v0.2.1 + +git checkout b +echo v0.2.2 >v0.2.2 +git add v0.2.2 +git commit -m v0.2.2 +git tag v0.2.2 + +git checkout master +git merge b -m merge + +zip -r ../tagtests.zip . +gsutil cp ../tagtests.zip gs://vcs-test/git/tagtests.zip diff --git a/src/cmd/go/testdata/script/mod_get_pseudo_prefix.txt b/src/cmd/go/testdata/script/mod_get_pseudo_prefix.txt new file mode 100644 index 0000000..b78e6e6 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_pseudo_prefix.txt @@ -0,0 +1,64 @@ +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off + +# Testing that a pseudo-version is based on the semantically-latest +# prefixed tag in any commit that is a parent of the commit supplied +# to 'go get', when using a repo with go.mod in a sub directory. + +[!net] skip +[!exec:git] skip + +# For this test repository go.mod resides in sub/ (only): +# master is not tagged +# tag v0.2.0 is most recent tag before master +# tag sub/v0.0.10 is most recent tag before v0.2.0 +# +# The pseudo-version is based on sub/v0.0.10, since v0.2.0 doesn't +# contain the prefix. +go get -d vcs-test.golang.org/git/prefixtagtests.git/sub +go list -m all +stdout '^vcs-test.golang.org/git/prefixtagtests.git/sub v0.0.10$' + +go get -d -u vcs-test.golang.org/git/prefixtagtests.git/sub@master +go list -m all +stdout '^vcs-test.golang.org/git/prefixtagtests.git/sub v0.0.11-0\.' + +-- go.mod -- +module x + +go 1.12 +-- x.go -- +package x + +import _ "vcs-test.golang.org/prefixtagtests.git/sub" +-- gen_prefixtagtests.sh -- +#!/bin/bash + +# This is not part of the test. +# Run this to generate and update the repository on vcs-test.golang.org. + +set -euo pipefail +cd "$(dirname "$0")" +rm -rf prefixtagtests +mkdir prefixtagtests +cd prefixtagtests + +git init +mkdir sub +echo module vcs-test.golang.org/git/prefixtagtests.git/sub >sub/go.mod +echo package sub >sub/sub.go +git add sub +git commit -m 'create module sub' +for i in v0.1.0 sub/v0.0.9 sub/v0.0.10 v0.2.0; do + echo $i >status + git add status + git commit -m $i + git tag $i +done +echo 'after last tag' >status +git add status +git commit -m 'after last tag' + +zip -r ../prefixtagtests.zip . +gsutil cp ../prefixtagtests.zip gs://vcs-test/git/prefixtagtests.zip diff --git a/src/cmd/go/testdata/script/mod_get_replaced.txt b/src/cmd/go/testdata/script/mod_get_replaced.txt new file mode 100644 index 0000000..d97f3f1 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_replaced.txt @@ -0,0 +1,111 @@ +cp go.mod go.mod.orig + +env oldGOPROXY=$GOPROXY + +# If a wildcard replacement exists for an otherwise-nonexistent module, +# 'go get' should resolve it to the minimum valid pseudo-version. + +go mod edit -replace=example.com/x=./x +go get -d example.com/x + +go list -m example.com/x +stdout '^example.com/x v0.0.0-00010101000000-000000000000 ' + +# If specific-version replacements exist, the highest matching version should be used. +go mod edit -replace=example.com/x@v0.1.0=./x +go mod edit -replace=example.com/x@v0.2.0=./x + +go get -d example.com/x +go list -m example.com/x +stdout '^example.com/x v0.2.0 ' + +go get -d example.com/x@v1.3.1 +go list -m rsc.io/quote +stdout '^rsc.io/quote v1.4.0' + + +# Replacements should allow 'go get' to work even with dotless module paths. + +cp go.mod.orig go.mod + +! go list example +stderr '^package example is not in GOROOT \(.*\)$' +! go get -d example +stderr '^go get: malformed module path "example": missing dot in first path element$' + +go mod edit -replace example@v0.1.0=./example + +! go list example +stderr '^module example provides package example and is replaced but not required; to add it:\n\tgo get example@v0.1.0$' + +go get -d example +go list -m example +stdout '^example v0.1.0 ' + + +-- go.mod -- +module example.com + +go 1.16 +-- x/go.mod -- +module example.com/x + +go 1.16 +-- x/x.go -- +package x +-- example/go.mod -- +module example +go 1.16 +-- example/example.go -- +package example diff --git a/src/cmd/go/testdata/script/mod_get_retract.txt b/src/cmd/go/testdata/script/mod_get_retract.txt new file mode 100644 index 0000000..560fa7b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_retract.txt @@ -0,0 +1,59 @@ +# 'go get pkg' should not upgrade to a retracted version. +cp go.mod.orig go.mod +go mod edit -require example.com/retract/self/prev@v1.1.0 +go get -d example.com/retract/self/prev +go list -m example.com/retract/self/prev +stdout '^example.com/retract/self/prev v1.1.0$' + +# 'go get pkg' should not downgrade from a retracted version when no higher +# version is available. +cp go.mod.orig go.mod +go mod edit -require example.com/retract/self/prev@v1.9.0 +go get -d example.com/retract/self/prev +stderr '^go: warning: example.com/retract/self/prev@v1.9.0: retracted by module author: self$' +stderr '^go: to switch to the latest unretracted version, run:\n\tgo get example.com/retract/self/prev@latest\n$' +go list -m example.com/retract/self/prev +stdout '^example.com/retract/self/prev v1.9.0$' + +# 'go get pkg@latest' should downgrade from a retracted version. +cp go.mod.orig go.mod +go mod edit -require example.com/retract/self/prev@v1.9.0 +go get -d example.com/retract/self/prev@latest +go list -m example.com/retract/self/prev +stdout '^example.com/retract/self/prev v1.1.0$' + +# 'go get pkg@version' should update to a specific version, even if that +# version is retracted. +cp go.mod.orig go.mod +go get -d example.com/retract@v1.0.0-bad +stderr '^go: warning: example.com/retract@v1.0.0-bad: retracted by module author: bad$' +go list -m example.com/retract +stdout '^example.com/retract v1.0.0-bad$' + +# 'go get -u' should not downgrade from a retracted version when no higher +# version is available. +cp go.mod.orig go.mod +go mod edit -require example.com/retract/self/prev@v1.9.0 +go get -d -u ./use +stderr '^go: warning: example.com/retract/self/prev@v1.9.0: retracted by module author: self$' +go list -m example.com/retract/self/prev +stdout '^example.com/retract/self/prev v1.9.0$' + +# 'go get' should warn if a module needed to build named packages is retracted. +# 'go get' should not warn about unrelated modules. +go get -d ./empty +! stderr retracted +go get -d ./use +stderr '^go: warning: example.com/retract/self/prev@v1.9.0: retracted by module author: self$' + +-- go.mod.orig -- +module example.com/use + +go 1.15 + +-- use/use.go -- +package use + +import _ "example.com/retract/self/prev" +-- empty/empty.go -- +package empty diff --git a/src/cmd/go/testdata/script/mod_get_retract_ambiguous.txt b/src/cmd/go/testdata/script/mod_get_retract_ambiguous.txt new file mode 100644 index 0000000..b49ba54 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_retract_ambiguous.txt @@ -0,0 +1,10 @@ +! go get -d example.com/retract/ambiguous/other +stderr 'ambiguous import: found package example.com/retract/ambiguous/nested in multiple modules:' +stderr '^go: warning: example.com/retract/ambiguous/nested@v1.9.0-bad: retracted by module author: nested modules are bad$' + +-- go.mod -- +module example.com/use + +go 1.16 + +require example.com/retract/ambiguous/nested v1.9.0-bad diff --git a/src/cmd/go/testdata/script/mod_get_split.txt b/src/cmd/go/testdata/script/mod_get_split.txt new file mode 100644 index 0000000..f4e7661 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_split.txt @@ -0,0 +1,157 @@ +cp go.mod go.mod.orig + + +# 'go get' on a package already provided by the build list should update +# the module already in the build list, not fail with an ambiguous import error. + +go get -d example.net/split/nested@patch +go list -m all +stdout '^example.net/split v0.2.1 ' +! stdout '^example.net/split/nested' + +# We should get the same behavior if we use a pattern that matches only that package. + +cp go.mod.orig go.mod + +go get -d example.net/split/nested/...@patch +go list -m all +stdout '^example.net/split v0.2.1 ' +! stdout '^example.net/split/nested' + + +# If we request a version for which the package only exists in one particular module, +# we should add that one particular module but not resolve import ambiguities. +# +# In particular, if the module that previously provided the package has a +# matching version, but does not itself match the pattern and contains no +# matching packages, we should not change its version. (We should *not* downgrade +# module example.net/split to v0.1.0, despite the fact that +# example.net/split v0.2.0 currently provides the package with the requested path.) +# +# TODO(#27899): Maybe we should resolve the ambiguities by upgrading. + +cp go.mod.orig go.mod + +! go get -d example.net/split/nested@v0.1.0 +stderr '^example.net/split/nested: ambiguous import: found package example.net/split/nested in multiple modules:\n\texample.net/split v0.2.0 \(.*split.2[/\\]nested\)\n\texample.net/split/nested v0.1.0 \(.*nested.1\)$' + +# A wildcard that matches packages in some module at its selected version +# but not at the requested version should fail. +# +# We can't set the module to the selected version, because that version doesn't +# even match the query: if we ran the same query twice, we wouldn't consider the +# module to match the wildcard during the second call, so why should we consider +# it to match during the first one? ('go get' should be idempotent, and if we +# did that then it would not be.) +# +# But we also can't leave it where it is: the user requested that we set everything +# matching the pattern to the given version, and right now we have packages +# that match the pattern but *not* the version. +# +# That only leaves two options: we can set the module to an arbitrary version +# (perhaps 'latest' or 'none'), or we can report an error and the let the user +# disambiguate. We would rather not choose arbitrarily, so we do the latter. +# +# TODO(#27899): Should we instead upgrade or downgrade to an arbirary version? + +! go get -d example.net/split/nested/...@v0.1.0 +stderr '^go get: example.net/split/nested/\.\.\.@v0.1.0 matches packages in example.net/split@v0.2.0 but not example.net/split@v0.1.0: specify a different version for module example.net/split$' + +cmp go.mod go.mod.orig + + +# If another argument resolves the ambiguity, we should be ok again. + +go get -d example.net/split@none example.net/split/nested@v0.1.0 +go list -m all +! stdout '^example.net/split ' +stdout '^example.net/split/nested v0.1.0 ' + +cp go.mod.orig go.mod + +go get -d example.net/split@v0.3.0 example.net/split/nested@v0.1.0 +go list -m all +stdout '^example.net/split v0.3.0 ' +stdout '^example.net/split/nested v0.1.0 ' + + +# If a pattern applies to modules and to packages, we should set all matching +# modules to the version indicated by the pattern, and also resolve packages +# to match the pattern if possible. + +cp go.mod.orig go.mod +go get -d example.net/split/nested@v0.0.0 + +go get -d example.net/...@v0.1.0 +go list -m all +stdout '^example.net/split v0.1.0 ' +stdout '^example.net/split/nested v0.1.0 ' + +go get -d example.net/... +go list -m all +stdout '^example.net/split v0.3.0 ' +stdout '^example.net/split/nested v0.2.0 ' + + +# @none applies to all matching module paths, +# regardless of whether they contain any packages. + +go get -d example.net/...@none +go list -m all +! stdout '^example.net' + +# Starting from no dependencies, a wildcard can resolve to an empty module with +# the same prefix even if it contains no packages. + +go get -d example.net/...@none +go get -d example.net/split/...@v0.1.0 +go list -m all +stdout '^example.net/split v0.1.0 ' + + +-- go.mod -- +module m + +go 1.16 + +require example.net/split v0.2.0 + +replace ( + example.net/split v0.1.0 => ./split.1 + example.net/split v0.2.0 => ./split.2 + example.net/split v0.2.1 => ./split.2 + example.net/split v0.3.0 => ./split.3 + example.net/split/nested v0.0.0 => ./nested.0 + example.net/split/nested v0.1.0 => ./nested.1 + example.net/split/nested v0.2.0 => ./nested.2 +) +-- split.1/go.mod -- +module example.net/split + +go 1.16 +-- split.2/go.mod -- +module example.net/split + +go 1.16 +-- split.2/nested/nested.go -- +package nested +-- split.3/go.mod -- +module example.net/split + +go 1.16 +-- nested.0/go.mod -- +module example.net/split/nested + +go 1.16 +-- nested.1/go.mod -- +module example.net/split/nested + +go 1.16 +-- nested.1/nested.go -- +package nested +-- nested.2/go.mod -- +module example.net/split/nested + +go 1.16 +-- nested.2/nested.go -- +package nested diff --git a/src/cmd/go/testdata/script/mod_get_sum_noroot.txt b/src/cmd/go/testdata/script/mod_get_sum_noroot.txt new file mode 100644 index 0000000..4f1cf03 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_sum_noroot.txt @@ -0,0 +1,11 @@ +# When 'go get' is invoked on a module without a package in the root directory, +# it should add sums for the module's go.mod file and its content to go.sum. +# Verifies golang.org/issue/41103. +go mod init m +go get -d rsc.io/QUOTE +grep '^rsc.io/QUOTE v1.5.2/go.mod ' go.sum +grep '^rsc.io/QUOTE v1.5.2 ' go.sum + +# Double-check rsc.io/QUOTE does not have a root package. +! go list -mod=readonly rsc.io/QUOTE +stderr '^cannot find module providing package rsc.io/QUOTE: import lookup disabled by -mod=readonly$' diff --git a/src/cmd/go/testdata/script/mod_get_svn.txt b/src/cmd/go/testdata/script/mod_get_svn.txt new file mode 100644 index 0000000..3817fce --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_svn.txt @@ -0,0 +1,36 @@ +[!net] skip +[!exec:svn] skip + +# 'go get' will fall back to svn+ssh once svn fails over protocols like https. +# If vcs-test.golang.org isn't in the user's known_hosts file, this will result +# in an ssh prompt, which will stop 'go test' entirely +# +# Unfortunately, there isn't a way to globally disable host checking for ssh, +# without modifying the real system's or user's configs. Changing $HOME won't +# affect ssh either, as it ignores the environment variable entirely. +# +# However, a useful trick is pointing SVN_SSH to a program that doesn't exist, +# resulting in svn skipping ssh entirely. Alternatives like +# SVN_SSH="ssh -o StrictHostKeyChecking=no" didn't avoid the prompt. +env SVN_SSH="svn_do_not_use_ssh" + +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off + +# Attempting to get a module zip using svn should succeed. +go get vcs-test.golang.org/svn/hello.svn@000000000001 +exists $GOPATH/pkg/mod/cache/download/vcs-test.golang.org/svn/hello.svn/@v/v0.0.0-20170922011245-000000000001.zip +exists $GOPATH/bin/hello.svn$GOEXE + +# Attempting to get a nonexistent module using svn should fail with a +# reasonable message instead of a panic. +! go get -d vcs-test.golang.org/svn/nonexistent.svn +! stderr panic +stderr 'go get vcs-test.golang.org/svn/nonexistent.svn: no matching versions for query "upgrade"' + +-- go.mod -- +module golang/go/issues/28943/main +-- go.sum -- +vcs-test.golang.org/svn/hello.svn v0.0.0-20170922011245-000000000001 h1:rZjvboXMfQICKXdhx/QHqJ2Y/AQsJVrXnwGqwcTxQiw= +vcs-test.golang.org/svn/hello.svn v0.0.0-20170922011245-000000000001/go.mod h1:0memnh/BRLuxiK2zF4rvUgz6ts/fhhB28l3ULFWPusc= diff --git a/src/cmd/go/testdata/script/mod_get_tags.txt b/src/cmd/go/testdata/script/mod_get_tags.txt new file mode 100644 index 0000000..e9869e3 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_tags.txt @@ -0,0 +1,45 @@ +env GO111MODULE=on + +[short] skip + +# get should add modules needed to build packages, even if those +# dependencies are in sources excluded by build tags. +# All build tags are considered true except "ignore". +go mod init m +go get -d . +go list -m all +stdout 'example.com/version v1.1.0' +stdout 'rsc.io/quote v1.5.2' + +[short] skip + +# Packages that are only imported in excluded files should not be built. +env GOCACHE=$WORK/gocache # Looking for compile commands, so need a clean cache. +go get -n -x . +stderr 'compile.* -p m ' +! stderr 'compile.* -p example.com/version ' +! stderr 'compile.* -p rsc.io/quote ' + +-- empty.go -- +package m + +-- excluded.go -- +// +build windows,mips + +package m + +import _ "example.com/version" + +-- tools.go -- +// +build tools + +package tools + +import _ "rsc.io/quote" + +-- ignore.go -- +// +build ignore + +package ignore + +import _ "example.com/doesnotexist" diff --git a/src/cmd/go/testdata/script/mod_get_test.txt b/src/cmd/go/testdata/script/mod_get_test.txt new file mode 100644 index 0000000..23722bd --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_test.txt @@ -0,0 +1,58 @@ +env GO111MODULE=on + +# By default, 'go get' should ignore tests +cp go.mod.empty go.mod +go get -d m/a +! grep rsc.io/quote go.mod + +# 'go get -t' should consider test dependencies of the named package. +cp go.mod.empty go.mod +go get -d -t m/a +grep 'rsc.io/quote v1.5.2$' go.mod + +# 'go get -t' should not consider test dependencies of imported packages, +# including packages imported from tests. +cp go.mod.empty go.mod +go get -d -t m/b +! grep rsc.io/quote go.mod + +# 'go get -t -u' should update test dependencies of the named package. +cp go.mod.empty go.mod +go mod edit -require=rsc.io/quote@v1.5.1 +go get -d -t -u m/a +grep 'rsc.io/quote v1.5.2$' go.mod + +# 'go get -t -u' should not add or update test dependencies +# of imported packages, including packages imported from tests. +cp go.mod.empty go.mod +go get -d -t -u m/b +! grep rsc.io/quote go.mod +go mod edit -require=rsc.io/quote@v1.5.1 +go get -d -t -u m/b +grep 'rsc.io/quote v1.5.1$' go.mod + +# 'go get all' should consider test dependencies with or without -t. +cp go.mod.empty go.mod +go get -d all +grep 'rsc.io/quote v1.5.2$' go.mod + +-- go.mod.empty -- +module m + +-- a/a.go -- +package a + +-- a/a_test.go -- +package a_test + +import _ "rsc.io/quote" + +-- b/b.go -- +package b + +import _ "m/a" + +-- b/b_test.go -- +package b_test + +import _ "m/a" diff --git a/src/cmd/go/testdata/script/mod_get_too_many_redirects.txt b/src/cmd/go/testdata/script/mod_get_too_many_redirects.txt new file mode 100644 index 0000000..9cbe0d2 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_too_many_redirects.txt @@ -0,0 +1,10 @@ +env GO111MODULE=on +env GOPROXYBASE=$GOPROXY +env GOPROXY=$GOPROXYBASE/redirect/11 +env GOSUMDB=off + +! go get -d rsc.io/quote@v1.2.0 +stderr 'stopped after 10 redirects' + +env GOPROXY=$GOPROXYBASE/redirect/9 +go get -d rsc.io/quote@v1.2.0 diff --git a/src/cmd/go/testdata/script/mod_get_trailing_slash.txt b/src/cmd/go/testdata/script/mod_get_trailing_slash.txt new file mode 100644 index 0000000..c536693 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_trailing_slash.txt @@ -0,0 +1,37 @@ +# go list should succeed to load a package ending with ".go" if the path does +# not correspond to an existing local file. Listing a pattern ending with +# ".go/" should try to list a package regardless of whether a file exists at the +# path without the suffixed "/" or not. +go list example.com/dotgo.go +stdout ^example.com/dotgo.go$ +go list example.com/dotgo.go/ +stdout ^example.com/dotgo.go$ + +# go get -d should succeed in either case, with or without a version. +# Arguments are interpreted as packages or package patterns with versions, +# not source files. +go get -d example.com/dotgo.go +go get -d example.com/dotgo.go/ +go get -d example.com/dotgo.go@v1.0.0 +go get -d example.com/dotgo.go/@v1.0.0 + +# go get (without -d) should also succeed in either case. +[short] skip +go get example.com/dotgo.go +go get example.com/dotgo.go/ +go get example.com/dotgo.go@v1.0.0 +go get example.com/dotgo.go/@v1.0.0 + +-- go.mod -- +module m + +go 1.13 + +require example.com/dotgo.go v1.0.0 +-- go.sum -- +example.com/dotgo.go v1.0.0 h1:XKJfs0V8x2PvY2tX8bJBCEbCDLnt15ma2onwhVpew/I= +example.com/dotgo.go v1.0.0/go.mod h1:Qi6z/X3AC5vHiuMt6HF2ICx3KhIBGrMdrA7YoPDKqR0= +-- use.go -- +package use + +import _ "example.com/dotgo.go" diff --git a/src/cmd/go/testdata/script/mod_get_upgrade.txt b/src/cmd/go/testdata/script/mod_get_upgrade.txt new file mode 100644 index 0000000..eeb6d6f --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_upgrade.txt @@ -0,0 +1,46 @@ +env GO111MODULE=on + +go get -d 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 dependencies of the package in the current directory +go get -d -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 -d -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 -d 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 -d -u +grep 'rsc.io/quote v0.0.0-20180628003336-dd9747d19b04' go.mod + +# move to earlier pseudo-version +go get -d 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 -d -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 + +-- use.go -- +package use + +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_get_upgrade_pseudo.txt b/src/cmd/go/testdata/script/mod_get_upgrade_pseudo.txt new file mode 100644 index 0000000..f5f415a --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_upgrade_pseudo.txt @@ -0,0 +1,70 @@ +env GO111MODULE=on + +# For this test module there are three versions: +# * v0.1.1-0.20190429073117-b5426c86b553 +# * v0.1.0 +# * v0.0.0-20190430073000-30950c05d534 +# Only v0.1.0 is tagged. +# +# The v0.1.1 pseudo-version is semantically higher than the latest tag. +# The v0.0.0 pseudo-version is chronologically newer. + +# Start at v0.1.1-0.20190429073117-b5426c86b553 +go get -d example.com/pseudoupgrade@b5426c8 +go list -m -u all +stdout '^example.com/pseudoupgrade v0.1.1-0.20190429073117-b5426c86b553$' + +# 'get -u' should not downgrade to the (lower) tagged version. +go get -d -u +go list -m -u all +stdout '^example.com/pseudoupgrade v0.1.1-0.20190429073117-b5426c86b553$' + +# 'get example.com/pseudoupgrade@upgrade' should not downgrade. +go get -d example.com/pseudoupgrade@upgrade +go list -m all +stdout '^example.com/pseudoupgrade v0.1.1-0.20190429073117-b5426c86b553$' + +# 'get example.com/pseudoupgrade' should not downgrade. +# This is equivalent to 'get example.com/pseudoupgrade@upgrade'. +go get -d example.com/pseudoupgrade +go list -m all +stdout '^example.com/pseudoupgrade v0.1.1-0.20190429073117-b5426c86b553$' + +# 'get example.com/pseudoupgrade@latest' should downgrade. +# @latest should not consider the current version. +go get -d example.com/pseudoupgrade@latest +go list -m all +stdout '^example.com/pseudoupgrade v0.1.0$' + +# We should observe the same behavior with the newer pseudo-version. +go get -d example.com/pseudoupgrade@v0.0.0-20190430073000-30950c05d534 + +# 'get -u' should not downgrade to the chronologically older tagged version. +go get -d -u +go list -m -u all +stdout '^example.com/pseudoupgrade v0.0.0-20190430073000-30950c05d534$' + +# 'get example.com/pseudoupgrade@upgrade should not downgrade. +go get -d example.com/pseudoupgrade@upgrade +go list -m -u all +stdout '^example.com/pseudoupgrade v0.0.0-20190430073000-30950c05d534$' + +# 'get example.com/pseudoupgrade' should not downgrade. +go get -d example.com/pseudoupgrade +go list -m -u all +stdout '^example.com/pseudoupgrade v0.0.0-20190430073000-30950c05d534$' + +# 'get example.com/pseudoupgrade@latest' should downgrade. +go get -d example.com/pseudoupgrade@latest +go list -m -u all +stdout '^example.com/pseudoupgrade v0.1.0$' + +-- go.mod -- +module x + +go 1.12 + +-- main.go -- +package x + +import _ "example.com/pseudoupgrade" diff --git a/src/cmd/go/testdata/script/mod_get_wild.txt b/src/cmd/go/testdata/script/mod_get_wild.txt new file mode 100644 index 0000000..78c645c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_wild.txt @@ -0,0 +1,95 @@ +# This test covers a crazy edge-case involving wildcards and multiple passes of +# patch-upgrades, but if we get it right we probably get many other edge-cases +# right too. + +go list -m all +stdout '^example.net/a v0.1.0 ' +! stdout '^example.net/b ' + + +# Requesting pattern example.../b by itself fails: there is no such module +# already in the build list, and the wildcard in the first element prevents us +# from attempting to resolve a new module whose path is a prefix of the pattern. + +! go get -d -u=patch example.../b@upgrade +stderr '^go get: no modules to query for example\.\.\./b@upgrade because first path element contains a wildcard$' + + +# Patching . causes a patch to example.net/a, which introduces a new match +# for example.net/b/..., which is itself patched and causes another upgrade to +# example.net/a, which is then patched again. + +go get -d -u=patch . example.../b@upgrade +go list -m all +stdout '^example.net/a v0.2.1 ' # upgraded by dependency of b and -u=patch +stdout '^example.net/b v0.2.0 ' # introduced by patch of a and upgraded by wildcard + + +-- go.mod -- +module example + +go 1.16 + +require example.net/a v0.1.0 + +replace ( + example.net/a v0.1.0 => ./a10 + example.net/a v0.1.1 => ./a11 + example.net/a v0.2.0 => ./a20 + example.net/a v0.2.1 => ./a20 + example.net/b v0.1.0 => ./b1 + example.net/b v0.1.1 => ./b1 + example.net/b v0.2.0 => ./b2 +) +-- example.go -- +package example + +import _ "example.net/a" + +-- a10/go.mod -- +module example.net/a + +go 1.16 +-- a10/a.go -- +package a + +-- a11/go.mod -- +module example.net/a + +go 1.16 + +require example.net/b v0.1.0 +-- a11/a.go -- +package a +-- a11/unimported/unimported.go -- +package unimported + +import _ "example.net/b" + + +-- a20/go.mod -- +module example.net/a + +go 1.16 +-- a20/a.go -- +package a + +-- b1/go.mod -- +module example.net/b + +go 1.16 +-- b1/b.go -- +package b + +-- b2/go.mod -- +module example.net/b + +go 1.16 + +require example.net/a v0.2.0 +-- b2/b.go -- +package b +-- b2/b_test.go -- +package b_test + +import _ "example.net/a" diff --git a/src/cmd/go/testdata/script/mod_getmode_vendor.txt b/src/cmd/go/testdata/script/mod_getmode_vendor.txt new file mode 100644 index 0000000..d3df207 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_getmode_vendor.txt @@ -0,0 +1,30 @@ +env GO111MODULE=on + +go get -d 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 -f '{{with .Module}}{{.Path}} {{.Version}}{{end}} {{.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[\\/]language$' + +! go list -mod=vendor -m rsc.io/quote@latest +stderr 'go list -m: rsc.io/quote@latest: cannot query module due to -mod=vendor' +! go get -mod=vendor -u +stderr 'flag provided but not defined: -mod' + +# Since we don't have a complete module graph, 'go list -m' queries +# that require the complete graph should fail with a useful error. +! go list -mod=vendor -m all +stderr 'go list -m: can''t compute ''all'' using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)' +! go list -mod=vendor -m ... +stderr 'go list -m: can''t match module patterns using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)' + +-- go.mod -- +module x + +-- x.go -- +package x +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_getx.txt b/src/cmd/go/testdata/script/mod_getx.txt new file mode 100644 index 0000000..ccb8d13 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_getx.txt @@ -0,0 +1,14 @@ +[short] skip +[!net] skip +[!exec:git] skip + +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off + +# 'go get -x' should log URLs with an HTTP or HTTPS scheme. +# A bug had caused us to log schemeless URLs instead. +go get -x -d golang.org/x/text@v0.1.0 +stderr '^# get https://golang.org/x/text\?go-get=1$' +stderr '^# get https://golang.org/x/text\?go-get=1: 200 OK \([0-9.]+s\)$' +! stderr '^# get //.*' diff --git a/src/cmd/go/testdata/script/mod_git_export_subst.txt b/src/cmd/go/testdata/script/mod_git_export_subst.txt new file mode 100644 index 0000000..a28b4f2 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_git_export_subst.txt @@ -0,0 +1,21 @@ +env GO111MODULE=on +env GOPROXY=direct + +# Testing that git export-subst is disabled +[!net] skip +[!exec:git] skip +go build + +-- x.go -- +package x + +import _ "github.com/jasonkeene/export-subst" + +-- go.mod -- +module x + +require github.com/jasonkeene/export-subst v0.0.0-20180927204031-5845945ec626 + +-- go.sum -- +github.com/jasonkeene/export-subst v0.0.0-20180927204031-5845945ec626 h1:AUkXi/xFnm7lH2pgtvVkGb7buRn1ywFHw+xDpZ29Rz0= +github.com/jasonkeene/export-subst v0.0.0-20180927204031-5845945ec626/go.mod h1:DwJXqVtrgrQkv3Giuf2Jh4YyubVe7y41S1eOIaysTJw= diff --git a/src/cmd/go/testdata/script/mod_go_version.txt b/src/cmd/go/testdata/script/mod_go_version.txt new file mode 100644 index 0000000..97d9975 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_go_version.txt @@ -0,0 +1,110 @@ +# Test support for declaring needed Go version in module. + +env GO111MODULE=on + +go list +go build +go build sub.1 +go build subver.1 +! stderr 'module requires' +! go build badsub.1 +stderr '^note: module requires Go 1.11111$' + +go build versioned.1 +go mod edit -require versioned.1@v1.1.0 +! go build versioned.1 +stderr '^note: module requires Go 1.99999$' + +[short] stop + +# The message should be printed even if the compiler emits no output. +go build -o $WORK/nooutput.exe nooutput.go +! go build -toolexec=$WORK/nooutput.exe versioned.1 +stderr '^# versioned.1\nnote: module requires Go 1.99999$' + +-- go.mod -- +module m +go 1.999 +require ( + sub.1 v1.0.0 + subver.1 v1.0.0 + badsub.1 v1.0.0 + versioned.1 v1.0.0 +) +replace ( + sub.1 => ./sub + subver.1 => ./subver + 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 + +-- subver/go.mod -- +module m +go 1.11111 + +-- subver/x.go -- +package x + +-- badsub/go.mod -- +module m +go 1.11111 + +-- badsub/x.go -- +package x +invalid syntax + +-- 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 +invalid syntax + +-- nooutput.go -- +// +build ignore + +package main + +import ( + "bytes" + "os" + "os/exec" + "strings" +) + +func main() { + stderr := new(bytes.Buffer) + stdout := new(bytes.Buffer) + + cmd := exec.Command(os.Args[1], os.Args[2:]...) + cmd.Stderr = stderr + cmd.Stdout = stdout + + err := cmd.Run() + if strings.HasPrefix(os.Args[2], "-V") { + os.Stderr.Write(stderr.Bytes()) + os.Stdout.Write(stdout.Bytes()) + } + if err != nil { + os.Exit(1) + } +} diff --git a/src/cmd/go/testdata/script/mod_go_version_mixed.txt b/src/cmd/go/testdata/script/mod_go_version_mixed.txt new file mode 100644 index 0000000..d6216ae --- /dev/null +++ b/src/cmd/go/testdata/script/mod_go_version_mixed.txt @@ -0,0 +1,43 @@ +# Test that dependencies can use Go language features newer than the +# Go version specified by the main module. + +env GO111MODULE=on + +go build + +-- go.mod -- +module m +go 1.12 +require ( + sub.1 v1.0.0 +) +replace ( + sub.1 => ./sub +) + +-- x.go -- +package x + +import "sub.1" + +func F() { sub.F(0, 0) } + +var A sub.Alias +var D sub.Defined + +-- sub/go.mod -- +module m +go 1.14 + +-- sub/sub.go -- +package sub + +// signed shift counts added in Go 1.13 +func F(l, r int) int { return l << r } + +type m1 interface { M() } +type m2 interface { M() } + +// overlapping interfaces added in Go 1.14 +type Alias = interface { m1; m2; M() } +type Defined interface { m1; m2; M() } diff --git a/src/cmd/go/testdata/script/mod_gobuild_import.txt b/src/cmd/go/testdata/script/mod_gobuild_import.txt new file mode 100644 index 0000000..c13ae84 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_gobuild_import.txt @@ -0,0 +1,133 @@ +[short] skip + +# go/build's Import should find modules by invoking the go command + +go build -o $WORK ./testimport ./testfindonly + +# GO111MODULE=off +env GO111MODULE=off +! exec $WORK/testimport$GOEXE gobuild.example.com/x/y/z/w . + +# GO111MODULE=auto in GOPATH/src +env GO111MODULE=auto +exec $WORK/testimport$GOEXE gobuild.example.com/x/y/z/w . + +# GO111MODULE=auto outside GOPATH/src +cd $GOPATH/other +env GO111MODULE=auto +exec $WORK/testimport$GOEXE other/x/y/z/w . +stdout w2.go + +! exec $WORK/testimport$GOEXE gobuild.example.com/x/y/z/w . +stderr 'no required module provides package gobuild.example.com/x/y/z/w; to add it:\n\tgo get gobuild.example.com/x/y/z/w' + +cd z +exec $WORK/testimport$GOEXE other/x/y/z/w . +stdout w2.go + +# GO111MODULE=on outside GOPATH/src +env GO111MODULE= +exec $WORK/testimport$GOEXE other/x/y/z/w . +stdout w2.go +env GO111MODULE=on +exec $WORK/testimport$GOEXE other/x/y/z/w . +stdout w2.go + +# GO111MODULE=on in GOPATH/src +cd $GOPATH/src +env GO111MODULE= +exec $WORK/testimport$GOEXE gobuild.example.com/x/y/z/w . +stdout w1.go +env GO111MODULE=on +exec $WORK/testimport$GOEXE gobuild.example.com/x/y/z/w . +stdout w1.go +cd w +exec $WORK/testimport$GOEXE gobuild.example.com/x/y/z/w .. +stdout w1.go + +# go/build's Import in FindOnly mode should find directories by invoking the go command +# +# Calling build.Import in build.FindOnly mode on an import path of a Go package +# that produces errors when loading (e.g., due to build constraints not matching +# the current build context) should return the package directory and nil error. + +# Issue 31603: Import with non-empty srcDir should work. +env GO111MODULE=on +exec $WORK/testfindonly$GOEXE gobuild.example.com/x/y/z/i $WORK +! stdout 'build constraints' +stdout '^dir=\$WORK.+i err=$' + +# Issue 37153: Import with empty srcDir should work. +env GO111MODULE=on +exec $WORK/testfindonly$GOEXE gobuild.example.com/x/y/z/i '' +! stdout 'build constraints' +stdout '^dir=\$WORK.+i err=$' + +-- go.mod -- +module gobuild.example.com/x/y/z + +-- z.go -- +package z + +-- w/w1.go -- +package w + +-- i/i.go -- +// +build i + +package i + +-- testimport/x.go -- +package main + +import ( + "fmt" + "go/build" + "log" + "os" + "path/filepath" + "strings" +) + +func main() { + // build.Import should support relative and absolute source dir paths. + path := os.Args[1] + srcDir := os.Args[2] + p1, err := build.Import(path, srcDir, 0) + if err != nil { + log.Fatal(err) + } + absSrcDir, err := filepath.Abs(srcDir) + if err != nil { + log.Fatal(err) + } + p2, err := build.Import(path, absSrcDir, 0) + if err != nil { + log.Fatal(err) + } + if p1.Dir != p2.Dir { + log.Fatalf("different packages loaded with relative and absolute paths:\n\t%s\n\t%s", p1.Dir, p2.Dir) + } + + fmt.Printf("%s\n%s\n", p1.Dir, strings.Join(p1.GoFiles, " ")) +} + +-- testfindonly/x.go -- +package main + +import ( + "fmt" + "go/build" + "os" +) + +func main() { + p, err := build.Import(os.Args[1], os.Args[2], build.FindOnly) + fmt.Printf("dir=%s err=%v\n", p.Dir, err) +} + +-- $GOPATH/other/go.mod -- +module other/x/y + +-- $GOPATH/other/z/w/w2.go -- +package w diff --git a/src/cmd/go/testdata/script/mod_gofmt_invalid.txt b/src/cmd/go/testdata/script/mod_gofmt_invalid.txt new file mode 100644 index 0000000..21edc7d --- /dev/null +++ b/src/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/src/cmd/go/testdata/script/mod_gomodcache.txt b/src/cmd/go/testdata/script/mod_gomodcache.txt new file mode 100644 index 0000000..b2143e2 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_gomodcache.txt @@ -0,0 +1,60 @@ +# Test GOMODCACHE +env GO111MODULE=on + +# Explicitly set GOMODCACHE +env GOMODCACHE=$WORK/modcache +go env GOMODCACHE +stdout $WORK[/\\]modcache +go get -d rsc.io/quote@v1.0.0 +exists $WORK/modcache/cache/download/rsc.io/quote/@v/v1.0.0.info +grep '{"Version":"v1.0.0","Time":"2018-02-14T00:45:20Z"}' $WORK/modcache/cache/download/rsc.io/quote/@v/v1.0.0.info + +# Ensure GOMODCACHE doesn't affect location of sumdb, but $GOMODCACHE/cache/download/sumdb is still written +exists $GOPATH/pkg/sumdb +! exists $WORK/modcache/sumdb +exists $WORK/modcache/cache/download/sumdb + +# Test that the default GOMODCACHE is $GOPATH[0]/pkg/mod +env GOMODCACHE= +go env GOMODCACHE +stdout $GOPATH[/\\]pkg[/\\]mod +go get -d rsc.io/quote@v1.0.0 +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.0.0.info +grep '{"Version":"v1.0.0","Time":"2018-02-14T00:45:20Z"}' $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.0.0.info + +# If neither GOMODCACHE or GOPATH are set, GOPATH defaults to the user's $HOME/go, so GOMODCACHE becomes $HOME/go/pkg/mod +[windows] env USERPROFILE=$WORK/home # Ensure USERPROFILE is a valid path (rather than /no-home/ so we don't run into the logic that "uninfers" GOPATH in cmd/go/main.go +[plan9] env home=$WORK/home +[!windows] [!plan9] env HOME=$WORK/home +env GOMODCACHE= +env GOPATH= +go env GOMODCACHE +stdout $HOME[/\\]go[/\\]pkg[/\\]mod + +# If GOMODCACHE isn't set and GOPATH starts with the path list separator, it's an error. +env GOMODCACHE= +env GOPATH=${:}$WORK/this/is/ignored +! go env GOMODCACHE +stderr 'missing \$GOPATH' + +# If GOMODCACHE isn't set and GOPATH has multiple elements only the first is used. +env GOMODCACHE= +env GOPATH=$WORK/first/path${:}$WORK/this/is/ignored +go env GOMODCACHE +stdout $WORK[/\\]first[/\\]path[/\\]pkg[/\\]mod + +env GOMODCACHE=$WORK/modcache +go mod download rsc.io/quote@v1.0.0 +exists $WORK/modcache/cache/download/rsc.io/quote/@v/v1.0.0.info + +# Test that the following work even with GO111MODULE=off +env GO111MODULE=off + +# Cleaning modcache +exists $WORK/modcache +env GOMODCACHE=$WORK/modcache +go clean -modcache +! exists $WORK/modcache + +-- go.mod -- +module m diff --git a/src/cmd/go/testdata/script/mod_gonoproxy.txt b/src/cmd/go/testdata/script/mod_gonoproxy.txt new file mode 100644 index 0000000..2047869 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_gonoproxy.txt @@ -0,0 +1,54 @@ +env GO111MODULE=on +env sumdb=$GOSUMDB +env proxy=$GOPROXY +env GOPRIVATE GOPROXY GONOPROXY GOSUMDB GONOSUMDB +env dbname=localhost.localdev/sumdb + +# disagree with sumdb fails +cp go.mod.orig go.mod +env GOSUMDB=$sumdb' '$proxy/sumdb-wrong +! go get -d rsc.io/quote +stderr 'SECURITY ERROR' + +# GONOSUMDB bypasses sumdb, for rsc.io/quote, rsc.io/sampler, golang.org/x/text +env GONOSUMDB='*/quote,*/*mple*,golang.org/x' +go get -d rsc.io/quote +rm go.sum +env GOPRIVATE='*/quote,*/*mple*,golang.org/x' +env GONOPROXY=none # that is, proxy all despite GOPRIVATE +go get -d rsc.io/quote + +# Download .info files needed for 'go list -m all' later. +# TODO(#42723): either 'go list -m' should not read these files, +# or 'go get' and 'go mod tidy' should download them. +go list -m all +stdout '^golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c$' + +# When GOPROXY is not empty but contains no entries, an error should be reported. +env GOPROXY=',' +! go get -d golang.org/x/text +stderr '^go get golang.org/x/text: GOPROXY list is not the empty string, but contains no entries$' + +# When GOPROXY=off, fetching modules not matched by GONOPROXY fails. +env GONOPROXY=*/fortune +env GOPROXY=off +! go get -d golang.org/x/text +stderr '^go get golang.org/x/text: module lookup disabled by GOPROXY=off$' + +# GONOPROXY bypasses proxy +[!net] skip +[!exec:git] skip +env GOPRIVATE=none +env GONOPROXY='*/fortune' +! go get -d rsc.io/fortune # does not exist in real world, only on test proxy +stderr 'git ls-remote' + +env GOSUMDB= +env GONOPROXY= +env GOPRIVATE='*/x' +go get -d golang.org/x/text +go list -m all +! stdout 'text.*v0.0.0-2017' # should not have the version from the proxy + +-- go.mod.orig -- +module m diff --git a/src/cmd/go/testdata/script/mod_gopkg_unstable.txt b/src/cmd/go/testdata/script/mod_gopkg_unstable.txt new file mode 100644 index 0000000..5ad9106 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_gopkg_unstable.txt @@ -0,0 +1,24 @@ +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 +[!exec:git] skip + +env GOPROXY=direct +env GOSUMDB=off +go get -d 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/src/cmd/go/testdata/script/mod_goroot_errors.txt b/src/cmd/go/testdata/script/mod_goroot_errors.txt new file mode 100644 index 0000000..9d7a94d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_goroot_errors.txt @@ -0,0 +1,53 @@ +env GO111MODULE=on + +# Regression test for https://golang.org/issue/34769. +# Missing standard-library imports should refer to GOROOT rather than +# complaining about a malformed module path. +# This is especially important when GOROOT is set incorrectly, +# since such an error will occur for every package in std. + +# Building a nonexistent std package directly should fail usefully. + +! go build -mod=readonly nonexist +! stderr 'import lookup disabled' +! stderr 'missing dot' +stderr '^package nonexist is not in GOROOT \('$GOROOT'[/\\]src[/\\]nonexist\)$' + +! go build nonexist +! stderr 'import lookup disabled' +! stderr 'missing dot' +stderr '^package nonexist is not in GOROOT \('$GOROOT'[/\\]src[/\\]nonexist\)$' + +# Building a nonexistent std package indirectly should also fail usefully. + +! go build -mod=readonly ./importnonexist +! stderr 'import lookup disabled' +! stderr 'missing dot' +stderr '^importnonexist[/\\]x.go:2:8: package nonexist is not in GOROOT \('$GOROOT'[/\\]src[/\\]nonexist\)$' + +! go build ./importnonexist +! stderr 'import lookup disabled' +! stderr 'missing dot' +stderr '^importnonexist[/\\]x.go:2:8: package nonexist is not in GOROOT \('$GOROOT'[/\\]src[/\\]nonexist\)$' + +# Building an *actual* std package should fail if GOROOT is set to something bogus. + +[!short] go build ./importjson # Prove that it works when GOROOT is valid. + +env GOROOT=$WORK/not-a-valid-goroot +! go build ./importjson +! stderr 'import lookup disabled' +! stderr 'missing dot' +stderr 'importjson[/\\]x.go:2:8: package encoding/json is not in GOROOT \('$WORK'[/\\]not-a-valid-goroot[/\\]src[/\\]encoding[/\\]json\)$' + +-- go.mod -- +module example.com +go 1.14 +-- importnonexist/x.go -- +package importnonexist +import _ "nonexist" +-- importjson/x.go -- +package importjson +import _ "encoding/json" +-- $WORK/not-a-valid-goroot/README -- +This directory is not a valid GOROOT. diff --git a/src/cmd/go/testdata/script/mod_graph.txt b/src/cmd/go/testdata/script/mod_graph.txt new file mode 100644 index 0000000..07968f5 --- /dev/null +++ b/src/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/src/cmd/go/testdata/script/mod_help.txt b/src/cmd/go/testdata/script/mod_help.txt new file mode 100644 index 0000000..b5cd30c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_help.txt @@ -0,0 +1,6 @@ +env GO111MODULE=on + +# go help get shows usage for get +go help get +stdout 'usage: go get' +stdout 'get using modules to manage source' \ No newline at end of file diff --git a/src/cmd/go/testdata/script/mod_import.txt b/src/cmd/go/testdata/script/mod_import.txt new file mode 100644 index 0000000..28358b5 --- /dev/null +++ b/src/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 get -d +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/src/cmd/go/testdata/script/mod_import_cycle.txt b/src/cmd/go/testdata/script/mod_import_cycle.txt new file mode 100644 index 0000000..7be0749 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_import_cycle.txt @@ -0,0 +1,40 @@ +env GO111MODULE=on + +# 'go list all' should fail with a reasonable error message +! go list all +stderr '^package m\n\timports m/a\n\timports m/b\n\timports m/a: import cycle not allowed' + +# 'go list -e' should not print to stderr, but should mark all three +# packages (m, m/a, and m/b) as Incomplete. +go list -e -json all +! stderr . +stdout -count=3 '"Incomplete": true,' + +-- go.mod -- +module m + +require ( + m/a v0.0.0 + m/b v0.0.0 +) + +replace ( + m/a => ./a + m/b => ./b +) +-- m.go -- +package m +import ( + _ "m/a" + _ "m/b" +) +-- a/go.mod -- +module m/a +-- a/a.go -- +package a +import _ "m/b" +-- b/go.mod -- +module m/b +-- b/b.go -- +package b +import _ "m/a" diff --git a/src/cmd/go/testdata/script/mod_import_issue41113.txt b/src/cmd/go/testdata/script/mod_import_issue41113.txt new file mode 100644 index 0000000..fed2510 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_import_issue41113.txt @@ -0,0 +1,28 @@ +# Regression test for https://golang.org/issue/41113. +# +# When resolving a missing import path, the inability to add the package from +# one module path should not interfere with adding a nested path. + +# Initially, our module depends on split-incompatible v2.1.0-pre+incompatible, +# from which an imported package has been removed (and relocated to the nested +# split-incompatible/subpkg module). modload.QueryPattern will suggest +# split-incompatible v2.0.0+incompatible, which we cannot use (because it would +# be an implicit downgrade), and split-incompatible/subpkg v0.1.0, which we +# *should* use. + +go mod tidy + +go list -m all +stdout '^example.com/split-incompatible/subpkg v0\.1\.0$' +! stdout '^example.com/split-incompatible .*' + +-- go.mod -- +module golang.org/issue/41113 + +go 1.16 + +require example.com/split-incompatible v2.1.0-pre+incompatible +-- x.go -- +package issue41113 + +import _ "example.com/split-incompatible/subpkg" diff --git a/src/cmd/go/testdata/script/mod_import_issue42891.txt b/src/cmd/go/testdata/script/mod_import_issue42891.txt new file mode 100644 index 0000000..a78cab2 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_import_issue42891.txt @@ -0,0 +1,14 @@ +# If an import declaration is an absolute path, most commands should report +# an error instead of going into an infinite loop. +# Verifies golang.org/issue/42891. +go list . +stdout '^m$' + +-- go.mod -- +module m + +go 1.16 +-- m.go -- +package m + +import "/" diff --git a/src/cmd/go/testdata/script/mod_import_meta.txt b/src/cmd/go/testdata/script/mod_import_meta.txt new file mode 100644 index 0000000..0e469d0 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_import_meta.txt @@ -0,0 +1,45 @@ +# The loader should not attempt to resolve imports of the "all", "std", and "cmd" meta-packages. + +! go list -deps ./importall +! stderr 'internal error' +stderr '^importall[/\\]x.go:3:8: "all" is not an importable package; see ''go help packages''$' + +! go list -deps ./importcmd +! stderr 'internal error' +stderr '^importcmd[/\\]x.go:3:8: "cmd" is not an importable package; see ''go help packages''$' + +! go list -deps ./importstd +! stderr 'internal error' +stderr '^importstd[/\\]x.go:3:8: "std" is not an importable package; see ''go help packages''$' + + +# Not even if such a path is theoretically provided by a (necessarily replaced) module. + +go mod edit -replace std@v0.1.0=./modstd +go mod edit -require std@v0.1.0 + +! go list -deps ./importstd +stderr '^importstd[/\\]x.go:3:8: "std" is not an importable package; see ''go help packages''$' + + +-- go.mod -- +module example.com +go 1.16 +-- importall/x.go -- +package importall + +import _ "all" +-- importcmd/x.go -- +package importcmd + +import _ "cmd" +-- importstd/x.go -- +package importstd + +import _ "std" +-- modstd/go.mod -- +module std +go 1.16 +-- modstd/std.go -- +// Package std is an incredibly confusingly-named package. +package std diff --git a/src/cmd/go/testdata/script/mod_import_mod.txt b/src/cmd/go/testdata/script/mod_import_mod.txt new file mode 100644 index 0000000..b035e3d --- /dev/null +++ b/src/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/src/cmd/go/testdata/script/mod_import_v1suffix.txt b/src/cmd/go/testdata/script/mod_import_v1suffix.txt new file mode 100644 index 0000000..a429450 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_import_v1suffix.txt @@ -0,0 +1,11 @@ +env GO111MODULE=on + +! go get -d example.com/invalidpath/v1 +! go install . + +-- go.mod -- +module example.com +-- main.go -- +package main +import _ "example.com/invalidpath/v1" +func main() {} diff --git a/src/cmd/go/testdata/script/mod_in_testdata_dir.txt b/src/cmd/go/testdata/script/mod_in_testdata_dir.txt new file mode 100644 index 0000000..66f79fa --- /dev/null +++ b/src/cmd/go/testdata/script/mod_in_testdata_dir.txt @@ -0,0 +1,45 @@ +# Regression test for golang.org/issue/28481: +# 'mod tidy' removed dependencies if the module root was +# within a directory named 'testdata' or '_foo'. + +env GO111MODULE=on + +# A module should be allowed in a directory named testdata. +cd $WORK/testdata +go mod init testdata.tld/foo + +# Getting a package within that module should resolve its dependencies. +go get -d +grep 'rsc.io/quote' go.mod + +# Tidying the module should preserve those dependencies. +go mod tidy +grep 'rsc.io/quote' go.mod + +[short] stop + +# Vendoring the module's dependencies should work too. +go mod vendor +exists vendor/rsc.io/quote + +# The same should work in directories with names starting with underscores. +cd $WORK/_ignored +go mod init testdata.tld/foo + +go get +grep 'rsc.io/quote' go.mod + +go mod tidy +grep 'rsc.io/quote' go.mod + +go mod vendor +exists vendor/rsc.io/quote + +-- $WORK/testdata/main.go -- +package foo + +import _ "rsc.io/quote" +-- $WORK/_ignored/main.go -- +package foo + +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_indirect.txt b/src/cmd/go/testdata/script/mod_indirect.txt new file mode 100644 index 0000000..6ea1cae --- /dev/null +++ b/src/cmd/go/testdata/script/mod_indirect.txt @@ -0,0 +1,81 @@ +env GO111MODULE=on + +# golang.org/issue/31248: required modules imposed by dependency versions +# older than the selected version must still be taken into account. + +env GOFLAGS=-mod=readonly + +# Indirect dependencies required via older-than-selected versions must exist in +# the module graph, but do not need to be listed explicitly in the go.mod file +# (since they are implied). +go mod graph +stdout i@v0.1.0 + +# The modules must also appear in the build list, not just the graph. +go list -m all +stdout '^i v0.1.0' + +# The packages provided by those dependencies must resolve. +go list all +stdout '^i$' + +-- go.mod -- +module main + +go 1.13 + +require ( + a v0.0.0 + b v0.0.0 + c v0.0.0 +) + +// Apply replacements so that the test can be self-contained. +// (It's easier to see all of the modules here than to go +// rooting around in testdata/mod.) +replace ( + a => ./a + b => ./b + c => ./c + x v0.1.0 => ./x1 + x v0.2.0 => ./x2 + i => ./i +) +-- main.go -- +package main + +import ( + _ "a" + _ "b" + _ "c" +) + +func main() {} +-- a/go.mod -- +module a +go 1.13 +require x v0.1.0 +-- a/a.go -- +package a +-- b/go.mod -- +module b +go 1.13 +require x v0.2.0 +-- b/b.go -- +package b +-- c/go.mod -- +module c +go 1.13 +-- c/c.go -- +package c +import _ "i" +-- x1/go.mod -- +module x +go1.13 +require i v0.1.0 +-- x2/go.mod -- +module x +go1.13 +-- i/go.mod -- +-- i/i.go -- +package i diff --git a/src/cmd/go/testdata/script/mod_indirect_main.txt b/src/cmd/go/testdata/script/mod_indirect_main.txt new file mode 100644 index 0000000..eeb93f1 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_indirect_main.txt @@ -0,0 +1,65 @@ +env GO111MODULE=on + +# Regression test for golang.org/issue/29773: 'go list -m' was not following +# dependencies through older versions of the main module. + +go list -f '{{with .Module}}{{.Path}}{{with .Version}} {{.}}{{end}}{{end}}' all +cmp stdout pkgmods.txt + +go list -m all +cmp stdout mods.txt + +go mod graph +cmp stdout graph.txt + +-- go.mod -- +module golang.org/issue/root + +go 1.12 + +replace ( + golang.org/issue/mirror v0.1.0 => ./mirror-v0.1.0 + golang.org/issue/pkg v0.1.0 => ./pkg-v0.1.0 + golang.org/issue/root v0.1.0 => ./root-v0.1.0 +) + +require golang.org/issue/mirror v0.1.0 + +-- root.go -- +package root + +import _ "golang.org/issue/mirror" + +-- mirror-v0.1.0/go.mod -- +module golang.org/issue/mirror + +require golang.org/issue/root v0.1.0 + +-- mirror-v0.1.0/mirror.go -- +package mirror + +import _ "golang.org/issue/pkg" + +-- pkg-v0.1.0/go.mod -- +module golang.org/issue/pkg + +-- pkg-v0.1.0/pkg.go -- +package pkg + +-- root-v0.1.0/go.mod -- +module golang.org/issue/root + +require golang.org/issue/pkg v0.1.0 + +-- pkgmods.txt -- +golang.org/issue/mirror v0.1.0 +golang.org/issue/pkg v0.1.0 +golang.org/issue/root +-- mods.txt -- +golang.org/issue/root +golang.org/issue/mirror v0.1.0 => ./mirror-v0.1.0 +golang.org/issue/pkg v0.1.0 => ./pkg-v0.1.0 +-- graph.txt -- +golang.org/issue/root golang.org/issue/mirror@v0.1.0 +golang.org/issue/mirror@v0.1.0 golang.org/issue/root@v0.1.0 +golang.org/issue/root@v0.1.0 golang.org/issue/pkg@v0.1.0 diff --git a/src/cmd/go/testdata/script/mod_indirect_tidy.txt b/src/cmd/go/testdata/script/mod_indirect_tidy.txt new file mode 100644 index 0000000..a12b35c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_indirect_tidy.txt @@ -0,0 +1,60 @@ +env GO111MODULE=on + +# golang.org/issue/31248: loading the build list must not add explicit entries +# for indirect dependencies already implied by older-than-selected versions +# already in the build list. + +cp go.mod.orig go.mod +go mod tidy +cmp go.mod go.mod.orig + +cp go.mod.orig go.mod +go list -m all +cmp go.mod go.mod.orig + +-- go.mod.orig -- +module main + +go 1.13 + +require a v0.0.0 + +replace ( + a v0.0.0 => ./a + b v0.0.0 => ./b + i v0.0.0 => ./i + x v0.1.0 => ./x1 + x v0.2.0 => ./x2 +) +-- main.go -- +package main + +import _ "a" + +func main() {} +-- a/go.mod -- +module a +go 1.13 +require ( + x v0.2.0 + b v0.0.0 +) +-- a/a.go -- +package a +-- b/go.mod -- +module b +go 1.13 +require x v0.1.0 +-- x1/go.mod -- +module x +go 1.13 +require ( + b v0.0.0 + i v0.0.0 +) +-- x2/go.mod -- +module x +go 1.13 +-- i/go.mod -- +module i +go 1.13 diff --git a/src/cmd/go/testdata/script/mod_init_dep.txt b/src/cmd/go/testdata/script/mod_init_dep.txt new file mode 100644 index 0000000..f8cf1d5 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_init_dep.txt @@ -0,0 +1,44 @@ +env GO111MODULE=on +env GOFLAGS=-mod=mod + +# modconv uses git directly to examine what old 'go get' would +[!net] skip +[!exec:git] skip + +# go mod init should populate go.mod from Gopkg.lock +go mod init x +stderr 'copying requirements from Gopkg.lock' +go list -m all +stdout 'rsc.io/sampler v1.0.0' + +# test dep replacement +cd y +go mod init +cmpenv go.mod go.mod.replace + +-- x.go -- +package x + +-- Gopkg.lock -- +[[projects]] + name = "rsc.io/sampler" + version = "v1.0.0" + +-- y/Gopkg.lock -- +[[projects]] + name = "z" + revision = "v1.0.0" + source = "rsc.io/quote" + +-- y/y.go -- +package y // import "y" +import _ "z" + +-- y/go.mod.replace -- +module y + +go $goversion + +replace z v1.0.0 => rsc.io/quote v1.0.0 + +require rsc.io/quote v1.0.0 diff --git a/src/cmd/go/testdata/script/mod_init_empty.txt b/src/cmd/go/testdata/script/mod_init_empty.txt new file mode 100644 index 0000000..1c3888c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_init_empty.txt @@ -0,0 +1,18 @@ +env GO111MODULE=on + +env GOPATH=$devnull + +go list -m +stdout '^example.com$' + +go list +stdout '^example.com$' + +-- go.mod -- +module example.com + +go 1.13 +-- main.go -- +package main + +func main() {} diff --git a/src/cmd/go/testdata/script/mod_init_glide.txt b/src/cmd/go/testdata/script/mod_init_glide.txt new file mode 100644 index 0000000..a351a6a --- /dev/null +++ b/src/cmd/go/testdata/script/mod_init_glide.txt @@ -0,0 +1,34 @@ +[!net] skip +[!exec:git] skip + +env GO111MODULE=on +env GOPROXY=direct + +# Regression test for golang.org/issue/32161: +# 'go mod init' did not locate tags when resolving a commit to a pseudo-version. +go mod init x +cmpenv go.mod go.mod.out + +-- main.go -- +package main + +import ( + _ "github.com/rsc/legacytest" +) + +func main() {} + +-- glide.lock -- +imports: +- name: github.com/rsc/legacytest + version: fb3c628075e32f7f3c248a3abbdafd69ad6e21e1 + +-- glide.yaml -- +package: x + +-- go.mod.out -- +module x + +go $goversion + +require github.com/rsc/legacytest v1.1.0-pre.0.20180717164849-fb3c628075e3 diff --git a/src/cmd/go/testdata/script/mod_init_path.txt b/src/cmd/go/testdata/script/mod_init_path.txt new file mode 100644 index 0000000..ccdfc92 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_init_path.txt @@ -0,0 +1,20 @@ +env GO111MODULE=on + +! go mod init . +stderr '^go: invalid module path "\.": is a local import path$' + +cd x +go mod init example.com/x + +cd ../y +go mod init m + +-- x/main.go -- +package main + +func main() {} + +-- y/main.go -- +package main + +func main() {} diff --git a/src/cmd/go/testdata/script/mod_init_tidy.txt b/src/cmd/go/testdata/script/mod_init_tidy.txt new file mode 100644 index 0000000..4a52590 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_init_tidy.txt @@ -0,0 +1,30 @@ +# 'go mod init' should not recommend 'go mod tidy' in an empty directory +# (one that contains no non-hidden .go files or subdirectories). +cd empty +go mod init m +! stderr tidy +cd .. + +# 'go mod init' should recommend 'go mod tidy' if the directory has a .go file. +cd pkginroot +go mod init m +stderr '^go: to add module requirements and sums:\n\tgo mod tidy$' +cd .. + +# 'go mod init' should recommend 'go mod tidy' if the directory has a +# subdirectory. We don't walk the tree to see if it has .go files. +cd subdir +go mod init m +stderr '^go: to add module requirements and sums:\n\tgo mod tidy$' +cd .. + +-- empty/empty.txt -- +Not a .go file. Still counts as an empty project. +-- empty/.hidden/empty.go -- +File in hidden directory. Still as an empty project. +-- empty/_hidden/empty.go -- +File in hidden directory. Still as an empty project. +-- pkginroot/hello.go -- +package vendorimport +-- subdir/sub/empty.txt -- +Subdirectory doesn't need to contain a package. diff --git a/src/cmd/go/testdata/script/mod_install_hint.txt b/src/cmd/go/testdata/script/mod_install_hint.txt new file mode 100644 index 0000000..ab02840 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_install_hint.txt @@ -0,0 +1,5 @@ +# Module is replaced but not required. No hint appears as no module is suggested. +go mod init m +go mod edit -replace=github.com/notrequired@v0.5.0=github.com/doesnotexist@v0.5.0 +! go install github.com/notrequired +! stderr 'to add it:' \ No newline at end of file diff --git a/src/cmd/go/testdata/script/mod_install_pkg_version.txt b/src/cmd/go/testdata/script/mod_install_pkg_version.txt new file mode 100644 index 0000000..6ed600f --- /dev/null +++ b/src/cmd/go/testdata/script/mod_install_pkg_version.txt @@ -0,0 +1,203 @@ +# 'go install pkg@version' works outside a module. +env GO111MODULE=auto +go install example.com/cmd/a@v1.0.0 +exists $GOPATH/bin/a$GOEXE +rm $GOPATH/bin + + +# 'go install pkg@version' reports an error if modules are disabled. +env GO111MODULE=off +! go install example.com/cmd/a@v1.0.0 +stderr '^go: modules disabled by GO111MODULE=off; see ''go help modules''$' +env GO111MODULE=auto + + +# 'go install pkg@version' ignores go.mod in current directory. +cd m +cp go.mod go.mod.orig +! go list -m all +stderr '^go: example.com/cmd@v1.1.0-doesnotexist: missing go.sum entry; to add it:\n\tgo mod download example.com/cmd$' +go install example.com/cmd/a@latest +cmp go.mod go.mod.orig +exists $GOPATH/bin/a$GOEXE +go version -m $GOPATH/bin/a$GOEXE +stdout '^\tmod\texample.com/cmd\tv1.0.0\t' # "latest", not from go.mod +rm $GOPATH/bin/a +cd .. + + +# 'go install -modfile=x.mod pkg@version' reports an error, but only if +# -modfile is specified explicitly on the command line. +cd m +env GOFLAGS=-modfile=go.mod +go install example.com/cmd/a@latest # same as above +env GOFLAGS= +! go install -modfile=go.mod example.com/cmd/a@latest +stderr '^go: -modfile cannot be used with commands that ignore the current module$' +cd .. + + +# Every test case requires linking, so we only cover the most important cases +# when -short is set. +[short] stop + + +# 'go install pkg@version' works on a module that doesn't have a go.mod file +# and with a module whose go.mod file has missing requirements. +# With a proxy, the two cases are indistinguishable. +go install rsc.io/fortune@v1.0.0 +stderr '^go: found rsc.io/quote in rsc.io/quote v1.5.2$' +exists $GOPATH/bin/fortune$GOEXE +! exists $GOPATH/pkg/mod/rsc.io/fortune@v1.0.0/go.mod # no go.mod file +go version -m $GOPATH/bin/fortune$GOEXE +stdout '^\tdep\trsc.io/quote\tv1.5.2\t' # latest version of fortune's dependency +rm $GOPATH/bin + + +# 'go install dir@version' works like a normal 'go install' command if +# dir is a relative or absolute path. +env GO111MODULE=on +go mod download rsc.io/fortune@v1.0.0 +! go install $GOPATH/pkg/mod/rsc.io/fortune@v1.0.0 +stderr '^go: go\.mod file not found in current directory or any parent directory; see ''go help modules''$' +! go install ../pkg/mod/rsc.io/fortune@v1.0.0 +stderr '^go: go\.mod file not found in current directory or any parent directory; see ''go help modules''$' +mkdir tmp +cd tmp +go mod init tmp +go mod edit -require=rsc.io/fortune@v1.0.0 +! go install -mod=readonly $GOPATH/pkg/mod/rsc.io/fortune@v1.0.0 +stderr '^go: rsc.io/fortune@v1.0.0: missing go.sum entry; to add it:\n\tgo mod download rsc.io/fortune$' +! go install -mod=readonly ../../pkg/mod/rsc.io/fortune@v1.0.0 +stderr '^go: rsc.io/fortune@v1.0.0: missing go.sum entry; to add it:\n\tgo mod download rsc.io/fortune$' +go get -d rsc.io/fortune@v1.0.0 +go install -mod=readonly $GOPATH/pkg/mod/rsc.io/fortune@v1.0.0 +exists $GOPATH/bin/fortune$GOEXE +cd .. +rm tmp +rm $GOPATH/bin +env GO111MODULE=auto + +# 'go install pkg@version' reports errors for meta packages, std packages, +# and directories. +! go install std@v1.0.0 +stderr '^go install std@v1.0.0: argument must be a package path, not a meta-package$' +! go install fmt@v1.0.0 +stderr '^go install fmt@v1.0.0: argument must not be a package in the standard library$' +! go install example.com//cmd/a@v1.0.0 +stderr '^go install example.com//cmd/a@v1.0.0: argument must be a clean package path$' +! go install example.com/cmd/a@v1.0.0 ./x@v1.0.0 +stderr '^go install ./x@v1.0.0: argument must be a package path, not a relative path$' +! go install example.com/cmd/a@v1.0.0 $GOPATH/src/x@v1.0.0 +stderr '^go install '$WORK'[/\\]gopath/src/x@v1.0.0: argument must be a package path, not an absolute path$' +! go install example.com/cmd/a@v1.0.0 cmd/...@v1.0.0 +stderr '^go install: package cmd/go not provided by module example.com/cmd@v1.0.0$' + +# 'go install pkg@version' should accept multiple arguments but report an error +# if the version suffixes are different, even if they refer to the same version. +go install example.com/cmd/a@v1.0.0 example.com/cmd/b@v1.0.0 +exists $GOPATH/bin/a$GOEXE +exists $GOPATH/bin/b$GOEXE +rm $GOPATH/bin + +env GO111MODULE=on +go list -m example.com/cmd@latest +stdout '^example.com/cmd v1.0.0$' +env GO111MODULE=auto + +! go install example.com/cmd/a@v1.0.0 example.com/cmd/b@latest +stderr '^go install example.com/cmd/b@latest: all arguments must have the same version \(@v1.0.0\)$' + + +# 'go install pkg@version' should report an error if the arguments are in +# different modules. +! go install example.com/cmd/a@v1.0.0 rsc.io/fortune@v1.0.0 +stderr '^go install: package rsc.io/fortune provided by module rsc.io/fortune@v1.0.0\n\tAll packages must be provided by the same module \(example.com/cmd@v1.0.0\).$' + + +# 'go install pkg@version' should report an error if an argument is not +# a main package. +! go install example.com/cmd/a@v1.0.0 example.com/cmd/err@v1.0.0 +stderr '^go install: package example.com/cmd/err is not a main package$' + +# Wildcards should match only main packages. This module has a non-main package +# with an error, so we'll know if that gets built. +mkdir tmp +cd tmp +go mod init m +go get -d example.com/cmd@v1.0.0 +! go build example.com/cmd/... +stderr 'err[/\\]err.go:3:9: undefined: DoesNotCompile$' +cd .. + +go install example.com/cmd/...@v1.0.0 +exists $GOPATH/bin/a$GOEXE +exists $GOPATH/bin/b$GOEXE +rm $GOPATH/bin + +# If a wildcard matches no packages, we should see a warning. +! go install example.com/cmd/nomatch...@v1.0.0 +stderr '^go install example.com/cmd/nomatch\.\.\.@v1.0.0: module example.com/cmd@v1.0.0 found, but does not contain packages matching example.com/cmd/nomatch\.\.\.$' +go install example.com/cmd/a@v1.0.0 example.com/cmd/nomatch...@v1.0.0 +stderr '^go: warning: "example.com/cmd/nomatch\.\.\." matched no packages$' + +# If a wildcard matches only non-main packges, we should see a different warning. +go install example.com/cmd/err...@v1.0.0 +stderr '^go: warning: "example.com/cmd/err\.\.\." matched no main packages$' + + +# 'go install pkg@version' should report errors if the module contains +# replace or exclude directives. +go mod download example.com/cmd@v1.0.0-replace +! go install example.com/cmd/a@v1.0.0-replace +cmp stderr replace-err + +go mod download example.com/cmd@v1.0.0-exclude +! go install example.com/cmd/a@v1.0.0-exclude +cmp stderr exclude-err + +# 'go install pkg@version' should report an error if the module requires a +# higher version of itself. +! go install example.com/cmd/a@v1.0.0-newerself +stderr '^go install example.com/cmd/a@v1.0.0-newerself: version constraints conflict:\n\texample.com/cmd@v1.0.0-newerself requires example.com/cmd@v1.0.0, but example.com/cmd@v1.0.0-newerself is requested$' + + +# 'go install pkg@version' will only match a retracted version if it's +# explicitly requested. +env GO111MODULE=on +go list -m -versions example.com/cmd +! stdout v1.9.0 +go list -m -versions -retracted example.com/cmd +stdout v1.9.0 +go install example.com/cmd/a@latest +go version -m $GOPATH/bin/a$GOEXE +stdout '^\tmod\texample.com/cmd\tv1.0.0\t' +go install example.com/cmd/a@v1.9.0 +go version -m $GOPATH/bin/a$GOEXE +stdout '^\tmod\texample.com/cmd\tv1.9.0\t' +env GO111MODULE= + +# 'go install pkg@version' succeeds when -mod=readonly is set explicitly. +# Verifies #43278. +go install -mod=readonly example.com/cmd/a@v1.0.0 + +-- m/go.mod -- +module m + +go 1.16 + +require example.com/cmd v1.1.0-doesnotexist +-- x/x.go -- +package main + +func main() {} +-- replace-err -- +go install example.com/cmd/a@v1.0.0-replace: example.com/cmd@v1.0.0-replace + The go.mod file for the module providing named packages contains one or + more replace directives. It must not contain directives that would cause + it to be interpreted differently than if it were the main module. +-- exclude-err -- +go install example.com/cmd/a@v1.0.0-exclude: example.com/cmd@v1.0.0-exclude + The go.mod file for the module providing named packages contains one or + more exclude directives. It must not contain directives that would cause + it to be interpreted differently than if it were the main module. diff --git a/src/cmd/go/testdata/script/mod_install_versioned.txt b/src/cmd/go/testdata/script/mod_install_versioned.txt new file mode 100644 index 0000000..c6bce41 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_install_versioned.txt @@ -0,0 +1,14 @@ +env GO111MODULE=on + +go get -d rsc.io/fortune +go list -f '{{.Target}}' rsc.io/fortune +! stdout fortune@v1 +stdout 'fortune(\.exe)?$' + +go get -d rsc.io/fortune/v2 +go list -f '{{.Target}}' rsc.io/fortune/v2 +! stdout v2 +stdout 'fortune(\.exe)?$' + +-- go.mod -- +module m diff --git a/src/cmd/go/testdata/script/mod_internal.txt b/src/cmd/go/testdata/script/mod_internal.txt new file mode 100644 index 0000000..687269d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_internal.txt @@ -0,0 +1,96 @@ +env GO111MODULE=on +[short] skip + +# golang.org/x/internal should be importable from other golang.org/x modules. +go mod edit -module=golang.org/x/anything +go get -d . + +# ...and their tests... +go test +stdout PASS + +# ...but that should not leak into other modules. +go get -d ./baddep +! 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 get -d ./fromstd +! go build ./fromstd +stderr 'use of internal package internal/testenv not allowed' + +# Dependencies should be able to use their own internal modules... +go mod edit -module=golang.org/notx +go get -d ./throughdep + +# ... but other modules should not, even if they have transitive dependencies. +go get -d . +! go build . +stderr 'use of internal package golang.org/x/.* not allowed' + +# And transitive dependencies still should not leak. +go get -d ./baddep +! 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. +go mod edit -module=golang.org/notx +go mod edit -replace golang.org/x/internal=./replace/golang.org/notx/internal +go get -d ./throughdep + +go get -d ./baddep +! 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 get -d ./throughdep + +go get -d ./baddep +! go build ./baddep +stderr golang.org[/\\]notx[/\\]useinternal +stderr 'use of internal package golang.org/x/.* not allowed' + +-- go.mod -- +module TBD +go 1.12 +-- 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" + +-- 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/src/cmd/go/testdata/script/mod_invalid_path.txt b/src/cmd/go/testdata/script/mod_invalid_path.txt new file mode 100644 index 0000000..c8c075d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_invalid_path.txt @@ -0,0 +1,64 @@ +# Test that mod files with invalid or missing paths produce an error. + +# Test that go list fails on a go.mod with no module declaration. +cd $WORK/gopath/src/mod +! go list . +stderr '^go: no module declaration in go.mod. To specify the module path:\n\tgo mod edit -module=example.com/mod$' + +# Test that go mod init in GOPATH doesn't add a module declaration +# with a path that can't possibly be a module path, because +# it isn't even a valid import path. +# The single quote and backtick are the only characters we don't allow +# in checkModulePathLax, but is allowed in a Windows file name. +# TODO(matloob): choose a different character once +# module.CheckImportPath is laxened and replaces +# checkModulePathLax. +cd $WORK/'gopath/src/m''d' +! go mod init +stderr 'cannot determine module path' + +# Test that a go.mod file is rejected when its module declaration has a path that can't +# possibly be a module path, because it isn't even a valid import path +cd $WORK/gopath/src/badname +! go list . +stderr 'invalid module path' + +# Test that an import path containing an element with a leading dot is valid, +# but such a module path is not. +# Verifies #43985. +cd $WORK/gopath/src/dotname +go list ./.dot +stdout '^example.com/dotname/.dot$' +go list ./use +stdout '^example.com/dotname/use$' +! go list -m example.com/dotname/.dot@latest +stderr '^go list -m: example.com/dotname/.dot@latest: malformed module path "example.com/dotname/.dot": leading dot in path element$' +go get -d example.com/dotname/.dot +go get -d example.com/dotname/use +go mod tidy + +-- mod/go.mod -- + +-- mod/foo.go -- +package foo + +-- m'd/foo.go -- +package mad + +-- badname/go.mod -- + +module .\. + +-- badname/foo.go -- +package badname + +-- dotname/go.mod -- +module example.com/dotname + +go 1.16 +-- dotname/.dot/dot.go -- +package dot +-- dotname/use/use.go -- +package use + +import _ "example.com/dotname/.dot" diff --git a/src/cmd/go/testdata/script/mod_invalid_path_plus.txt b/src/cmd/go/testdata/script/mod_invalid_path_plus.txt new file mode 100644 index 0000000..2f2488f --- /dev/null +++ b/src/cmd/go/testdata/script/mod_invalid_path_plus.txt @@ -0,0 +1,32 @@ +# https://golang.org/issue/44776 +# The '+' character should be disallowed in module paths, but allowed in package +# paths within valid modules. + +go get -d example.net/cmd +go list example.net/cmd/x++ + +! go list -versions -m 'example.net/bad++' +stderr '^go list -m: module example.net/bad\+\+: malformed module path "example.net/bad\+\+": invalid char ''\+''$' + +# TODO(bcmills): 'go get -d example.net/cmd/x++' should also work, but currently +# it does not. This might be fixed by https://golang.org/cl/297891. +! go get -d example.net/cmd/x++ +stderr '^go get: malformed module path "example.net/cmd/x\+\+": invalid char ''\+''$' + +-- go.mod -- +module example.com/m + +go 1.16 + +replace ( + example.net/cmd => ./cmd +) + +-- cmd/go.mod -- +module example.net/cmd + +go 1.16 +-- cmd/x++/main.go -- +package main + +func main() {} diff --git a/src/cmd/go/testdata/script/mod_invalid_version.txt b/src/cmd/go/testdata/script/mod_invalid_version.txt new file mode 100644 index 0000000..43b9564 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_invalid_version.txt @@ -0,0 +1,251 @@ +[!net] skip +[!exec:git] skip + +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off +env GOFLAGS=-mod=mod + +# Regression test for golang.org/issue/27173: if the user (or go.mod file) +# requests a pseudo-version that does not match both the module path and commit +# metadata, reject it with a helpful error message. +# +# TODO(bcmills): Replace the github.com/pierrec/lz4 examples with something +# equivalent on vcs-test.golang.org. + +# An incomplete commit hash is not a valid semantic version, +# but can appear in the main go.mod file anyway and should be resolved. +cp go.mod.orig go.mod +go mod edit -require golang.org/x/text@14c0d48ead0c +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 \(replaced by \./\..\): parsing ../go.mod: '$WORK'/gopath/src/go.mod:5: require golang.org/x/text: version "14c0d48ead0c" invalid: must be of the form v1.2.3' +cd .. +go list -m golang.org/x/text +stdout 'golang.org/x/text v0.1.1-0.20170915032832-14c0d48ead0c' +grep 'golang.org/x/text v0.1.1-0.20170915032832-14c0d48ead0c' go.mod + +# A module path below the repo root that does not contain a go.mod file is invalid. +cp go.mod.orig go.mod +go mod edit -require golang.org/x/text/unicode@v0.0.0-20170915032832-14c0d48ead0c +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text/unicode@v0.0.0-20170915032832-14c0d48ead0c: invalid version: missing golang.org/x/text/unicode/go.mod at revision 14c0d48ead0c' +cd .. +! go list -m golang.org/x/text +stderr 'golang.org/x/text/unicode@v0.0.0-20170915032832-14c0d48ead0c: invalid version: missing golang.org/x/text/unicode/go.mod at revision 14c0d48ead0c' + +# However, arguments to 'go get' can name packages above the root. +cp go.mod.orig go.mod +go get -d golang.org/x/text/unicode@v0.0.0-20170915032832-14c0d48ead0c +go list -m golang.org/x/text/... +stdout 'golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c' +! stdout 'golang.org/x/text/unicode' + +# A major version that does not match the module path is invalid. +cp go.mod.orig go.mod +go mod edit -require golang.org/x/text@v2.1.1-0.20170915032832-14c0d48ead0c +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 \(replaced by \./\.\.\): parsing ../go.mod: '$WORK'/gopath/src/go.mod:5: require golang.org/x/text: version "v2.1.1-0.20170915032832-14c0d48ead0c" invalid: should be v0 or v1, not v2' +cd .. +! go list -m golang.org/x/text +stderr $WORK'/gopath/src/go.mod:5: require golang.org/x/text: version "v2.1.1-0.20170915032832-14c0d48ead0c" invalid: should be v0 or v1, not v2' + +# A pseudo-version with fewer than 12 digits of SHA-1 prefix is invalid. +cp go.mod.orig go.mod +go mod edit -require golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0 +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0: invalid pseudo-version: revision is shorter than canonical \(14c0d48ead0c\)' +cd .. +! go list -m golang.org/x/text +stderr 'golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0: invalid pseudo-version: revision is shorter than canonical \(14c0d48ead0c\)' + +# A pseudo-version with more than 12 digits of SHA-1 prefix is invalid. +cp go.mod.orig go.mod +go mod edit -require golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0cd47e3104ada247d91be04afc7a5a +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0cd47e3104ada247d91be04afc7a5a: invalid pseudo-version: revision is longer than canonical \(14c0d48ead0c\)' +cd .. +! go list -m golang.org/x/text +stderr 'golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0cd47e3104ada247d91be04afc7a5a: invalid pseudo-version: revision is longer than canonical \(14c0d48ead0c\)' + +# A pseudo-version that does not match the commit timestamp is invalid. +cp go.mod.orig go.mod +go mod edit -require golang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c: invalid pseudo-version: does not match version-control timestamp \(expected 20170915032832\)' +cd .. +! go list -m golang.org/x/text +stderr 'golang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c: invalid pseudo-version: does not match version-control timestamp \(expected 20170915032832\)' + +# A 'replace' directive in the main module can replace an invalid timestamp +# with a valid one. +go mod edit -replace golang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c=golang.org/x/text@14c0d48ead0c +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20190915032832-14c0d48ead0c: invalid pseudo-version: does not match version-control timestamp \(expected 20170915032832\)' +cd .. +go list -m golang.org/x/text +stdout 'golang.org/x/text v0.1.1-0.20190915032832-14c0d48ead0c => golang.org/x/text v0.1.1-0.20170915032832-14c0d48ead0c' + +# A pseudo-version that is not derived from a tag is invalid. +cp go.mod.orig go.mod +go mod edit -require golang.org/x/text@v1.999.999-0.20170915032832-14c0d48ead0c +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v1.999.999-0.20170915032832-14c0d48ead0c: invalid pseudo-version: preceding tag \(v1.999.998\) not found' +cd .. +! go list -m golang.org/x/text +stderr 'golang.org/x/text@v1.999.999-0.20170915032832-14c0d48ead0c: invalid pseudo-version: preceding tag \(v1.999.998\) not found' + +# A v1.0.0- pseudo-version that is not derived from a tag is invalid: +# v1.0.0- implies no tag, but the correct no-tag prefix for a module path +# without a major-version suffix is v0.0.0-. +cp go.mod.orig go.mod +go mod edit -require golang.org/x/text@v1.0.0-20170915032832-14c0d48ead0c +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v1.0.0-20170915032832-14c0d48ead0c: invalid pseudo-version: major version without preceding tag must be v0, not v1' +cd .. +! go list -m golang.org/x/text +stderr 'golang.org/x/text@v1.0.0-20170915032832-14c0d48ead0c: invalid pseudo-version: major version without preceding tag must be v0, not v1' + +# A pseudo-version vX.Y.Z+1 cannot have Z+1 == 0, since that would +# imply a base tag with a negative patch field. +cp go.mod.orig go.mod +go mod edit -require golang.org/x/text@v0.0.0-0.20170915032832-14c0d48ead0c +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.0.0-0.20170915032832-14c0d48ead0c: invalid pseudo-version: version before v0.0.0 would have negative patch number' +cd .. +! go list -m golang.org/x/text +stderr 'golang.org/x/text@v0.0.0-0.20170915032832-14c0d48ead0c: invalid pseudo-version: version before v0.0.0 would have negative patch number' + +# A 'replace' directive in the main module can replace an +# invalid pseudo-version base with a valid one. +go mod edit -replace golang.org/x/text@v0.0.0-0.20170915032832-14c0d48ead0c=golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.0.0-0.20170915032832-14c0d48ead0c: invalid pseudo-version: version before v0.0.0 would have negative patch number' +cd .. +go list -m golang.org/x/text +stdout 'golang.org/x/text v0.0.0-0.20170915032832-14c0d48ead0c => golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c' + +# A 'replace' directive can replace an invalid 'latest' version, and +# should suppress errors for that version in 'go get -u' +cp go.mod.orig go.mod +go mod edit -require golang.org/x/text@v1.999999.0 +go mod edit -replace golang.org/x/text@v1.999999.0=golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c +cd outside +! go get -d golang.org/x/text@upgrade +stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v1.999999.0: reading golang.org/x/text/go.mod at revision v1.999999.0: unknown revision v1.999999.0' +cd .. +go get -d golang.org/x/text@upgrade +go list -m golang.org/x/text +stdout 'golang.org/x/text v1.999999.0 => golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c' + +# A pseudo-version derived from a non-ancestor tag is invalid. +cp go.mod.orig go.mod +go mod edit -require golang.org/x/text@v0.2.1-0.20170915032832-14c0d48ead0c +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.2.1-0.20170915032832-14c0d48ead0c: invalid pseudo-version: revision 14c0d48ead0c is not a descendent of preceding tag \(v0.2.0\)' +cd .. +! go list -m golang.org/x/text +stderr 'golang.org/x/text@v0.2.1-0.20170915032832-14c0d48ead0c: invalid pseudo-version: revision 14c0d48ead0c is not a descendent of preceding tag \(v0.2.0\)' + +# A pseudo-version derived from a canonical tag on the same revision is invalid. +cp go.mod.orig go.mod +go mod edit -require golang.org/x/text@v0.2.1-0.20171213102548-c4d099d611ac +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.2.1-0.20171213102548-c4d099d611ac: invalid pseudo-version: tag \(v0.2.0\) found on revision c4d099d611ac is already canonical, so should not be replaced with a pseudo-version derived from that tag' +cd .. +! go list -m golang.org/x/text +stderr 'golang.org/x/text@v0.2.1-0.20171213102548-c4d099d611ac: invalid pseudo-version: tag \(v0.2.0\) found on revision c4d099d611ac is already canonical, so should not be replaced with a pseudo-version derived from that tag' + +# A +incompatible suffix is not allowed on a version that is actually compatible. +cp go.mod.orig go.mod +go mod edit -require golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0c+incompatible +cd outside +! go list -m golang.org/x/text +stderr 'go: example.com@v0.0.0 requires\n\tgolang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0c\+incompatible: invalid version: \+incompatible suffix not allowed: major version v0 is compatible' +cd .. +! go list -m golang.org/x/text +stderr 'golang.org/x/text@v0.1.1-0.20170915032832-14c0d48ead0c\+incompatible: invalid version: \+incompatible suffix not allowed: major version v0 is compatible' + +# The pseudo-version for a commit after a tag with a non-matching major version +# should instead be based on the last matching tag. +cp go.mod.orig go.mod +go mod edit -require github.com/pierrec/lz4@473cd7ce01a1 +go list -m github.com/pierrec/lz4 +stdout 'github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1' +cd outside +go list -m github.com/pierrec/lz4 +stdout 'github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1' +cd .. + +# A +incompatible pseudo-version for a module that has an explicit go.mod file is invalid. +cp go.mod.orig go.mod +go mod edit -require github.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d+incompatible +cd outside +! go list -m github.com/pierrec/lz4 +stderr 'go: example.com@v0.0.0 requires\n\tgithub.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required' +cd .. +! go list -m github.com/pierrec/lz4 +stderr 'github.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required' + +# A +incompatible pseudo-version is valid for a revision of the module +# that lacks a go.mod file. +cp go.mod.orig go.mod +go mod edit -require github.com/pierrec/lz4@v2.0.4-0.20180826165652-dbe9298ce099+incompatible +cd outside +go list -m github.com/pierrec/lz4 +stdout 'github.com/pierrec/lz4 v2.0.4-0.20180826165652-dbe9298ce099\+incompatible' +cd .. +go list -m github.com/pierrec/lz4 +stdout 'github.com/pierrec/lz4 v2.0.4-0.20180826165652-dbe9298ce099\+incompatible' + +# 'go get' for a mismatched major version without a go.mod file should resolve +# to the equivalent +incompatible version, not a pseudo-version with a different +# major version. +cp go.mod.orig go.mod +go get -d github.com/pierrec/lz4@v2.0.5 +go list -m github.com/pierrec/lz4 +stdout 'github.com/pierrec/lz4 v2.0.5\+incompatible' + +# 'go get' for a mismatched major version with a go.mod file should error out, +# not resolve to a pseudo-version with a different major version. +cp go.mod.orig go.mod +! go get -d github.com/pierrec/lz4@v2.0.8 +stderr 'go get: github.com/pierrec/lz4@v2.0.8: invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v2' + +# An invalid +incompatible suffix for a canonical version should error out, +# not resolve to a pseudo-version. +# +# TODO(bcmills): The "outside" view for this failure mode is missing its import stack. +# Figure out why and fix it. +cp go.mod.orig go.mod +go mod edit -require github.com/pierrec/lz4@v2.0.8+incompatible +cd outside +! go list -m github.com/pierrec/lz4 +stderr 'github.com/pierrec/lz4@v2.0.8\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required' +cd .. +! go list -m github.com/pierrec/lz4 +stderr 'github.com/pierrec/lz4@v2.0.8\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required' + +-- go.mod.orig -- +module example.com + +go 1.13 +-- outside/go.mod -- +module example.com/outside + +go 1.13 + +require example.com v0.0.0 +replace example.com v0.0.0 => ./.. diff --git a/src/cmd/go/testdata/script/mod_issue35317.txt b/src/cmd/go/testdata/script/mod_issue35317.txt new file mode 100644 index 0000000..b1852ab --- /dev/null +++ b/src/cmd/go/testdata/script/mod_issue35317.txt @@ -0,0 +1,8 @@ +# Regression test for golang.org/issue/35317: +# 'go get' with multiple module-only arguments was racy. + +env GO111MODULE=on +[short] skip + +go mod init example.com +go get -d golang.org/x/text@v0.3.0 golang.org/x/internal@v0.1.0 golang.org/x/exp@none diff --git a/src/cmd/go/testdata/script/mod_lazy_downgrade.txt b/src/cmd/go/testdata/script/mod_lazy_downgrade.txt new file mode 100644 index 0000000..1e84820 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_lazy_downgrade.txt @@ -0,0 +1,145 @@ +# This test illustrates the interaction between lazy loading and downgrading in +# 'go get. + +# The package import graph used in this test looks like: +# +# lazy ---- a +# | +# a_test ---- b +# b_test ---- c +# +# The module dependency graph initially looks like: +# +# lazy ---- a.1 ---- b.1 ---- c.1 +# \ / +# b.3 ---- c.2 b.2 +# +# (Note that lazy loading will prune out the dependency from b.1 on c.1.) + +cp go.mod go.mod.orig +go mod tidy +cmp go.mod.orig go.mod + +go list -m all +stdout '^example.com/a v0.1.0 ' +stdout '^example.com/b v0.3.0 ' +stdout '^example.com/c v0.2.0 ' + +# Downgrading c should also downgrade the b that requires it. + +go get -d example.com/c@v0.1.0 +go list -m all +stdout '^example.com/a v0.1.0 ' +stdout '^example.com/b v0.2.0 ' +stdout '^example.com/c v0.1.0 ' + +# Removing c entirely should also remove the a and b that require it. + +go get -d example.com/c@none +go list -m all +! stdout '^example.com/a ' +! stdout '^example.com/b ' +! stdout '^example.com/c ' + + +# With lazy loading, downgrading c should work the same way, but dependencies +# outside of the deepening scan should not affect the downgrade. + +cp go.mod.orig go.mod +go mod edit -go=1.16 + +go list -m all +stdout '^example.com/a v0.1.0 ' +stdout '^example.com/b v0.3.0 ' +stdout '^example.com/c v0.2.0 ' + +go get -d example.com/c@v0.1.0 +go list -m all +stdout '^example.com/a v0.1.0 ' +stdout '^example.com/b v0.2.0 ' +stdout '^example.com/c v0.1.0 ' + +go get -d example.com/c@none +go list -m all +! stdout '^example.com/a ' # TODO(#36460): example.com/a v0.1.0 +! stdout '^example.com/b ' # TODO(#36460): example.com/b v0.1.0 +! stdout '^example.com/c ' + +-- go.mod -- +module example.com/lazy + +go 1.15 + +require ( + example.com/a v0.1.0 + example.com/b v0.3.0 // indirect +) + +replace ( + example.com/a v0.1.0 => ./a + example.com/b v0.1.0 => ./b1 + example.com/b v0.2.0 => ./b2 + example.com/b v0.3.0 => ./b3 + example.com/c v0.1.0 => ./c + example.com/c v0.2.0 => ./c +) +-- lazy.go -- +package lazy + +import _ "example.com/a" + +-- a/go.mod -- +module example.com/a + +go 1.15 + +require example.com/b v0.1.0 +-- a/a.go -- +package a +-- a/a_test.go -- +package a_test + +import _ "example.com/b" + +-- b1/go.mod -- +module example.com/b + +go 1.15 + +require example.com/c v0.1.0 +-- b1/b.go -- +package b +-- b1/b_test.go -- +package b_test +import _ "example.com/c" + +-- b2/go.mod -- +module example.com/b + +go 1.15 + +require example.com/c v0.1.0 +-- b2/b.go -- +package b +-- b2/b_test.go -- +package b_test +import _ "example.com/c" + +-- b3/go.mod -- +module example.com/b + +go 1.15 + +require example.com/c v0.2.0 +-- b3/b.go -- +package b +-- b3/b_test.go -- +package b_test +import _ "example.com/c" + +-- c/go.mod -- +module example.com/c + +go 1.15 +-- c/c.go -- +package c diff --git a/src/cmd/go/testdata/script/mod_lazy_import_allmod.txt b/src/cmd/go/testdata/script/mod_lazy_import_allmod.txt new file mode 100644 index 0000000..4ad8cbf --- /dev/null +++ b/src/cmd/go/testdata/script/mod_lazy_import_allmod.txt @@ -0,0 +1,172 @@ +# This test demonstrates dependency resolution when the main module imports a +# new package from a previously-test-only dependency. +# +# When lazy loading is active, the loader will not load dependencies of any +# module whose packages are *only* imported by tests outside the main module. If +# the main module is changed to import a package from such a module, the +# dependencies of that module will need to be reloaded. + +# The import graph used in this test looks like: +# +# m ---- a +# \ | +# \ a_test ---- b/x +# \ +# --------------b/y (new) ---- c +# +# Where b/x and b/y are disjoint packages, but both contained in module b. +# +# The module dependency graph initially looks like: +# +# m ---- a.1 ---- b.1 ---- c.1 +# +# This configuration is similar to that used in mod_lazy_new_import, +# but the new import is from what is initially a test-only dependency. + +# Control case: in Go 1.14, the original go.mod is tidy, +# and the dependency on c is eagerly loaded. + +cp go.mod go.mod.orig +go mod tidy +cmp go.mod.orig go.mod + +go list -m all +stdout '^a v0.1.0 ' +stdout '^b v0.1.0 ' +stdout '^c v0.1.0 ' + +# After adding a new import of b/y, +# the import of c from b/y should resolve to the version required by b. + +cp m.go m.go.orig +cp m.go.new m.go +go mod tidy +cmp go.mod.new go.mod + +go list -m all +stdout '^a v0.1.0 ' +stdout '^b v0.1.0 ' +stdout '^c v0.1.0 ' + +# With lazy loading, the go.mod requirements are the same, +# but the dependency on c is initially pruned out. + +cp m.go.orig m.go +cp go.mod.orig go.mod +go mod edit -go=1.16 +go mod edit -go=1.16 go.mod.new + +cp go.mod go.mod.orig +go mod tidy +cmp go.mod.orig go.mod + +go list -m all +stdout '^a v0.1.0 ' +stdout '^b v0.1.0 ' +stdout '^c v0.1.0 ' # TODO(#36460): This should be pruned out. + +# After adding a new import of b/y, +# the import of c from b/y should again resolve to the version required by b. + +cp m.go.new m.go +go mod tidy +cmp go.mod.new go.mod + +go list -m all +stdout '^a v0.1.0 ' +stdout '^b v0.1.0 ' +stdout '^c v0.1.0 ' + +-- m.go -- +package main + +import ( + "fmt" + + _ "a" // a_test imports b/x. +) + +func main() { +} +-- m.go.new -- +package main + +import ( + "fmt" + + _ "a" // a_test imports b/x. + "b/y" // This is a new import, not yet reflected in the go.mod file. +) + +func main() { + fmt.Println(b.CVersion()) +} +-- go.mod -- +module m + +go 1.14 + +require a v0.1.0 + +replace ( + a v0.1.0 => ./a1 + b v0.1.0 => ./b1 + c v0.1.0 => ./c1 + c v0.2.0 => ./c2 +) +-- go.mod.new -- +module m + +go 1.14 + +require ( + a v0.1.0 + b v0.1.0 +) + +replace ( + a v0.1.0 => ./a1 + b v0.1.0 => ./b1 + c v0.1.0 => ./c1 + c v0.2.0 => ./c2 +) +-- a1/go.mod -- +module a + +go 1.16 + +require b v0.1.0 +-- a1/a.go -- +package a +-- a1/a_test.go -- +package a_test + +import _ "b/x" +-- b1/go.mod -- +module b + +go 1.16 + +require c v0.1.0 +-- b1/x/x.go -- +package x +-- b1/y/y.go -- +package y + +import "c" + +func CVersion() string { + return c.Version +} +-- c1/go.mod -- +module c + +go 1.16 +-- c1/c.go -- +package c + +const Version = "v0.1.0" +-- c2/go.mod -- +This file should be unused. +-- c2/c.go -- +This file should be unused. diff --git a/src/cmd/go/testdata/script/mod_lazy_new_import.txt b/src/cmd/go/testdata/script/mod_lazy_new_import.txt new file mode 100644 index 0000000..02935bf --- /dev/null +++ b/src/cmd/go/testdata/script/mod_lazy_new_import.txt @@ -0,0 +1,107 @@ +# This test illustrates the use of a deepening scan to resolve transitive +# imports of imports of new packages from within existing dependencies. + +# The package import graph used in this test looks like: +# +# lazy ---- a/x ---- b +# \ +# ---- a/y ---- c +# +# Where a/x and x/y are disjoint packages, but both contained in module a. +# +# The module dependency graph initially looks like: +# +# lazy ---- a.1 ---- b.1 +# \ +# c.1 + + +cp go.mod go.mod.old +cp lazy.go lazy.go.old +go mod tidy +cmp go.mod go.mod.old + +# Before adding a new import, the go.mod file should +# enumerate modules for all packages already imported. +go list all +cmp go.mod go.mod.old + +# When we add a new import of a package in an existing dependency, +# and that dependency is already tidy, its transitive dependencies +# should already be present. +cp lazy.go.new lazy.go +go list all +go list -m all +stdout '^example.com/c v0.1.0' # not v0.2.0 as would be be resolved by 'latest' +cmp go.mod go.mod.old + +# TODO(#36460): +cp lazy.go.old lazy.go +cp go.mod.old go.mod +go mod edit -go=1.16 + +# When a new import is found, we should perform a deepening scan of the existing +# dependencies and add a requirement on the version required by those +# dependencies — not re-resolve 'latest'. + + +-- go.mod -- +module example.com/lazy + +go 1.15 + +require example.com/a v0.1.0 + +replace ( + example.com/a v0.1.0 => ./a + example.com/b v0.1.0 => ./b + example.com/c v0.1.0 => ./c1 + example.com/c v0.2.0 => ./c2 +) +-- lazy.go -- +package lazy + +import ( + _ "example.com/a/x" +) +-- lazy.go.new -- +package lazy + +import ( + _ "example.com/a/x" + _ "example.com/a/y" +) +-- a/go.mod -- +module example.com/a + +go 1.15 + +require ( + example.com/b v0.1.0 + example.com/c v0.1.0 +) +-- a/x/x.go -- +package x +import _ "example.com/b" +-- a/y/y.go -- +package y +import _ "example.com/c" +-- b/go.mod -- +module example.com/b + +go 1.15 +-- b/b.go -- +package b +-- c1/go.mod -- +module example.com/c + +go 1.15 +-- c1/c.go -- +package c +-- c2/go.mod -- +module example.com/c + +go 1.15 +-- c2/c.go -- +package c +This file should not be used, so this syntax error should be ignored. diff --git a/src/cmd/go/testdata/script/mod_lazy_test_horizon.txt b/src/cmd/go/testdata/script/mod_lazy_test_horizon.txt new file mode 100644 index 0000000..9cdfad7 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_lazy_test_horizon.txt @@ -0,0 +1,131 @@ +# This file demonstrates the effect of lazy loading on the selected +# versions of test dependencies. + +# The package import graph used in this test looks like: +# +# m ---- a +# \ | +# \ a_test ---- b +# \ | +# x b_test +# | \ +# x_test -------------- c +# +# And the module dependency graph looks like: +# +# m -- a.1 -- b.1 -- c.2 +# \ +# x.1 ------------ c.1 + +# Control case: in Go 1.15, the version of c imported by 'go test x' is the +# version required by module b, even though b_test is not relevant to the main +# module. (The main module imports a, and a_test imports b, but all of the +# packages and tests in the main module can be built without b.) + +go list -m c +stdout '^c v0.2.0 ' + +[!short] go test -v x +[!short] stdout ' c v0.2.0$' + +# With lazy loading, the go.mod requirements are the same, +# but the irrelevant dependency on c v0.2.0 should be pruned out, +# leaving only the relevant dependency on c v0.1.0. + +go mod edit -go=1.16 +go list -m c +stdout '^c v0.2.0' # TODO(#36460): v0.1.0 + +[!short] go test -v x +[!short] stdout ' c v0.2.0$' # TODO(#36460): v0.1.0 + +-- m.go -- +package m + +import ( + _ "a" + _ "x" +) +-- go.mod -- +module m + +go 1.15 + +require ( + a v0.1.0 + x v0.1.0 +) + +replace ( + a v0.1.0 => ./a1 + b v0.1.0 => ./b1 + c v0.1.0 => ./c1 + c v0.2.0 => ./c2 + x v0.1.0 => ./x1 +) +-- a1/go.mod -- +module a + +go 1.16 + +require b v0.1.0 +-- a1/a.go -- +package a +-- a1/a_test.go -- +package a_test + +import _ "b" +-- b1/go.mod -- +module b + +go 1.16 + +require c v0.2.0 +-- b1/b.go -- +package b +-- b1/b_test.go -- +package b_test + +import ( + "c" + "testing" +) + +func TestCVersion(t *testing.T) { + t.Log(c.Version) +} +-- c1/go.mod -- +module c + +go 1.16 +-- c1/c.go -- +package c + +const Version = "v0.1.0" +-- c2/go.mod -- +module c + +go 1.16 +-- c2/c.go -- +package c + +const Version = "v0.2.0" +-- x1/go.mod -- +module x + +go 1.16 + +require c v0.1.0 +-- x1/x.go -- +package x +-- x1/x_test.go -- +package x_test + +import ( + "c" + "testing" +) + +func TestCVersion(t *testing.T) { + t.Log("c", c.Version) +} diff --git a/src/cmd/go/testdata/script/mod_lazy_test_of_test_dep.txt b/src/cmd/go/testdata/script/mod_lazy_test_of_test_dep.txt new file mode 100644 index 0000000..ca6c550 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_lazy_test_of_test_dep.txt @@ -0,0 +1,145 @@ +# This file demonstrates the effect of lazy loading on the reproducibility of +# tests (and tests of test dependencies) outside the main module. +# +# It is similar to the cases in mod_all.txt and mod_lazy_test_horizon.txt, but +# focuses on the effect of "go test" on specific packages instead of the "all" +# pattern. + +# The package import graph used in this test looks like: +# +# lazy ---- a +# | +# a_test ---- b +# | +# b_test ---- c +# +# And the non-lazy module dependency graph looks like: +# +# lazy ---- a.1 ---- b.1 ---- c.1 + +cp go.mod go.mod.old +go mod tidy +cmp go.mod go.mod.old + +# In Go 1.15 mode, 'go list -m all' includes modules needed by the +# transitive closure of tests of dependencies of tests of dependencies of …. + +go list -m all +stdout 'example.com/b v0.1.0' +stdout 'example.com/c v0.1.0' +cmp go.mod go.mod.old + +# 'go test' (or equivalent) of any such dependency, no matter how remote, does +# not update the go.mod file. + +go list -test -deps example.com/a +stdout example.com/b +! stdout example.com/c + +[!short] go test -c example.com/a +[!short] cmp go.mod go.mod.old + +go list -test -deps example.com/b +stdout example.com/c + +[!short] go test -c example.com/b +[!short] cmp go.mod go.mod.old + +# TODO(#36460): + +# After changing to 'go 1.16` uniformly, 'go list -m all' should prune out +# example.com/c, because it is not imported by any package (or test of a package) +# transitively imported by the main module. +# +# example.com/a is imported, +# and example.com/b is needed in order to run 'go test example.com/a', +# but example.com/c is not needed because we don't expect the user to need to run +# 'go test example.com/b'. + +# If we skip directly to adding a new import of c, the dependency is too far +# away for a deepening scan to find, which is fine because the package whose +# test imported it wasn't even it "all". It should resolve from the latest +# version of its module. + +# However, if we reach c by running successive tests starting from the main +# module, we should end up with exactly the version require by c, with an update +# to the go.mod file as soon as we test a test dependency that is not itself in +# "all". + +-- go.mod -- +module example.com/lazy + +go 1.15 + +require example.com/a v0.1.0 + +replace ( + example.com/a v0.1.0 => ./a + example.com/b v0.1.0 => ./b1 + example.com/b v0.2.0 => ./b2 + example.com/c v0.1.0 => ./c1 + example.com/c v0.2.0 => ./c2 +) +-- lazy.go -- +package lazy + +import ( + _ "example.com/a" +) +-- a/go.mod -- +module example.com/a + +go 1.15 + +require example.com/b v0.1.0 +-- a/a.go -- +package a +-- a/a_test.go -- +package a + +import ( + "testing" + + _ "example.com/b" +) + +func TestUsingB(t *testing.T) { + // … +} +-- b1/go.mod -- +module example.com/b + +go 1.15 + +require example.com/c v0.1.0 +-- b1/b.go -- +package b +-- b1/b_test.go -- +package b + +import _ "example.com/c" +-- b2/go.mod -- +module example.com/b + +go 1.15 + +require example.com/c v0.1.0 +-- b2/b.go -- +package b +This file should not be used, so this syntax error should be ignored. +-- b2/b_test.go -- +package b +This file should not be used, so this syntax error should be ignored. +-- c1/go.mod -- +module example.com/c + +go 1.15 +-- c1/c.go -- +package c +-- c2/go.mod -- +module example.com/c + +go 1.15 +-- c2/c.go -- +package c +This file should not be used, so this syntax error should be ignored. diff --git a/src/cmd/go/testdata/script/mod_list.txt b/src/cmd/go/testdata/script/mod_list.txt new file mode 100644 index 0000000..1ba6d7c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list.txt @@ -0,0 +1,61 @@ +env GO111MODULE=on +[short] skip + +# list {{.Dir}} shows main module and go.mod but not not-yet-downloaded dependency dir. +go list -mod=mod -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 -mod=mod -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 -mod=mod -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 +stdout ^math/big + +# rsc.io/quote/buggy should be listable as a package +go list -mod=mod 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: not a known dependency$' +stdout '^module rsc.io/quote/buggy: not a known dependency$' + +! go list -m nonexist rsc.io/quote/buggy +stderr '^go list -m: module nonexist: not a known dependency' +stderr '^go list -m: module rsc.io/quote/buggy: not a known dependency' + +# Module loader does not interfere with list -e (golang.org/issue/24149). +go list -e -f '{{.Error.Err}}' database +stdout 'no Go files in ' +! go list database +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/src/cmd/go/testdata/script/mod_list_bad_import.txt b/src/cmd/go/testdata/script/mod_list_bad_import.txt new file mode 100644 index 0000000..b128408 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_bad_import.txt @@ -0,0 +1,75 @@ +# 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. +! go list -deps example.com/direct +stderr example.com/notfound + +# But -e -deps should succeed. +go list -e -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. +! go list -deps example.com/indirect +stderr example.com/notfound + +# But -e -deps should succeed. +go list -e -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 required module provides package example.com/notfound; to add it:\n\tgo get 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 actually 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/src/cmd/go/testdata/script/mod_list_compiled_concurrent.txt b/src/cmd/go/testdata/script/mod_list_compiled_concurrent.txt new file mode 100644 index 0000000..b08713d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_compiled_concurrent.txt @@ -0,0 +1,41 @@ +env GO111MODULE=on + +[short] skip + +# Regression test for golang.org/issue/29667: +# spurious 'failed to cache compiled Go files' errors. +# This test failed reliably when run with -count=10 +# on a Linux workstation. + +env GOCACHE=$WORK/gocache +mkdir $GOCACHE + +go list -json -compiled -test=false -export=false -deps=true -- . & +go list -json -compiled -test=false -export=false -deps=true -- . & +go list -json -compiled -test=false -export=false -deps=true -- . & +go list -json -compiled -test=false -export=false -deps=true -- . & +go list -json -compiled -test=false -export=false -deps=true -- . & +go list -json -compiled -test=false -export=false -deps=true -- . & +go list -json -compiled -test=false -export=false -deps=true -- . & +go list -json -compiled -test=false -export=false -deps=true -- . & +go list -json -compiled -test=false -export=false -deps=true -- . & +go list -json -compiled -test=false -export=false -deps=true -- . & +go list -json -compiled -test=false -export=false -deps=true -- . & +go list -json -compiled -test=false -export=false -deps=true -- . & +go list -json -compiled -test=false -export=false -deps=true -- . & +go list -json -compiled -test=false -export=false -deps=true -- . & +go list -json -compiled -test=false -export=false -deps=true -- . & +go list -json -compiled -test=false -export=false -deps=true -- . & +go list -json -compiled -test=false -export=false -deps=true -- . & +go list -json -compiled -test=false -export=false -deps=true -- . & +go list -json -compiled -test=false -export=false -deps=true -- . & +go list -json -compiled -test=false -export=false -deps=true -- . & + +wait + +-- go.mod -- +module sandbox/bar +-- bar.go -- +package bar + +import "C" diff --git a/src/cmd/go/testdata/script/mod_list_dir.txt b/src/cmd/go/testdata/script/mod_list_dir.txt new file mode 100644 index 0000000..1adab8f --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_dir.txt @@ -0,0 +1,36 @@ +[short] skip + +# go list with path to directory should work + +# populate go.sum +go get -d + +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 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 + +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_list_direct.txt b/src/cmd/go/testdata/script/mod_list_direct.txt new file mode 100644 index 0000000..62a472f --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_direct.txt @@ -0,0 +1,24 @@ +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off + +[!net] skip +[!exec:git] skip + +# golang.org/issue/33099: if an import path ends in a major-version suffix, +# ensure that 'direct' mode can resolve the package to the module. +# For a while, (*modfetch.codeRepo).Stat was not checking for a go.mod file, +# which would produce a hard error at the subsequent call to GoMod. + +go get -d + +-- go.mod -- +module example.com +go 1.13 + +-- main.go -- +package main + +import _ "vcs-test.golang.org/git/v3pkg.git/v3" + +func main() {} diff --git a/src/cmd/go/testdata/script/mod_list_e_readonly.txt b/src/cmd/go/testdata/script/mod_list_e_readonly.txt new file mode 100644 index 0000000..4969434 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_e_readonly.txt @@ -0,0 +1,15 @@ +# 'go list -mod=readonly -e should attribute errors +# to individual missing packages. +# Verifies golang.org/issue/34829. +go list -mod=readonly -e -deps -f '{{if .Error}}{{.ImportPath}}: {{.Error}}{{end}}' . +stdout 'example.com/missing: use.go:3:8: cannot find module providing package example.com/missing: import lookup disabled by -mod=readonly' + +-- go.mod -- +module example.com/m + +go 1.14 + +-- use.go -- +package use + +import _ "example.com/missing" diff --git a/src/cmd/go/testdata/script/mod_list_pseudo.txt b/src/cmd/go/testdata/script/mod_list_pseudo.txt new file mode 100644 index 0000000..056c093 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_pseudo.txt @@ -0,0 +1,39 @@ +env GO111MODULE=on + +# Regression test for golang.org/issue/32715. + +# When using $GOPATH/pkg/mod/cache/download as a proxy, +# 'latest' queries should prefer tagged versions over pseudo-versions. + +go mod download github.com/dmitshur-test/modtest5@v0.0.0-20190619020302-197a620e0c9a +go mod download github.com/dmitshur-test/modtest5@v0.5.0-alpha +go mod download github.com/dmitshur-test/modtest5@v0.5.0-alpha.0.20190619023908-3da23a9deb9e +cmp $GOPATH/pkg/mod/cache/download/github.com/dmitshur-test/modtest5/@v/list $WORK/modtest5.list + +env GOSUMDB=off # don't verify go.mod files when loading retractions +env GOPROXY=file:///$GOPATH/pkg/mod/cache/download +env GOPATH=$WORK/gopath2 +mkdir $GOPATH + +go list -m -f '{{.Path}} {{.Version}} {{.Time.Format "2006-01-02"}}' github.com/dmitshur-test/modtest5@latest +stdout '^github.com/dmitshur-test/modtest5 v0.5.0-alpha 2019-06-18$' + +# If the module proxy contains only pseudo-versions, 'latest' should stat +# the version with the most recent timestamp — not the highest semantic +# version — and return its metadata. +env GOPROXY=file:///$WORK/tinyproxy +go list -m -f '{{.Path}} {{.Version}} {{.Time.Format "2006-01-02"}}' dmitri.shuralyov.com/test/modtest3@latest +stdout '^dmitri.shuralyov.com/test/modtest3 v0.0.0-20181023043359-a85b471d5412 2018-10-22$' + +-- $WORK/modtest5.list -- +v0.0.0-20190619020302-197a620e0c9a +v0.5.0-alpha +v0.5.0-alpha.0.20190619023908-3da23a9deb9e +-- $WORK/tinyproxy/dmitri.shuralyov.com/test/modtest3/@v/list -- +v0.1.0-0.20161023043300-000000000000 +v0.0.0-20181023043359-a85b471d5412 +-- $WORK/tinyproxy/dmitri.shuralyov.com/test/modtest3/@v/v0.0.0-20181023043359-a85b471d5412.info -- +{ + "Version": "v0.0.0-20181023043359-a85b471d5412", + "Time": "2018-10-22T21:33:59-07:00" +} diff --git a/src/cmd/go/testdata/script/mod_list_replace_dir.txt b/src/cmd/go/testdata/script/mod_list_replace_dir.txt new file mode 100644 index 0000000..f2f2d2b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_replace_dir.txt @@ -0,0 +1,27 @@ +# Test that "go list" succeeds when given a directory in a replacement +# module within the module cache. +# Verifies golang.org/issue/29548 + +# Populate go.sum and download dependencies. +go get -d + +# Ensure v1.5.2 is also in the cache so we can list it. +go mod download rsc.io/quote@v1.5.2 + +! go list $GOPATH/pkg/mod/rsc.io/quote@v1.5.2 +stderr '^directory ..[/\\]pkg[/\\]mod[/\\]rsc.io[/\\]quote@v1.5.2 outside available modules$' + +go list $GOPATH/pkg/mod/rsc.io/quote@v1.5.1 +stdout 'rsc.io/quote' + +-- go.mod -- +module example.com/quoter + +require rsc.io/quote v1.5.2 + +replace rsc.io/quote => rsc.io/quote v1.5.1 + +-- use.go -- +package use + +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_list_retract.txt b/src/cmd/go/testdata/script/mod_list_retract.txt new file mode 100644 index 0000000..3ba53bc --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_retract.txt @@ -0,0 +1,108 @@ +# 'go list -mod=vendor -retracted' reports an error. +go mod vendor +! go list -m -retracted -mod=vendor +stderr '^go list -retracted cannot be used when vendoring is enabled$' +rm vendor + +# 'go list -retracted' reports an error in GOPATH mode. +env GO111MODULE=off +! go list -retracted +stderr '^go list -retracted can only be used in module-aware mode$' +env GO111MODULE= + +# 'go list pkg' does not show retraction. +go list -f '{{with .Module}}{{with .Retracted}}retracted{{end}}{{end}}' example.com/retract +! stdout . + +# 'go list -retracted pkg' shows retraction. +go list -retracted -f '{{with .Module}}{{with .Retracted}}retracted{{end}}{{end}}' example.com/retract +stdout retracted + +# 'go list -m' does not show retraction. +go list -m -f '{{with .Retracted}}retracted{{end}}' example.com/retract +! stdout . + +# 'go list -m -retracted' shows retraction. +go list -m -retracted -f '{{with .Retracted}}retracted{{end}}' example.com/retract + +# 'go list -m mod@version' does not show retraction. +go list -m -f '{{with .Retracted}}retracted{{end}}' example.com/retract@v1.0.0-unused +! stdout . + +# 'go list -m -retracted mod@version' shows an error if the go.mod that should +# contain the retractions is not available. +! go list -m -retracted example.com/retract/missingmod@v1.0.0 +stderr '^go list -m: loading module retractions for example.com/retract/missingmod@v1.0.0: .*404 Not Found$' +go list -e -m -retracted -f '{{.Error.Err}}' example.com/retract/missingmod@v1.0.0 +stdout '^loading module retractions for example.com/retract/missingmod@v1.0.0: .*404 Not Found$' + +# 'go list -m -retracted mod@version' shows retractions. +go list -m -retracted example.com/retract@v1.0.0-unused +stdout '^example.com/retract v1.0.0-unused \(retracted\)$' +go list -m -retracted -f '{{with .Retracted}}retracted{{end}}' example.com/retract@v1.0.0-unused +stdout retracted + +# 'go list -m mod@latest' selects a previous release version, not self-retracted latest. +go list -m -f '{{.Version}}{{with .Retracted}} retracted{{end}}' example.com/retract/self/prev@latest +stdout '^v1.1.0$' + +# 'go list -m -retracted mod@latest' selects the self-retracted latest version. +go list -m -retracted -f '{{.Version}}{{with .Retracted}} retracted{{end}}' example.com/retract/self/prev@latest +stdout '^v1.9.0 retracted$' + +# 'go list -m mod@latest' selects a pre-release version if all release versions are retracted. +go list -m -f '{{.Version}}{{with .Retracted}} retracted{{end}}' example.com/retract/self/prerelease@latest +stdout '^v1.9.1-pre$' + +# 'go list -m -retracted mod@latest' selects the self-retracted latest version. +go list -m -retracted -f '{{.Version}}{{with .Retracted}} retracted{{end}}' example.com/retract/self/prerelease@latest +stdout '^v1.9.0 retracted$' + +# 'go list -m mod@latest' selects a pseudo-version if all versions are retracted. +# TODO(golang.org/issue/24031): the proxy does not expose the pseudo-version, +# even if all release versions are retracted. +go list -m -e -f '{{.Error.Err}}' example.com/retract/self/pseudo@latest +stdout '^module example.com/retract/self/pseudo: no matching versions for query "latest"$' + +# 'go list -m mod@latest' reports an error if all versions are retracted. +go list -m -e -f '{{.Error.Err}}' example.com/retract/self/all@latest +stdout '^module example.com/retract/self/all: no matching versions for query "latest"$' + +# 'go list -m mod@ ./sub +-- sub/go.mod -- +module sub +hello world diff --git a/src/cmd/go/testdata/script/mod_load_badzip.txt b/src/cmd/go/testdata/script/mod_load_badzip.txt new file mode 100644 index 0000000..65374d2 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_load_badzip.txt @@ -0,0 +1,13 @@ +# Zip files with unexpected file names inside should be rejected. +env GO111MODULE=on + +! go get -d rsc.io/badzip +stderr 'zip for rsc.io/badzip@v1.0.0 has unexpected file rsc.io/badzip@v1.0.0.txt' +! grep rsc.io/badzip go.mod + +go mod edit -require rsc.io/badzip@v1.0.0 +! go build -mod=mod rsc.io/badzip +stderr 'zip for rsc.io/badzip@v1.0.0 has unexpected file rsc.io/badzip@v1.0.0.txt' + +-- go.mod -- +module m diff --git a/src/cmd/go/testdata/script/mod_load_replace_mismatch.txt b/src/cmd/go/testdata/script/mod_load_replace_mismatch.txt new file mode 100644 index 0000000..2ca8b3c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_load_replace_mismatch.txt @@ -0,0 +1,23 @@ +# If a replacement module declares a module path different from both +# the original module and its location, report an error with all three paths. +# In particular, the "required as" path should be the original. +# Verifies golang.org/issue/38220. +! go mod download +cmp stderr want + +-- go.mod -- +module m + +require rsc.io/quote v1.5.2 + +replace rsc.io/quote v1.5.2 => example.com/quote v1.5.2 + +-- use.go -- +package use + +import _ "rsc.io/quote" + +-- want -- +go: rsc.io/quote@v1.5.2 (replaced by example.com/quote@v1.5.2): parsing go.mod: + module declares its path as: rsc.io/Quote + but was required as: rsc.io/quote diff --git a/src/cmd/go/testdata/script/mod_local_replace.txt b/src/cmd/go/testdata/script/mod_local_replace.txt new file mode 100644 index 0000000..19bc8f3 --- /dev/null +++ b/src/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/src/cmd/go/testdata/script/mod_missing_repo.txt b/src/cmd/go/testdata/script/mod_missing_repo.txt new file mode 100644 index 0000000..8dae85f --- /dev/null +++ b/src/cmd/go/testdata/script/mod_missing_repo.txt @@ -0,0 +1,15 @@ +# Regression test for golang.org/issue/34094: modules hosted within gitlab.com +# subgroups could not be fetched because the server returned bogus go-import +# tags for prefixes of the module path. + +[!net] skip +[!exec:git] skip + +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off + +! go get -d vcs-test.golang.org/go/missingrepo/missingrepo-git +stderr 'vcs-test.golang.org/go/missingrepo/missingrepo-git: git ls-remote .*: exit status .*' + +go get -d vcs-test.golang.org/go/missingrepo/missingrepo-git/notmissing diff --git a/src/cmd/go/testdata/script/mod_missingpkg_prerelease.txt b/src/cmd/go/testdata/script/mod_missingpkg_prerelease.txt new file mode 100644 index 0000000..9c250e7 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_missingpkg_prerelease.txt @@ -0,0 +1,17 @@ +env GO111MODULE=on + +! go list -mod=mod -deps use.go +stderr '^use.go:4:2: package example.com/missingpkg/deprecated provided by example.com/missingpkg at latest version v1.0.0 but not at required version v1.0.1-beta$' + +-- go.mod -- +module m + +go 1.14 + +-- use.go -- +package use + +import ( + _ "example.com/missingpkg/deprecated" + _ "example.com/usemissingpre" +) diff --git a/src/cmd/go/testdata/script/mod_modinfo.txt b/src/cmd/go/testdata/script/mod_modinfo.txt new file mode 100644 index 0000000..8d77e22 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_modinfo.txt @@ -0,0 +1,89 @@ +# Test to ensure runtime/debug.ReadBuildInfo parses +# the modinfo embedded in a binary by the go tool +# when module is enabled. +env GO111MODULE=on + +cd x +go mod edit -require=rsc.io/quote@v1.5.2 +go mod edit -replace=rsc.io/quote@v1.5.2=rsc.io/quote@v1.0.0 +go mod tidy # populate go.sum + +# Build a binary and ensure that it can output its own debug info. +# The debug info should be accessible before main starts (golang.org/issue/29628). +go build +exec ./x$GOEXE +stderr 'mod\s+x\s+\(devel\)' +stderr 'dep\s+rsc.io/quote\s+v1.5.2\s+' +stderr '=>\s+rsc.io/quote\s+v1.0.0\s+h1:' +stderr 'Hello, world.' + +[short] skip + +# Build a binary that accesses its debug info by reading the binary directly +# (rather than through debug.ReadBuildInfo). +# The debug info should still be present (golang.org/issue/28753). +cd unused +go build +exec ./unused$GOEXE + +-- x/go.mod -- +module x + +-- x/lib/lib.go -- +// Package lib accesses runtime/debug.modinfo before package main's init +// functions have run. +package lib + +import "runtime/debug" + +func init() { + m, ok := debug.ReadBuildInfo() + if !ok { + panic("failed debug.ReadBuildInfo") + } + println("mod", m.Main.Path, m.Main.Version) + for _, d := range m.Deps { + println("dep", d.Path, d.Version, d.Sum) + if r := d.Replace; r != nil { + println("=>", r.Path, r.Version, r.Sum) + } + } +} + +-- x/main.go -- +package main + +import ( + "rsc.io/quote" + _ "x/lib" +) + +func main() { + println(quote.Hello()) +} + +-- x/unused/main.go -- +// The unused binary does not access runtime/debug.modinfo. +package main + +import ( + "bytes" + "encoding/hex" + "log" + "os" + + _ "rsc.io/quote" +) + +func main() { + b, err := os.ReadFile(os.Args[0]) + if err != nil { + log.Fatal(err) + } + + infoStart, _ := hex.DecodeString("3077af0c9274080241e1c107e6d618e6") + if !bytes.Contains(b, infoStart) { + log.Fatal("infoStart not found in binary") + } + log.Println("ok") +} diff --git a/src/cmd/go/testdata/script/mod_multirepo.txt b/src/cmd/go/testdata/script/mod_multirepo.txt new file mode 100644 index 0000000..0f335a1 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_multirepo.txt @@ -0,0 +1,41 @@ +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 get -d . +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/src/cmd/go/testdata/script/mod_nomod.txt b/src/cmd/go/testdata/script/mod_nomod.txt new file mode 100644 index 0000000..7e0f55a --- /dev/null +++ b/src/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 +! go test +! go vet + +# clean succeeds, even with -modcache +go clean -modcache + +# doc succeeds for standard library +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/src/cmd/go/testdata/script/mod_notall.txt b/src/cmd/go/testdata/script/mod_notall.txt new file mode 100644 index 0000000..1657c8d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_notall.txt @@ -0,0 +1,99 @@ +# This test demonstrates go commands that combine the 'all' pattern +# with packages outside of 'all'. + +# With -deps, 'all' should include test dependencies of packages in the main +# module, but not should not include test dependencies of packages imported only +# by other root patterns. + +env GOFLAGS=-mod=mod +cp go.mod go.mod.orig + +go list -deps all x/otherroot + +stdout '^x/inall$' +stdout '^x/inall/fromtest$' +stdout '^x/inall/fromtestinall$' +stdout '^x/otherroot$' +stdout '^x/otherdep$' + +! stdout '^x/fromotherroottest$' +! stdout '^y/fromotherdeptest$' + +cmp go.mod go.mod.orig + +# With -deps -test, test dependencies of other roots should be included, +# but test dependencies of non-roots should not. + +go list -deps -test all x/otherroot +stdout '^x/inall$' +stdout '^x/inall/fromtest$' +stdout '^x/inall/fromtestinall$' +stdout '^x/otherroot$' +stdout '^x/otherdep$' + +stdout '^x/fromotherroottest$' +! stdout '^y/fromotherdeptest$' + +cmp go.mod go.mod.orig + +-- m.go -- +package m + +import _ "x/inall" +-- m_test.go -- +package m_test + +import _ "x/inall/fromtest" +-- go.mod -- +module m + +go 1.15 + +require x v0.1.0 + +replace ( + x v0.1.0 => ./x + y v0.1.0 => ./y +) +-- x/go.mod -- +module x + +go 1.15 +-- x/inall/inall.go -- +package inall +-- x/inall/inall_test.go -- +package inall_test + +import _ "x/inall/fromtestinall" +-- x/inall/fromtest/fromtest.go -- +package fromtest +-- x/inall/fromtestinall/fromtestinall.go -- +package fromtestinall +-- x/otherroot/otherroot.go -- +package otherroot + +import _ "x/otherdep" +-- x/otherroot/otherroot_test.go -- +package otherroot_test + +import _ "x/fromotherroottest" +-- x/fromotherroottest/fromotherroottest.go -- +package fromotherroottest +-- x/otherdep/otherdep.go -- +package otherdep +-- x/otherdep/otherdep_test.go -- +package otherdep_test + +import _ "y/fromotherdeptest" +-- x/otherroot/testonly/testonly.go -- +package testonly +-- y/go.mod -- +module y + +go 1.15 +-- y/fromotherdeptest/fromotherdeptest.go -- +// Package fromotherdeptest is a test dependency of x/otherdep that is +// not declared in x/go.mod. If the loader resolves this package, +// it will add this module to the main module's go.mod file, +// and we can detect the mistake. +package fromotherdeptest diff --git a/src/cmd/go/testdata/script/mod_off.txt b/src/cmd/go/testdata/script/mod_off.txt new file mode 100644 index 0000000..a73a58d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_off.txt @@ -0,0 +1,35 @@ +env GO111MODULE=off + +# This script tests that running go mod with +# GO111MODULE=off when outside of GOPATH will fatal +# with an error message, even with some source code in the directory and a go.mod. +! go mod init +stderr 'go: modules disabled by GO111MODULE=off; see ''go help modules''' +! go mod graph +stderr 'go: modules disabled by GO111MODULE=off; see ''go help modules''' +! go mod verify +stderr 'go: modules disabled by GO111MODULE=off; see ''go help modules''' +! go mod download +stderr 'go: modules disabled by GO111MODULE=off; see ''go help modules''' + +# Same result in an empty directory +mkdir z +cd z +! go mod init +stderr 'go: modules disabled by GO111MODULE=off; see ''go help modules''' +! go mod graph +stderr 'go: modules disabled by GO111MODULE=off; see ''go help modules''' +! go mod verify +stderr 'go: modules disabled by GO111MODULE=off; see ''go help modules''' +! go mod download +stderr 'go: modules disabled by GO111MODULE=off; see ''go help modules''' + +-- sample.go -- +package sample + +func main() {} + +-- go.mod -- +module sample + +go 1.12 diff --git a/src/cmd/go/testdata/script/mod_off_init.txt b/src/cmd/go/testdata/script/mod_off_init.txt new file mode 100644 index 0000000..2aec0b3 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_off_init.txt @@ -0,0 +1,5 @@ +# 'go mod init' should refuse to initialize a module if it will be +# ignored anyway due to GO111MODULE=off. +env GO111MODULE=off +! go mod init +stderr 'go: modules disabled by GO111MODULE=off; see ''go help modules''' diff --git a/src/cmd/go/testdata/script/mod_outside.txt b/src/cmd/go/testdata/script/mod_outside.txt new file mode 100644 index 0000000..5655892 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_outside.txt @@ -0,0 +1,328 @@ +env GO111MODULE=on +[short] skip + +# This script tests commands in module mode outside of any module. +# +# First, ensure that we really are in module mode, and that we really don't have +# a go.mod file. +go env GOMOD +stdout 'NUL|/dev/null' + + +# 'go list' without arguments implicitly operates on the current directory, +# which is not in a module. +! go list +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' +go list -m +stdout '^command-line-arguments$' +# 'go list' in the working directory should fail even if there is a a 'package +# main' present: without a main module, we do not know its package path. +! go list ./needmod +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + +# 'go list all' lists the transitive import graph of the main module, +# which is empty if there is no main module. +go list all +! stdout . +stderr 'warning: "all" matched no packages' + +# 'go list' on standard-library packages should work, since they do not depend +# on the contents of any module. +go list -deps cmd +stdout '^fmt$' +stdout '^cmd/go$' + +go list $GOROOT/src/fmt +stdout '^fmt$' + +# 'go list' should work with file arguments. +go list ./needmod/needmod.go +stdout 'command-line-arguments' + +# 'go list' on a package from a module should fail. +! go list example.com/printversion +stderr '^no required module provides package example.com/printversion: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + + +# 'go list -m' with an explicit version should resolve that version. +go list -m example.com/version@latest +stdout 'example.com/version v1.1.0' + +# 'go list -m -versions' should succeed even without an explicit version. +go list -m -versions example.com/version +stdout 'v1.0.0\s+v1.0.1\s+v1.1.0' + +# 'go list -m all' should fail. "all" is not meaningful outside of a module. +! go list -m all +stderr 'go: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$' + +# 'go list -m all' should also fail. +! go list -m example.com/printversion@v1.0.0 all +stderr 'go: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$' +! stdout 'example.com/version' + +# 'go list -m' with wildcards should fail. Wildcards match modules in the +# build list, so they aren't meaningful outside a module. +! go list -m ... +stderr 'go: cannot match "...": go.mod file not found in current directory or any parent directory; see ''go help modules''$' +! go list -m rsc.io/quote/... +stderr 'go: cannot match "rsc.io/quote/...": go.mod file not found in current directory or any parent directory; see ''go help modules''$' + + +# 'go clean' should skip the current directory if it isn't in a module. +go clean -n +! stdout . +! stderr . + +# 'go mod graph' should fail, since there's no module graph. +! go mod graph +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + +# 'go mod why' should fail, since there is no main module to depend on anything. +! go mod why -m example.com/version +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + +# 'go mod edit', 'go mod tidy', and 'go mod fmt' should fail: +# there is no go.mod file to edit. +! go mod tidy +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' +! go mod edit -fmt +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' +! go mod edit -require example.com/version@v1.0.0 +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + + +# 'go mod download' without arguments should report an error. +! go mod download +stderr 'no modules specified' + +# 'go mod download' should download exactly the requested module without dependencies. +rm -r $GOPATH/pkg/mod/cache/download/example.com +go mod download example.com/printversion@v1.0.0 +exists $GOPATH/pkg/mod/cache/download/example.com/printversion/@v/v1.0.0.zip +! exists $GOPATH/pkg/mod/cache/download/example.com/version/@v/v1.0.0.zip + +# 'go mod download all' should fail. "all" is not meaningful outside of a module. +! go mod download all +stderr 'go: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$' + + +# 'go mod vendor' should fail: it starts by clearing the existing vendor +# directory, and we don't know where that is. +! go mod vendor +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + + +# 'go mod verify' should fail: we have no modules to verify. +! go mod verify +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + + +# 'go get' without arguments implicitly operates on the main module, and thus +# should fail. +! go get +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' +! go get -u +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' +! go get -u ./needmod +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + +# 'go get -u all' upgrades the transitive import graph of the main module, +# which is empty. +! go get -u all +stderr '^go get: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$' + +# 'go get' should check the proposed module graph for consistency, +# even though we won't write it anywhere. +! go get -d example.com/printversion@v1.0.0 example.com/version@none +stderr '^go get: example.com/printversion@v1.0.0 requires example.com/version@v1.0.0, not example.com/version@none$' + +# 'go get -d' should download and extract the source code needed to build the requested version. +rm -r $GOPATH/pkg/mod/example.com +go get -d example.com/printversion@v1.0.0 +exists $GOPATH/pkg/mod/example.com/printversion@v1.0.0 +exists $GOPATH/pkg/mod/example.com/version@v1.0.0 + + +# 'go build' without arguments implicitly operates on the current directory, and should fail. +cd needmod +! go build +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' +cd .. + +# 'go build' of a non-module directory should fail too. +! go build ./needmod +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + +# 'go build' of source files should fail if they import anything outside std. +! go build -n ./needmod/needmod.go +stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + +# 'go build' of source files should succeed if they do not import anything outside std. +go build -n -o ignore ./stdonly/stdonly.go + +# 'go build' should succeed for standard-library packages. +go build -n fmt + + +# 'go doc' without arguments implicitly operates on the current directory, and should fail. +# TODO(golang.org/issue/32027): currently, it succeeds. +cd needmod +go doc +cd .. + +# 'go doc' of a non-module directory should also succeed. +go doc ./needmod + +# 'go doc' should succeed for standard-library packages. +go doc fmt + +# 'go doc' should fail for a package path outside a module. +! go doc example.com/version +stderr 'doc: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + +# 'go install' with a version should succeed if all constraints are met. +# See mod_install_pkg_version. +rm $GOPATH/bin +go install example.com/printversion@v0.1.0 +exists $GOPATH/bin/printversion$GOEXE + +# 'go install' should fail if a package argument must be resolved to a module. +! go install example.com/printversion +stderr '^go install: version is required when current directory is not in a module\n\tTry ''go install example.com/printversion@latest'' to install the latest version$' + +# 'go install' should fail if a source file imports a package that must be +# resolved to a module. +! go install ./needmod/needmod.go +stderr 'needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + +# 'go install' should succeed with a package in GOROOT. +go install cmd/addr2line +! stderr . + +# 'go run' with a verison should fail due to syntax. +! go run example.com/printversion@v1.0.0 +stderr 'can only use path@version syntax with' + +# 'go run' should fail if a package argument must be resolved to a module. +! go run example.com/printversion +stderr '^no required module provides package example.com/printversion: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + +# 'go run' should fail if a source file imports a package that must be +# resolved to a module. +! go run ./needmod/needmod.go +stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$' + + +# 'go fmt' should be able to format files outside of a module. +go fmt needmod/needmod.go + + +# The remainder of the test checks dependencies by linking and running binaries. + +# 'go get' of a binary without a go.mod should install the requested version, +# resolving outside dependencies to the latest available versions. +go get example.com/printversion@v0.1.0 +exec ../bin/printversion +stdout 'path is example.com/printversion' +stdout 'main is example.com/printversion v0.1.0' +stdout 'using example.com/version v1.1.0' + +# 'go get' of a versioned binary should build and install the latest version +# using its minimal required modules, ignoring replacements and exclusions. +go get example.com/printversion +exec ../bin/printversion +stdout 'path is example.com/printversion' +stdout 'main is example.com/printversion v1.0.0' +stdout 'using example.com/version v1.0.0' + +# 'go get -u=patch' should patch dependencies before installing, +# again ignoring replacements and exclusions. +go get -u=patch example.com/printversion@v1.0.0 +exec ../bin/printversion +stdout 'path is example.com/printversion' +stdout 'main is example.com/printversion v1.0.0' +stdout 'using example.com/version v1.0.1' + +# 'go run' should work with file arguments if they don't import anything +# outside std. +go run ./stdonly/stdonly.go +stdout 'path is command-line-arguments$' +stdout 'main is command-line-arguments \(devel\)' + +# 'go generate' should work with file arguments. +[exec:touch] go generate ./needmod/needmod.go +[exec:touch] exists ./needmod/gen.txt + +# 'go install' should work with file arguments. +go install ./stdonly/stdonly.go + +# 'go test' should work with file arguments. +go test -v ./stdonly/stdonly_test.go +stdout 'stdonly was tested' + +# 'go vet' should work with file arguments. +go vet ./stdonly/stdonly.go + + +-- README.txt -- +There is no go.mod file in the working directory. + +-- needmod/needmod.go -- +//go:generate touch gen.txt + +package main + +import ( + "fmt" + "os" + "runtime/debug" + + _ "example.com/version" +) + +func main() { + info, ok := debug.ReadBuildInfo() + if !ok { + panic("missing build info") + } + fmt.Fprintf(os.Stdout, "path is %s\n", info.Path) + fmt.Fprintf(os.Stdout, "main is %s %s\n", info.Main.Path, info.Main.Version) + for _, m := range info.Deps { + fmt.Fprintf(os.Stdout, "using %s %s\n", m.Path, m.Version) + } +} + +-- stdonly/stdonly.go -- +package main + +import ( + "fmt" + "os" + "runtime/debug" +) + +func main() { + info, ok := debug.ReadBuildInfo() + if !ok { + panic("missing build info") + } + fmt.Fprintf(os.Stdout, "path is %s\n", info.Path) + fmt.Fprintf(os.Stdout, "main is %s %s\n", info.Main.Path, info.Main.Version) + for _, m := range info.Deps { + fmt.Fprintf(os.Stdout, "using %s %s\n", m.Path, m.Version) + } +} + +-- stdonly/stdonly_test.go -- +package main + +import ( + "fmt" + "testing" +) + +func Test(t *testing.T) { + fmt.Println("stdonly was tested") +} + diff --git a/src/cmd/go/testdata/script/mod_overlay.txt b/src/cmd/go/testdata/script/mod_overlay.txt new file mode 100644 index 0000000..92e79c7 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_overlay.txt @@ -0,0 +1,254 @@ +# Test overlays that affect go.mod files + +# The go.mod file can exist only in the overlay. +cd $WORK/gopath/src/no-go-mod +go list -overlay overlay.json . +stdout example.com/simple + +# Check content of overlaid go.mod is used. +cd $WORK/gopath/src/overlay-go-mod +go list -overlay overlay.json . +stdout use.this/module/name + +# Check content of overlaid go.mod in a replacement module is used. +# The go.mod in the replacement module is missing a requirement +# that the overlay has, so it will fail to list without the overlay. +cd $WORK/gopath/src/overlay-replaced-go-mod +! go list -deps . +go list -deps -overlay overlay.json . + +# Overlaid go.mod is not rewritten by 'go get'. +cd $WORK/gopath/src/get-doesnt-add-dep +cp $WORK/overlay/get_doesnt_add_dep_go_mod $WORK/want_go_mod +! go get -d -overlay overlay.json . +stderr 'overlaid files can''t be opened for write' +cmp $WORK/overlay/get_doesnt_add_dep_go_mod $WORK/want_go_mod + +# Content of overlaid go.sum is used. +# The go.sum in the module directory has garbage values for its +# hashes, but the overlaid file has the correct values. If +# the correct go.sum is used with the overlay, 'go get .' should +# not report a security error. +cd $WORK/gopath/src/overlay-sum-used +! go get -d . +stderr 'SECURITY ERROR' +! go mod verify +stderr 'SECURITY ERROR' +go get -d -overlay overlay.json . +go mod verify -overlay overlay.json +# Overlaid go.sum is not rewritten. +# Copy an incomplete file to the overlay file, and expect an error +# attempting to update the file +cp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums +! go get -d -overlay overlay.json . +stderr 'overlaid files can''t be opened for write' +cmp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums +! go mod tidy -overlay overlay.json +stderr 'overlaid files can''t be opened for write' +cmp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums + +# -overlay works with -modfile. +# There's an empty go.mod file in the directory, and the file alternate.mod is +# overlaid to the true go.mod file, so the -modfile flag and the overlay +# mechanism need to work together to determine the name of the module. +cd $WORK/gopath/src/overlay-and-dash-modfile +go list -modfile=alternate.mod -overlay overlay.json . +stdout 'found.the/module' +# Even with -modfile, overlaid files can't be opened for write. +! go get -modfile=alternate.mod -overlay overlay.json -d rsc.io/quote +stderr 'overlaid files can''t be opened for write' + +# Carving out a module by adding an overlaid go.mod file +cd $WORK/gopath/src/carve +go list ./... # without an overlay, hasmod is carved out and nomod isn't +stdout carve/nomod +! stdout carve/hasmod +go list -overlay overlay_carve_module.json ./... # The overlay carves out nomod, leaving nothing +! stdout . +stderr 'matched no packages' +go list -overlay overlay_uncarve_module.json ./... # The overlay uncarves out hasmod +stdout carve/nomod +stdout carve/hasmod + +# Carving out a module by adding an overlaid go.mod file and using +# -modfile to write to that file. +cd $WORK/gopath/src/carve2/nomod +go list -overlay overlay.json all +! stdout ^carve2$ +stdout ^carve2/nomod$ +# Editing go.mod file fails because overlay is read only +! go get -overlay overlay.json -d rsc.io/quote +stderr 'overlaid files can''t be opened for write' +! grep rsc.io/quote $WORK/overlay/carve2-nomod-go.mod +# Editing go.mod file succeeds because we use -modfile to redirect to same file +go get -overlay overlay.json -modfile $WORK/overlay/carve2-nomod-go.mod -d rsc.io/quote +grep rsc.io/quote $WORK/overlay/carve2-nomod-go.mod + +-- no-go-mod/file.go -- +package simple +-- no-go-mod/overlay.json -- +{ + "Replace": { + "go.mod": "../../../overlay/simple_go_mod" + } +} +-- $WORK/overlay/simple_go_mod -- +module example.com/simple +-- overlay-go-mod/file.go -- +package name +-- overlay-go-mod/go.mod -- +module dont.use/this/module/name +-- overlay-go-mod/overlay.json -- +{ + "Replace": { + "go.mod": "../../../overlay/use_this_go_mod" + } +} +-- $WORK/overlay/use_this_go_mod -- +module use.this/module/name +-- overlay-replaced-go-mod/go.mod -- +module m + +go 1.15 + +require replaced/mod v1.0.0 +replace replaced/mod v1.0.0 => ../replaced-mod +replace dep/mod v1.0.0 => ../dep-mod +-- overlay-replaced-go-mod/source.go -- +package m + +import "replaced/mod/foo" + +func main() { + foo.f() +} +-- overlay-replaced-go-mod/overlay.json -- +{ + "Replace": { + "../replaced-mod/go.mod": "../../../overlay/replacement_module_go_mod" + } +} +-- replaced-mod/go.mod -- +module replaced/mod +-- replaced-mod/foo/foo.go -- +package foo + +import "dep/mod/foo" + +func f() { foo.g() } +-- dep-mod/go.mod -- +invalid +-- dep-mod/foo/foo.go -- +package foo + +func g() { fmt.Println("hello") } +-- $WORK/overlay/replacement_module_go_mod -- +module replaced/mod + +require dep/mod v1.0.0 + +-- get-doesnt-add-dep/overlay.json -- +{ + "Replace": { + "go.mod": "../../../overlay/get_doesnt_add_dep_go_mod" + } +} +-- get-doesnt-add-dep/p.go -- +package p + +import "dependency/mod" + +func f() { mod.G() } +-- get-doesnt-add-dep-dependency/go.mod -- +module dependency/mod +-- get-doesnt-add-dep-dependency/mod.go -- +package mod + +func G() {} +-- $WORK/overlay/get_doesnt_add_dep_go_mod -- +module get.doesnt/add/dep + +replace dependency/mod v1.0.0 => ../get-doesnt-add-dep-dependency +-- overlay-sum-used/go.mod -- +module overlay.sum/used + +require rsc.io/quote v1.5.0 +-- overlay-sum-used/p.go -- +package p + +import "rsc.io/quote" + +func f() string { + return quote.Hello() +} +-- overlay-sum-used/incomplete-sum-file -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw= +rsc.io/quote v1.5.0 h1:6fJa6E+wGadANKkUMlZ0DhXFpoKlslOQDCo259XtdIE= +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +-- overlay-sum-used/overlay.json -- +{ + "Replace": { + "go.sum": "../../../overlay/overlay-sum-used-correct-sums" + } +} +-- overlay-sum-used/go.sum -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:garbage+hash +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:garbage+hash +rsc.io/quote v1.5.0 h1:garbage+hash +rsc.io/quote v1.5.0/go.mod h1:garbage+hash +rsc.io/sampler v1.3.0 h1:garbage+hash +rsc.io/sampler v1.3.0/go.mod h1:garbage+hash +-- $WORK/overlay/overlay-sum-used-correct-sums -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.0 h1:6fJa6E+wGadANKkUMlZ0DhXFpoKlslOQDCo259XtdIE= +rsc.io/quote v1.5.0/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +-- overlay-and-dash-modfile/p.go -- +package module +-- overlay-and-dash-modfile/go.mod -- +-- overlay-and-dash-modfile/overlay.json -- +{ + "Replace": { + "alternate.mod": "../../../overlay/overlay-and-dash-modfile-alternate-mod" + } +} +-- $WORK/overlay/overlay-and-dash-modfile-alternate-mod -- +module found.the/module +-- carve/go.mod -- +module carve +-- carve/overlay_carve_module.json -- +{ + "Replace": { + "nomod/go.mod": "../../../overlay/carve-nomod-go-mod" + } +} +-- carve/overlay_uncarve_module.json -- +{ + "Replace": { + "hasmod/go.mod": "" + } +} +-- carve/hasmod/a.go -- +package hasmod +-- carve/hasmod/go.mod -- +module carve/hasmod +-- carve/nomod/b.go -- +package nomod +-- $WORK/overlay/carve-nomod-go-mod -- +module carve/nomod +-- carve2/go.mod -- +module carve2 +-- carve2/p.go -- +package p +-- carve2/nomod/overlay.json -- +{ + "Replace": { + "go.mod": "../../../../overlay/carve2-nomod-go.mod" + } +} +-- carve2/nomod/b.go -- +package nomod +-- $WORK/overlay/carve2-nomod-go.mod -- +module carve2/nomod diff --git a/src/cmd/go/testdata/script/mod_patterns.txt b/src/cmd/go/testdata/script/mod_patterns.txt new file mode 100644 index 0000000..1b4b438 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_patterns.txt @@ -0,0 +1,78 @@ +env GO111MODULE=on +[short] skip + +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. +# +# '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 "./..." +stdout '^unicode: \[all \.\.\.\]' +stdout '^unsafe: \[all \.\.\.\]' +stdout 'index/suffixarray: \[\.\.\.\]' +stdout 'cmd/pprof: \[\.\.\.\]' + +stderr -count=1 '^go: warning: "./xyz..." matched no packages$' + +# 'go list ./...' should not try to resolve the main module. +cd ../empty +go list -deps ./... +! stdout . +! stderr 'finding' +stderr -count=1 '^go: warning: "./..." matched no packages' + +# disabling cgo should drop useC +[short] skip +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" + +-- empty/go.mod -- +module example.com/empty diff --git a/src/cmd/go/testdata/script/mod_patterns_vendor.txt b/src/cmd/go/testdata/script/mod_patterns_vendor.txt new file mode 100644 index 0000000..b4dc401 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_patterns_vendor.txt @@ -0,0 +1,28 @@ +env GO111MODULE=on + +go list -mod=vendor example.com/... +stdout ^example.com/x$ +stdout ^example.com/x/y$ +! stdout ^example.com/x/vendor + +-- go.mod -- +module example.com/m + +-- vendor/modules.txt -- +# example.com/x v0.0.0 +example.com/x +# example.com/x/y v0.1.0 +example.com/x/y + +-- vendor/example.com/x/go.mod -- +module example.com/x +-- vendor/example.com/x/x.go -- +package x + +-- vendor/example.com/x/y/go.mod -- +module example.com/x/y +-- vendor/example.com/x/y/y.go -- +package y + +-- vendor/example.com/x/vendor/z/z.go -- +package z diff --git a/src/cmd/go/testdata/script/mod_permissions.txt b/src/cmd/go/testdata/script/mod_permissions.txt new file mode 100644 index 0000000..2d32dcd --- /dev/null +++ b/src/cmd/go/testdata/script/mod_permissions.txt @@ -0,0 +1,57 @@ +# Regression test for golang.org/issue/34634: permissions for the go.sum and +# go.mod files should be preserved when overwriting them. + +env GO111MODULE=on +[short] skip + +# Skip platforms that do not have Unix-style file permissions. +[windows] skip +[plan9] skip + +chmod 0640 go.mod +chmod 0604 go.sum +go mod edit -module=golang.org/issue/34634 + +go get -d +cmp go.mod go.mod.want +cmp go.sum go.sum.want + +go run . +stdout 'go.mod: 0640' +stdout 'go.sum: 0604' + +-- read_perm.go -- +package main + +import ( + "fmt" + "os" + _ "rsc.io/sampler" +) + +func main() { + for _, name := range []string{"go.mod", "go.sum"} { + fi, err := os.Stat(name) + if err != nil { + fmt.Fprintf(os.Stderr, "%s: %v\n", err) + continue + } + fmt.Printf("%s: 0%o\n", name, fi.Mode().Perm()) + } +} +-- go.mod -- +module TODO + +go 1.14 +-- go.sum -- +-- go.mod.want -- +module golang.org/issue/34634 + +go 1.14 + +require rsc.io/sampler v1.99.99 +-- go.sum.want -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/sampler v1.99.99 h1:iMG9lbEG/8MdeR4lgL+Q8IcwbLNw7ijW7fTiK8Miqts= +rsc.io/sampler v1.99.99/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/src/cmd/go/testdata/script/mod_prefer_compatible.txt b/src/cmd/go/testdata/script/mod_prefer_compatible.txt new file mode 100644 index 0000000..aa6260f --- /dev/null +++ b/src/cmd/go/testdata/script/mod_prefer_compatible.txt @@ -0,0 +1,65 @@ +# Regression test for golang.org/issue/34189 and golang.org/issue/34165: +# @latest, @upgrade, and @patch should prefer compatible versions over +# +incompatible ones, even if offered by a proxy. + +[!net] skip + +env GO111MODULE=on +env GOPROXY= +env GOSUMDB= + +# github.com/russross/blackfriday v2.0.0+incompatible exists, +# and should be resolved if we ask for v2.0 explicitly. + +go list -m github.com/russross/blackfriday@v2.0 +stdout '^github.com/russross/blackfriday v2\.0\.0\+incompatible$' + +# blackfriday v1.5.2 has a go.mod file, so v1.5.2 should be preferred over +# v2.0.0+incompatible when resolving latest, upgrade, and patch. + +go list -m github.com/russross/blackfriday@latest +stdout '^github.com/russross/blackfriday v1\.' + +go list -m github.com/russross/blackfriday@upgrade +stdout '^github.com/russross/blackfriday v1\.' + +go list -m github.com/russross/blackfriday@patch +stdout '^github.com/russross/blackfriday v1\.' + +# If we're fetching directly from version control, ignored +incompatible +# versions should also be omitted by 'go list'. + +# (Note that they may still be included in results from a proxy: in proxy mode, +# we would need to fetch the whole zipfile for the latest compatible version in +# order to determine whether it contains a go.mod file, and part of the point of +# the proxy is to avoid fetching unnecessary data.) + +[!exec:git] stop +env GOPROXY=direct + +go list -versions -m github.com/russross/blackfriday github.com/russross/blackfriday +stdout '^github.com/russross/blackfriday v1\.5\.1 v1\.5\.2' # and possibly others +! stdout ' v2\.' + +# However, if the latest compatible version does not include a go.mod file, +# +incompatible versions should still be listed, as they may still reflect the +# intent of the module author. + +go list -versions -m github.com/rsc/legacytest +stdout '^github.com/rsc/legacytest v1\.0\.0 v1\.1\.0-pre v1\.2\.0 v2\.0\.0\+incompatible' + +# If we're fetching directly from version control, asking for a commit hash +# corresponding to a +incompatible version should continue to produce the +# +incompatible version tagged for that commit, even if it is no longer listed. + +go list -m github.com/russross/blackfriday@cadec560ec52 +stdout '^github.com/russross/blackfriday v2\.0\.0\+incompatible$' + +# Similarly, requesting an untagged commit should continue to produce a +incompatible +# pseudo-version. + +go list -m github.com/rsc/legacytest@7303f7796364 +stdout '^github.com/rsc/legacytest v2\.0\.1-0\.20180717164253-7303f7796364\+incompatible$' + +-- go.mod -- +module github.com/golang.org/issue/34165 diff --git a/src/cmd/go/testdata/script/mod_proxy_errors.txt b/src/cmd/go/testdata/script/mod_proxy_errors.txt new file mode 100644 index 0000000..9cd1a82 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_proxy_errors.txt @@ -0,0 +1,19 @@ +[!net] skip + +env GO111MODULE=on +env GOSUMDB=off +env GOPROXY=direct + +# Server responses should be truncated to some reasonable number of lines. +# (For now, exactly eight.) +! go list -m vcs-test.golang.org/auth/ormanylines@latest +stderr '\tserver response:\n(.|\n)*\tline 8\n\t\[Truncated: too many lines.\]$' + +# Server responses should be truncated to some reasonable number of characters. +! go list -m vcs-test.golang.org/auth/oronelongline@latest +! stderr 'blah{40}' +stderr '\tserver response: \[Truncated: too long\.\]$' + +# Responses from servers using the 'mod' protocol should be propagated. +! go list -m vcs-test.golang.org/go/modauth404@latest +stderr '\tserver response: File\? What file\?' diff --git a/src/cmd/go/testdata/script/mod_proxy_https.txt b/src/cmd/go/testdata/script/mod_proxy_https.txt new file mode 100644 index 0000000..a23090c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_proxy_https.txt @@ -0,0 +1,19 @@ +env GO111MODULE=on + +# GOPROXY file paths must provide the "file://" prefix explicitly. +env GOPROXY=$WORK/proxydir +! go list -versions -m golang.org/x/text +stderr 'invalid proxy URL.*proxydir' + +[!net] stop + +# GOPROXY HTTPS paths may elide the "https://" prefix. +# (See golang.org/issue/32191.) +env GOPROXY=proxy.golang.org +go list -versions -m golang.org/x/text + +-- go.mod -- +module example.com +go 1.13 +-- $WORK/proxydir/README.md -- +This proxy contains no data. diff --git a/src/cmd/go/testdata/script/mod_proxy_invalid.txt b/src/cmd/go/testdata/script/mod_proxy_invalid.txt new file mode 100644 index 0000000..6427cc1 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_proxy_invalid.txt @@ -0,0 +1,8 @@ +env GO111MODULE=on +env GOPROXY=$GOPROXY/invalid + +! go list -m rsc.io/quote@latest +stderr '^go list -m: module rsc.io/quote: invalid response from proxy "'$GOPROXY'": invalid character ''i'' looking for beginning of value$' + +! go list -m rsc.io/quote@1.5.2 +stderr '^go list -m: rsc.io/quote@1.5.2: invalid version: invalid response from proxy "'$GOPROXY'": invalid character ''i'' looking for beginning of value$' diff --git a/src/cmd/go/testdata/script/mod_proxy_list.txt b/src/cmd/go/testdata/script/mod_proxy_list.txt new file mode 100644 index 0000000..89129f4 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_proxy_list.txt @@ -0,0 +1,37 @@ +env GO111MODULE=on +env proxy=$GOPROXY + +# Proxy that can't serve should fail. +env GOPROXY=$proxy/404 +! go get -d rsc.io/quote@v1.0.0 +stderr '404 Not Found' + +# get should walk down the proxy list past 404 and 410 responses. +env GOPROXY=$proxy/404,$proxy/410,$proxy +go get -d rsc.io/quote@v1.1.0 + +# get should not walk past other 4xx errors if proxies are separated with ','. +env GOPROXY=$proxy/403,$proxy +! go get -d rsc.io/quote@v1.2.0 +stderr 'reading.*/403/rsc.io/.*: 403 Forbidden' + +# get should not walk past non-4xx errors if proxies are separated with ','. +env GOPROXY=$proxy/500,$proxy +! go get -d rsc.io/quote@v1.3.0 +stderr 'reading.*/500/rsc.io/.*: 500 Internal Server Error' + +# get should walk past other 4xx errors if proxies are separated with '|'. +env GOPROXY=$proxy/403|https://0.0.0.0|$proxy +go get -d rsc.io/quote@v1.2.0 + +# get should walk past non-4xx errors if proxies are separated with '|'. +env GOPROXY=$proxy/500|https://0.0.0.0|$proxy +go get -d rsc.io/quote@v1.3.0 + +# get should return the final error if that's all we have. +env GOPROXY=$proxy/404,$proxy/410 +! go get -d rsc.io/quote@v1.4.0 +stderr 'reading.*/410/rsc.io/.*: 410 Gone' + +-- go.mod -- +module x diff --git a/src/cmd/go/testdata/script/mod_pseudo_cache.txt b/src/cmd/go/testdata/script/mod_pseudo_cache.txt new file mode 100644 index 0000000..dd89614 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_pseudo_cache.txt @@ -0,0 +1,29 @@ +[!net] skip +[!exec:git] skip + +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off + +# Regression test for golang.org/issue/27171: after resolving an older +# pseudo-version of a commit, future resolution of that commit by hash should +# choose the highest appropriate pseudo-version instead of the cached one. + +go mod download -json golang.org/x/text@v0.0.0-20171215141712-a1b916ed6726 +stdout '"Version": "v0.0.0-20171215141712-a1b916ed6726",' + +# If GOPROXY is 'off', lookups should use whatever pseudo-version is available. +env GOPROXY=off +go mod download -json golang.org/x/text@a1b916ed6726 +stdout '"Version": "v0.0.0-20171215141712-a1b916ed6726",' + +# If we can re-resolve the commit to a pseudo-version, fetching the commit by +# hash should use the highest such pseudo-version appropriate to the commit. +env GOPROXY=direct +go mod download -json golang.org/x/text@a1b916ed6726 +stdout '"Version": "v0.3.1-0.20171215141712-a1b916ed6726",' + +# If GOPROXY is 'off', lookups should use the highest pseudo-version in the cache. +env GOPROXY=off +go mod download -json golang.org/x/text@a1b916ed6726 +stdout '"Version": "v0.3.1-0.20171215141712-a1b916ed6726",' diff --git a/src/cmd/go/testdata/script/mod_query.txt b/src/cmd/go/testdata/script/mod_query.txt new file mode 100644 index 0000000..a75f86e --- /dev/null +++ b/src/cmd/go/testdata/script/mod_query.txt @@ -0,0 +1,43 @@ +env GO111MODULE=on + +# TODO(golang.org/issue/41297): we shouldn't need go.sum. None of the commands +# below depend on the build list. + +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$' + +# Same for rsc.io/quote@v1 and rsc.io/quote@v1.5 (with no patch version). +go list -m rsc.io/quote@v1 +stdout 'rsc.io/quote v1.5.2$' +go list -m rsc.io/quote@v1.5 +stdout 'rsc.io/quote v1.5.2$' + +# We should fall back to prereleases if no release tags match... +go list -m rsc.io/quote@>v1.5.2 +stdout 'rsc.io/quote v1.5.3-pre1$' + +# ...but prefer release versions when given the option. +go list -m rsc.io/quote@v1.5.3 +stderr 'go list -m: module 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 + +-- go.sum -- +rsc.io/quote v1.0.0 h1:kQ3IZQzPTiDJxSZI98YaWgxFEhlNdYASHvh+MplbViw= +rsc.io/quote v1.0.0/go.mod h1:v83Ri/njykPcgJltBc/gEkJTmjTsNgtO1Y7vyIK1CQA= +-- use.go -- +package use + +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_query_empty.txt b/src/cmd/go/testdata/script/mod_query_empty.txt new file mode 100644 index 0000000..f8b6e3e --- /dev/null +++ b/src/cmd/go/testdata/script/mod_query_empty.txt @@ -0,0 +1,73 @@ +env GO111MODULE=on +env GOSUMDB=off + +go mod download example.com/join@v1.1.0 + +# If the proxy serves a bogus result for the @latest version, +# reading that version should cause 'go get' to fail. +env GOPROXY=file:///$WORK/badproxy +cp go.mod.orig go.mod +! go get -d example.com/join/subpkg +stderr 'go get: example.com/join/subpkg@v0.0.0-20190624000000-123456abcdef: .*' + +# If @v/list is empty, the 'go' command should still try to resolve +# other module paths. +env GOPROXY=file:///$WORK/emptysub +cp go.mod.orig go.mod +go get -d example.com/join/subpkg +go list -m example.com/join/... +! stdout 'example.com/join/subpkg' +stdout 'example.com/join v1.1.0' + +# If @v/list includes a version that the proxy does not actually serve, +# that version is treated as nonexistent. +env GOPROXY=file:///$WORK/notfound +cp go.mod.orig go.mod +go get -d example.com/join/subpkg +go list -m example.com/join/... +! stdout 'example.com/join/subpkg' +stdout 'example.com/join v1.1.0' + +# If the proxy provides an empty @v/list but rejects @latest with +# some other explicit error (for example, a "permission denied" error), +# that error should be reported to the user (and override a successful +# result for other possible module paths). +# +# Depending on how the specific platform enforces permissions, the 'go get' may +# fail either due to the intended permission error or due to a parse error. +# We accept either failure message. +env GOPROXY=file:///$WORK/gatekeeper +chmod 0000 $WORK/gatekeeper/example.com/join/subpkg/@latest +cp go.mod.orig go.mod +! go get -d example.com/join/subpkg +stderr 'go get: module example.com/join/subpkg: (invalid response from proxy ".+": invalid character .+|reading file://.*/gatekeeper/example.com/join/subpkg/@latest: .+)' + +-- go.mod.orig -- +module example.com/othermodule +go 1.13 +-- $WORK/badproxy/example.com/join/subpkg/@v/list -- +v0.0.0-20190624000000-123456abcdef +-- $WORK/badproxy/example.com/join/subpkg/@v/v0.0.0-20190624000000-123456abcdef.info -- +This file is not valid JSON. +-- $WORK/badproxy/example.com/join/@v/list -- +v1.1.0 +-- $WORK/badproxy/example.com/join/@v/v1.1.0.info -- +{"Version": "v1.1.0"} +-- $WORK/emptysub/example.com/join/subpkg/@v/list -- +-- $WORK/emptysub/example.com/join/@v/list -- +v1.1.0 +-- $WORK/emptysub/example.com/join/@v/v1.1.0.info -- +{"Version": "v1.1.0"} +-- $WORK/notfound/example.com/join/subpkg/@v/list -- +v1.0.0-does-not-exist +-- $WORK/notfound/example.com/join/@v/list -- +v1.1.0 +-- $WORK/notfound/example.com/join/@v/v1.1.0.info -- +{"Version": "v1.1.0"} +-- $WORK/gatekeeper/example.com/join/subpkg/@v/list -- +-- $WORK/gatekeeper/example.com/join/subpkg/@latest -- +ERROR: Latest version is forbidden. +-- $WORK/gatekeeper/example.com/join/@v/list -- +v1.1.0 +-- $WORK/gatekeeper/example.com/join/@v/v1.1.0.info -- +{"Version": "v1.1.0"} diff --git a/src/cmd/go/testdata/script/mod_query_exclude.txt b/src/cmd/go/testdata/script/mod_query_exclude.txt new file mode 100644 index 0000000..b001969 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_query_exclude.txt @@ -0,0 +1,46 @@ +env GO111MODULE=on + +# list excluded version +go list -modfile=go.exclude.mod -m rsc.io/quote@v1.5.0 +stdout '^rsc.io/quote v1.5.0$' + +# list versions should not print excluded versions +go list -m -versions rsc.io/quote +stdout '\bv1.5.0\b' +go list -modfile=go.exclude.mod -m -versions rsc.io/quote +! stdout '\bv1.5.0\b' + +# list query with excluded version +go list -m rsc.io/quote@>=v1.5 +stdout '^rsc.io/quote v1.5.0$' +go list -modfile=go.exclude.mod -m rsc.io/quote@>=v1.5 +stdout '^rsc.io/quote v1.5.1$' + +# get excluded version +cp go.exclude.mod go.exclude.mod.orig +! go get -modfile=go.exclude.mod -d rsc.io/quote@v1.5.0 +stderr '^go get: rsc.io/quote@v1.5.0: excluded by go.mod$' + +# get non-excluded version +cp go.exclude.mod.orig go.exclude.mod +go get -modfile=go.exclude.mod -d rsc.io/quote@v1.5.1 +stderr 'rsc.io/quote v1.5.1' + +# get query with excluded version +cp go.exclude.mod.orig go.exclude.mod +go get -modfile=go.exclude.mod -d rsc.io/quote@>=v1.5 +go list -modfile=go.exclude.mod -m ...quote +stdout 'rsc.io/quote v1.5.[1-9]' + +-- go.mod -- +module x + +-- go.exclude.mod -- +module x + +exclude rsc.io/quote v1.5.0 + +-- x.go -- +package x +import _ "rsc.io/quote" + diff --git a/src/cmd/go/testdata/script/mod_query_main.txt b/src/cmd/go/testdata/script/mod_query_main.txt new file mode 100644 index 0000000..39e5841 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_query_main.txt @@ -0,0 +1,43 @@ +# 'go mod download' can download specific versions of the main module. +go mod download rsc.io/quote@5d9f230b +go mod download rsc.io/quote@v1.5.2 +go mod download rsc.io/quote@latest + +# 'go mod download' will not download @upgrade or @patch, since they always +# resolve to the main module. +go mod download rsc.io/quote@upgrade +stderr '^go mod download: skipping argument rsc.io/quote@upgrade that resolves to the main module$' +go mod download rsc.io/quote@patch +stderr '^go mod download: skipping argument rsc.io/quote@patch that resolves to the main module$' + +# 'go list -m' can show a version of the main module. +go list -m rsc.io/quote@5d9f230b +stdout '^rsc.io/quote v0.0.0-20180710144737-5d9f230bcfba$' +go list -m rsc.io/quote@v1.5.2 +stdout '^rsc.io/quote v1.5.2$' +go list -m rsc.io/quote@latest +stdout '^rsc.io/quote v1.5.2$' + +# 'go list -m -versions' shows available versions. +go list -m -versions rsc.io/quote +stdout '^rsc.io/quote.*v1.5.2' + +# 'go list -m' resolves @upgrade and @patch to the main module. +go list -m rsc.io/quote@upgrade +stdout '^rsc.io/quote$' +go list -m rsc.io/quote@patch +stdout '^rsc.io/quote$' + +# 'go get' will not attempt to upgrade the main module to any specific version. +# See also: mod_get_main.txt. +! go get rsc.io/quote@5d9f230b +stderr '^go get: can''t request version "5d9f230b" of the main module \(rsc.io/quote\)$' +! go get rsc.io/quote@v1.5.2 +stderr '^go get: can''t request version "v1.5.2" of the main module \(rsc.io/quote\)$' +! go get rsc.io/quote@latest +stderr '^go get: can''t request version "latest" of the main module \(rsc.io/quote\)$' + +-- go.mod -- +module rsc.io/quote + +go 1.16 diff --git a/src/cmd/go/testdata/script/mod_readonly.txt b/src/cmd/go/testdata/script/mod_readonly.txt new file mode 100644 index 0000000..d05ad2a --- /dev/null +++ b/src/cmd/go/testdata/script/mod_readonly.txt @@ -0,0 +1,131 @@ +env GO111MODULE=on +[short] skip + +# -mod=readonly must not resolve missing modules nor update go.mod +env GOFLAGS=-mod=readonly +go mod edit -fmt +cp go.mod go.mod.empty +! go list all +stderr '^x.go:2:8: cannot find module providing package rsc\.io/quote: import lookup disabled by -mod=readonly' +! stderr '\(\)' # If we don't have a reason for -mod=readonly, don't log an empty one. +cmp go.mod go.mod.empty + +# -mod=readonly should be set by default. +env GOFLAGS= +! go list all +stderr '^x.go:2:8: no required module provides package rsc\.io/quote; to add it:\n\tgo get rsc\.io/quote$' +cmp go.mod go.mod.empty + +env GOFLAGS=-mod=readonly + +# update go.mod - go get allowed +go get -d 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 +cp go.mod go.mod.tidy + +# -mod=readonly must succeed once go.mod is up-to-date... +go list all + +# ... even if it needs downloads +go clean -modcache +go list all + +# -mod=readonly must not cause 'go list -m' to fail. +# (golang.org/issue/36478) +go list -m all +! stderr 'cannot query module' + +# -mod=readonly should reject inconsistent go.mod files +# (ones that would be rewritten). +go get -d rsc.io/sampler@v1.2.0 +go mod edit -require rsc.io/quote@v1.5.2 +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 + +# We get a different message when -mod=readonly is used by default. +env GOFLAGS= +! go list +stderr '^go: updates to go.mod needed; to update it:\n\tgo mod tidy' + +# However, it should not reject files missing a 'go' directive, +# since that was not always required. +cp go.mod.nogo go.mod +go list all +cmp go.mod go.mod.nogo + +# Nor should it reject files with redundant (not incorrect) +# requirements. +cp go.mod.redundant go.mod +go list all +cmp go.mod go.mod.redundant + +cp go.mod.indirect go.mod +go list all +cmp go.mod go.mod.indirect + + +# If we identify a missing package as a dependency of some other package in the +# main module, we should suggest 'go mod tidy' instead of resolving it. + +cp go.mod.untidy go.mod +! go list all +stderr '^x.go:2:8: no required module provides package rsc.io/quote; to add it:\n\tgo get rsc.io/quote$' + +! go list -deps . +stderr '^x.go:2:8: no required module provides package rsc.io/quote; to add it:\n\tgo get rsc.io/quote$' + +# However, if we didn't see an import from the main module, we should suggest +# 'go get -d' instead, because we don't know whether 'go mod tidy' would add it. +! go list rsc.io/quote +stderr '^no required module provides package rsc.io/quote; to add it:\n\tgo get rsc.io/quote$' + + +-- go.mod -- +module m + +go 1.16 + +-- x.go -- +package x +import _ "rsc.io/quote" +-- go.mod.nogo -- +module m + +require ( + rsc.io/quote v1.5.2 + rsc.io/testonly v1.0.0 // indirect +) +-- go.mod.redundant -- +module m + +go 1.16 + +require ( + rsc.io/quote v1.5.2 + rsc.io/sampler v1.3.0 // indirect + rsc.io/testonly v1.0.0 // indirect +) +-- go.mod.indirect -- +module m + +go 1.16 + +require ( + rsc.io/quote v1.5.2 // indirect + rsc.io/sampler v1.3.0 // indirect + rsc.io/testonly v1.0.0 // indirect +) +-- go.mod.untidy -- +module m + +go 1.16 + +require ( + rsc.io/sampler v1.3.0 // indirect +) diff --git a/src/cmd/go/testdata/script/mod_replace.txt b/src/cmd/go/testdata/script/mod_replace.txt new file mode 100644 index 0000000..dc9667f --- /dev/null +++ b/src/cmd/go/testdata/script/mod_replace.txt @@ -0,0 +1,129 @@ +env GO111MODULE=on +[short] skip + +cp go.mod go.mod.orig + +# Make sure the test builds without replacement. +go build -mod=mod -o a1.exe . +exec ./a1.exe +stdout 'Don''t communicate by sharing memory' + +# Modules can be replaced by local packages. +cp go.mod.orig go.mod +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.) +cp go.mod.orig go.mod +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. +cp go.mod.orig go.mod +go mod edit -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\)' + +# Modules that do not (yet) exist upstream can be replaced too. +cp go.mod.orig go.mod +go mod edit -replace=not-rsc.io/quote/v3@v3.1.0=./local/rsc.io/quote/v3 +go build -mod=mod -o a5.exe ./usenewmodule +! stderr 'finding not-rsc.io/quote/v3' +grep 'not-rsc.io/quote/v3 v3.1.0' go.mod +exec ./a5.exe +stdout 'Concurrency is not parallelism.' + +# Error messages for modules not found in replacements should +# indicate the replacement module. +cp go.mod.orig go.mod +go mod edit -replace=rsc.io/quote/v3=./local/rsc.io/quote/v3 +! go get -d rsc.io/quote/v3/missing-package +stderr 'module rsc.io/quote/v3@upgrade found \(v3.0.0, replaced by ./local/rsc.io/quote/v3\), but does not contain package' + +# The reported Dir and GoMod for a replaced module should be accurate. +cp go.mod.orig go.mod +go mod edit -replace=rsc.io/quote/v3=not-rsc.io/quote@v0.1.0-nomod +go mod download +go list -m -f '{{.Path}} {{.Version}} {{.Dir}} {{.GoMod}}{{with .Replace}} => {{.Path}} {{.Version}} {{.Dir}} {{.GoMod}}{{end}}' rsc.io/quote/v3 +stdout '^rsc.io/quote/v3 v3.0.0 '$GOPATH'[/\\]pkg[/\\]mod[/\\]not-rsc.io[/\\]quote@v0.1.0-nomod '$GOPATH'[/\\]pkg[/\\]mod[/\\]cache[/\\]download[/\\]not-rsc.io[/\\]quote[/\\]@v[/\\]v0.1.0-nomod.mod => not-rsc.io/quote v0.1.0-nomod '$GOPATH'[/\\]pkg[/\\]mod[/\\]not-rsc.io[/\\]quote@v0.1.0-nomod '$GOPATH'[/\\]pkg[/\\]mod[/\\]cache[/\\]download[/\\]not-rsc.io[/\\]quote[/\\]@v[/\\]v0.1.0-nomod.mod$' + +-- 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()) +} + +-- usenewmodule/main.go -- +package main + +import ( + "fmt" + "not-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/src/cmd/go/testdata/script/mod_replace_gopkgin.txt b/src/cmd/go/testdata/script/mod_replace_gopkgin.txt new file mode 100644 index 0000000..df752d9 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_replace_gopkgin.txt @@ -0,0 +1,80 @@ +# Regression test for golang.org/issue/34254: +# a clone of gopkg.in/[…].vN should be replaceable by +# a fork hosted at corp.example.com/[…]/vN, +# even if there is an explicit go.mod file containing the +# gopkg.in path. + +[short] skip +[!net] skip +[!exec:git] skip + +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off +env GOFLAGS=-mod=mod + +# Replacing gopkg.in/[…].vN with a repository with a root go.mod file +# specifying […].vN and a compatible version should succeed, even if +# the replacement path is not a gopkg.in path. +cd 4-to-4 +go list -m gopkg.in/src-d/go-git.v4 + +# Previous versions of the "go" command accepted v0 and v1 pseudo-versions +# as replacements for gopkg.in/[…].v4. +# As a special case, we continue to accept those. + +cd ../4-to-0 +go list -m gopkg.in/src-d/go-git.v4 + +cd ../4-to-1 +go list -m gopkg.in/src-d/go-git.v4 + +cd ../4-to-incompatible +go list -m gopkg.in/src-d/go-git.v4 + +# A mismatched gopkg.in path should not be able to replace a different major version. +cd ../3-to-gomod-4 +! go list -m gopkg.in/src-d/go-git.v3 +stderr '^go: gopkg\.in/src-d/go-git\.v3@v3\.2\.0 \(replaced by gopkg\.in/src-d/go-git\.v3@v3\.0\.0-20190801152248-0d1a009cbb60\): version "v3\.0\.0-20190801152248-0d1a009cbb60" invalid: go\.mod has non-\.\.\.\.v3 module path "gopkg\.in/src-d/go-git\.v4" at revision 0d1a009cbb60$' + +-- 4-to-4/go.mod -- +module golang.org/issue/34254 + +go 1.13 + +require gopkg.in/src-d/go-git.v4 v4.13.1 + +replace gopkg.in/src-d/go-git.v4 v4.13.1 => github.com/src-d/go-git/v4 v4.13.1 +-- 4-to-1/go.mod -- +module golang.org/issue/34254 + +go 1.13 + +require gopkg.in/src-d/go-git.v4 v4.13.1 + +replace gopkg.in/src-d/go-git.v4 v4.13.1 => github.com/src-d/go-git v1.0.1-0.20190801152248-0d1a009cbb60 +-- 4-to-0/go.mod -- +module golang.org/issue/34254 + +go 1.13 + +require gopkg.in/src-d/go-git.v4 v4.13.1 + +replace gopkg.in/src-d/go-git.v4 v4.13.1 => github.com/src-d/go-git v0.0.0-20190801152248-0d1a009cbb60 +-- 4-to-incompatible/go.mod -- +module golang.org/issue/34254 + +go 1.13 + +require gopkg.in/src-d/go-git.v4 v4.13.1 + +replace gopkg.in/src-d/go-git.v4 v4.13.1 => github.com/src-d/go-git v4.6.0+incompatible +-- 3-to-gomod-4/go.mod -- +module golang.org/issue/34254 +go 1.13 + +require gopkg.in/src-d/go-git.v3 v3.2.0 + +// This replacement has a go.mod file declaring its path to be +// gopkg.in/src-d/go-git.v4, so it cannot be used as a replacement for v3. +replace gopkg.in/src-d/go-git.v3 v3.2.0 => gopkg.in/src-d/go-git.v3 v3.0.0-20190801152248-0d1a009cbb60 diff --git a/src/cmd/go/testdata/script/mod_replace_import.txt b/src/cmd/go/testdata/script/mod_replace_import.txt new file mode 100644 index 0000000..2add31f --- /dev/null +++ b/src/cmd/go/testdata/script/mod_replace_import.txt @@ -0,0 +1,144 @@ +env GO111MODULE=on + +# 'go list' should not add requirements even if they can be resolved locally. +cp go.mod go.mod.orig +! go list all +cmp go.mod go.mod.orig + +# 'go list' should resolve imports using replacements. +go get -d +go list all +stdout 'example.com/a/b$' +stdout 'example.com/x/v3$' +stdout 'example.com/y/z/w$' +stdout 'example.com/v' + +# The selected modules should prefer longer paths, +# but should try shorter paths if needed. +# Modules with a major-version suffix should have a corresponding pseudo-version. +# Replacements that specify a version should use the latest such version. +go list -m all +stdout 'example.com/a/b v0.0.0-00010101000000-000000000000 => ./b' +stdout 'example.com/y v0.0.0-00010101000000-000000000000 => ./y' +stdout 'example.com/x/v3 v3.0.0-00010101000000-000000000000 => ./v3' +stdout 'example.com/v v1.12.0 => ./v12' + +# The go command should print an informative error when the matched +# module does not contain a package. +# TODO(#26909): Ideally these errors should include line numbers for the imports within the main module. +cd fail +! go mod tidy +stderr '^localhost.fail imports\n\tw: module w@latest found \(v0.0.0-00010101000000-000000000000, replaced by ../w\), but does not contain package w$' +stderr '^localhost.fail imports\n\tnonexist: nonexist@v0.1.0: replacement directory ../nonexist does not exist$' + +-- go.mod -- +module example.com/m + +replace ( + example.com/a => ./a + example.com/a/b => ./b +) + +replace ( + example.com/x => ./x + example.com/x/v3 => ./v3 +) + +replace ( + example.com/y/z/w => ./w + example.com/y => ./y +) + +replace ( + example.com/v v1.11.0 => ./v11 + example.com/v v1.12.0 => ./v12 + example.com/v => ./v +) + +replace ( + example.com/i v2.0.0+incompatible => ./i2 +) + +-- m.go -- +package main +import ( + _ "example.com/a/b" + _ "example.com/x/v3" + _ "example.com/y/z/w" + _ "example.com/v" + _ "example.com/i" +) +func main() {} + +-- a/go.mod -- +module a.localhost +-- a/a.go -- +package a +-- a/b/b.go-- +package b + +-- b/go.mod -- +module a.localhost/b +-- b/b.go -- +package b + +-- x/go.mod -- +module x.localhost +-- x/x.go -- +package x +-- x/v3.go -- +package v3 +import _ "x.localhost/v3" + +-- v3/go.mod -- +module x.localhost/v3 +-- v3/x.go -- +package x + +-- w/go.mod -- +module w.localhost +-- w/skip/skip.go -- +// Package skip is nested below nonexistent package w. +package skip + +-- y/go.mod -- +module y.localhost +-- y/z/w/w.go -- +package w + +-- v12/go.mod -- +module v.localhost +-- v12/v.go -- +package v + +-- v11/go.mod -- +module v.localhost +-- v11/v.go -- +package v + +-- v/go.mod -- +module v.localhost +-- v/v.go -- +package v + +-- i2/go.mod -- +module example.com/i +-- i2/i.go -- +package i + +-- fail/m.go -- +package main + +import ( + _ "w" + _ "nonexist" +) + +func main() {} + +-- fail/go.mod -- +module localhost.fail + +replace w => ../w + +replace nonexist v0.1.0 => ../nonexist diff --git a/src/cmd/go/testdata/script/mod_replace_readonly.txt b/src/cmd/go/testdata/script/mod_replace_readonly.txt new file mode 100644 index 0000000..d950d78 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_replace_readonly.txt @@ -0,0 +1,62 @@ +# Check that with -mod=readonly, when we load a package in a module that is +# replaced but not required, we emit an error with the command to add the +# requirement. +# Verifies golang.org/issue/41416, golang.org/issue/41577. +cp go.mod go.mod.orig + +# Replace all versions of a module without requiring it. +# With -mod=mod, we'd add a requirement for a "zero" pseudo-version, but we +# can't in readonly mode, since its go.mod may alter the build list. +go mod edit -replace rsc.io/quote=./quote +! go list rsc.io/quote +stderr '^module rsc.io/quote provides package rsc.io/quote and is replaced but not required; to add it:\n\tgo get rsc.io/quote$' +go get -d rsc.io/quote +cmp go.mod go.mod.latest +go list rsc.io/quote +cp go.mod.orig go.mod + +# Same test with a specific version. +go mod edit -replace rsc.io/quote@v1.0.0-doesnotexist=./quote +! go list rsc.io/quote +stderr '^module rsc.io/quote provides package rsc.io/quote and is replaced but not required; to add it:\n\tgo get rsc.io/quote@v1.0.0-doesnotexist$' +go get -d rsc.io/quote@v1.0.0-doesnotexist +cmp go.mod go.mod.specific +go list rsc.io/quote +cp go.mod.orig go.mod + +# If there are multiple versions, the highest is suggested. +go mod edit -replace rsc.io/quote@v1.0.0-doesnotexist=./quote +go mod edit -replace rsc.io/quote@v1.1.0-doesnotexist=./quote +! go list rsc.io/quote +stderr '^module rsc.io/quote provides package rsc.io/quote and is replaced but not required; to add it:\n\tgo get rsc.io/quote@v1.1.0-doesnotexist$' + +-- go.mod -- +module m + +go 1.16 +-- go.mod.latest -- +module m + +go 1.16 + +replace rsc.io/quote => ./quote + +require rsc.io/quote v1.5.2 // indirect +-- go.mod.specific -- +module m + +go 1.16 + +replace rsc.io/quote v1.0.0-doesnotexist => ./quote + +require rsc.io/quote v1.0.0-doesnotexist // indirect +-- use.go -- +package use + +import _ "rsc.io/quote" +-- quote/go.mod -- +module rsc.io/quote + +go 1.16 +-- quote/quote.go -- +package quote diff --git a/src/cmd/go/testdata/script/mod_require_exclude.txt b/src/cmd/go/testdata/script/mod_require_exclude.txt new file mode 100644 index 0000000..9156d4c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_require_exclude.txt @@ -0,0 +1,81 @@ +# build with no newer version to satisfy exclude +env GO111MODULE=on +cp go.mod go.mod.orig + +# With the selected version excluded, commands that query that version without +# updating go.mod should fail. + +! go list -mod=readonly -m all +stderr '^go: ignoring requirement on excluded version rsc.io/sampler v1\.99\.99$' +stderr '^go: updates to go.mod needed, disabled by -mod=readonly$' +! stdout '^rsc.io/sampler v1.99.99' +cmp go.mod go.mod.orig + +! go list -mod=vendor -m rsc.io/sampler +stderr '^go: ignoring requirement on excluded version rsc.io/sampler v1\.99\.99$' +stderr '^go list -m: module rsc.io/sampler: can''t resolve module using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass\.\)$' +! stdout '^rsc.io/sampler v1.99.99' +cmp go.mod go.mod.orig + +# With the selected version excluded, commands that load only modules should +# drop the excluded module. + +go list -m -mod=mod all +stderr '^go: dropping requirement on excluded version rsc.io/sampler v1\.99\.99$' +stdout '^x$' +! stdout '^rsc.io/sampler' +cmp go.mod go.moddrop + +# With the latest version excluded, 'go list' should resolve needed packages +# from the next-highest version. + +cp go.mod.orig go.mod +go list -mod=mod -f '{{with .Module}}{{.Path}} {{.Version}}{{end}}' all +stderr '^go: dropping requirement on excluded version rsc.io/sampler v1\.99\.99$' +stdout '^x $' +! stdout '^rsc.io/sampler v1.99.99' +stdout '^rsc.io/sampler v1.3.0' + +# build with newer version available +cp go.mod2 go.mod +go list -mod=mod -f '{{with .Module}}{{.Path}} {{.Version}}{{end}}' all +stderr '^go: dropping requirement on excluded version rsc.io/quote v1\.5\.1$' +stdout 'rsc.io/quote v1.5.2' + +# build with excluded newer version +cp go.mod3 go.mod +go list -mod=mod -f '{{with .Module}}{{.Path}} {{.Version}}{{end}}' all +! stderr '^go: dropping requirement' +stdout 'rsc.io/quote v1.5.1' + +-- x.go -- +package x +import _ "rsc.io/quote" + +-- go.mod -- +module x + +go 1.13 + +exclude rsc.io/sampler v1.99.99 +require rsc.io/sampler v1.99.99 +-- go.moddrop -- +module x + +go 1.13 + +exclude rsc.io/sampler v1.99.99 +-- go.mod2 -- +module x + +go 1.13 + +exclude rsc.io/quote v1.5.1 +require rsc.io/quote v1.5.1 +-- go.mod3 -- +module x + +go 1.13 + +exclude rsc.io/quote v1.5.2 +require rsc.io/quote v1.5.1 diff --git a/src/cmd/go/testdata/script/mod_retention.txt b/src/cmd/go/testdata/script/mod_retention.txt new file mode 100644 index 0000000..a4441c4 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_retention.txt @@ -0,0 +1,145 @@ +# Regression test for golang.org/issue/34822: the 'go' command should prefer not +# to update the go.mod file if the changes only affect formatting, and should only +# remove redundant requirements in 'go mod tidy'. + +env GO111MODULE=on +[short] skip + +# Control case: verify that go.mod.tidy is actually tidy. +cp go.mod.tidy go.mod +go list -mod=mod all +cmp go.mod go.mod.tidy + + +# If the only difference in the go.mod file is the line endings, +# it should not be overwritten automatically. +cp go.mod.crlf go.mod +go list all +cmp go.mod go.mod.crlf + +# However, 'go mod tidy' should fix whitespace even if there are no other changes. +go mod tidy +cmp go.mod go.mod.tidy + + +# Out-of-order requirements should not be overwritten automatically... +cp go.mod.unsorted go.mod +go list all +cmp go.mod go.mod.unsorted + +# ...but 'go mod edit -fmt' should sort them. +go mod edit -fmt +cmp go.mod go.mod.tidy + + +# "// indirect" comments should be removed if direct dependencies are seen. +# changes. +cp go.mod.indirect go.mod +go list -mod=mod all +cmp go.mod go.mod.tidy + +# "// indirect" comments should be added if appropriate. +cp go.mod.toodirect go.mod +go list all +cmp go.mod go.mod.toodirect +go mod vendor # loads everything, so adds "// indirect" comments. +cmp go.mod go.mod.tidy +rm -r vendor + + +# Redundant requirements should be preserved... +cp go.mod.redundant go.mod +go list all +cmp go.mod go.mod.redundant +go mod vendor +cmp go.mod go.mod.redundant +rm -r vendor + +# ...except by 'go mod tidy'. +go mod tidy +cmp go.mod go.mod.tidy + + +# A missing "go" version directive should be added. +# However, that should not remove other redundant requirements. +cp go.mod.nogo go.mod +go list -mod=mod all +cmpenv go.mod go.mod.currentgo + + +-- go.mod.tidy -- +module m + +go 1.14 + +require ( + rsc.io/quote v1.5.2 + rsc.io/testonly v1.0.0 // indirect +) +-- x.go -- +package x +import _ "rsc.io/quote" +-- go.mod.crlf -- +module m + +go 1.14 + +require ( + rsc.io/quote v1.5.2 + rsc.io/testonly v1.0.0 // indirect +) +-- go.mod.unsorted -- +module m + +go 1.14 + +require ( + rsc.io/testonly v1.0.0 // indirect + rsc.io/quote v1.5.2 +) +-- go.mod.indirect -- +module m + +go 1.14 + +require ( + rsc.io/quote v1.5.2 // indirect + rsc.io/testonly v1.0.0 // indirect +) +-- go.mod.toodirect -- +module m + +go 1.14 + +require ( + rsc.io/quote v1.5.2 + rsc.io/testonly v1.0.0 +) +-- go.mod.redundant -- +module m + +go 1.14 + +require ( + rsc.io/quote v1.5.2 + rsc.io/sampler v1.3.0 // indirect + rsc.io/testonly v1.0.0 // indirect +) +-- go.mod.nogo -- +module m + +require ( + rsc.io/quote v1.5.2 + rsc.io/sampler v1.3.0 // indirect + rsc.io/testonly v1.0.0 // indirect +) +-- go.mod.currentgo -- +module m + +go $goversion + +require ( + rsc.io/quote v1.5.2 + rsc.io/sampler v1.3.0 // indirect + rsc.io/testonly v1.0.0 // indirect +) diff --git a/src/cmd/go/testdata/script/mod_retract.txt b/src/cmd/go/testdata/script/mod_retract.txt new file mode 100644 index 0000000..4f95ece --- /dev/null +++ b/src/cmd/go/testdata/script/mod_retract.txt @@ -0,0 +1,45 @@ +cp go.mod go.mod.orig + +# 'go list pkg' does not report an error when a retracted version is used. +go list -e -f '{{if .Error}}{{.Error}}{{end}}' ./use +! stdout . +cmp go.mod go.mod.orig + +# Nor does 'go build'. +[!short] go build ./use +[!short] ! stderr . +[!short] cmp go.mod go.mod.orig + +# Neither 'go list' nor 'go build' should download go.mod from the version +# that would list retractions. +exists $GOPATH/pkg/mod/cache/download/example.com/retract/@v/v1.0.0-bad.mod +! exists $GOPATH/pkg/mod/cache/download/example.com/retract/@v/v1.1.0.mod + +# Importing a package from a module with a retracted latest version will +# select the latest non-retracted version. +go get -d ./use_self_prev +go list -m example.com/retract/self/prev +stdout '^example.com/retract/self/prev v1.1.0$' +exists $GOPATH/pkg/mod/cache/download/example.com/retract/self/prev/@v/v1.9.0.mod + +-- go.mod -- +module example.com/use + +go 1.15 + +require example.com/retract v1.0.0-bad + +-- go.sum -- +example.com/retract v1.0.0-bad h1:liAW69rbtjY67x2CcNzat668L/w+YGgNX3lhJsWIJis= +example.com/retract v1.0.0-bad/go.mod h1:0DvGGofJ9hr1q63cBrOY/jSY52OwhRGA0K47NE80I5Y= +example.com/retract/self/prev v1.1.0 h1:0/8I/GTG+1eJTFeDQ/fUbgrMsVHHyKhh3Z8DSZp1fuA= +example.com/retract/self/prev v1.1.0/go.mod h1:xl2EcklWuZZHVtHWcpzfSJQmnzAGpKZYpA/Wto7SZN4= +-- use/use.go -- +package use + +import _ "example.com/retract" + +-- use_self_prev/use.go -- +package use_self_prev + +import _ "example.com/retract/self/prev" diff --git a/src/cmd/go/testdata/script/mod_retract_fix_version.txt b/src/cmd/go/testdata/script/mod_retract_fix_version.txt new file mode 100644 index 0000000..e45758b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_retract_fix_version.txt @@ -0,0 +1,48 @@ +# retract must not be used without a module directive. +! go list -m all +stderr 'go.mod:3: no module directive found, so retract cannot be used$' + +# Commands that update go.mod should fix non-canonical versions in +# retract directives. +# Verifies #44494. +go mod edit -module=rsc.io/quote/v2 +! go list -m all +stderr '^go: updates to go.mod needed; to update it:\n\tgo mod tidy$' +go mod tidy +go list -m all +cmp go.mod go.mod.want + +# If a retracted version doesn't match the module's major version suffx, +# an error should be reported. +! go mod edit -retract=v3.0.1 +stderr '^go mod: -retract=v3.0.1: version "v3.0.1" invalid: should be v2, not v3$' +cp go.mod.mismatch-v2 go.mod +! go list -m all +stderr 'go.mod:3: retract rsc.io/quote/v2: version "v3.0.1" invalid: should be v2, not v3$' + +cp go.mod.mismatch-v1 go.mod +! go list -m all +stderr 'go.mod:3: retract rsc.io/quote: version "v3.0.1" invalid: should be v0 or v1, not v3$' + +-- go.mod -- +go 1.16 + +retract latest +-- go.mod.want -- +go 1.16 + +retract v2.0.1 + +module rsc.io/quote/v2 +-- go.mod.mismatch-v2 -- +go 1.16 + +retract v3.0.1 + +module rsc.io/quote/v2 +-- go.mod.mismatch-v1 -- +go 1.16 + +retract v3.0.1 + +module rsc.io/quote diff --git a/src/cmd/go/testdata/script/mod_retract_incompatible.txt b/src/cmd/go/testdata/script/mod_retract_incompatible.txt new file mode 100644 index 0000000..61538e8 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_retract_incompatible.txt @@ -0,0 +1,15 @@ +# The current version of a module should not be considered when loading +# retractions. If the current version is +incompatible, we should not prefer +# +incompatible versions when looking for retractions. +# Verifies #42601. + +go mod init m + +# Request a +incompatible version retracted in v1.0.0. +go get -d example.com/retract/incompatible@v2.0.0+incompatible +stderr '^go: warning: example.com/retract/incompatible@v2.0.0\+incompatible: retracted by module author$' + +# We should still see a warning if the +incompatible was previously in the +# build list. +go get -d example.com/retract/incompatible@v2.0.0+incompatible +stderr '^go: warning: example.com/retract/incompatible@v2.0.0\+incompatible: retracted by module author$' diff --git a/src/cmd/go/testdata/script/mod_retract_pseudo_base.txt b/src/cmd/go/testdata/script/mod_retract_pseudo_base.txt new file mode 100644 index 0000000..eb00e84 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_retract_pseudo_base.txt @@ -0,0 +1,62 @@ +# When converting a commit to a pseudo-version, don't use a retracted version +# as the base. +# Verifies golang.org/issue/41700. + +[!net] skip +[!exec:git] skip +env GOPROXY=direct +env GOSUMDB=off +go mod init m + +# Control: check that v1.0.0 is the only version and is retracted. +go list -m -versions vcs-test.golang.org/git/retract-pseudo.git +stdout '^vcs-test.golang.org/git/retract-pseudo.git$' +go list -m -versions -retracted vcs-test.golang.org/git/retract-pseudo.git +stdout '^vcs-test.golang.org/git/retract-pseudo.git v1.0.0$' + +# 713affd19d7b is a commit after v1.0.0. Don't use v1.0.0 as the base. +go list -m vcs-test.golang.org/git/retract-pseudo.git@713affd19d7b +stdout '^vcs-test.golang.org/git/retract-pseudo.git v0.0.0-20201009173747-713affd19d7b$' + +# 64c061ed4371 is the commit v1.0.0 refers to. Don't convert to v1.0.0. +go list -m vcs-test.golang.org/git/retract-pseudo.git@64c061ed4371 +stdout '^vcs-test.golang.org/git/retract-pseudo.git v0.0.0-20201009173747-64c061ed4371' + +# A retracted version is a valid base. Retraction should not validate existing +# pseudo-versions, nor should it turn invalid pseudo-versions valid. +go get -d vcs-test.golang.org/git/retract-pseudo.git@v1.0.1-0.20201009173747-713affd19d7b +go list -m vcs-test.golang.org/git/retract-pseudo.git +stdout '^vcs-test.golang.org/git/retract-pseudo.git v1.0.1-0.20201009173747-713affd19d7b$' + +! go get -d vcs-test.golang.org/git/retract-pseudo.git@v1.0.1-0.20201009173747-64c061ed4371 +stderr '^go get: vcs-test.golang.org/git/retract-pseudo.git@v1.0.1-0.20201009173747-64c061ed4371: invalid pseudo-version: tag \(v1.0.0\) found on revision 64c061ed4371 is already canonical, so should not be replaced with a pseudo-version derived from that tag$' + +-- retract-pseudo.sh -- +#!/bin/bash + +# This is not part of the test. +# Run this to generate and update the repository on vcs-test.golang.org. + +set -euo pipefail + +rm -rf retract-pseudo +mkdir retract-pseudo +cd retract-pseudo +git init + +# Create the module. +# Retract v1.0.0 and tag v1.0.0 at the same commit. +# The module has no unretracted release versions. +go mod init vcs-test.golang.org/git/retract-pseudo.git +go mod edit -retract v1.0.0 +echo 'package p' >p.go +git add -A +git commit -m 'create module retract-pseudo' +git tag v1.0.0 + +# Commit a trivial change so the default branch does not point to v1.0.0. +git mv p.go q.go +git commit -m 'trivial change' + +zip -r ../retract-pseudo.zip . +gsutil cp ../retract-pseudo.zip gs://vcs-test/git/retract-pseudo.zip diff --git a/src/cmd/go/testdata/script/mod_retract_rationale.txt b/src/cmd/go/testdata/script/mod_retract_rationale.txt new file mode 100644 index 0000000..4d3a3d6 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_retract_rationale.txt @@ -0,0 +1,79 @@ +# When there is no rationale, 'go get' should print a hard-coded message. +go get -d example.com/retract/rationale@v1.0.0-empty +stderr '^go: warning: example.com/retract/rationale@v1.0.0-empty: retracted by module author$' + +# 'go list' should print the same hard-coded message. +go list -m -retracted -f '{{.Retracted}}' example.com/retract/rationale +stdout '^\[retracted by module author\]$' + + +# When there is a multi-line message, 'go get' should print the first line. +go get -d example.com/retract/rationale@v1.0.0-multiline1 +stderr '^go: warning: example.com/retract/rationale@v1.0.0-multiline1: retracted by module author: short description$' +! stderr 'detail' + +# 'go list' should show the full message. +go list -m -retracted -f '{{.Retracted}}' example.com/retract/rationale +cmp stdout multiline + +# 'go get' output should be the same whether the retraction appears at top-level +# or in a block. +go get -d example.com/retract/rationale@v1.0.0-multiline2 +stderr '^go: warning: example.com/retract/rationale@v1.0.0-multiline2: retracted by module author: short description$' +! stderr 'detail' + +# Same for 'go list'. +go list -m -retracted -f '{{.Retracted}}' example.com/retract/rationale +cmp stdout multiline + + +# 'go get' should omit long messages. +go get -d example.com/retract/rationale@v1.0.0-long +stderr '^go: warning: example.com/retract/rationale@v1.0.0-long: retracted by module author: \(rationale omitted: too long\)' + +# 'go list' should show the full message. +go list -m -retracted -f '{{.Retracted}}' example.com/retract/rationale +stdout '^\[lo{500}ng\]$' + + +# 'go get' should omit messages with unprintable characters. +go get -d example.com/retract/rationale@v1.0.0-unprintable +stderr '^go: warning: example.com/retract/rationale@v1.0.0-unprintable: retracted by module author: \(rationale omitted: contains non-printable characters\)' + +# 'go list' should show the full message. +go list -m -retracted -f '{{.Retracted}}' example.com/retract/rationale +stdout '^\[Ends with a BEL character. Beep!\x07\]$' + + +# When there is a comment on a block, but not on individual retractions within +# the block, the rationale should come from the block comment. +go list -m -retracted -f '{{.Retracted}}' example.com/retract/rationale@v1.0.0-block +stdout '^\[block comment\]$' +go list -m -retracted -f '{{.Retracted}}' example.com/retract/rationale@v1.0.0-blockwithcomment +stdout '^\[inner comment\]$' + + +# When a version is covered by multiple retractions, all retractions should +# be reported in the order they appear in the file. +go list -m -retracted -f '{{range .Retracted}}{{.}},{{end}}' example.com/retract/rationale@v1.0.0-order +stdout '^degenerate range,single version,$' +go list -m -retracted -f '{{range .Retracted}}{{.}},{{end}}' example.com/retract/rationale@v1.0.1-order +stdout '^single version,degenerate range,$' + +# 'go get' will only report the first retraction to avoid being too verbose. +go get -d example.com/retract/rationale@v1.0.0-order +stderr '^go: warning: example.com/retract/rationale@v1.0.0-order: retracted by module author: degenerate range$' +go get -d example.com/retract/rationale@v1.0.1-order +stderr '^go: warning: example.com/retract/rationale@v1.0.1-order: retracted by module author: single version$' + +-- go.mod -- +module m + +go 1.14 + +-- multiline -- +[short description +more + +detail +suffix] diff --git a/src/cmd/go/testdata/script/mod_retract_rename.txt b/src/cmd/go/testdata/script/mod_retract_rename.txt new file mode 100644 index 0000000..f54742c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_retract_rename.txt @@ -0,0 +1,28 @@ +# Populate go.sum. +go get -d + +# 'go list -m -retracted' should load retractions, even if the version +# containing retractions has a different module path. +go list -m -retracted -f '{{with .Retracted}}retracted{{end}}' example.com/retract/rename + +# 'go list -m -u' should load retractions, too. +go list -m -u -f '{{with .Retracted}}retracted{{end}}' example.com/retract/rename + +# 'go get' should warn about the retracted version. +go get -d +stderr '^go: warning: example.com/retract/rename@v1.0.0-bad: retracted by module author: bad$' + +# We can't upgrade, since this latest version has a different module path. +! go get -d example.com/retract/rename +stderr 'module declares its path as: example.com/retract/newname' + +-- go.mod -- +module example.com/use + +go 1.16 + +require example.com/retract/rename v1.0.0-bad +-- use.go -- +package use + +import _ "example.com/retract/rename" diff --git a/src/cmd/go/testdata/script/mod_retract_replace.txt b/src/cmd/go/testdata/script/mod_retract_replace.txt new file mode 100644 index 0000000..770aea4 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_retract_replace.txt @@ -0,0 +1,61 @@ +# If the latest unretracted version of a module is replaced, 'go list' should +# obtain retractions from the replacement. + +# Populate go.sum. +go get -d + +# The latest version, v1.9.0, is not available on the proxy. +! go list -m -retracted example.com/retract/missingmod +stderr '^go list -m: loading module retractions for example.com/retract/missingmod@v1.0.0: .*404 Not Found$' + +# If we replace that version, we should see retractions. +go mod edit -replace=example.com/retract/missingmod@v1.9.0=./missingmod-v1.9.0 +go list -m -retracted -f '{{range .Retracted}}{{.}}{{end}}' example.com/retract/missingmod +stdout '^bad version$' + +# If we replace the retracted version, we should not see a retraction. +go mod edit -replace=example.com/retract/missingmod=./missingmod-v1.9.0 +go list -m -retracted -f '{{if not .Retracted}}good version{{end}}' example.com/retract/missingmod +stdout '^good version$' + + +# If a replacement version is retracted, we should see a retraction. +# It should appear in both the replaced module and the replacement, as other +# fields like GoMod do. +go list -m -retracted -f '{{range .Retracted}}{{.}}{{end}}' example.com/retract +! stdout . +go list -m -retracted -f '{{if .Replace}}replaced{{end}}' example.com/retract +! stdout . +go mod edit -replace example.com/retract@v1.0.0-good=example.com/retract@v1.0.0-bad +go list -m -mod=mod -retracted -f '{{range .Retracted}}{{.}}{{end}}' example.com/retract +stdout '^bad$' +go list -m -mod=mod -retracted -f '{{with .Replace}}{{range .Retracted}}{{.}}{{end}}{{end}}' example.com/retract +stdout '^bad$' + +-- go.mod -- +module m + +go 1.14 + +require ( + example.com/retract v1.0.0-good + example.com/retract/missingmod v1.0.0 +) +-- use.go -- +package use + +import ( + _ "example.com/retract" + _ "example.com/retract/missingmod" +) +-- missingmod-v1.0.0/go.mod -- +module example.com/retract/missingmod + +go 1.14 +-- missingmod-v1.9.0/go.mod -- +module example.com/retract/missingmod + +go 1.14 + +// bad version +retract v1.0.0 diff --git a/src/cmd/go/testdata/script/mod_run_path.txt b/src/cmd/go/testdata/script/mod_run_path.txt new file mode 100644 index 0000000..4369ee4 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_run_path.txt @@ -0,0 +1,15 @@ +# Test that go run does not get confused by conflict +# between go.mod's module path and what you'd +# expect from GOPATH. golang.org/issue/26046. + +env GO111MODULE=on + +cd $GOPATH/src/example.com/hello +go run main.go + +-- $GOPATH/src/example.com/hello/go.mod -- +module example.com/hello/v2 + +-- $GOPATH/src/example.com/hello/main.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/mod_std_vendor.txt b/src/cmd/go/testdata/script/mod_std_vendor.txt new file mode 100644 index 0000000..fb954d7 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_std_vendor.txt @@ -0,0 +1,78 @@ +env GO111MODULE=on +env GOPROXY=off + +[!gc] skip + +# 'go list' should report imports from _test.go in the TestImports field. +go list -f '{{.TestImports}}' +stdout net/http # from .TestImports + +# 'go list' should find standard-vendored packages. +go list -f '{{.Dir}}' vendor/golang.org/x/net/http2/hpack +stdout $GOROOT[/\\]src[/\\]vendor + +# 'go list -test' should report vendored transitive dependencies of _test.go +# imports in the Deps field. +go list -test -f '{{range .Deps}}{{.}}{{"\n"}}{{end}}' +stdout ^vendor/golang.org/x/crypto # dep of .TestImports + + +# Modules outside the standard library should not use the packages vendored there... +cd broken +! go build -mod=readonly +stderr 'disabled by -mod=readonly' +! go build -mod=vendor +stderr 'cannot find package' +stderr 'hpack' + +# ...even if they explicitly use the "cmd/vendor/" or "vendor/" prefix. +cd ../importcmd +! go build . +stderr 'use of vendored package' + +cd ../importstd +! go build . +stderr 'use of vendored package' + + +# When run within the 'std' module, 'go list -test' should report vendored +# transitive dependencies at their original module paths. +cd $GOROOT/src +go list -test -f '{{range .Deps}}{{.}}{{"\n"}}{{end}}' net/http +stdout ^golang.org/x/net/http2/hpack +! stdout ^vendor/golang.org/x/net/http2/hpack + +-- go.mod -- +module m + +-- x.go -- +package x + +-- x_test.go -- +package x +import "testing" +import _ "net/http" +func Test(t *testing.T) {} + +-- broken/go.mod -- +module broken +-- broken/http.go -- +package broken + +import ( + _ "net/http" + _ "golang.org/x/net/http2/hpack" +) + +-- importcmd/go.mod -- +module importcmd +-- importcmd/x.go -- +package importcmd + +import _ "cmd/vendor/golang.org/x/tools/go/analysis" +-- importstd/go.mod -- +module importvendor +-- importstd/x.go -- +package importstd + +import _ "vendor/golang.org/x/net/http2/hpack" diff --git a/src/cmd/go/testdata/script/mod_string_alias.txt b/src/cmd/go/testdata/script/mod_string_alias.txt new file mode 100644 index 0000000..5c3d428 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_string_alias.txt @@ -0,0 +1,14 @@ +[short] skip + +env GO111MODULE=on + +go mod init golang.org/issue/27584 + +go build . + +-- main.go -- +package main + +type string = []int + +func main() {} diff --git a/src/cmd/go/testdata/script/mod_sum_ambiguous.txt b/src/cmd/go/testdata/script/mod_sum_ambiguous.txt new file mode 100644 index 0000000..07c6659 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_sum_ambiguous.txt @@ -0,0 +1,62 @@ +# Confirm our build list. +cp go.sum.buildlist-only go.sum +go list -m all +stdout '^example.com/ambiguous/a v1.0.0$' +stdout '^example.com/ambiguous/a/b v0.0.0-empty$' + +# If two modules could provide a package, but only one does, +# 'go mod tidy' should retain sums for both zips. +go mod tidy +grep '^example.com/ambiguous/a v1.0.0 h1:' go.sum +grep '^example.com/ambiguous/a/b v0.0.0-empty h1:' go.sum + +# 'go mod download' should also add sums. +cp go.sum.buildlist-only go.sum +go mod download example.com/ambiguous/a +grep '^example.com/ambiguous/a v1.0.0 h1:' go.sum +! grep '^example.com/ambiguous/a/b v0.0.0-empty h1:' go.sum +go mod download example.com/ambiguous/a/b +grep '^example.com/ambiguous/a/b v0.0.0-empty h1:' go.sum + +# If two modules could provide a package, and we're missing a sum for one, +# we should see a missing sum error, even if we have a sum for a module that +# provides the package. +cp go.sum.a-only go.sum +! go list example.com/ambiguous/a/b +stderr '^missing go.sum entry needed to verify package example.com/ambiguous/a/b is provided by exactly one module; to add:\n\tgo mod download example.com/ambiguous/a/b$' +! go list -deps . +stderr '^use.go:3:8: missing go.sum entry needed to verify package example.com/ambiguous/a/b \(imported by m\) is provided by exactly one module; to add:\n\tgo get m$' + +cp go.sum.b-only go.sum +! go list example.com/ambiguous/a/b +stderr '^missing go.sum entry for module providing package example.com/ambiguous/a/b; to add:\n\tgo mod download example.com/ambiguous/a$' +! go list -deps . +stderr '^use.go:3:8: missing go.sum entry for module providing package example.com/ambiguous/a/b \(imported by m\); to add:\n\tgo get m$' + +cp go.sum.buildlist-only go.sum +! go list example.com/ambiguous/a/b +stderr '^missing go.sum entry for module providing package example.com/ambiguous/a/b; to add:\n\tgo mod download example.com/ambiguous/a example.com/ambiguous/a/b$' +! go list -deps . +stderr '^use.go:3:8: missing go.sum entry for module providing package example.com/ambiguous/a/b \(imported by m\); to add:\n\tgo get m$' + +-- go.mod -- +module m + +go 1.15 + +require example.com/ambiguous/a v1.0.0 +-- go.sum.buildlist-only -- +example.com/ambiguous/a v1.0.0/go.mod h1:TrBl/3xTPFJ2gmMIYz53h2gkNtg0dokszEMuyS1QEb0= +example.com/ambiguous/a/b v0.0.0-empty/go.mod h1:MajJq5jPEBnnXP+NTWIeXX7kwaPS1sbVEJdooTmsePQ= +-- go.sum.a-only -- +example.com/ambiguous/a v1.0.0 h1:pGZhTXy6+titE2rNfwHwJykSjXDR4plO52PfZrBM0T8= +example.com/ambiguous/a v1.0.0/go.mod h1:TrBl/3xTPFJ2gmMIYz53h2gkNtg0dokszEMuyS1QEb0= +example.com/ambiguous/a/b v0.0.0-empty/go.mod h1:MajJq5jPEBnnXP+NTWIeXX7kwaPS1sbVEJdooTmsePQ= +-- go.sum.b-only -- +example.com/ambiguous/a v1.0.0/go.mod h1:TrBl/3xTPFJ2gmMIYz53h2gkNtg0dokszEMuyS1QEb0= +example.com/ambiguous/a/b v0.0.0-empty h1:xS29ReXXuhjT7jc79mo91h/PevaZ2oS9PciF1DucXtg= +example.com/ambiguous/a/b v0.0.0-empty/go.mod h1:MajJq5jPEBnnXP+NTWIeXX7kwaPS1sbVEJdooTmsePQ= +-- use.go -- +package use + +import _ "example.com/ambiguous/a/b" diff --git a/src/cmd/go/testdata/script/mod_sum_lookup.txt b/src/cmd/go/testdata/script/mod_sum_lookup.txt new file mode 100644 index 0000000..e021921 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_sum_lookup.txt @@ -0,0 +1,34 @@ +# When we attempt to resolve an import that doesn't exist, we should not save +# hashes for downloaded modules. +# Verifies golang.org/issue/36260. +# TODO(golang.org/issue/26603): use 'go mod tidy -e' when implemented. +go list -e -mod=mod -tags=ignore ./noexist +! exists go.sum + +# When an import is resolved successfully, we should only save hashes for +# the module that provides the package, not for other modules looked up. +# Verifies golang.org/issue/31580. +go get -d ./exist +grep '^example.com/join v1.1.0 h1:' go.sum +! grep '^example.com/join/subpkg' go.sum +cp go.sum go.list.sum +go mod tidy +cmp go.sum go.list.sum + +-- go.mod -- +module m + +go 1.15 + +-- noexist/use.go -- +// ignore tags prevents errors in 'go mod tidy' +// +build ignore + +package use + +import _ "example.com/join/subpkg/noexist" + +-- exist/use.go -- +package use + +import _ "example.com/join/subpkg" diff --git a/src/cmd/go/testdata/script/mod_sum_readonly.txt b/src/cmd/go/testdata/script/mod_sum_readonly.txt new file mode 100644 index 0000000..57c5bbe --- /dev/null +++ b/src/cmd/go/testdata/script/mod_sum_readonly.txt @@ -0,0 +1,87 @@ +# Test that go.sum does not get updated when -mod=readonly flag is set +env GO111MODULE=on + +# When a sum is needed to load the build list, we get an error for the +# specific module. The .mod file is not downloaded, and go.sum is not written. +! go list -m all +stderr '^go: rsc.io/quote@v1.5.2: missing go.sum entry; to add it:\n\tgo mod download rsc.io/quote$' +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod +! exists go.sum + +# If go.sum exists but contains hashes from an algorithm we don't know about, +# we should see the same error. +cp go.sum.h2only go.sum +! go list -m all +stderr '^go: rsc.io/quote@v1.5.2: missing go.sum entry; to add it:\n\tgo mod download rsc.io/quote$' +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod +cmp go.sum go.sum.h2only +rm go.sum + +# If we replace a module, we should see a missing sum error for the replacement. +cp go.mod go.mod.orig +go mod edit -replace rsc.io/quote@v1.5.2=rsc.io/quote@v1.5.1 +! go list -m all +stderr '^go: rsc.io/quote@v1.5.2 \(replaced by rsc.io/quote@v1.5.1\): missing go.sum entry; to add it:\n\tgo mod download rsc.io/quote$' +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.1.mod +! exists go.sum +cp go.mod.orig go.mod + +# Control: when sums are present, loading the build list downloads .mod files. +cp go.sum.buildlistonly go.sum +go list -m all +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod + + +# When a sum is needed to load a .mod file for a package outside the build list, +# we get a generic missing import error. +! go list example.com/doesnotexist +stderr '^no required module provides package example.com/doesnotexist; to add it:\n\tgo get example.com/doesnotexist$' + +# When a sum is needed to load a .zip file, we get a more specific error. +# The .zip file is not downloaded. +! go list rsc.io/quote +stderr '^missing go.sum entry for module providing package rsc.io/quote; to add:\n\tgo mod download rsc.io/quote$' +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip + +# The error is attached to the package from the missing module. We can load +# a package that imports it without that error. +go list -e -deps -f '{{.ImportPath}}{{with .Error}} {{.Err}}{{end}}' . +stdout '^m$' +stdout '^rsc.io/quote missing go.sum entry for module providing package rsc.io/quote \(imported by m\); to add:\n\tgo get m$' +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip + +# go.sum should not have been written. +cmp go.sum go.sum.buildlistonly + +# Control: when sums are present, 'go list' downloads .zip files. +cp go.sum.tidy go.sum +go list . +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip + +-- go.mod -- +module m + +go 1.15 + +require rsc.io/quote v1.5.2 +-- use.go -- +package use + +import _ "rsc.io/quote" +-- go.sum.h2only -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h2:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.2/go.mod h2:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0/go.mod h2:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +-- go.sum.buildlistonly -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +-- go.sum.tidy -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/testonly v1.0.0 h1:K/VWHdO+Jv7woUXG0GzVNx1czBXUt3Ib1deaMn+xk64= +rsc.io/testonly v1.0.0/go.mod h1:OqmGbIFOcF+XrFReLOGZ6BhMM7uMBiQwZsyNmh74SzY= diff --git a/src/cmd/go/testdata/script/mod_sum_replaced.txt b/src/cmd/go/testdata/script/mod_sum_replaced.txt new file mode 100644 index 0000000..b03982d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_sum_replaced.txt @@ -0,0 +1,28 @@ +env GO111MODULE=on + +# After 'go get -d', the go.sum file should contain the sum for the module. +go get -d rsc.io/quote@v1.5.0 +grep 'rsc.io/quote v1.5.0' go.sum + +# If we replace the module and run 'go mod tidy', we should get a sum for the replacement. +go mod edit -replace rsc.io/quote@v1.5.0=rsc.io/quote@v1.5.1 +go mod tidy +grep 'rsc.io/quote v1.5.1' go.sum +cp go.sum go.sum.tidy + +# 'go mod vendor' should preserve that sum, and should not need to add any new entries. +go mod vendor +grep 'rsc.io/quote v1.5.1' go.sum +cmp go.sum go.sum.tidy + +-- go.mod -- +module golang.org/issue/27868 + +require rsc.io/quote v1.5.0 + +-- main.go -- +package main + +import _ "rsc.io/quote" + +func main() {} diff --git a/src/cmd/go/testdata/script/mod_sumdb.txt b/src/cmd/go/testdata/script/mod_sumdb.txt new file mode 100644 index 0000000..9a688e1 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_sumdb.txt @@ -0,0 +1,39 @@ +env GO111MODULE=on +env sumdb=$GOSUMDB +env proxy=$GOPROXY +env GOPROXY GONOPROXY GOSUMDB GONOSUMDB +env dbname=localhost.localdev/sumdb + +# disagreeing with the sumdb produces security errors +# (this also populates tiles on the sumdb server). +cp go.mod.orig go.mod +env GOSUMDB=$sumdb' '$proxy/sumdb-wrong +! go get -d rsc.io/quote +stderr 'go get: rsc.io/quote@v1.5.2: verifying module: checksum mismatch' +stderr 'downloaded: h1:3fEy' +stderr 'localhost.localdev/sumdb: h1:wrong' +stderr 'SECURITY ERROR\nThis download does NOT match the one reported by the checksum server.' +! go get -d rsc.io/sampler +! go get -d golang.org/x/text + +go mod edit -require rsc.io/quote@v1.5.2 +! go mod tidy +stderr 'go: rsc.io/quote@v1.5.2: verifying go.mod: checksum mismatch' +stderr 'SECURITY ERROR\n' + +rm go.sum + +# switching to truthful sumdb detects timeline inconsistency +cp go.mod.orig go.mod +env GOSUMDB=$sumdb +! go get -d rsc.io/fortune +stderr 'SECURITY ERROR\ngo.sum database server misbehavior detected!' +stderr 'proof of misbehavior:' + +# removing the cached wrong tree head and cached tiles clears the bad data +rm $GOPATH/pkg/sumdb/$dbname/latest +go clean -modcache +go get -d rsc.io/fortune + +-- go.mod.orig -- +module m diff --git a/src/cmd/go/testdata/script/mod_sumdb_cache.txt b/src/cmd/go/testdata/script/mod_sumdb_cache.txt new file mode 100644 index 0000000..2937b2e --- /dev/null +++ b/src/cmd/go/testdata/script/mod_sumdb_cache.txt @@ -0,0 +1,54 @@ +env GO111MODULE=on +env sumdb=$GOSUMDB +env proxy=$GOPROXY +env GOPROXY GONOPROXY GOSUMDB GONOSUMDB + +# rejected proxy fails verification +cp go.mod.orig go.mod +rm go.sum +env GOPROXY=$proxy/sumdb-503 +! go get -d rsc.io/quote +stderr 503 + +# fetch through working proxy is OK +cp go.mod.orig go.mod +rm go.sum +env GOPROXY=$proxy +go get -d rsc.io/quote + +# repeated fetch works entirely from cache, does not consult sumdb +cp go.mod.orig go.mod +rm go.sum +env GOPROXY=$proxy/sumdb-503 +go get -d rsc.io/quote +rm go.sum + +# fetch specific module can work without proxy, using cache or go.sum +cp go.mod.orig go.mod +rm go.sum +env GOPROXY=off +go get -d rsc.io/quote@v1.5.2 # using cache +rm $GOPATH/pkg/mod/cache/download/sumdb/localhost.localdev/sumdb/lookup/rsc.io/quote@v1.5.2 +go get -d rsc.io/quote@v1.5.2 # using go.sum + +# fetch fails once we lose access to both cache and go.sum +rm go.sum +env GOPROXY=$proxy/sumdb-504 +! go get -d rsc.io/quote@v1.5.2 +stderr 504 + +# GOINSECURE does not bypass checksum lookup +env GOINSECURE=rsc.io +env GOPROXY=$proxy/sumdb-504 +! go get -d rsc.io/quote@v1.5.2 +stderr 504 + +# but -insecure bypasses the checksum lookup entirely +env GOINSECURE= +go get -d -insecure rsc.io/quote@v1.5.2 + +# and then it is in go.sum again +go get -d rsc.io/quote@v1.5.2 + +-- go.mod.orig -- +module m diff --git a/src/cmd/go/testdata/script/mod_sumdb_file_path.txt b/src/cmd/go/testdata/script/mod_sumdb_file_path.txt new file mode 100644 index 0000000..22fcbf3 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_sumdb_file_path.txt @@ -0,0 +1,56 @@ +[!net] skip + +env GO111MODULE=on +env GOSUMDB= +env GOPATH=$WORK/gopath1 + +# With a file-based proxy with an empty checksum directory, +# downloading a new module should fail, even if a subsequent +# proxy contains a more complete mirror of the sum database. +# +# TODO(bcmills): The error message here is a bit redundant. +# It comes from the sumweb package, which isn't yet producing structured errors. +[windows] env GOPROXY=file:///$WORK/sumproxy,https://proxy.golang.org +[!windows] env GOPROXY=file://$WORK/sumproxy,https://proxy.golang.org +! go get -d golang.org/x/text@v0.3.2 +stderr '^go get: golang.org/x/text@v0.3.2: verifying module: golang.org/x/text@v0.3.2: reading file://.*/sumdb/sum.golang.org/lookup/golang.org/x/text@v0.3.2: (no such file or directory|.*cannot find the path specified.*)' + +# If the proxy does not claim to support the database, +# checksum verification should fall through to the next proxy, +# and downloading should succeed. +[windows] env GOPROXY=file:///$WORK/emptyproxy,https://proxy.golang.org +[!windows] env GOPROXY=file://$WORK/emptyproxy,https://proxy.golang.org +go get -d golang.org/x/text@v0.3.2 + +# After a successful sumdb lookup, the lookup can be repeated +# using the download cache as a proxy. +cp supported $GOPATH/pkg/mod/cache/download/sumdb/sum.golang.org/supported +[windows] env GOPROXY=file:///$WORK/gopath1/pkg/mod/cache/download,file:///$WORK/sumproxy +[!windows] env GOPROXY=file://$WORK/gopath1/pkg/mod/cache/download,file://$WORK/sumproxy +env GOPATH=$WORK/gopath2 +rm go.sum +go get -d -x -v golang.org/x/text@v0.3.2 + +# Once the checksum is present in the go.sum file, +# an empty file-based sumdb can be used in conjunction with +# a fallback module mirror. +grep golang.org/x/text go.sum +env GOPATH=$WORK/gopath3 +[windows] env GOPROXY=file:///$WORK/sumproxy +[!windows] env GOPROXY=file://$WORK/sumproxy +! go get -d golang.org/x/text@v0.3.2 +[windows] env GOPROXY=file:///$WORK/sumproxy,https://proxy.golang.org +[!windows] env GOPROXY=file://$WORK/sumproxy,https://proxy.golang.org +go get -d golang.org/x/text@v0.3.2 + +-- supported -- + +-- go.mod -- +module example.com +go 1.13 +-- $WORK/emptyproxy/README.md -- +This proxy contains no modules. +-- $WORK/sumproxy/README.md -- +This proxy contains no modules. +-- $WORK/sumproxy/sumdb/sum.golang.org/supported -- +This proxy blocks checksum downloads from sum.golang.org. diff --git a/src/cmd/go/testdata/script/mod_sumdb_golang.txt b/src/cmd/go/testdata/script/mod_sumdb_golang.txt new file mode 100644 index 0000000..cc0b0da --- /dev/null +++ b/src/cmd/go/testdata/script/mod_sumdb_golang.txt @@ -0,0 +1,54 @@ +# Test default GOPROXY and GOSUMDB +env GOPROXY= +env GOSUMDB= +go env GOPROXY +stdout '^https://proxy.golang.org,direct$' +go env GOSUMDB +stdout '^sum.golang.org$' +env GOPROXY=https://proxy.golang.org +go env GOSUMDB +stdout '^sum.golang.org$' + +# Download direct from github. +[!net] skip +[!exec:git] skip +env GOSUMDB=sum.golang.org +env GOPROXY=direct +go get -d rsc.io/quote@v1.5.2 +cp go.sum saved.sum + +# Download from proxy.golang.org with go.sum entry already. +# Use 'go list' instead of 'go get' since the latter may download extra go.mod +# files not listed in go.sum. +go clean -modcache +env GOSUMDB= +env GOPROXY= +go list -x -deps rsc.io/quote +! stderr github +stderr proxy.golang.org/rsc.io/quote +! stderr sum.golang.org/tile +! stderr sum.golang.org/lookup/rsc.io/quote +cmp go.sum saved.sum + +# Download again. +# Should use the checksum database to validate new go.sum lines, +# but not need to fetch any new data from the proxy. +rm go.sum +go list -mod=mod -x rsc.io/quote +! stderr github +! stderr proxy.golang.org/rsc.io/quote +stderr sum.golang.org/tile +stderr sum.golang.org/lookup/rsc.io/quote +cmp go.sum saved.sum + +# test fallback to direct +env TESTGOPROXY404=1 +go clean -modcache +rm go.sum +go list -mod=mod -x rsc.io/quote +stderr 'proxy.golang.org.*404 testing' +stderr github.com/rsc +cmp go.sum saved.sum + +-- go.mod -- +module m diff --git a/src/cmd/go/testdata/script/mod_sumdb_proxy.txt b/src/cmd/go/testdata/script/mod_sumdb_proxy.txt new file mode 100644 index 0000000..70b8e3f --- /dev/null +++ b/src/cmd/go/testdata/script/mod_sumdb_proxy.txt @@ -0,0 +1,65 @@ +env GO111MODULE=on +env sumdb=$GOSUMDB +env proxy=$GOPROXY +env GOPROXY GONOPROXY GOSUMDB GONOSUMDB + +# basic fetch (through proxy) works +cp go.mod.orig go.mod +go get -d rsc.io/fortune@v1.0.0 # note: must use test proxy, does not exist in real world +rm $GOPATH/pkg/mod/cache/download/sumdb # rm sumdb cache but NOT package download cache +rm go.sum + +# can fetch by explicit URL +cp go.mod.orig go.mod +env GOSUMDB=$sumdb' '$proxy/sumdb-direct +go get -d rsc.io/fortune@v1.0.0 +rm $GOPATH/pkg/mod/cache/download/sumdb +rm go.sum + +# direct access fails (because localhost.localdev does not exist) +# web.get is providing the error message - there's no actual network access. +cp go.mod.orig go.mod +env GOSUMDB=$sumdb +env GOPROXY=direct +! go get -d rsc.io/fortune@v1.0.0 +stderr 'verifying module: rsc.io/fortune@v1.0.0: .*: no such host localhost.localdev' +rm $GOPATH/pkg/mod/cache/download/sumdb +rm go.sum + +# proxy 404 falls back to direct access (which fails) +cp go.mod.orig go.mod +env GOSUMDB=$sumdb +env GOPROXY=$proxy/sumdb-404 +! go get -d rsc.io/fortune@v1.0.0 +stderr 'verifying.*localhost.localdev' +rm $GOPATH/pkg/mod/cache/download/sumdb +rm go.sum + +# proxy non-200/404/410 stops direct access +cp go.mod.orig go.mod +env GOSUMDB=$sumdb +env GOPROXY=$proxy/sumdb-503 +! go get -d rsc.io/fortune@v1.0.0 +stderr '503 Service Unavailable' +rm $GOPATH/pkg/mod/cache/download/sumdb +rm go.sum + +# the error from the last attempted proxy should be returned. +cp go.mod.orig go.mod +env GOSUMDB=$sumdb +env GOPROXY=$proxy/sumdb-404,$proxy/sumdb-503 +! go get -d rsc.io/fortune@v1.0.0 +stderr '503 Service Unavailable' +rm $GOPATH/pkg/mod/cache/download/sumdb +rm go.sum + +# if proxies are separated with '|', fallback is allowed on any error. +cp go.mod.orig go.mod +env GOSUMDB=$sumdb +env GOPROXY=$proxy/sumdb-503|https://0.0.0.0|$proxy +go get -d rsc.io/fortune@v1.0.0 +rm $GOPATH/pkg/mod/cache/download/sumdb +rm go.sum + +-- go.mod.orig -- +module m diff --git a/src/cmd/go/testdata/script/mod_symlink.txt b/src/cmd/go/testdata/script/mod_symlink.txt new file mode 100644 index 0000000..dbc23fb --- /dev/null +++ b/src/cmd/go/testdata/script/mod_symlink.txt @@ -0,0 +1,45 @@ +env GO111MODULE=on +[!symlink] skip + +# 'go get -d' should resolve modules of imported packages. +go get -d +go list -deps -f '{{.Module}}' . +stdout golang.org/x/text + +go get -d ./subpkg +go list -deps -f '{{.Module}}' ./subpkg +stdout golang.org/x/text + +# Create a copy of the module using symlinks in src/links. +mkdir links +symlink links/go.mod -> $GOPATH/src/go.mod +symlink links/go.sum -> $GOPATH/src/go.sum +symlink links/issue.go -> $GOPATH/src/issue.go +mkdir links/subpkg +symlink links/subpkg/issue.go -> $GOPATH/src/subpkg/issue.go + +# We should see the copy as a valid module root. +cd links +go env GOMOD +stdout links[/\\]go.mod +go list -m +stdout golang.org/issue/28107 + +# The symlink-based copy should contain the same packages +# and have the same dependencies as the original. +go list -deps -f '{{.Module}}' . +stdout golang.org/x/text +go list -deps -f '{{.Module}}' ./subpkg +stdout golang.org/x/text + +-- go.mod -- +module golang.org/issue/28107 + +-- issue.go -- +package issue + +import _ "golang.org/x/text/language" +-- subpkg/issue.go -- +package issue + +import _ "golang.org/x/text/language" diff --git a/src/cmd/go/testdata/script/mod_symlink_dotgo.txt b/src/cmd/go/testdata/script/mod_symlink_dotgo.txt new file mode 100644 index 0000000..d4cc143 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_symlink_dotgo.txt @@ -0,0 +1,17 @@ +env GO111MODULE=on +[!symlink] skip + +symlink dir.go -> dir + +# Issue #39841: symlinks to directories should be ignored, not treated as source files. +go list -f '{{range .GoFiles}}{{.}}{{"\n"}}{{end}}' . +stdout 'p\.go$' +! stdout 'dir\.go$' + +-- go.mod -- +module example.com +go 1.15 +-- p.go -- +package p +-- dir/README.txt -- +This file exists to ensure that dir is a directory. diff --git a/src/cmd/go/testdata/script/mod_tagged_import_cycle.txt b/src/cmd/go/testdata/script/mod_tagged_import_cycle.txt new file mode 100644 index 0000000..0491acb --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tagged_import_cycle.txt @@ -0,0 +1,106 @@ +# Because 'go mod' subcommands ignore build constraints, they can encounter +# package-import cycles that are not possible in an ordinary build. This test +# verifies that such cycles are handled even when they cross module boundaries. + +# First, verify that the import graph depends on build tags as expected. +go list -deps example.com/left +stdout '^example.com/right$' +go list -deps example.com/right +! stdout left + +env GOFLAGS=-tags=mirror +go list -deps example.com/left +! stdout right +go list -deps example.com/right +stdout '^example.com/left$' +env GOFLAGS='' + +# 'go mod why' should be agnostic to build tags. +go mod why example.com/left +stdout '^example.com/chiral$\n^example.com/left$' +go mod why example.com/right +stdout '^example.com/chiral$\n^example.com/right$' + +env GOFLAGS='-tags=mirror' +go mod why example.com/left +stdout '^example.com/chiral$\n^example.com/left$' +go mod why example.com/right +stdout '^example.com/chiral$\n^example.com/right$' +env GOFLAGS='' + +# 'go mod tidy' should successfully handle the cycle. +env GOFLAGS=-mod=readonly +go mod tidy + +# 'go mod vendor' should copy in both packages without crashing. +go mod vendor +exists vendor/example.com/left/default.go +exists vendor/example.com/left/mirror.go +exists vendor/example.com/right/default.go +exists vendor/example.com/right/mirror.go + +-- go.mod -- +module example.com/chiral + +go 1.14 + +require ( + example.com/left v0.1.0 + example.com/right v0.1.0 +) + +replace ( + example.com/left => ./left + example.com/right => ./right +) +-- chiral.go -- +// Package chiral imports packages in an order that depends on build tags. +package chiral +-- default.go -- +// +build !mirror + +package chiral + +import _ "example.com/left" +-- mirror.go -- +// +build mirror + +package chiral + +import _ "example.com/right" +-- left/go.mod -- +module example.com/left + +go 1.14 + +require example.com/right v0.1.0 + +replace example.com/right v0.1.0 => ../right +-- left/default.go -- +// +build !mirror + +package left + +import _ "example.com/right" +-- left/mirror.go -- +// +build mirror + +package left +-- right/go.mod -- +module example.com/right + +go 1.14 + +require example.com/left v0.1.0 + +replace example.com/left v0.1.0 => ../left +-- right/default.go -- +// +build !mirror + +package right +-- right/mirror.go -- +// +build mirror + +package right + +import _ "example.com/left" diff --git a/src/cmd/go/testdata/script/mod_test.txt b/src/cmd/go/testdata/script/mod_test.txt new file mode 100644 index 0000000..50f0035 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_test.txt @@ -0,0 +1,128 @@ +env GO111MODULE=on +env GOFLAGS=-mod=mod +[short] skip + +# TODO(bcmills): Convert the 'go test' calls below to 'go list -test' once 'go +# list' is more sensitive to package loading errors. + +# A test in the module's root package should work. +cd a/ +cp go.mod.empty go.mod +go list -test +! stderr error + +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 list -test +! stderr error + +# A test with the "_test" suffix in the module root should also work. +cd ../b/ +go list -test +! stderr error + +# 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 list -test +! stderr error + +cd ../d_test +go list -test +! stderr error + +cd ../e +go list -test +! stderr error + +-- 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/src/cmd/go/testdata/script/mod_test_cached.txt b/src/cmd/go/testdata/script/mod_test_cached.txt new file mode 100644 index 0000000..3da4358 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_test_cached.txt @@ -0,0 +1,76 @@ +[short] skip + +env GO111MODULE=on +env GOCACHE=$WORK/gocache +env GODEBUG=gocachetest=1 + +# The first run of a test should not be cached. +# The second run should be. +go test -run=WriteTmp . +! stdout '(cached)' +go test -run=WriteTmp . +stdout '(cached)' + +# 'go test' without arguments should never be cached. +go test -run=WriteTmp +! stdout '(cached)' +go test -run=WriteTmp +! stdout '(cached)' + +# We should never cache a test run from command-line files. +go test -run=WriteTmp ./foo_test.go +! stdout '(cached)' +go test -run=WriteTmp ./foo_test.go +! stdout '(cached)' + +[!exec:sleep] stop +# The go command refuses to cache access to files younger than 2s, so sleep that long. +exec sleep 2 + +# Touching a file that the test reads from within its testdata should invalidate the cache. +go test -run=ReadTestdata . +! stdout '(cached)' +go test -run=ReadTestdata . +stdout '(cached)' +cp testdata/bar.txt testdata/foo.txt +go test -run=ReadTestdata . +! stdout '(cached)' + +-- go.mod -- +module golang.org/issue/29111/foo + +-- foo.go -- +package foo + +-- testdata/foo.txt -- +foo +-- testdata/bar.txt -- +bar + +-- foo_test.go -- +package foo_test + +import ( + "os" + "path/filepath" + "testing" +) + +func TestWriteTmp(t *testing.T) { + dir, err := os.MkdirTemp("", "") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + err = os.WriteFile(filepath.Join(dir, "x"), nil, 0666) + if err != nil { + t.Fatal(err) + } +} + +func TestReadTestdata(t *testing.T) { + _, err := os.ReadFile("testdata/foo.txt") + if err != nil { + t.Fatal(err) + } +} diff --git a/src/cmd/go/testdata/script/mod_test_files.txt b/src/cmd/go/testdata/script/mod_test_files.txt new file mode 100644 index 0000000..6f520c7 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_test_files.txt @@ -0,0 +1,50 @@ +env GO111MODULE=on + +cd foo + +# Testing an explicit source file should use the same import visibility as the +# package in the same directory. +go list -test -deps +go list -test -deps foo_test.go + +# If the file is inside the main module's vendor directory, it should have +# visibility based on the vendor-relative import path. +mkdir vendor/example.com/foo +cp foo_test.go vendor/example.com/foo +go list -test -deps vendor/example.com/foo/foo_test.go + +# If the file is outside the main module entirely, it should be treated as outside. +cp foo_test.go ../foo_test.go +! go list -test -deps ../foo_test.go +stderr 'use of internal package' + +-- foo/go.mod -- +module example.com/foo +go 1.12 +require example.com/internal v0.0.0 +replace example.com/internal => ../internal + +-- foo/internal.go -- +package foo +import _ "example.com/internal" + +-- foo/foo_test.go -- +package foo_test + +import ( + "testing" + "example.com/internal" +) + +func TestHacksEnabled(t *testing.T) { + if !internal.Hacks { + t.Fatal("hacks not enabled") + } +} + +-- internal/go.mod -- +module example.com/internal + +-- internal/internal.go -- +package internal +const Hacks = true diff --git a/src/cmd/go/testdata/script/mod_tidy.txt b/src/cmd/go/testdata/script/mod_tidy.txt new file mode 100644 index 0000000..b1d9371 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy.txt @@ -0,0 +1,72 @@ +env GO111MODULE=on + +# tidy removes unused y, but everything else is used +go mod tidy -v +stderr '^unused y.1' +! stderr '^unused [^y]' + +grep 'go 1.10' go.mod + +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 +! grep 'go ' go.mod +go mod tidy + +# tidy should add missing go line +grep 'go ' go.mod + +-- go.mod -- +module m + +go 1.10 + +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/src/cmd/go/testdata/script/mod_tidy_cycle.txt b/src/cmd/go/testdata/script/mod_tidy_cycle.txt new file mode 100644 index 0000000..e46f37d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_cycle.txt @@ -0,0 +1,75 @@ +# Regression test for https://golang.org/issue/34086: +# 'go mod tidy' produced different go.mod file from other +# subcommands when certain kinds of cycles were present +# in the build graph. + +env GO111MODULE=on + +cp go.mod go.mod.orig +go mod tidy +cmp go.mod go.mod.orig + +# If the go.mod file is already tidy, 'go mod graph' should not modify it. +go mod graph +cmp go.mod go.mod.orig + +-- go.mod -- +module root + +go 1.13 + +replace ( + a v0.1.0 => ./a1 + b v0.1.0 => ./b1 + b v0.2.0 => ./b2 + c v0.1.0 => ./c1 + c v0.2.0 => ./c2 +) + +require ( + a v0.1.0 + b v0.2.0 // indirect +) +-- main.go -- +package main + +import _ "a" + +func main() {} + +-- a1/go.mod -- +module a + +go 1.13 + +require b v0.1.0 +-- a1/a.go -- +package a + +import _ "c" +-- b1/go.mod -- +module b + +go 1.13 + +require c v0.1.0 +-- b2/go.mod -- +module b + +go 1.13 + +require c v0.2.0 +-- c1/go.mod -- +module c + +go 1.13 +-- c2/c.go -- +package c +-- c2/go.mod -- +module c + +go 1.13 + +require b v0.2.0 +-- c2/c.go -- +package c diff --git a/src/cmd/go/testdata/script/mod_tidy_error.txt b/src/cmd/go/testdata/script/mod_tidy_error.txt new file mode 100644 index 0000000..395537b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_error.txt @@ -0,0 +1,39 @@ +env GO111MODULE=on + +# Regression test for golang.org/issue/27063: +# 'go mod tidy' and 'go mod vendor' should not hide loading errors. + +! go mod tidy +! stderr 'package nonexist is not in GOROOT' +stderr '^issue27063 imports\n\tnonexist.example.com: cannot find module providing package nonexist.example.com' +stderr '^issue27063 imports\n\tissue27063/other imports\n\tother.example.com/nonexist: cannot find module providing package other.example.com/nonexist' + +! go mod vendor +! stderr 'package nonexist is not in GOROOT' +stderr '^issue27063 imports\n\tnonexist.example.com: cannot find module providing package nonexist.example.com' +stderr '^issue27063 imports\n\tissue27063/other imports\n\tother.example.com/nonexist: cannot find module providing package other.example.com/nonexist' + +-- go.mod -- +module issue27063 + +go 1.13 + +require issue27063/other v0.0.0 +replace issue27063/other => ./other +-- x.go -- +package main + +import ( + "nonexist" + + "nonexist.example.com" + "issue27063/other" +) + +func main() {} +-- other/go.mod -- +module issue27063/other +-- other/other.go -- +package other + +import "other.example.com/nonexist" diff --git a/src/cmd/go/testdata/script/mod_tidy_old.txt b/src/cmd/go/testdata/script/mod_tidy_old.txt new file mode 100644 index 0000000..7428f0c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_old.txt @@ -0,0 +1,46 @@ +# 'go mod tidy' should remove content sums for module versions that aren't +# in the build list. It should preserve go.mod sums for module versions that +# are in the module graph though. +# Verifies golang.org/issue/33008. +go mod tidy +! grep '^rsc.io/quote v1.5.0 h1:' go.sum +grep '^rsc.io/quote v1.5.0/go.mod h1:' go.sum + +-- go.mod -- +module m + +go 1.15 + +require ( + rsc.io/quote v1.5.2 + example.com/r v0.0.0 +) + +replace example.com/r => ./r + +-- go.sum -- +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.0 h1:6fJa6E+wGadANKkUMlZ0DhXFpoKlslOQDCo259XtdIE= +rsc.io/quote v1.5.0/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/testonly v1.0.0 h1:K/VWHdO+Jv7woUXG0GzVNx1czBXUt3Ib1deaMn+xk64= +rsc.io/testonly v1.0.0/go.mod h1:OqmGbIFOcF+XrFReLOGZ6BhMM7uMBiQwZsyNmh74SzY= + +-- r/go.mod -- +module example.com/r + +require rsc.io/quote v1.5.0 + +-- use.go -- +package use + +import _ "example.com/r" + +-- r/use.go -- +package use + +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_tidy_quote.txt b/src/cmd/go/testdata/script/mod_tidy_quote.txt new file mode 100644 index 0000000..423c7c2 --- /dev/null +++ b/src/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/src/cmd/go/testdata/script/mod_tidy_replace.txt b/src/cmd/go/testdata/script/mod_tidy_replace.txt new file mode 100644 index 0000000..dd99438 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_replace.txt @@ -0,0 +1,138 @@ +env GO111MODULE=on +env GOFLAGS=-mod=mod +[short] skip + +# golang.org/issue/30166: 'go mod tidy' should not crash if a replaced module is +# involved in a cycle. +cd cycle +env GOTRACEBACK=off +go mod tidy +cd .. + +# From inside the module, 'go list -m all' should NOT include transitive +# requirements of modules that have been replaced. +go list -m all +stdout 'rsc.io/quote/v3 v3.0.0' +! stdout 'rsc.io/sampler' +! stdout 'golang.org/x/text' + +# From outside the module, 'go list -m all' should include them. +cd outside +go list -m all +stdout 'rsc.io/quote/v3 v3.0.0' +stdout 'rsc.io/sampler v1.3.0' +stdout 'golang.org/x/text' +cd .. + +# 'go list all' should add indirect requirements to satisfy the packages +# imported from replacement modules. +! grep 'rsc.io/sampler' go.mod +! grep 'golang.org/x/text' go.mod +go list all +grep 'rsc.io/sampler' go.mod +grep 'golang.org/x/text' go.mod + +# 'go get' and 'go mod tidy' should follow the requirements of the replacements, +# not the originals, even if that results in a set of versions that are +# misleading or redundant without those replacements. +go get -d rsc.io/sampler@v1.2.0 +go mod tidy +go list -m all +stdout 'rsc.io/quote/v3 v3.0.0' +stdout 'rsc.io/sampler v1.2.0' +stdout 'golang.org/x/text' + +# The requirements seen from outside may be higher (or lower) +# than those seen from within the module. +grep 'rsc.io/sampler v1.2.0' go.mod +cd outside +go list -m all +stdout 'rsc.io/sampler v1.3.0' +cd .. + +# The same module can't be used as two different paths. +cd multiple-paths +! go mod tidy +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 example.com/tidy + +require rsc.io/quote/v3 v3.0.0 +replace rsc.io/quote/v3 => ./not-rsc.io/quote/v3 + +-- imports.go -- +package tidy + +import _ "rsc.io/quote/v3" + +-- outside/go.mod -- +module example.com/tidy/outside + +require example.com/tidy v0.0.0 +replace example.com/tidy => ./.. + +-- not-rsc.io/quote/v3/go.mod -- +module not-rsc.io/quote/v3 + +// No requirements specified! + +-- not-rsc.io/quote/v3/quote.go -- +package quote + +import ( + _ "rsc.io/sampler" + _ "golang.org/x/text/language" +) + +-- cycle/go.mod -- +module golang.org/issue/30166 + +require ( + golang.org/issue/30166/a v0.0.0 + golang.org/issue/30166/b v0.0.0 +) + +replace ( + golang.org/issue/30166/a => ./a + golang.org/issue/30166/b => ./b +) +-- cycle/cycle.go -- +package cycle + +import ( + _ "golang.org/issue/30166/a" + _ "golang.org/issue/30166/b" +) +-- cycle/a/a.go -- +package a +-- cycle/a/go.mod -- +module golang.org/issue/30166/a + +require golang.org/issue/30166/b v0.0.0 +-- cycle/b/b.go -- +package b +-- cycle/b/go.mod -- +module golang.org/issue/30166/b + +require golang.org/issue/30166/a v0.0.0 +-- multiple-paths/main.go -- +package main + +import ( + "fmt" + "rsc.io/quote/v3" +) + +func main() { + fmt.Println(quote.GoV3()) +} +-- multiple-paths/go.mod -- +module quoter + +require ( + rsc.io/quote/v3 v3.0.0 + not-rsc.io/quote/v3 v3.0.0 +) + +replace not-rsc.io/quote/v3 => rsc.io/quote/v3 v3.0.0 diff --git a/src/cmd/go/testdata/script/mod_tidy_sum.txt b/src/cmd/go/testdata/script/mod_tidy_sum.txt new file mode 100644 index 0000000..c583f56 --- /dev/null +++ b/src/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 -d 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 -d 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/src/cmd/go/testdata/script/mod_tidy_too_new.txt b/src/cmd/go/testdata/script/mod_tidy_too_new.txt new file mode 100644 index 0000000..ca3163e --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_too_new.txt @@ -0,0 +1,48 @@ +# https://golang.org/issue/46142: 'go mod tidy' should error out if the version +# in the go.mod file is newer than the most recent supported version. + +cp go.mod go.mod.orig + + +# If the go.mod file specifies an unsupported Go version, 'go mod tidy' should +# refuse to edit it: we don't know what a tidy go.mod file for that version +# would look like. + +! go mod tidy +stderr 'go mod tidy: go.mod file indicates go 2000.0, but maximum supported version is '$goversion'$' +cmp go.mod go.mod.orig + + +# The -e flag should push past the error and edit the file anyway, +# but preserve the too-high version. + +cp go.mod.orig go.mod +go mod tidy -e +stderr 'go mod tidy: go.mod file indicates go 2000.0, but maximum supported version is '$goversion'$' +cmp go.mod go.mod.tidy + + +-- go.mod -- +module example.net/from/the/future + +go 2000.0 + +replace example.net/m v0.0.0 => ./m +-- go.mod.tidy -- +module example.net/from/the/future + +go 2000.0 + +replace example.net/m v0.0.0 => ./m + +require example.net/m v0.0.0 +-- x.go -- +package x + +import "example.net/m" +-- m/go.mod -- +module example.net/m + +go 1.17 +-- m/m.go -- +package m diff --git a/src/cmd/go/testdata/script/mod_upgrade_patch.txt b/src/cmd/go/testdata/script/mod_upgrade_patch.txt new file mode 100644 index 0000000..8b34f8b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_upgrade_patch.txt @@ -0,0 +1,110 @@ +env GO111MODULE=on +[short] skip + +# Initially, we are at v1.0.0 for all dependencies. +go get -d +cp go.mod go.mod.orig +go list -m all +stdout '^patch.example.com/direct v1.0.0' +stdout '^patch.example.com/indirect v1.0.0' +! stdout '^patch.example.com/depofdirectpatch' + +# @patch should be rejected for modules not already in the build list. +! go get -d patch.example.com/depofdirectpatch@patch +stderr '^go get: can''t query version "patch" of module patch.example.com/depofdirectpatch: no existing version is required$' +cmp go.mod.orig go.mod + +# get -u=patch, with no arguments, should patch-update all dependencies +# of the package in the current directory, pulling in transitive dependencies +# and also patching those. +cp go.mod.orig go.mod +go get -d -u=patch +go list -m all +stdout '^patch.example.com/direct v1.0.1' +stdout '^patch.example.com/indirect v1.0.1' +stdout '^patch.example.com/depofdirectpatch v1.0.0' + +# 'get all@patch' should patch the modules that provide packages in 'all'. +cp go.mod.orig go.mod +go get -d all@patch +go list -m all +stdout '^patch.example.com/direct v1.0.1' +stdout '^patch.example.com/indirect v1.0.1' +stdout '^patch.example.com/depofdirectpatch v1.0.0' + +# ...but 'all@patch' should fail if any of the affected modules do not already +# have a selected version. +cp go.mod.orig go.mod +go mod edit -droprequire=patch.example.com/direct +cp go.mod go.mod.dropped +! go get -d all@patch +stderr '^go get all@patch: can''t query version "patch" of module patch.example.com/direct: no existing version is required$' +cmp go.mod.dropped go.mod + +# Requesting the direct dependency with -u=patch but without an explicit version +# should patch-update it and its dependencies. +cp go.mod.orig go.mod +go get -d -u=patch patch.example.com/direct +go list -m all +stdout '^patch.example.com/direct v1.0.1' +stdout '^patch.example.com/indirect v1.0.1' +stdout '^patch.example.com/depofdirectpatch v1.0.0' + +# Requesting only the indirect dependency should not update the direct one. +cp go.mod.orig go.mod +go get -d -u=patch patch.example.com/indirect +go list -m all +stdout '^patch.example.com/direct v1.0.0' +stdout '^patch.example.com/indirect v1.0.1' +! stdout '^patch.example.com/depofdirectpatch' + +# @patch should apply only to the specific module, +# but the result must reflect its upgraded requirements. +cp go.mod.orig go.mod +go get -d patch.example.com/direct@patch +go list -m all +stdout '^patch.example.com/direct v1.0.1' +stdout '^patch.example.com/indirect v1.0.0' +stdout '^patch.example.com/depofdirectpatch v1.0.0' + +# An explicit @patch should override a general -u. +cp go.mod.orig go.mod +go get -d -u patch.example.com/direct@patch +go list -m all +stdout '^patch.example.com/direct v1.0.1' +stdout '^patch.example.com/indirect v1.1.0' +stdout '^patch.example.com/depofdirectpatch v1.0.0' + +# An explicit @latest should override a general -u=patch. +cp go.mod.orig go.mod +go get -d -u=patch patch.example.com/direct@latest +go list -m all +stdout '^patch.example.com/direct v1.1.0' +stdout '^patch.example.com/indirect v1.0.1' +! stdout '^patch.example.com/depofdirectpatch' + +# Standard library packages cannot be upgraded explicitly. +cp go.mod.orig go.mod +! go get cmd/vet@patch +stderr 'go get: can''t request explicit version "patch" of standard library package cmd/vet$' + +# However, standard-library packages without explicit versions are fine. +go get -d -u=patch -d cmd/go + +# We can upgrade to a new version of a module with no root package. +go get -d example.com/noroot@v1.0.0 +go list -m all +stdout '^example.com/noroot v1.0.0$' +go get -d example.com/noroot@patch +go list -m all +stdout '^example.com/noroot v1.0.1$' + + +-- go.mod -- +module x + +require patch.example.com/direct v1.0.0 + +-- main.go -- +package x +import _ "patch.example.com/direct" diff --git a/src/cmd/go/testdata/script/mod_vcs_missing.txt b/src/cmd/go/testdata/script/mod_vcs_missing.txt new file mode 100644 index 0000000..f8be43c --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vcs_missing.txt @@ -0,0 +1,28 @@ +[exec:bzr] skip 'tests NOT having bzr' +[!net] skip + +env GO111MODULE=on +env GOPROXY=direct + +cd empty +! go get -d launchpad.net/gocheck +stderr '"bzr": executable file not found' +cd .. + +# 1.11 used to give the cryptic error "cannot find module for path" here, but +# only for a main package. +cd main +! go build -mod=mod +stderr '"bzr": executable file not found' +cd .. + +-- empty/go.mod -- +module m +-- main/go.mod -- +module m +-- main/main.go -- +package main + +import _ "launchpad.net/gocheck" + +func main() {} diff --git a/src/cmd/go/testdata/script/mod_vendor.txt b/src/cmd/go/testdata/script/mod_vendor.txt new file mode 100644 index 0000000..2622916 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vendor.txt @@ -0,0 +1,312 @@ +env GO111MODULE=on + +# Without vendoring, a build should succeed unless -mod=vendor is set. +[!short] go build +[!short] ! go build -mod=vendor + +# Without vendoring, 'go list' should report the replacement directory for +# a package in a replaced module. +go list -f {{.Dir}} x +stdout 'src[\\/]x' + +# 'go mod vendor' should copy all replaced modules to the vendor directory. +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' +grep 'a/foo/bar/b\na/foo/bar/c' vendor/modules.txt # must be sorted + +# An explicit '-mod=mod' should ignore the vendor directory. +go list -mod=mod -f {{.Dir}} x +stdout 'src[\\/]x' + +go list -mod=mod -f {{.Dir}} -m x +stdout 'src[\\/]x' + +# An explicit '-mod=vendor' should report package directories within +# the vendor directory. +go list -mod=vendor -f {{.Dir}} x +stdout 'src[\\/]vendor[\\/]x' + +# 'go list -mod=vendor -m' should successfully list vendored modules, +# but should not provide a module directory because no directory contains +# the complete module. +go list -mod=vendor -f '{{.Version}} {{.Dir}}' -m x +stdout '^v1.0.0 $' + +# -mod=vendor should cause 'go list' flags that look up versions to fail. +! go list -mod=vendor -versions -m x +stderr '^go list -m: can''t determine available versions using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)$' +! go list -mod=vendor -u -m x +stderr '^go list -m: can''t determine available upgrades using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)$' + +# 'go list -mod=vendor -m' on a transitive dependency that does not +# provide vendored packages should give a helpful error rather than +# 'not a known dependency'. +! go list -mod=vendor -f '{{.Version}} {{.Dir}}' -m diamondright +stderr 'go list -m: module diamondright: can''t resolve module using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)' + +# 'go list -mod=mod' should report packages outside the import graph, +# but 'go list -mod=vendor' should error out for them. +go list -mod=mod -f {{.Dir}} w +stdout 'src[\\/]w' +! go list -mod=vendor -f {{.Dir}} w +stderr 'src[\\/]vendor[\\/]w' + +go list -mod=mod -f {{.Dir}} diamondright +stdout 'src[\\/]diamondright' + +# Test dependencies should not be copied. +! exists vendor/x/testdata +! exists vendor/a/foo/bar/b/ignored.go +! exists vendor/a/foo/bar/b/main_test.go + +# Licenses and other metadata for each module should be copied +# if any package within their module is copied. +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' and 'go test' using vendored packages should succeed. +go build -mod=mod +go build -mod=vendor +go test -mod=vendor . ./subdir +go test -mod=vendor ./... +go fmt -mod=vendor ./... + +-- go.mod -- +module m + +go 1.13 + +require ( + a v1.0.0 + diamondroot v0.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 + diamondleft => ./diamondleft + diamondpoint => ./diamondpoint + diamondright => ./diamondright + diamondroot => ./diamondroot + 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/ignored.go -- +// This file is intended for use with "go run"; it isn't really part of the package. + +// +build ignore + +package main + +func main() {} +-- 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 +import _ "a/foo/bar/b" +-- 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" +-- 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/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" +-- importdiamond.go -- +package m + +import _ "diamondroot" +-- 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 + +-- diamondroot/go.mod -- +module diamondroot + +require ( + diamondleft v0.0.0 + diamondright v0.0.0 +) +-- diamondroot/x.go -- +package diamondroot + +import _ "diamondleft" +-- diamondroot/unused/unused.go -- +package unused + +import _ "diamondright" +-- diamondleft/go.mod -- +module diamondleft + +require ( + diamondpoint v0.0.0 +) +-- diamondleft/x.go -- +package diamondleft + +import _ "diamondpoint" +-- diamondright/go.mod -- +module diamondright + +require ( + diamondpoint v0.0.0 +) +-- diamondright/x.go -- +package diamondright + +import _ "diamondpoint" +-- diamondpoint/go.mod -- +module diamondpoint +-- diamondpoint/x.go -- +package diamondpoint diff --git a/src/cmd/go/testdata/script/mod_vendor_auto.txt b/src/cmd/go/testdata/script/mod_vendor_auto.txt new file mode 100644 index 0000000..b0ea907 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vendor_auto.txt @@ -0,0 +1,256 @@ +# Integration test for golang.org/issue/33848: automatically check and use vendored packages. + +env GO111MODULE=on + +[short] skip + +cd $WORK/auto +cp go.mod go.mod.orig +cp $WORK/modules-1.13.txt $WORK/auto/modules.txt + +# An explicit -mod=vendor should force use of the vendor directory. +env GOFLAGS=-mod=vendor + +go list -f {{.Dir}} -tags tools all +stdout '^'$WORK'[/\\]auto$' +stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]printversion$' +stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]version$' + +! go list -m all +stderr 'go list -m: can''t compute ''all'' using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)' + +! go list -m -f '{{.Dir}}' all +stderr 'go list -m: can''t compute ''all'' using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)' + +# An explicit -mod=mod should force the vendor directory to be ignored. +env GOFLAGS=-mod=mod + +go list -f {{.Dir}} -tags tools all +stdout '^'$WORK'[/\\]auto$' +stdout '^'$GOPATH'[/\\]pkg[/\\]mod[/\\]example.com[/\\]printversion@v1.0.0$' +stdout '^'$WORK'[/\\]auto[/\\]replacement-version$' + +go list -m all +stdout '^example.com/auto$' +stdout 'example.com/printversion v1.0.0' +stdout 'example.com/version v1.0.0' + +go list -m -f '{{.Dir}}' all +stdout '^'$WORK'[/\\]auto$' +stdout '^'$GOPATH'[/\\]pkg[/\\]mod[/\\]example.com[/\\]printversion@v1.0.0$' +stdout '^'$WORK'[/\\]auto[/\\]replacement-version$' + +# If the main module's "go" directive says 1.13, we should default to -mod=mod. +env GOFLAGS= +go mod edit -go=1.13 + +go list -f {{.Dir}} -tags tools all +stdout '^'$WORK'[/\\]auto$' +stdout '^'$GOPATH'[/\\]pkg[/\\]mod[/\\]example.com[/\\]printversion@v1.0.0$' +stdout '^'$WORK'[/\\]auto[/\\]replacement-version$' + +go list -m -f '{{.Dir}}' all +stdout '^'$WORK'[/\\]auto$' +stdout '^'$GOPATH'[/\\]pkg[/\\]mod[/\\]example.com[/\\]printversion@v1.0.0$' +stdout '^'$WORK'[/\\]auto[/\\]replacement-version$' + +# A 'go 1.14' directive in the main module's go.mod file should enable +# -mod=vendor by default, along with stronger checks for consistency +# between the go.mod file and vendor/modules.txt. +# A 'go 1.13' vendor/modules.txt file is not usually sufficient +# to pass those checks. +go mod edit -go=1.14 + +! go list -f {{.Dir}} -tags tools all +stderr '^go: inconsistent vendoring in '$WORK[/\\]auto':$' +stderr '^\texample.com/printversion@v1.0.0: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt' +stderr '^\texample.com/unused: is replaced in go.mod, but not marked as replaced in vendor/modules.txt' +stderr '^\texample.com/version@v1.2.0: is replaced in go.mod, but not marked as replaced in vendor/modules.txt' +stderr '^\tTo ignore the vendor directory, use -mod=readonly or -mod=mod.\n\tTo sync the vendor directory, run:\n\t\tgo mod vendor$' + +# Module-specific subcommands should continue to load the full module graph. +go mod graph +stdout '^example.com/printversion@v1.0.0 example.com/version@v1.0.0$' + +# An explicit -mod=mod should still force the vendor directory to be ignored. +env GOFLAGS=-mod=mod + +go list -f {{.Dir}} -tags tools all +stdout '^'$WORK'[/\\]auto$' +stdout '^'$GOPATH'[/\\]pkg[/\\]mod[/\\]example.com[/\\]printversion@v1.0.0$' +stdout '^'$WORK'[/\\]auto[/\\]replacement-version$' + +go list -m all +stdout '^example.com/auto$' +stdout 'example.com/printversion v1.0.0' +stdout 'example.com/version v1.0.0' + +go list -m -f '{{.Dir}}' all +stdout '^'$WORK'[/\\]auto$' +stdout '^'$GOPATH'[/\\]pkg[/\\]mod[/\\]example.com[/\\]printversion@v1.0.0$' +stdout '^'$WORK'[/\\]auto[/\\]replacement-version$' + +# 'go mod vendor' should repair vendor/modules.txt so that the implicit +# -mod=vendor works again. +env GOFLAGS= + +go mod edit -go=1.14 +go mod vendor + +go list -f {{.Dir}} -tags tools all +stdout '^'$WORK'[/\\]auto$' +stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]printversion$' +stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]version$' + +# ...but 'go list -m' should continue to fail, this time without +# referring to a -mod default that the user didn't set. +! go list -m all +stderr 'go list -m: can''t compute ''all'' using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)' + +! go list -m -f '{{.Dir}}' all +stderr 'go list -m: can''t compute ''all'' using the vendor directory\n\t\(Use -mod=mod or -mod=readonly to bypass.\)' + + +# 'go mod init' should work if there is already a GOPATH-mode vendor directory +# present. If there are no module dependencies, -mod=vendor should be used by +# default and should not fail the consistency check even though no module +# information is present. + +rm go.mod +rm vendor/modules.txt + +go mod init example.com/auto +go list -f {{.Dir}} -tags tools all +stdout '^'$WORK'[/\\]auto$' +stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]printversion$' +stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]version$' + +# If information about dependencies is added to a 1.14 go.mod file, subsequent +# list commands should error out if vendor/modules.txt is missing or incomplete. + +cp go.mod.orig go.mod +go mod edit -go=1.14 +! go list -f {{.Dir}} -tags tools all +stderr '^go: inconsistent vendoring in '$WORK[/\\]auto':$' +stderr '^\texample.com/printversion@v1.0.0: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt' +stderr '^\texample.com/unused: is replaced in go.mod, but not marked as replaced in vendor/modules.txt' +stderr '^\texample.com/version@v1.2.0: is replaced in go.mod, but not marked as replaced in vendor/modules.txt' +stderr '^\tTo ignore the vendor directory, use -mod=readonly or -mod=mod.\n\tTo sync the vendor directory, run:\n\t\tgo mod vendor$' + +# If -mod=vendor is set, limited consistency checks should apply even when +# the go version is 1.13 or earlier. +# An incomplete or missing vendor/modules.txt should resolve the vendored packages... +go mod edit -go=1.13 +go list -mod=vendor -f {{.Dir}} -tags tools all +stdout '^'$WORK'[/\\]auto$' +stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]printversion$' +stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]version$' + +# ...but a version mismatch for an explicit dependency should be noticed. +cp $WORK/modules-bad-1.13.txt vendor/modules.txt +! go list -mod=vendor -f {{.Dir}} -tags tools all +stderr '^go: inconsistent vendoring in '$WORK[/\\]auto':$' +stderr '^\texample.com/printversion@v1.0.0: is explicitly required in go.mod, but vendor/modules.txt indicates example.com/printversion@v1.1.0$' +stderr '^\tTo ignore the vendor directory, use -mod=readonly or -mod=mod.\n\tTo sync the vendor directory, run:\n\t\tgo mod vendor$' + +# If the go version is still 1.13, 'go mod vendor' should write a +# matching vendor/modules.txt containing the corrected 1.13 data. +go mod vendor +cmp $WORK/modules-1.13.txt vendor/modules.txt + +go list -mod=vendor -f {{.Dir}} -tags tools all +stdout '^'$WORK'[/\\]auto$' +stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]printversion$' +stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]version$' + +# When the version is upgraded to 1.14, 'go mod vendor' should write a +# vendor/modules.txt with the updated 1.14 annotations. +go mod edit -go=1.14 +go mod vendor +cmp $WORK/modules-1.14.txt vendor/modules.txt + +# Then, -mod=vendor should kick in automatically and succeed. +go list -f {{.Dir}} -tags tools all +stdout '^'$WORK'[/\\]auto$' +stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]printversion$' +stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]version$' + +# 'go get' should update from the network or module cache, +# even if a vendor directory is present. +go get -d example.com/version@v1.1.0 +! go list -f {{.Dir}} -tags tools all +stderr '^go: inconsistent vendoring' + +-- $WORK/auto/go.mod -- +module example.com/auto + +go 1.13 + +require example.com/printversion v1.0.0 + +replace ( + example.com/unused => nonexistent.example.com/unused v1.0.0-whatever + example.com/version v1.0.0 => ./replacement-version + example.com/version v1.2.0 => nonexistent.example.com/version v1.2.0 +) +-- $WORK/auto/tools.go -- +// +build tools + +package auto + +import _ "example.com/printversion" +-- $WORK/auto/auto.go -- +package auto +-- $WORK/auto/replacement-version/go.mod -- +module example.com/version +-- $WORK/auto/replacement-version/version.go -- +package version + +const V = "v1.0.0-replaced" +-- $WORK/modules-1.14.txt -- +# example.com/printversion v1.0.0 +## explicit +example.com/printversion +# example.com/version v1.0.0 => ./replacement-version +example.com/version +# example.com/unused => nonexistent.example.com/unused v1.0.0-whatever +# example.com/version v1.2.0 => nonexistent.example.com/version v1.2.0 +-- $WORK/modules-1.13.txt -- +# example.com/printversion v1.0.0 +example.com/printversion +# example.com/version v1.0.0 => ./replacement-version +example.com/version +-- $WORK/modules-bad-1.13.txt -- +# example.com/printversion v1.1.0 +example.com/printversion +# example.com/version v1.1.0 +example.com/version +-- $WORK/auto/vendor/example.com/printversion/go.mod -- +module example.com/printversion + +require example.com/version v1.0.0 +replace example.com/version v1.0.0 => ../oops v0.0.0 +exclude example.com/version v1.0.1 +-- $WORK/auto/vendor/example.com/printversion/printversion.go -- +package main + +import ( + "fmt" + "os" + "runtime/debug" + + _ "example.com/version" +) + +func main() { + info, _ := debug.ReadBuildInfo() + fmt.Fprintf(os.Stdout, "path is %s\n", info.Path) + fmt.Fprintf(os.Stdout, "main is %s %s\n", info.Main.Path, info.Main.Version) + for _, m := range info.Deps { + fmt.Fprintf(os.Stdout, "using %s %s\n", m.Path, m.Version) + } +} +-- $WORK/auto/vendor/example.com/version/version.go -- +package version + +const V = "v1.0.0-replaced" diff --git a/src/cmd/go/testdata/script/mod_vendor_build.txt b/src/cmd/go/testdata/script/mod_vendor_build.txt new file mode 100644 index 0000000..3b8eec0 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vendor_build.txt @@ -0,0 +1,41 @@ +env GO111MODULE=on +[short] skip + +# Populate go.mod and go.sum. +go mod tidy + +# 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 -d 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 + +# With a clean (and empty) module cache, 'go list -mod=vendor' should not download modules. +go clean -modcache +env GOPROXY=off +! go list ... +go list -mod=vendor ... + +# However, it should still list packages in the main module. +go list -mod=vendor m/... +stdout m + +-- go.mod -- +module m +go 1.12 +-- x.go -- +package x +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_vendor_embed.txt b/src/cmd/go/testdata/script/mod_vendor_embed.txt new file mode 100644 index 0000000..be11415 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vendor_embed.txt @@ -0,0 +1,179 @@ +go mod vendor +cmp vendor/example.com/a/samedir_embed.txt a/samedir_embed.txt +cmp vendor/example.com/a/subdir/embed.txt a/subdir/embed.txt +cmp vendor/example.com/a/subdir/test/embed.txt a/subdir/test/embed.txt +cmp vendor/example.com/a/subdir/test/xtest/embed.txt a/subdir/test/xtest/embed.txt + +cd broken_no_matching_files +! go mod vendor +stderr 'go mod vendor: pattern foo.txt: no matching files found' + +cd ../broken_bad_pattern +! go mod vendor +stderr 'go mod vendor: pattern ../foo.txt: invalid pattern syntax' + +# matchPotentialSourceFile prunes out tests and unbuilt code. +# Make sure that they are vendored if they are embedded files. +cd ../embed_unbuilt +go mod vendor +cmp vendor/example.com/dep/unbuilt.go dep/unbuilt.go +cmp vendor/example.com/dep/dep_test.go dep/dep_test.go +! exists vendor/example.com/dep/not_embedded_unbuilt.go +! exists vendor/example.com/dep/not_embedded_dep_test.go +-- go.mod -- +module example.com/foo +go 1.16 + +require ( + example.com/a v0.1.0 +) + +replace ( + example.com/a v0.1.0 => ./a +) +-- foo.go -- +package main + +import ( + "fmt" + + "example.com/a" +) + +func main() { + fmt.Println(a.Str()) +} +-- a/go.mod -- +module example.com/a +-- a/a.go -- +package a + +import _ "embed" + +//go:embed samedir_embed.txt +var sameDir string + +//go:embed subdir/embed.txt +var subDir string + +func Str() string { + return sameDir + subDir +} +-- a/a_test.go -- +package a + +import _ "embed" + +//go:embed subdir/test/embed.txt +var subderTest string +-- a/a_x_test.go -- +package a_test + +import _ "embed" + +//go:embed subdir/test/xtest/embed.txt +var subdirXtest string +-- a/samedir_embed.txt -- +embedded file in same directory as package +-- a/subdir/embed.txt -- +embedded file in subdirectory of package +-- a/subdir/test/embed.txt -- +embedded file of test in subdirectory of package +-- a/subdir/test/xtest/embed.txt -- +embedded file of xtest in subdirectory of package +-- broken_no_matching_files/go.mod -- +module example.com/broken +go 1.16 + +require ( + example.com/brokendep v0.1.0 +) + +replace ( + example.com/brokendep v0.1.0 => ./brokendep +) +-- broken_no_matching_files/f.go -- +package broken + +import _ "example.com/brokendep" + +func F() {} +-- broken_no_matching_files/brokendep/go.mod -- +module example.com/brokendep +go 1.16 +-- broken_no_matching_files/brokendep/f.go -- +package brokendep + +import _ "embed" + +//go:embed foo.txt +var foo string +-- broken_bad_pattern/go.mod -- +module example.com/broken +go 1.16 + +require ( + example.com/brokendep v0.1.0 +) + +replace ( + example.com/brokendep v0.1.0 => ./brokendep +) +-- broken_bad_pattern/f.go -- +package broken + +import _ "example.com/brokendep" + +func F() {} +-- broken_bad_pattern/brokendep/go.mod -- +module example.com/brokendep +go 1.16 +-- broken_bad_pattern/brokendep/f.go -- +package brokendep + +import _ "embed" + +//go:embed ../foo.txt +var foo string +-- embed_unbuilt/go.mod -- +module example.com/foo +go 1.16 + +require ( + example.com/dep v0.1.0 +) + +replace ( + example.com/dep v0.1.0 => ./dep +) +-- embed_unbuilt/foo.go -- +package a + +import _ "example.com/dep" + +func F() {} +-- embed_unbuilt/dep/go.mod -- +module example.com/dep +go 1.16 +-- embed_unbuilt/dep/dep.go -- +package dep + +import _ "embed" + +//go:embed unbuilt.go +var unbuilt string + +//go:embed dep_test.go +var depTest string +-- embed_unbuilt/dep/unbuilt.go -- +// +build ignore + +package dep +-- embed_unbuilt/dep/not_embedded_unbuilt.go -- +// +build ignore + +package dep +-- embed_unbuilt/dep/dep_test.go -- +package dep +-- embed_unbuilt/dep/not_embedded_dep_test.go -- +package dep diff --git a/src/cmd/go/testdata/script/mod_vendor_nodeps.txt b/src/cmd/go/testdata/script/mod_vendor_nodeps.txt new file mode 100644 index 0000000..e9a84ca --- /dev/null +++ b/src/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/src/cmd/go/testdata/script/mod_vendor_replace.txt b/src/cmd/go/testdata/script/mod_vendor_replace.txt new file mode 100644 index 0000000..0c1c1d2 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vendor_replace.txt @@ -0,0 +1,66 @@ +env GO111MODULE=on + +# Before vendoring, we expect to see the original directory. +go list -f '{{with .Module}}{{.Version}}{{end}} {{.Dir}}' rsc.io/quote/v3 +stdout 'v3.0.0' +stdout '.*[/\\]not-rsc.io[/\\]quote[/\\]v3' + +# Since all dependencies are replaced, 'go mod vendor' should not +# have to download anything from the network. +go mod vendor +! stderr 'downloading' +! stderr 'finding' + +# After vendoring, we expect to see the replacement in the vendor directory, +# without attempting to look up the non-replaced version. +cmp vendor/rsc.io/quote/v3/quote.go local/not-rsc.io/quote/v3/quote.go + +go list -mod=vendor -f '{{with .Module}}{{.Version}}{{end}} {{.Dir}}' rsc.io/quote/v3 +stdout 'v3.0.0' +stdout '.*[/\\]vendor[/\\]rsc.io[/\\]quote[/\\]v3' +! stderr 'finding' +! stderr 'lookup disabled' + +# 'go list' should provide the original replacement directory as the module's +# replacement path. +go list -mod=vendor -f '{{with .Module}}{{with .Replace}}{{.Path}}{{end}}{{end}}' rsc.io/quote/v3 +stdout '.*[/\\]not-rsc.io[/\\]quote[/\\]v3' + +# The same module can't be used as two different paths. +cd multiple-paths +! go mod vendor +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 example.com/replace + +require rsc.io/quote/v3 v3.0.0 +replace rsc.io/quote/v3 => ./local/not-rsc.io/quote/v3 + +-- imports.go -- +package replace + +import _ "rsc.io/quote/v3" + +-- local/not-rsc.io/quote/v3/go.mod -- +module not-rsc.io/quote/v3 + +-- local/not-rsc.io/quote/v3/quote.go -- +package quote + +-- multiple-paths/main.go -- +package main +import ( + "fmt" + "rsc.io/quote/v3" +) +func main() { + fmt.Println(quote.GoV3()) +} +-- multiple-paths/go.mod -- +module quoter +require ( + rsc.io/quote/v3 v3.0.0 + not-rsc.io/quote/v3 v3.0.0 +) +replace not-rsc.io/quote/v3 => rsc.io/quote/v3 v3.0.0 diff --git a/src/cmd/go/testdata/script/mod_vendor_trimpath.txt b/src/cmd/go/testdata/script/mod_vendor_trimpath.txt new file mode 100644 index 0000000..5451aa7 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vendor_trimpath.txt @@ -0,0 +1,45 @@ +# Check that when -trimpath and -mod=vendor are used together, +# paths in vendored packages are properly trimmed. +# Verifies golang.org/issue/36566. + +[short] skip + +# Only the main module has a root directory in vendor mode. +go mod vendor +go list -f {{.Module.Dir}} example.com/main +stdout $PWD +go list -f {{.Module.Dir}} example.com/stack +! stdout . + +# The program prints a file name from a vendored package. +# Without -trimpath, the name should include the vendor directory. +go run main.go +stdout vendor + +# With -trimpath, everything before the package path should be trimmed. +# As with -mod=mod, the version should appear as part of the module path. +go run -mod=vendor -trimpath main.go +stdout '^example.com/stack@v1.0.0/stack.go$' + +# With pristinely vendored source code, a trimmed binary built from vendored +# code should have the same behavior as one build from the module cache. +go run -mod=mod -trimpath main.go +stdout '^example.com/stack@v1.0.0/stack.go$' + +-- go.mod -- +module example.com/main + +require example.com/stack v1.0.0 + +-- main.go -- +package main + +import ( + "fmt" + + "example.com/stack" +) + +func main() { + fmt.Println(stack.TopFile()) +} diff --git a/src/cmd/go/testdata/script/mod_vendor_unused.txt b/src/cmd/go/testdata/script/mod_vendor_unused.txt new file mode 100644 index 0000000..96251bb --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vendor_unused.txt @@ -0,0 +1,67 @@ +# Auxiliary test for inclusion of otherwise-unused replacements in +# vendor/modules.txt for golang.org/issue/33848. +# We need metadata about replacements in order to verify that modules.txt +# remains in sync with the main module's go.mod file. + +env GO111MODULE=on + +go mod vendor +cmp go1.14-modules.txt vendor/modules.txt + +-- go.mod -- +module example.com/foo +go 1.14 + +require ( + example.com/a v0.1.0 +) + +replace ( + example.com/a v0.1.0 => ./a + example.com/b v0.1.0 => ./b1 + example.com/b v0.2.0-unused => ./b2 + example.com/c => ./c + example.com/d v0.1.0 => ./d1 + example.com/d v0.2.0 => ./d2 + example.com/e => example.com/e v0.1.0-unused +) +-- foo.go -- +package foo +import _ "example.com/a" +-- a/go.mod -- +module example.com/a +require ( + example.com/b v0.1.0 // indirect + example.com/c v0.1.0 // indirect +) +-- a/a.go -- +package a +import _ "example.com/d" +-- b1/go.mod -- +module example.com/b +require example.com/d v0.1.0 +-- b2/go.mod -- +module example.com/b +require example.com/c v0.2.0 +-- c/go.mod -- +module example.com/c +require example.com/d v0.2.0 +-- d1/go.mod -- +module example.com/d +-- d1/d1.go -- +package d +-- d2/go.mod -- +module example.com/d +-- d2/d2.go -- +package d +-- go1.14-modules.txt -- +# example.com/a v0.1.0 => ./a +## explicit +example.com/a +# example.com/d v0.2.0 => ./d2 +example.com/d +# example.com/b v0.1.0 => ./b1 +# example.com/b v0.2.0-unused => ./b2 +# example.com/c => ./c +# example.com/d v0.1.0 => ./d1 +# example.com/e => example.com/e v0.1.0-unused diff --git a/src/cmd/go/testdata/script/mod_vendor_unused_only.txt b/src/cmd/go/testdata/script/mod_vendor_unused_only.txt new file mode 100644 index 0000000..839c645 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vendor_unused_only.txt @@ -0,0 +1,17 @@ +# Ensure that we generate a vendor/modules.txt file even when the only +# requirements in go.mod are unused. Regression test for +# golang.org/issue/36580 + +env GO111MODULE=on + +go mod vendor +cmp go1.14-modules.txt vendor/modules.txt + +-- go.mod -- +module example.com/m +go 1.14 + +require example.com v1.0.0 // indirect +-- go1.14-modules.txt -- +# example.com v1.0.0 +## explicit diff --git a/src/cmd/go/testdata/script/mod_verify.txt b/src/cmd/go/testdata/script/mod_verify.txt new file mode 100644 index 0000000..b510665 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_verify.txt @@ -0,0 +1,87 @@ +env GO111MODULE=on +[short] skip + +# 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. +rm go.sum +cp go.sum.bad go.sum +! 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. +rm go.sum +cp go.sum.good go.sum +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 + +# 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 + +# verify should fail on a missing ziphash. tidy should restore it. +rm $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.1.0.ziphash +! go mod verify +stderr '^rsc.io/quote v1.1.0: missing ziphash: open '$GOPATH'[/\\]pkg[/\\]mod[/\\]cache[/\\]download[/\\]rsc.io[/\\]quote[/\\]@v[/\\]v1.1.0.ziphash' +go mod tidy +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.1.0.ziphash +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 get -d rsc.io/quote/buggy +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/src/cmd/go/testdata/script/mod_versions.txt b/src/cmd/go/testdata/script/mod_versions.txt new file mode 100644 index 0000000..9e6322b --- /dev/null +++ b/src/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 '^go: can only use path@version syntax with ''go get'' and ''go install'' in module-aware mode$' +! go build rsc.io/quote@v1.5.1 +stderr '^package rsc.io/quote@v1.5.1: can only use path@version syntax with ''go get'' and ''go install'' in module-aware mode$' + +env GO111MODULE=on +cd x +! go build rsc.io/quote@v1.5.1 +stderr '^package rsc.io/quote@v1.5.1: can only use path@version syntax with ''go get'' and ''go install'' in module-aware mode$' + +-- x/go.mod -- +module x diff --git a/src/cmd/go/testdata/script/mod_why.txt b/src/cmd/go/testdata/script/mod_why.txt new file mode 100644 index 0000000..b3036fa --- /dev/null +++ b/src/cmd/go/testdata/script/mod_why.txt @@ -0,0 +1,130 @@ +env GO111MODULE=on +[short] skip + +# Populate go.sum. +go mod tidy +cp go.mod go.mod.orig + +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 a test of a dependency? +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 + +# package in a module that isn't even in the module graph +# (https://golang.org/issue/26977) +go mod why rsc.io/fortune +cmp stdout why-missing.txt + +# None of these command should have changed the go.mod file. +cmp go.mod go.mod.orig + +-- 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 +-- why-missing.txt -- +# rsc.io/fortune +(main module does not need package rsc.io/fortune) diff --git a/src/cmd/go/testdata/script/modfile_flag.txt b/src/cmd/go/testdata/script/modfile_flag.txt new file mode 100644 index 0000000..0ad0880 --- /dev/null +++ b/src/cmd/go/testdata/script/modfile_flag.txt @@ -0,0 +1,93 @@ +# Tests the behavior of the -modfile flag in commands that support it. +# The go.mod file exists but should not be read or written. +# Same with go.sum. + +env GOFLAGS=-modfile=go.alt.mod +cp go.mod go.mod.orig +cp go.sum go.sum.orig + + +# go mod init should create a new file, even though go.mod already exists. +go mod init example.com/m +grep example.com/m go.alt.mod + +# 'go env GOMOD' should print the path to the real file. +# 'go env' does not recognize the '-modfile' flag. +go env GOMOD +stdout '^\$WORK[/\\]gopath[/\\]src[/\\]go.mod$' + +# 'go list -m' should print the effective go.mod file as GoMod though. +go list -m -f '{{.GoMod}}' +stdout '^go.alt.mod$' + +# go mod edit should operate on the alternate file +go mod edit -require rsc.io/quote@v1.5.2 +grep rsc.io/quote go.alt.mod + +# other 'go mod' commands should work. 'go mod vendor' is tested later. +go mod download rsc.io/quote +go mod graph +stdout rsc.io/quote +go mod tidy +grep rsc.io/quote go.alt.sum +go mod verify +go mod why rsc.io/quote + + +# 'go list' and other commands with build flags should work. +# They should update the alternate go.mod when a dependency is missing. +go mod edit -droprequire rsc.io/quote +go list -mod=mod . +grep rsc.io/quote go.alt.mod +go build -n -mod=mod . +go test -n -mod=mod . +go get -d rsc.io/quote + + +# 'go mod vendor' should work. +go mod vendor +exists vendor + +# Automatic vendoring should be broken by editing an explicit requirement +# in the alternate go.mod file. +go mod edit -require rsc.io/quote@v1.5.1 +! go list . +go list -mod=mod +rm vendor + + +# 'go generate' should use the alternate file when resolving packages. +# Recursive go commands started with 'go generate' should not get an explicitly +# passed -modfile, but they should see arguments from GOFLAGS. +cp go.alt.mod go.gen.mod +env OLD_GOFLAGS=$GOFLAGS +env GOFLAGS=-modfile=go.gen.mod +go generate -modfile=go.alt.mod . +env GOFLAGS=$OLD_GOFLAGS +grep example.com/exclude go.gen.mod +! grep example.com/exclude go.alt.mod + + +# The original files should not have been modified. +cmp go.mod go.mod.orig +cmp go.sum go.sum.orig + + +# If the altnernate mod file does not have a ".mod" suffix, an error +# should be reported. +cp go.alt.mod goaltmod +! go mod tidy -modfile=goaltmod +stderr '-modfile=goaltmod: file does not have .mod extension' + +-- go.mod -- +ʕ◔ϖ◔ʔ +-- go.sum -- +ʕ◔ϖ◔ʔ +-- use.go -- +package main + +import _ "rsc.io/quote" +-- gen.go -- +//go:generate go mod edit -exclude example.com/exclude@v1.0.0 + +package main diff --git a/src/cmd/go/testdata/script/noncanonical_import.txt b/src/cmd/go/testdata/script/noncanonical_import.txt new file mode 100644 index 0000000..018cb01 --- /dev/null +++ b/src/cmd/go/testdata/script/noncanonical_import.txt @@ -0,0 +1,19 @@ +env GO111MODULE=off + +! go build canonical/d +stderr '^canonical[/\\]b[/\\]b.go:3:8: non-canonical import path "canonical/a/": should be "canonical/a"$' + +-- canonical/a/a.go -- +package a + +import _ "c" +-- canonical/b/b.go -- +package b + +import _ "canonical/a/" +-- canonical/a/vendor/c/c.go -- +package c +-- canonical/d/d.go -- +package d + +import _ "canonical/b" diff --git a/src/cmd/go/testdata/script/pattern_syntax_error.txt b/src/cmd/go/testdata/script/pattern_syntax_error.txt new file mode 100644 index 0000000..9a1f5e5 --- /dev/null +++ b/src/cmd/go/testdata/script/pattern_syntax_error.txt @@ -0,0 +1,12 @@ +env GO111MODULE=off + +# 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/src/cmd/go/testdata/script/prevent_sys_unix_import.txt b/src/cmd/go/testdata/script/prevent_sys_unix_import.txt new file mode 100644 index 0000000..ea1ad78 --- /dev/null +++ b/src/cmd/go/testdata/script/prevent_sys_unix_import.txt @@ -0,0 +1,6 @@ +# Policy decision: we shouldn't vendor golang.org/x/sys/unix in std +# See https://golang.org/issue/32102 + +env GO111MODULE=on +go list std +! stdout vendor/golang.org/x/sys/unix diff --git a/src/cmd/go/testdata/script/run_dirs.txt b/src/cmd/go/testdata/script/run_dirs.txt new file mode 100644 index 0000000..538a6ac --- /dev/null +++ b/src/cmd/go/testdata/script/run_dirs.txt @@ -0,0 +1,11 @@ +cd rundir + +! go run x.go sub/sub.go +stderr 'named files must all be in one directory; have ./ and sub/' +! go run sub/sub.go x.go +stderr 'named files must all be in one directory; have sub/ and ./' + +-- rundir/sub/sub.go -- +package main +-- rundir/x.go -- +package main diff --git a/src/cmd/go/testdata/script/run_hello.txt b/src/cmd/go/testdata/script/run_hello.txt new file mode 100644 index 0000000..939b661 --- /dev/null +++ b/src/cmd/go/testdata/script/run_hello.txt @@ -0,0 +1,9 @@ +env GO111MODULE=off + +# hello world +go run hello.go +stderr 'hello world' + +-- hello.go -- +package main +func main() { println("hello world") } diff --git a/src/cmd/go/testdata/script/run_hello_pkg.txt b/src/cmd/go/testdata/script/run_hello_pkg.txt new file mode 100644 index 0000000..ea2b4d7 --- /dev/null +++ b/src/cmd/go/testdata/script/run_hello_pkg.txt @@ -0,0 +1,17 @@ +go run m/hello +stderr 'hello, world' + +cd hello +go run . +stderr 'hello, world' + +-- go.mod -- +module m + +go 1.16 +-- hello/hello.go -- +package main + +func main() { + println("hello, world") +} diff --git a/src/cmd/go/testdata/script/run_internal.txt b/src/cmd/go/testdata/script/run_internal.txt new file mode 100644 index 0000000..d021850 --- /dev/null +++ b/src/cmd/go/testdata/script/run_internal.txt @@ -0,0 +1,64 @@ +env GO111MODULE=off + +go list -e -f '{{.Incomplete}}' m/runbad1.go +stdout true +! go run m/runbad1.go +stderr 'use of internal package m/x/internal not allowed' + +go list -e -f '{{.Incomplete}}' m/runbad2.go +stdout true +! go run m/runbad2.go +stderr 'use of internal package m/x/internal/y not allowed' + +go list -e -f '{{.Incomplete}}' m/runok.go +stdout false +go run m/runok.go + +cd m +env GO111MODULE=on + +go list -e -f '{{.Incomplete}}' runbad1.go +stdout true +! go run runbad1.go +stderr 'use of internal package m/x/internal not allowed' + +go list -e -f '{{.Incomplete}}' runbad2.go +stdout true +! go run runbad2.go +stderr 'use of internal package m/x/internal/y not allowed' + +go list -e -f '{{.Incomplete}}' runok.go +stdout false +go run runok.go + + +-- m/go.mod -- +module m + +-- m/x/internal/internal.go -- +package internal + +-- m/x/internal/y/y.go -- +package y + +-- m/internal/internal.go -- +package internal + +-- m/internal/z/z.go -- +package z + +-- m/runbad1.go -- +package main +import _ "m/x/internal" +func main() {} + +-- m/runbad2.go -- +package main +import _ "m/x/internal/y" +func main() {} + +-- m/runok.go -- +package main +import _ "m/internal" +import _ "m/internal/z" +func main() {} diff --git a/src/cmd/go/testdata/script/run_issue11709.txt b/src/cmd/go/testdata/script/run_issue11709.txt new file mode 100644 index 0000000..c8ba998 --- /dev/null +++ b/src/cmd/go/testdata/script/run_issue11709.txt @@ -0,0 +1,15 @@ +# 'go run' should not pass extraneous environment variables to the subprocess. +go run run.go +! stdout . +! stderr . + +-- run.go -- +package main + +import "os" + +func main() { + if os.Getenv("TERM") != "" { + os.Exit(1) + } +} \ No newline at end of file diff --git a/src/cmd/go/testdata/script/run_set_executable_name.txt b/src/cmd/go/testdata/script/run_set_executable_name.txt new file mode 100644 index 0000000..54ddee9 --- /dev/null +++ b/src/cmd/go/testdata/script/run_set_executable_name.txt @@ -0,0 +1,50 @@ +env GO111MODULE=on +[short] skip + +# Check for correct naming of temporary executable + +#Test for single file specified +cd x/y/z +go run foo.go +stderr 'foo' + +#Test for current directory +go run . +stderr 'z' + +#Test for set path +go run m/x/y/z/ +stderr 'z' + +-- m/x/y/z/foo.go -- +package main +import( + "os" + "path/filepath" +) +func main() { + println(filepath.Base(os.Args[0])) +} + +-- x/y/z/foo.go -- +package main +import( + "os" + "path/filepath" +) +func main() { + println(filepath.Base(os.Args[0])) +} + +-- x/y/z/foo.go -- +package main +import( + "os" + "path/filepath" +) +func main() { + println(filepath.Base(os.Args[0])) +} + +-- go.mod -- +module m \ No newline at end of file diff --git a/src/cmd/go/testdata/script/run_vendor.txt b/src/cmd/go/testdata/script/run_vendor.txt new file mode 100644 index 0000000..46cac06 --- /dev/null +++ b/src/cmd/go/testdata/script/run_vendor.txt @@ -0,0 +1,34 @@ +# Run +env GO111MODULE=off +cd vend/hello +go run hello.go +stdout 'hello, world' + +-- vend/hello/hello.go -- +package main + +import ( + "fmt" + "strings" // really ../vendor/strings +) + +func main() { + fmt.Printf("%s\n", strings.Msg) +} +-- vend/hello/hello_test.go -- +package main + +import ( + "strings" // really ../vendor/strings + "testing" +) + +func TestMsgInternal(t *testing.T) { + if strings.Msg != "hello, world" { + t.Fatalf("unexpected msg: %v", strings.Msg) + } +} +-- vend/vendor/strings/msg.go -- +package strings + +var Msg = "hello, world" diff --git a/src/cmd/go/testdata/script/run_wildcard.txt b/src/cmd/go/testdata/script/run_wildcard.txt new file mode 100644 index 0000000..72036d1 --- /dev/null +++ b/src/cmd/go/testdata/script/run_wildcard.txt @@ -0,0 +1,7 @@ +env GO111MODULE=off + +# Fix for https://github.com/golang/go/issues/28696: +# go run x/... should not panic when directory x doesn't exist. + +! go run nonexistent/... +stderr '^go run: no packages loaded from nonexistent/...$' diff --git a/src/cmd/go/testdata/script/script_wait.txt b/src/cmd/go/testdata/script/script_wait.txt new file mode 100644 index 0000000..acaccfe --- /dev/null +++ b/src/cmd/go/testdata/script/script_wait.txt @@ -0,0 +1,25 @@ +env GO111MODULE=off + +[!exec:echo] skip +[!exec:false] skip + +exec echo foo +stdout foo + +exec echo foo & +exec echo bar & +! exec false & + +# Starting a background process should clear previous output. +! stdout foo + +# Wait should set the output to the concatenated outputs of the background +# programs, in the order in which they were started. +wait +stdout 'foo\nbar' + +# The end of the test should interrupt or kill any remaining background +# programs, but that should not cause the test to fail if it does not +# care about the exit status of those programs. +[!exec:sleep] stop +? exec sleep 86400 & diff --git a/src/cmd/go/testdata/script/std_vendor.txt b/src/cmd/go/testdata/script/std_vendor.txt new file mode 100644 index 0000000..6cb015f --- /dev/null +++ b/src/cmd/go/testdata/script/std_vendor.txt @@ -0,0 +1,43 @@ +env GO111MODULE=off + +[!gc] skip + +# 'go list' should report imports from _test.go in the TestImports field. +go list -f '{{.TestImports}}' +stdout net/http # from .TestImports + +# 'go list' should report standard-vendored packages by path. +go list -f '{{.Dir}}' vendor/golang.org/x/net/http2/hpack +stdout $GOROOT[/\\]src[/\\]vendor + +# 'go list -test' should report vendored transitive dependencies of _test.go +# imports in the Deps field, with a 'vendor' prefix on their import paths. +go list -test -f '{{.Deps}}' +stdout golang.org/x/crypto # dep of .TestImports + +# Packages outside the standard library should not use its copy of vendored packages. +cd broken +! go build +stderr 'cannot find package' + +-- go.mod -- +module m + +-- x.go -- +package x + +-- x_test.go -- +package x +import "testing" +import _ "net/http" +func Test(t *testing.T) {} + +-- broken/go.mod -- +module broken +-- broken/http.go -- +package broken + +import ( + _ "net/http" + _ "golang.org/x/net/http/httpproxy" +) diff --git a/src/cmd/go/testdata/script/test_bad_example.txt b/src/cmd/go/testdata/script/test_bad_example.txt new file mode 100644 index 0000000..1d147b6 --- /dev/null +++ b/src/cmd/go/testdata/script/test_bad_example.txt @@ -0,0 +1,13 @@ +# Tests that invalid examples are ignored. +# Verifies golang.org/issue/35284 +go test x_test.go + +-- x_test.go -- +package x + +import "fmt" + +func ExampleThisShouldNotHaveAParameter(thisShouldntExist int) { + fmt.Println("X") + // Output: +} \ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_badtest.txt b/src/cmd/go/testdata/script/test_badtest.txt new file mode 100644 index 0000000..e79fc51 --- /dev/null +++ b/src/cmd/go/testdata/script/test_badtest.txt @@ -0,0 +1,49 @@ +env GO111MODULE=off + +! go test badtest/badexec +! stdout ^ok +stdout ^FAIL\tbadtest/badexec + +! go test badtest/badsyntax +! stdout ^ok +stdout ^FAIL\tbadtest/badsyntax + +! go test badtest/badvar +! stdout ^ok +stdout ^FAIL\tbadtest/badvar + +! go test notest +! stdout ^ok +stderr '^notest.hello.go:6:1: syntax error: non-declaration statement outside function body' # Exercise issue #7108 + +-- 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 +} +-- notest/hello.go -- +package notest + +func hello() { + println("hello world") +} +Hello world \ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_benchmark_chatty_fail.txt b/src/cmd/go/testdata/script/test_benchmark_chatty_fail.txt new file mode 100644 index 0000000..6031ead --- /dev/null +++ b/src/cmd/go/testdata/script/test_benchmark_chatty_fail.txt @@ -0,0 +1,32 @@ +# Run chatty tests. Assert on CONT lines. +! go test chatty_test.go -v -bench . chatty_bench + +# Sanity check that output occurs. +stdout -count=2 'this is sub-0' +stdout -count=2 'this is sub-1' +stdout -count=2 'this is sub-2' +stdout -count=1 'error from sub-0' +stdout -count=1 'error from sub-1' +stdout -count=1 'error from sub-2' + +# Benchmarks should not print CONT. +! stdout CONT + +-- chatty_test.go -- +package chatty_bench + +import ( + "testing" + "fmt" +) + +func BenchmarkChatty(b *testing.B) { + for i := 0; i < 3; i++ { + b.Run(fmt.Sprintf("sub-%d", i), func(b *testing.B) { + for j := 0; j < 2; j++ { + b.Logf("this is sub-%d", i) + } + b.Errorf("error from sub-%d", i) + }) + } +} \ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_benchmark_chatty_success.txt b/src/cmd/go/testdata/script/test_benchmark_chatty_success.txt new file mode 100644 index 0000000..a1c0d65 --- /dev/null +++ b/src/cmd/go/testdata/script/test_benchmark_chatty_success.txt @@ -0,0 +1,29 @@ +# Run chatty tests. Assert on CONT lines. +go test chatty_test.go -v -bench . chatty_bench + +# Sanity check that output happens. We don't provide -count because the amount +# of output is variable. +stdout 'this is sub-0' +stdout 'this is sub-1' +stdout 'this is sub-2' + +# Benchmarks should not print CONT. +! stdout CONT + +-- chatty_test.go -- +package chatty_bench + +import ( + "testing" + "fmt" +) + +func BenchmarkChatty(b *testing.B) { + for i := 0; i < 3; i++ { + b.Run(fmt.Sprintf("sub-%d", i), func(b *testing.B) { + for j := 0; j < 2; j++ { + b.Logf("this is sub-%d", i) + } + }) + } +} \ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_benchmark_fatal.txt b/src/cmd/go/testdata/script/test_benchmark_fatal.txt new file mode 100644 index 0000000..e281379 --- /dev/null +++ b/src/cmd/go/testdata/script/test_benchmark_fatal.txt @@ -0,0 +1,19 @@ +# Test that calling t.Fatal in a benchmark causes a non-zero exit status. + +! go test -run '^$' -bench . benchfatal +! stdout ^ok +! stderr ^ok +stdout FAIL.*benchfatal + +-- go.mod -- +module benchfatal + +go 1.16 +-- x_test.go -- +package benchfatal + +import "testing" + +func BenchmarkThatCallsFatal(b *testing.B) { + b.Fatal("called by benchmark") +} diff --git a/src/cmd/go/testdata/script/test_benchmark_labels.txt b/src/cmd/go/testdata/script/test_benchmark_labels.txt new file mode 100644 index 0000000..6b424c1 --- /dev/null +++ b/src/cmd/go/testdata/script/test_benchmark_labels.txt @@ -0,0 +1,23 @@ +# Tests that go test -bench prints out goos, goarch, and pkg. + +# Check for goos, goarch, and pkg. +go test -run ^$ -bench . bench +stdout '^goos: '$GOOS +stdout '^goarch: '$GOARCH +stdout '^pkg: bench' + +# Check go test does not print pkg multiple times +! stdout 'pkg:.*pkg: ' +! stderr 'pkg:.*pkg:' + +-- go.mod -- +module bench + +go 1.16 +-- x_test.go -- +package bench + +import "testing" + +func Benchmark(b *testing.B) { +} diff --git a/src/cmd/go/testdata/script/test_benchmark_timeout.txt b/src/cmd/go/testdata/script/test_benchmark_timeout.txt new file mode 100644 index 0000000..4bae7e7 --- /dev/null +++ b/src/cmd/go/testdata/script/test_benchmark_timeout.txt @@ -0,0 +1,18 @@ +# Tests issue #18845 +[short] skip + +go test -bench . -timeout=750ms timeoutbench_test.go +stdout ok +stdout PASS + +-- timeoutbench_test.go -- +package timeoutbench_test + +import ( + "testing" + "time" +) + +func BenchmarkSleep1s(b *testing.B) { + time.Sleep(1 * time.Second) +} diff --git a/src/cmd/go/testdata/script/test_build_failure.txt b/src/cmd/go/testdata/script/test_build_failure.txt new file mode 100644 index 0000000..8d13634 --- /dev/null +++ b/src/cmd/go/testdata/script/test_build_failure.txt @@ -0,0 +1,31 @@ +[short] skip + +! go test -x coverbad +! stderr '[\\/]coverbad\.test( |$)' # 'go test' should not claim to have run the test. +stderr 'undefined: g' +stderr 'undefined: j' + +-- go.mod -- +module coverbad + +go 1.16 +-- p.go -- +package p + +func f() { + g() +} +-- p1.go -- +package p + +import "C" + +func h() { + j() +} +-- p_test.go -- +package p + +import "testing" + +func Test(t *testing.T) {} diff --git a/src/cmd/go/testdata/script/test_cache_inputs.txt b/src/cmd/go/testdata/script/test_cache_inputs.txt new file mode 100644 index 0000000..50486e1 --- /dev/null +++ b/src/cmd/go/testdata/script/test_cache_inputs.txt @@ -0,0 +1,251 @@ +env GO111MODULE=off + +# Test that cached test results are invalidated in response to +# changes to the external inputs to the test. + +[short] skip +[GODEBUG:gocacheverify=1] skip + +# We're testing cache behavior, so start with a clean GOCACHE. +env GOCACHE=$WORK/cache + +# Build a helper binary to invoke os.Chtimes. +go build -o mkold$GOEXE mkold.go + +# Make test input files appear to be a minute old. +exec ./mkold$GOEXE 1m testcache/file.txt +exec ./mkold$GOEXE 1m testcache/script.sh + +# If the test reads an environment variable, changes to that variable +# should invalidate cached test results. +env TESTKEY=x +go test testcache -run=TestLookupEnv +go test testcache -run=TestLookupEnv +stdout '\(cached\)' + +env TESTKEY=y +go test testcache -run=TestLookupEnv +! stdout '\(cached\)' +go test testcache -run=TestLookupEnv +stdout '\(cached\)' + +# Changes in arguments forwarded to the test should invalidate cached test +# results. +go test testcache -run=TestOSArgs -v hello +! stdout '\(cached\)' +stdout 'hello' +go test testcache -run=TestOSArgs -v goodbye +! stdout '\(cached\)' +stdout 'goodbye' + +# golang.org/issue/36134: that includes the `-timeout` argument. +go test testcache -run=TestOSArgs -timeout=20m -v +! stdout '\(cached\)' +stdout '-test\.timeout[= ]20m' +go test testcache -run=TestOSArgs -timeout=5s -v +! stdout '\(cached\)' +stdout '-test\.timeout[= ]5s' + +# If the test stats a file, changes to the file should invalidate the cache. +go test testcache -run=FileSize +go test testcache -run=FileSize +stdout '\(cached\)' + +cp 4x.txt testcache/file.txt +go test testcache -run=FileSize +! stdout '\(cached\)' +go test testcache -run=FileSize +stdout '\(cached\)' + +# Files should be tracked even if the test changes its working directory. +go test testcache -run=Chdir +go test testcache -run=Chdir +stdout '\(cached\)' +cp 6x.txt testcache/file.txt +go test testcache -run=Chdir +! stdout '\(cached\)' +go test testcache -run=Chdir +stdout '\(cached\)' + +# The content of files should affect caching, provided that the mtime also changes. +exec ./mkold$GOEXE 1m testcache/file.txt +go test testcache -run=FileContent +go test testcache -run=FileContent +stdout '\(cached\)' +cp 2y.txt testcache/file.txt +exec ./mkold$GOEXE 50s testcache/file.txt +go test testcache -run=FileContent +! stdout '\(cached\)' +go test testcache -run=FileContent +stdout '\(cached\)' + +# Directory contents read via os.ReadDirNames should affect caching. +go test testcache -run=DirList +go test testcache -run=DirList +stdout '\(cached\)' +rm testcache/file.txt +go test testcache -run=DirList +! stdout '\(cached\)' +go test testcache -run=DirList +stdout '\(cached\)' + +# Files outside GOROOT and GOPATH should not affect caching. +env TEST_EXTERNAL_FILE=$WORK/external.txt +go test testcache -run=ExternalFile +go test testcache -run=ExternalFile +stdout '\(cached\)' + +rm $WORK/external.txt +go test testcache -run=ExternalFile +stdout '\(cached\)' + +# Executables within GOROOT and GOPATH should affect caching, +# even if the test does not stat them explicitly. + +[!exec:/bin/sh] skip +chmod 0755 ./testcache/script.sh + +exec ./mkold$GOEXEC 1m testcache/script.sh +go test testcache -run=Exec +go test testcache -run=Exec +stdout '\(cached\)' + +exec ./mkold$GOEXE 50s testcache/script.sh +go test testcache -run=Exec +! stdout '\(cached\)' +go test testcache -run=Exec +stdout '\(cached\)' + +-- testcache/file.txt -- +xx +-- 4x.txt -- +xxxx +-- 6x.txt -- +xxxxxx +-- 2y.txt -- +yy +-- $WORK/external.txt -- +This file is outside of GOPATH. +-- testcache/script.sh -- +#!/bin/sh +exit 0 +-- testcache/testcache_test.go -- +// 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 testcache + +import ( + "io" + "os" + "testing" +) + +func TestChdir(t *testing.T) { + os.Chdir("..") + defer os.Chdir("testcache") + info, err := os.Stat("testcache/file.txt") + if err != nil { + t.Fatal(err) + } + if info.Size()%2 != 1 { + t.Fatal("even file") + } +} + +func TestOddFileContent(t *testing.T) { + f, err := os.Open("file.txt") + if err != nil { + t.Fatal(err) + } + data, err := io.ReadAll(f) + f.Close() + if err != nil { + t.Fatal(err) + } + if len(data)%2 != 1 { + t.Fatal("even file") + } +} + +func TestOddFileSize(t *testing.T) { + info, err := os.Stat("file.txt") + if err != nil { + t.Fatal(err) + } + if info.Size()%2 != 1 { + t.Fatal("even file") + } +} + +func TestOddGetenv(t *testing.T) { + val := os.Getenv("TESTKEY") + if len(val)%2 != 1 { + t.Fatal("even env value") + } +} + +func TestLookupEnv(t *testing.T) { + _, ok := os.LookupEnv("TESTKEY") + if !ok { + t.Fatal("env missing") + } +} + +func TestDirList(t *testing.T) { + f, err := os.Open(".") + if err != nil { + t.Fatal(err) + } + f.Readdirnames(-1) + f.Close() +} + +func TestExec(t *testing.T) { + // Note: not using os/exec to make sure there is no unexpected stat. + p, err := os.StartProcess("./script.sh", []string{"script"}, new(os.ProcAttr)) + if err != nil { + t.Fatal(err) + } + ps, err := p.Wait() + if err != nil { + t.Fatal(err) + } + if !ps.Success() { + t.Fatalf("script failed: %v", err) + } +} + +func TestExternalFile(t *testing.T) { + os.Open(os.Getenv("TEST_EXTERNAL_FILE")) + _, err := os.Stat(os.Getenv("TEST_EXTERNAL_FILE")) + if err != nil { + t.Fatal(err) + } +} + +func TestOSArgs(t *testing.T) { + t.Log(os.Args) +} +-- mkold.go -- +package main + +import ( + "log" + "os" + "time" +) + +func main() { + d, err := time.ParseDuration(os.Args[1]) + if err != nil { + log.Fatal(err) + } + path := os.Args[2] + old := time.Now().Add(-d) + err = os.Chtimes(path, old, old) + if err != nil { + log.Fatal(err) + } +} diff --git a/src/cmd/go/testdata/script/test_chatty_fail.txt b/src/cmd/go/testdata/script/test_chatty_fail.txt new file mode 100644 index 0000000..a5ef559 --- /dev/null +++ b/src/cmd/go/testdata/script/test_chatty_fail.txt @@ -0,0 +1,32 @@ +# Run chatty tests. Assert on CONT lines. +! go test chatty_test.go -v + +# Sanity check that output occurs. +stdout -count=2 'this is sub-0' +stdout -count=2 'this is sub-1' +stdout -count=2 'this is sub-2' +stdout -count=1 'error from sub-0' +stdout -count=1 'error from sub-1' +stdout -count=1 'error from sub-2' + +# Non-parallel tests should not print CONT. +! stdout CONT + +-- chatty_test.go -- +package chatty_test + +import ( + "testing" + "fmt" +) + +func TestChatty(t *testing.T) { + for i := 0; i < 3; i++ { + t.Run(fmt.Sprintf("sub-%d", i), func(t *testing.T) { + for j := 0; j < 2; j++ { + t.Logf("this is sub-%d", i) + } + t.Errorf("error from sub-%d", i) + }) + } +} \ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_chatty_parallel_fail.txt b/src/cmd/go/testdata/script/test_chatty_parallel_fail.txt new file mode 100644 index 0000000..3f7360b --- /dev/null +++ b/src/cmd/go/testdata/script/test_chatty_parallel_fail.txt @@ -0,0 +1,58 @@ +# Run parallel chatty tests. Assert on CONT lines. This test makes sure that +# multiple parallel outputs have the appropriate CONT lines between them. +! go test -parallel 3 chatty_parallel_test.go -v + +stdout -count=1 '^=== CONT TestChattyParallel/sub-0\n chatty_parallel_test.go:38: error from sub-0$' +stdout -count=1 '^=== CONT TestChattyParallel/sub-1\n chatty_parallel_test.go:38: error from sub-1$' +stdout -count=1 '^=== CONT TestChattyParallel/sub-2\n chatty_parallel_test.go:38: error from sub-2$' + +# Run parallel chatty tests with -json. Assert on CONT lines as above - make +# sure there are CONT lines before each output line. +! go test -json -parallel 3 chatty_parallel_test.go -v +stdout -count=1 '{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-0","Output":"=== CONT TestChattyParallel/sub-0\\n"}\n{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-0","Output":" chatty_parallel_test.go:38: error from sub-0\\n"}' +stdout -count=1 '{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-1","Output":"=== CONT TestChattyParallel/sub-1\\n"}\n{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-1","Output":" chatty_parallel_test.go:38: error from sub-1\\n"}' +stdout -count=1 '{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-2","Output":"=== CONT TestChattyParallel/sub-2\\n"}\n{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-2","Output":" chatty_parallel_test.go:38: error from sub-2\\n"}' + +-- chatty_parallel_test.go -- +package chatty_paralell_test + +import ( + "testing" + "fmt" + "flag" +) + +// This test ensures the the order of CONT lines in parallel chatty tests. +func TestChattyParallel(t *testing.T) { + t.Parallel() + + // The number of concurrent tests running. This is closely tied to the + // -parallel test flag, so we grab it from the flag rather than setting it + // to some constant. + parallel := flag.Lookup("test.parallel").Value.(flag.Getter).Get().(int) + + // ready is a synchronization mechanism that causes subtests to execute + // round robin. + ready := make([]chan bool, parallel) + for i := range ready { + ready[i] = make(chan bool, 1) + } + ready[0] <- true + + for i := range ready { + i := i + t.Run(fmt.Sprintf("sub-%d", i), func(t *testing.T) { + t.Parallel() + + // Some basic log output to precede the failures. + <-ready[i] + t.Logf("this is sub-%d", i) + ready[(i+1)%len(ready)] <- true + + // The actual failure messages we care about. + <-ready[i] + t.Errorf("error from sub-%d", i) + ready[(i+1)%len(ready)] <- true + }) + } +} diff --git a/src/cmd/go/testdata/script/test_chatty_parallel_success.txt b/src/cmd/go/testdata/script/test_chatty_parallel_success.txt new file mode 100644 index 0000000..4a86d74 --- /dev/null +++ b/src/cmd/go/testdata/script/test_chatty_parallel_success.txt @@ -0,0 +1,52 @@ +# Run parallel chatty tests. Assert on CONT lines. This test makes sure that +# multiple parallel outputs have the appropriate CONT lines between them. +go test -parallel 3 chatty_parallel_test.go -v +stdout -count=2 '^=== CONT TestChattyParallel/sub-0\n chatty_parallel_test.go:32: this is sub-0$' +stdout -count=2 '^=== CONT TestChattyParallel/sub-1\n chatty_parallel_test.go:32: this is sub-1$' +stdout -count=2 '^=== CONT TestChattyParallel/sub-2\n chatty_parallel_test.go:32: this is sub-2$' + +# Run parallel chatty tests with -json. Assert on CONT lines as above - make +# sure there are CONT lines before each output line. +go test -json -parallel 3 chatty_parallel_test.go -v +stdout -count=2 '{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-0","Output":"=== CONT TestChattyParallel/sub-0\\n"}\n{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-0","Output":" chatty_parallel_test.go:32: this is sub-0\\n"}' +stdout -count=2 '{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-1","Output":"=== CONT TestChattyParallel/sub-1\\n"}\n{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-1","Output":" chatty_parallel_test.go:32: this is sub-1\\n"}' +stdout -count=2 '{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-2","Output":"=== CONT TestChattyParallel/sub-2\\n"}\n{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-2","Output":" chatty_parallel_test.go:32: this is sub-2\\n"}' + +-- chatty_parallel_test.go -- +package chatty_paralell_test + +import ( + "testing" + "fmt" + "flag" +) + +// This test ensures the the order of CONT lines in parallel chatty tests. +func TestChattyParallel(t *testing.T) { + t.Parallel() + + // The number of concurrent tests running. This is closely tied to the + // -parallel test flag, so we grab it from the flag rather than setting it + // to some constant. + parallel := flag.Lookup("test.parallel").Value.(flag.Getter).Get().(int) + + // ready is a synchronization mechanism that causes subtests to execute + // round robin. + ready := make([]chan bool, parallel) + for i := range ready { + ready[i] = make(chan bool, 1) + } + ready[0] <- true + + for i := range ready { + i := i + t.Run(fmt.Sprintf("sub-%d", i), func(t *testing.T) { + t.Parallel() + for j := 0; j < 2; j++ { + <-ready[i] + t.Logf("this is sub-%d", i) + ready[(i+1)%len(ready)] <- true + } + }) + } +} diff --git a/src/cmd/go/testdata/script/test_chatty_parallel_success_sleepy.txt b/src/cmd/go/testdata/script/test_chatty_parallel_success_sleepy.txt new file mode 100644 index 0000000..5952a87 --- /dev/null +++ b/src/cmd/go/testdata/script/test_chatty_parallel_success_sleepy.txt @@ -0,0 +1,39 @@ +# Run parallel chatty tests. Assert on CONT lines. This test makes sure that +# multiple parallel outputs have the appropriate CONT lines between them. +go test -parallel 3 chatty_parallel_test.go -v + +stdout '--- PASS: TestFast \([0-9.]{4}s\)\n=== CONT TestSlow\n chatty_parallel_test.go:31: this is the second TestSlow log\n--- PASS: TestSlow \([0-9.]{4}s\)' + +-- chatty_parallel_test.go -- +package chatty_paralell_test + +import ( + "testing" + "time" +) + +var ( + run = make(chan struct{}) + afterFirstLog = make(chan struct{}) + afterPass = make(chan struct{}) +) + +func TestFast(t *testing.T) { + t.Parallel() + + <-afterFirstLog + t.Cleanup(func() { + close(afterPass) + }) +} + +func TestSlow(t *testing.T) { + t.Parallel() + + t.Logf("this is the first TestSlow log") + close(afterFirstLog) + + <-afterPass + time.Sleep(100 * time.Millisecond) + t.Logf("this is the second TestSlow log") +} diff --git a/src/cmd/go/testdata/script/test_chatty_success.txt b/src/cmd/go/testdata/script/test_chatty_success.txt new file mode 100644 index 0000000..8bfa569 --- /dev/null +++ b/src/cmd/go/testdata/script/test_chatty_success.txt @@ -0,0 +1,27 @@ +# Run chatty tests. Assert on CONT lines. +go test chatty_test.go -v + +# Non-parallel tests should not print CONT. +! stdout CONT + +# The assertion is condensed into one line so that it precisely matches output, +# rather than skipping lines and allow rogue CONT lines. +stdout '=== RUN TestChatty\n=== RUN TestChatty/sub-0\n chatty_test.go:12: this is sub-0\n chatty_test.go:12: this is sub-0\n=== RUN TestChatty/sub-1\n chatty_test.go:12: this is sub-1\n chatty_test.go:12: this is sub-1\n=== RUN TestChatty/sub-2\n chatty_test.go:12: this is sub-2\n chatty_test.go:12: this is sub-2\n--- PASS: TestChatty' + +-- chatty_test.go -- +package chatty_test + +import ( + "testing" + "fmt" +) + +func TestChatty(t *testing.T) { + for i := 0; i < 3; i++ { + t.Run(fmt.Sprintf("sub-%d", i), func(t *testing.T) { + for j := 0; j < 2; j++ { + t.Logf("this is sub-%d", i) + } + }) + } +} \ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_cleanup_failnow.txt b/src/cmd/go/testdata/script/test_cleanup_failnow.txt new file mode 100644 index 0000000..0737a93 --- /dev/null +++ b/src/cmd/go/testdata/script/test_cleanup_failnow.txt @@ -0,0 +1,47 @@ +# For issue 41355 +[short] skip + +# This test could fail if the testing package does not wait until +# a panicking test does the panic. Turn off multithreading, GC, and +# async preemption to increase the probability of such a failure. +env GOMAXPROCS=1 +env GOGC=off +env GODEBUG=asyncpreempt=off + +# If the test exits with 'no tests to run', it means the testing package +# implementation is incorrect and does not wait until a test panic. +# If the test exits with '(?s)panic: die.*panic: die', it means +# the testing package did an extra panic for a panicking test. + +! go test -v cleanup_failnow/panic_nocleanup_test.go +! stdout 'no tests to run' +stdout '(?s)panic: die \[recovered\].*panic: die' +! stdout '(?s)panic: die \[recovered\].*panic: die.*panic: die' + +! go test -v cleanup_failnow/panic_withcleanup_test.go +! stdout 'no tests to run' +stdout '(?s)panic: die \[recovered\].*panic: die' +! stdout '(?s)panic: die \[recovered\].*panic: die.*panic: die' + +-- cleanup_failnow/panic_nocleanup_test.go -- +package panic_nocleanup_test +import "testing" +func TestX(t *testing.T) { + t.Run("x", func(t *testing.T) { + panic("die") + }) +} + +-- cleanup_failnow/panic_withcleanup_test.go -- +package panic_withcleanup_test +import "testing" +func TestCleanupWithFailNow(t *testing.T) { + t.Cleanup(func() { + t.FailNow() + }) + t.Run("x", func(t *testing.T) { + t.Run("y", func(t *testing.T) { + panic("die") + }) + }) +} \ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_compile_binary.txt b/src/cmd/go/testdata/script/test_compile_binary.txt new file mode 100644 index 0000000..63bb8ec --- /dev/null +++ b/src/cmd/go/testdata/script/test_compile_binary.txt @@ -0,0 +1,8 @@ +env GO111MODULE=off + +! go test -c compile_binary/... +stderr 'build comment' + +-- compile_binary/foo_test.go -- +// +build foo +package foo diff --git a/src/cmd/go/testdata/script/test_compile_tempfile.txt b/src/cmd/go/testdata/script/test_compile_tempfile.txt new file mode 100644 index 0000000..05f721a --- /dev/null +++ b/src/cmd/go/testdata/script/test_compile_tempfile.txt @@ -0,0 +1,11 @@ +[short] skip + +# Ensure that the target of 'go build -o' can be an existing, empty file so that +# its name can be reserved using os.CreateTemp or the 'mktemp` command. + +go build -o empty-file$GOEXE main.go + +-- main.go -- +package main +func main() {} +-- empty-file$GOEXE -- diff --git a/src/cmd/go/testdata/script/test_deadline.txt b/src/cmd/go/testdata/script/test_deadline.txt new file mode 100644 index 0000000..06ae16f --- /dev/null +++ b/src/cmd/go/testdata/script/test_deadline.txt @@ -0,0 +1,54 @@ +[short] skip + +go test -timeout=0 -run=TestNoDeadline +go test -timeout=1m -run=TestDeadlineWithinMinute +go test -timeout=1m -run=TestSubtestDeadlineWithinMinute + +-- go.mod -- +module m + +go 1.16 +-- deadline_test.go -- +package testing_test + +import ( + "testing" + "time" +) + +func TestNoDeadline(t *testing.T) { + d, ok := t.Deadline() + if ok || !d.IsZero() { + t.Fatalf("t.Deadline() = %v, %v; want 0, false", d, ok) + } +} + +func TestDeadlineWithinMinute(t *testing.T) { + now := time.Now() + d, ok := t.Deadline() + if !ok || d.IsZero() { + t.Fatalf("t.Deadline() = %v, %v; want nonzero deadline", d, ok) + } + if !d.After(now) { + t.Fatalf("t.Deadline() = %v; want after start of test (%v)", d, now) + } + if d.Sub(now) > time.Minute { + t.Fatalf("t.Deadline() = %v; want within one minute of start of test (%v)", d, now) + } +} + +func TestSubtestDeadlineWithinMinute(t *testing.T) { + t.Run("sub", func(t *testing.T) { + now := time.Now() + d, ok := t.Deadline() + if !ok || d.IsZero() { + t.Fatalf("t.Deadline() = %v, %v; want nonzero deadline", d, ok) + } + if !d.After(now) { + t.Fatalf("t.Deadline() = %v; want after start of test (%v)", d, now) + } + if d.Sub(now) > time.Minute { + t.Fatalf("t.Deadline() = %v; want within one minute of start of test (%v)", d, now) + } + }) +} diff --git a/src/cmd/go/testdata/script/test_empty.txt b/src/cmd/go/testdata/script/test_empty.txt new file mode 100644 index 0000000..5ebbecd --- /dev/null +++ b/src/cmd/go/testdata/script/test_empty.txt @@ -0,0 +1,53 @@ +[!race] skip + +cd $GOPATH/src/empty/pkg +go test -cover -coverpkg=. -race + +[short] stop # Only run first case in short mode + +cd $GOPATH/src/empty/test +go test -cover -coverpkg=. -race + +cd $GOPATH/src/empty/xtest +go test -cover -coverpkg=. -race + +cd $GOPATH/src/empty/pkgtest +go test -cover -coverpkg=. -race + +cd $GOPATH/src/empty/pkgxtest +go test -cover -coverpkg=. -race + +cd $GOPATH/src/empty/pkgtestxtest +go test -cover -coverpkg=. -race + +cd $GOPATH/src/empty/testxtest +go test -cover -coverpkg=. -race + +-- empty/go.mod -- +module empty + +go 1.16 +-- empty/pkg/pkg.go -- +package p +-- empty/pkgtest/pkg.go -- +package p +-- empty/pkgtest/test_test.go -- +package p +-- empty/pkgtestxtest/pkg.go -- +package p +-- empty/pkgtestxtest/test_test.go -- +package p +-- empty/pkgtestxtest/xtest_test.go -- +package p_test +-- empty/pkgxtest/pkg.go -- +package p +-- empty/pkgxtest/xtest_test.go -- +package p_test +-- empty/test/test_test.go -- +package p +-- empty/testxtest/test_test.go -- +package p +-- empty/testxtest/xtest_test.go -- +package p_test +-- empty/xtest/xtest_test.go -- +package p_test diff --git a/src/cmd/go/testdata/script/test_env_term.txt b/src/cmd/go/testdata/script/test_env_term.txt new file mode 100644 index 0000000..8a5f79a --- /dev/null +++ b/src/cmd/go/testdata/script/test_env_term.txt @@ -0,0 +1,15 @@ +# Tests golang.org/issue/12096 + +env TERM='' +go test test_test.go +! stdout '^ok.*\[no tests to run\]' +stdout '^ok' + +-- test_test.go -- +package main +import ("os"; "testing") +func TestEnv(t *testing.T) { + if os.Getenv("TERM") != "" { + t.Fatal("TERM is set") + } +} \ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_example_goexit.txt b/src/cmd/go/testdata/script/test_example_goexit.txt new file mode 100644 index 0000000..984f434 --- /dev/null +++ b/src/cmd/go/testdata/script/test_example_goexit.txt @@ -0,0 +1,29 @@ +# For issue golang.org/issue/41084 +[short] skip + +! go test -v examplegoexit +stdout '(?s)--- PASS.*--- FAIL.*' +stdout 'panic: test executed panic\(nil\) or runtime\.Goexit' + +-- go.mod -- +module examplegoexit + +go 1.16 +-- example_test.go -- +package main + +import ( + "fmt" + "runtime" +) + +func ExamplePass() { + fmt.Println("pass") + // Output: + // pass +} + +func ExampleGoexit() { + runtime.Goexit() + // Output: +} diff --git a/src/cmd/go/testdata/script/test_exit.txt b/src/cmd/go/testdata/script/test_exit.txt new file mode 100644 index 0000000..3703ba5 --- /dev/null +++ b/src/cmd/go/testdata/script/test_exit.txt @@ -0,0 +1,131 @@ +# Builds and runs test binaries, so skip in short mode. +[short] skip + +env GO111MODULE=on + +# If a test invoked by 'go test' exits with a zero status code, +# it will panic. +! go test ./zero +! stdout ^ok +! stdout 'exit status' +stdout 'panic' +stdout ^FAIL + +# If a test exits with a non-zero status code, 'go test' fails normally. +! go test ./one +! stdout ^ok +stdout 'exit status' +! stdout 'panic' +stdout ^FAIL + +# Ensure that other flags still do the right thing. +go test -list=. ./zero +stdout ExitZero + +! go test -bench=. ./zero +stdout 'panic' + +# 'go test' with no args streams output without buffering. Ensure that it still +# catches a zero exit with missing output. +cd zero +! go test +stdout 'panic' +cd ../normal +go test +stdout ^ok +cd .. + +# If a TestMain exits with a zero status code, 'go test' shouldn't +# complain about that. It's a common way to skip testing a package +# entirely. +go test ./main_zero +! stdout 'skipping all tests' +stdout ^ok + +# With -v, we'll see the warning from TestMain. +go test -v ./main_zero +stdout 'skipping all tests' +stdout ^ok + +# Listing all tests won't actually give a result if TestMain exits. That's okay, +# because this is how TestMain works. If we decide to support -list even when +# TestMain is used to skip entire packages, we can change this test case. +go test -list=. ./main_zero +stdout 'skipping all tests' +! stdout TestNotListed + +# Running the test directly still fails, if we pass the flag. +go test -c -o ./zero.exe ./zero +! exec ./zero.exe -test.paniconexit0 + +# Using -json doesn't affect the exit status. +! go test -json ./zero +! stdout '"Output":"ok' +! stdout 'exit status' +stdout 'panic' +stdout '"Output":"FAIL' + +# Running the test via test2json also fails. +! go tool test2json ./zero.exe -test.v -test.paniconexit0 +! stdout '"Output":"ok' +! stdout 'exit status' +stdout 'panic' + +-- go.mod -- +module m + +-- ./normal/normal.go -- +package normal +-- ./normal/normal_test.go -- +package normal + +import "testing" + +func TestExitZero(t *testing.T) { +} + +-- ./zero/zero.go -- +package zero +-- ./zero/zero_test.go -- +package zero + +import ( + "os" + "testing" +) + +func TestExitZero(t *testing.T) { + os.Exit(0) +} + +-- ./one/one.go -- +package one +-- ./one/one_test.go -- +package one + +import ( + "os" + "testing" +) + +func TestExitOne(t *testing.T) { + os.Exit(1) +} + +-- ./main_zero/zero.go -- +package zero +-- ./main_zero/zero_test.go -- +package zero + +import ( + "fmt" + "os" + "testing" +) + +func TestMain(m *testing.M) { + fmt.Println("skipping all tests") + os.Exit(0) +} + +func TestNotListed(t *testing.T) {} diff --git a/src/cmd/go/testdata/script/test_fail_fast.txt b/src/cmd/go/testdata/script/test_fail_fast.txt new file mode 100644 index 0000000..132ea70 --- /dev/null +++ b/src/cmd/go/testdata/script/test_fail_fast.txt @@ -0,0 +1,113 @@ +[short] skip + +# test fail fast +! go test ./failfast_test.go -run='TestFailingA' -failfast=true +stdout -count=1 'FAIL - ' +! go test ./failfast_test.go -run='TestFailing[AB]' -failfast=true +stdout -count=1 'FAIL - ' +! go test ./failfast_test.go -run='TestFailing[AB]' -failfast=false +stdout -count=2 'FAIL - ' + +# mix with non-failing tests +! go test ./failfast_test.go -run='TestA|TestFailing[AB]' -failfast=true +stdout -count=1 'FAIL - ' +! go test ./failfast_test.go -run='TestA|TestFailing[AB]' -failfast=false +stdout -count=2 'FAIL - ' + +# mix with parallel tests +! go test ./failfast_test.go -run='TestFailingB|TestParallelFailingA' -failfast=true +stdout -count=2 'FAIL - ' +! go test ./failfast_test.go -run='TestFailingB|TestParallelFailingA' -failfast=false +stdout -count=2 'FAIL - ' +! go test ./failfast_test.go -run='TestFailingB|TestParallelFailing[AB]' -failfast=true +stdout -count=3 'FAIL - ' +! go test ./failfast_test.go -run='TestFailingB|TestParallelFailing[AB]' -failfast=false +stdout -count=3 'FAIL - ' + +# mix with parallel sub-tests +! go test ./failfast_test.go -run='TestFailingB|TestParallelFailing[AB]|TestParallelFailingSubtestsA' -failfast=true +stdout -count=3 'FAIL - ' +! go test ./failfast_test.go -run='TestFailingB|TestParallelFailing[AB]|TestParallelFailingSubtestsA' -failfast=false +stdout -count=5 'FAIL - ' +! go test ./failfast_test.go -run='TestParallelFailingSubtestsA' -failfast=true +stdout -count=1 'FAIL - ' + +# only parallels +! go test ./failfast_test.go -run='TestParallelFailing[AB]' -failfast=false +stdout -count=2 'FAIL - ' + +# non-parallel subtests +! go test ./failfast_test.go -run='TestFailingSubtestsA' -failfast=true +stdout -count=1 'FAIL - ' +! go test ./failfast_test.go -run='TestFailingSubtestsA' -failfast=false +stdout -count=2 'FAIL - ' + +# fatal test +! go test ./failfast_test.go -run='TestFatal[CD]' -failfast=true +stdout -count=1 'FAIL - ' +! go test ./failfast_test.go -run='TestFatal[CD]' -failfast=false +stdout -count=2 'FAIL - ' + +-- failfast_test.go -- +// 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 failfast + +import "testing" + +func TestA(t *testing.T) { + // Edge-case testing, mixing unparallel tests too + t.Logf("LOG: %s", t.Name()) +} + +func TestFailingA(t *testing.T) { + t.Errorf("FAIL - %s", t.Name()) +} + +func TestB(t *testing.T) { + // Edge-case testing, mixing unparallel tests too + t.Logf("LOG: %s", t.Name()) +} + +func TestParallelFailingA(t *testing.T) { + t.Parallel() + t.Errorf("FAIL - %s", t.Name()) +} + +func TestParallelFailingB(t *testing.T) { + t.Parallel() + t.Errorf("FAIL - %s", t.Name()) +} + +func TestParallelFailingSubtestsA(t *testing.T) { + t.Parallel() + t.Run("TestFailingSubtestsA1", func(t *testing.T) { + t.Errorf("FAIL - %s", t.Name()) + }) + t.Run("TestFailingSubtestsA2", func(t *testing.T) { + t.Errorf("FAIL - %s", t.Name()) + }) +} + +func TestFailingSubtestsA(t *testing.T) { + t.Run("TestFailingSubtestsA1", func(t *testing.T) { + t.Errorf("FAIL - %s", t.Name()) + }) + t.Run("TestFailingSubtestsA2", func(t *testing.T) { + t.Errorf("FAIL - %s", t.Name()) + }) +} + +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/src/cmd/go/testdata/script/test_flag.txt b/src/cmd/go/testdata/script/test_flag.txt new file mode 100644 index 0000000..0142b3f --- /dev/null +++ b/src/cmd/go/testdata/script/test_flag.txt @@ -0,0 +1,40 @@ +[short] skip + +go test flag_test.go -v -args -v=7 # Two distinct -v flags +go test -v flag_test.go -args -v=7 # Two distinct -v flags + +# Using a custom flag mixed with regular 'go test' flags should be OK. +go test -count=1 -custom -args -v=7 + +# However, it should be an error to use custom flags when -i or -c are used, +# since we know for sure that no test binary will run at all. +! go test -i -custom +stderr '^go test: unknown flag -custom cannot be used with -i$' +! go test -c -custom +stderr '^go test: unknown flag -custom cannot be used with -c$' + +# The same should apply even if -c or -i come after a custom flag. +! go test -custom -c +stderr '^go test: unknown flag -custom cannot be used with -c$' + +-- go.mod -- +module m +-- flag_test.go -- +package flag_test + +import ( + "flag" + "log" + "testing" +) + +var v = flag.Int("v", 0, "v flag") + +var custom = flag.Bool("custom", false, "") + +// Run this as go test pkg -v=7 +func TestVFlagIsSet(t *testing.T) { + if *v != 7 { + log.Fatal("v flag not set") + } +} diff --git a/src/cmd/go/testdata/script/test_flags.txt b/src/cmd/go/testdata/script/test_flags.txt new file mode 100644 index 0000000..63385e6 --- /dev/null +++ b/src/cmd/go/testdata/script/test_flags.txt @@ -0,0 +1,132 @@ +env GO111MODULE=on + +[short] skip + +# Arguments after the flag terminator should be ignored. +# If we pass '-- -test.v', we should not get verbose output +# *and* output from the test should not be echoed. +go test ./x -- -test.v +stdout '\Aok\s+example.com/x\s+[0-9.s]+\n\z' +! stderr . + +# For backward-compatibility with previous releases of the 'go' command, +# arguments that appear after unrecognized flags should not be treated +# as packages, even if they are unambiguously not arguments to flags. +# Even though ./x looks like a package path, the real package should be +# the implicit '.'. +! go test --answer=42 ./x +stderr '^no Go files in .+$' +! stderr '/x' + +# However, *flags* that appear after unrecognized flags should still be +# interpreted as flags, under the (possibly-erroneous) assumption that +# unrecognized flags are non-boolean. + +go test -v -x ./x -timeout 24h -boolflag=true foo -timeout 25h +stdout 'args: foo -timeout 25h' +stdout 'timeout: 24h0m0s$' # -timeout is unambiguously not a flag, so the real flag wins. + +go test -v -x ./x -timeout 24h -boolflag foo -timeout 25h +stdout 'args: foo -test\.timeout=25h0m0s' # For legacy reasons, '-timeout ' is erroneously rewritten to -test.timeout; see https://golang.org/issue/40763. +stdout 'timeout: 24h0m0s$' # Actual flag wins. + +go test -v -x ./x -timeout 24h -stringflag foo -timeout 25h +stdout 'args: $' +stdout 'timeout: 25h0m0s$' # Later flag wins. + +# An explicit '-outputdir=' argument should set test.outputdir +# to the 'go' command's working directory, not zero it out +# for the test binary. +go test -x -coverprofile=cover.out '-outputdir=' ./x +stderr '-test.outputdir=[^ ]' +exists ./cover.out +! exists ./x/cover.out + +# Test flags from GOFLAGS should be forwarded to the test binary, +# with the 'test.' prefix in the GOFLAGS entry... +env GOFLAGS='-test.timeout=24h0m0s -count=1' +go test -v -x ./x +stdout 'timeout: 24h0m0s$' +stderr '-test.count=1' + +# ...or without. +env GOFLAGS='-timeout=24h0m0s -count=1' +go test -v -x ./x +stdout 'timeout: 24h0m0s$' +stderr '-test.count=1' + +# Arguments from the command line should override GOFLAGS... +go test -v -x -timeout=25h0m0s ./x +stdout 'timeout: 25h0m0s$' +stderr '-test.count=1' + +# ...even if they use a different flag name. +go test -v -x -test.timeout=26h0m0s ./x +stdout 'timeout: 26h0m0s$' +stderr '-test\.timeout=26h0m0s' +! stderr 'timeout=24h0m0s' +stderr '-test.count=1' + +# Invalid flags should be reported exactly once. +! go test -covermode=walrus ./x +stderr -count=1 'invalid value "walrus" for flag -covermode: valid modes are .*$' +stderr '^usage: go test .*$' +stderr '^Run ''go help test'' and ''go help testflag'' for details.$' + +# Passing -help to the test binary should show flag help. +go test ./x -args -help +stdout 'usage_message' + +# -covermode, -coverpkg, and -coverprofile should imply -cover +go test -covermode=set ./x +stdout '\s+coverage:\s+' + +go test -coverpkg=encoding/binary ./x +stdout '\s+coverage:\s+' + +go test -coverprofile=cover.out ./x +stdout '\s+coverage:\s+' +exists ./cover.out +rm ./cover.out + +# -*profile and -trace flags should force output to the current working directory +# or -outputdir, not the directory containing the test. + +go test -memprofile=mem.out ./x +exists ./mem.out +rm ./mem.out + +go test -trace=trace.out ./x +exists ./trace.out +rm ./trace.out + +# Relative paths with -outputdir should be relative to the go command's working +# directory, not the directory containing the test. +mkdir profiles +go test -memprofile=mem.out -outputdir=./profiles ./x +exists ./profiles/mem.out +rm profiles + +-- go.mod -- +module example.com +go 1.14 +-- x/x_test.go -- +package x + +import ( + "flag" + "strings" + "testing" +) + +var _ = flag.String("usage_message", "", "dummy flag to check usage message") +var boolflag = flag.Bool("boolflag", false, "ignored boolean flag") +var stringflag = flag.String("stringflag", "", "ignored string flag") + +func TestLogTimeout(t *testing.T) { + t.Logf("timeout: %v", flag.Lookup("test.timeout").Value) +} + +func TestLogArgs(t *testing.T) { + t.Logf("args: %s", strings.Join(flag.Args(), " ")) +} diff --git a/src/cmd/go/testdata/script/test_generated_main.txt b/src/cmd/go/testdata/script/test_generated_main.txt new file mode 100644 index 0000000..2e991a5 --- /dev/null +++ b/src/cmd/go/testdata/script/test_generated_main.txt @@ -0,0 +1,34 @@ +# Tests that the generated test main file has a generated code comment. +# This is needed by analyzers that access source files through 'go list'. +# Verifies golang.org/issue/31971. +# TODO(jayconrod): This test is brittle. We should write _testmain.go as +# a build action instead of with an ad-hoc WriteFile call +# in internal/test/test.go. Then we could just grep 'go get -n'. +go test x_test.go + +-- x_test.go -- +package x + +import ( + "os" + "path/filepath" + "regexp" + "testing" +) + +func Test(t *testing.T) { + exePath, err := os.Executable() + if err != nil { + t.Fatal(err) + } + testmainPath := filepath.Join(filepath.Dir(exePath), "_testmain.go") + source, err := os.ReadFile(testmainPath) + if err != nil { + t.Fatal(err) + } + if matched, err := regexp.Match(`(?m)^// Code generated .* DO NOT EDIT\.$`, source); err != nil { + t.Fatal(err) + } else if !matched { + t.Error("_testmain.go does not have generated code comment") + } +} diff --git a/src/cmd/go/testdata/script/test_go111module_cache.txt b/src/cmd/go/testdata/script/test_go111module_cache.txt new file mode 100644 index 0000000..ca1de43 --- /dev/null +++ b/src/cmd/go/testdata/script/test_go111module_cache.txt @@ -0,0 +1,15 @@ +env GO111MODULE=on +go mod init foo +go test +stdout ^ok\s+foo +env GO111MODULE=off +go test +stdout ^ok\s+ +! stdout ^ok\s+(cache)$ + +-- main_test.go -- +package main + +import "testing" + +func TestF(t *testing.T) {} diff --git a/src/cmd/go/testdata/script/test_import_error_stack.txt b/src/cmd/go/testdata/script/test_import_error_stack.txt new file mode 100644 index 0000000..6c60f3d --- /dev/null +++ b/src/cmd/go/testdata/script/test_import_error_stack.txt @@ -0,0 +1,31 @@ +env GO111MODULE=off +! go test testdep/p1 +stderr 'package testdep/p1 \(test\)\n\timports testdep/p2\n\timports testdep/p3: build constraints exclude all Go files ' # check for full import stack +! go vet testdep/p1 +stderr 'package testdep/p1 \(test\)\n\timports testdep/p2\n\timports testdep/p3: build constraints exclude all Go files ' # check for full import stack + +env GO111MODULE=on +cd testdep +! go test testdep/p1 +stderr 'package testdep/p1 \(test\)\n\timports testdep/p2\n\timports testdep/p3: build constraints exclude all Go files ' # check for full import stack +! go vet testdep/p1 +stderr 'package testdep/p1 \(test\)\n\timports testdep/p2\n\timports testdep/p3: build constraints exclude all Go files ' # check for full import stack + +-- testdep/go.mod -- +module testdep + +go 1.16 +-- testdep/p1/p1.go -- +package p1 +-- testdep/p1/p1_test.go -- +package p1 + +import _ "testdep/p2" +-- testdep/p2/p2.go -- +package p2 + +import _ "testdep/p3" +-- testdep/p3/p3.go -- +// +build ignore + +package ignored diff --git a/src/cmd/go/testdata/script/test_json.txt b/src/cmd/go/testdata/script/test_json.txt new file mode 100644 index 0000000..cd5b0b9 --- /dev/null +++ b/src/cmd/go/testdata/script/test_json.txt @@ -0,0 +1,74 @@ +[gccgo] skip # gccgo does not have standard packages +[short] skip + +env GOCACHE=$WORK/tmp + +# Run go test -json on errors m/empty/pkg and m/skipper +# It would be nice to test that the output is interlaced +# but it seems to be impossible to do that in a short test +# that isn't also flaky. Just check that we get JSON output. +go test -json -short -v errors m/empty/pkg m/skipper + +# Check errors for run action +stdout '"Package":"errors"' +stdout '"Action":"run","Package":"errors"' + +# Check m/empty/pkg for output and skip actions +stdout '"Action":"output","Package":"m/empty/pkg","Output":".*no test files' +stdout '"Action":"skip","Package":"m/empty/pkg"' + +# Check skipper for output and skip actions +stdout '"Action":"output","Package":"m/skipper","Test":"Test","Output":"--- SKIP:' +stdout '"Action":"skip","Package":"m/skipper","Test":"Test"' + +# Run go test -json on errors and check it's cached +go test -json -short -v errors +stdout '"Action":"output","Package":"errors","Output":".*\(cached\)' + +go test -json -bench=NONE -short -v errors +stdout '"Package":"errors"' +stdout '"Action":"run"' + +# Test running test2json +go test -o $WORK/tmp/errors.test$GOEXE -c errors +go tool test2json -p errors $WORK/tmp/errors.test$GOEXE -test.v -test.short +stdout '"Package":"errors"' +stdout '"Action":"run"' +stdout '\{"Action":"pass","Package":"errors"\}' + +-- go.mod -- +module m + +go 1.16 +-- skipper/skip_test.go -- +package skipper + +import "testing" + +func Test(t *testing.T) { + t.Skip("skipping") +} +-- empty/pkg/pkg.go -- +package p +-- empty/pkgtest/pkg.go -- +package p +-- empty/pkgtest/test_test.go -- +package p +-- empty/pkgtestxtest/pkg.go -- +package p +-- empty/pkgtestxtest/test_test.go -- +package p +-- empty/pkgtestxtest/xtest_test.go -- +package p_test +-- empty/pkgxtest/pkg.go -- +package p +-- empty/pkgxtest/xtest_test.go -- +package p_test +-- empty/test/test_test.go -- +package p +-- empty/testxtest/test_test.go -- +package p +-- empty/testxtest/xtest_test.go -- +package p_test +-- empty/xtest/xtest_test.go -- +package p_test diff --git a/src/cmd/go/testdata/script/test_json_exit.txt b/src/cmd/go/testdata/script/test_json_exit.txt new file mode 100644 index 0000000..dc7ffb0 --- /dev/null +++ b/src/cmd/go/testdata/script/test_json_exit.txt @@ -0,0 +1,102 @@ +[short] skip + +go test -c -o mainpanic.exe ./mainpanic & +go test -c -o mainexit0.exe ./mainexit0 & +go test -c -o testpanic.exe ./testpanic & +go test -c -o testbgpanic.exe ./testbgpanic & +wait + +# Test binaries that panic in TestMain should be marked as failing. + +! go test -json ./mainpanic +stdout '"Action":"fail"' +! stdout '"Action":"pass"' + +! go tool test2json ./mainpanic.exe +stdout '"Action":"fail"' +! stdout '"Action":"pass"' + +# Test binaries that exit with status 0 should be marked as passing. + +go test -json ./mainexit0 +stdout '"Action":"pass"' +! stdout '"Action":"fail"' + +go tool test2json ./mainexit0.exe +stdout '"Action":"pass"' +! stdout '"Action":"fail"' + +# Test functions that panic should never be marked as passing +# (https://golang.org/issue/40132). + +! go test -json ./testpanic +stdout '"Action":"fail"' +! stdout '"Action":"pass"' + +! go tool test2json ./testpanic.exe -test.v +stdout '"Action":"fail"' +! stdout '"Action":"pass"' + +! go tool test2json ./testpanic.exe +stdout '"Action":"fail"' +! stdout '"Action":"pass"' + +# Tests that panic in a background goroutine should be marked as failing. + +! go test -json ./testbgpanic +stdout '"Action":"fail"' +! stdout '"Action":"pass"' + +! go tool test2json ./testbgpanic.exe -test.v +stdout '"Action":"fail"' +! stdout '"Action":"pass"' + +! go tool test2json ./testbgpanic.exe +stdout '"Action":"fail"' +! stdout '"Action":"pass"' + +-- go.mod -- +module m +go 1.14 +-- mainpanic/mainpanic_test.go -- +package mainpanic_test + +import "testing" + +func TestMain(m *testing.M) { + panic("haha no") +} +-- mainexit0/mainexit0_test.go -- +package mainexit0_test + +import ( + "fmt" + "os" + "testing" +) + +func TestMain(m *testing.M) { + fmt.Println("nothing to do") + os.Exit(0) +} +-- testpanic/testpanic_test.go -- +package testpanic_test + +import "testing" + +func TestPanic(*testing.T) { + panic("haha no") +} +-- testbgpanic/testbgpanic_test.go -- +package testbgpanic_test + +import "testing" + +func TestPanicInBackground(*testing.T) { + c := make(chan struct{}) + go func() { + panic("haha no") + close(c) + }() + <-c +} diff --git a/src/cmd/go/testdata/script/test_json_interleaved.txt b/src/cmd/go/testdata/script/test_json_interleaved.txt new file mode 100644 index 0000000..e2d349e --- /dev/null +++ b/src/cmd/go/testdata/script/test_json_interleaved.txt @@ -0,0 +1,27 @@ +# Regression test for https://golang.org/issue/40657: output from the main test +# function should be attributed correctly even if interleaved with the PAUSE +# line for a new parallel subtest. + +[short] skip + +go test -json +stdout '"Test":"TestWeirdTiming","Output":"[^"]* logging to outer again\\n"' + +-- go.mod -- +module example.com +go 1.15 +-- main_test.go -- +package main + +import ( + "testing" +) + +func TestWeirdTiming(outer *testing.T) { + outer.Run("pauser", func(pauser *testing.T) { + outer.Logf("logging to outer") + pauser.Parallel() + }) + + outer.Logf("logging to outer again") +} diff --git a/src/cmd/go/testdata/script/test_json_panic_exit.txt b/src/cmd/go/testdata/script/test_json_panic_exit.txt new file mode 100644 index 0000000..d0a7991 --- /dev/null +++ b/src/cmd/go/testdata/script/test_json_panic_exit.txt @@ -0,0 +1,69 @@ +# Verifies golang.org/issue/37555. + +[short] skip + +# 'go test -json' should say a test passes if it says it passes. +go test -json ./pass +stdout '"Action":"pass".*\n\z' +! stdout '"Test":.*\n\z' + +# 'go test -json' should say a test passes if it exits 0 and prints nothing. +# TODO(golang.org/issue/29062): this should fail in the future. +go test -json ./exit0main +stdout '"Action":"pass".*\n\z' +! stdout '"Test":.*\n\z' + +# 'go test -json' should say a test fails if it exits 1 and prints nothing. +! go test -json ./exit1main +stdout '"Action":"fail".*\n\z' +! stdout '"Test":.*\n\z' + +# 'go test -json' should say a test fails if it panics. +! go test -json ./panic +stdout '"Action":"fail".*\n\z' +! stdout '"Test":.*\n\z' + +-- go.mod -- +module example.com/test + +go 1.14 + +-- pass/pass_test.go -- +package pass_test + +import "testing" + +func TestPass(t *testing.T) {} + +-- exit0main/exit0main_test.go -- +package exit0_test + +import ( + "os" + "testing" +) + +func TestMain(m *testing.M) { + os.Exit(0) +} + +-- exit1main/exit1main_test.go -- +package exit1_test + +import ( + "os" + "testing" +) + +func TestMain(m *testing.M) { + os.Exit(1) +} + +-- panic/panic_test.go -- +package panic_test + +import "testing" + +func TestPanic(t *testing.T) { + panic("oh no") +} diff --git a/src/cmd/go/testdata/script/test_main.txt b/src/cmd/go/testdata/script/test_main.txt new file mode 100644 index 0000000..25d02e4 --- /dev/null +++ b/src/cmd/go/testdata/script/test_main.txt @@ -0,0 +1,92 @@ +# Test TestMain +go test standalone_main_normal_test.go +! stdout '^ok.*\[no tests to run\]' +! stderr '^ok.*\[no tests to run\]' +stdout '^ok' + +# Test TestMain sees testing flags +go test standalone_testmain_flag_test.go +stdout '^ok.*\[no tests to run\]' + +# Test TestMain with wrong signature (Issue #22388) +! go test standalone_main_wrong_test.go +stderr 'wrong signature for TestMain, must be: func TestMain\(m \*testing.M\)' + +# Test TestMain does not call os.Exit (Issue #34129) +! go test standalone_testmain_not_call_os_exit_test.go +! stdout '^ok' + +-- standalone_main_normal_test.go -- +// 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 standalone_main_normal_test + +import "testing" + +func TestMain(t *testing.T) { +} +-- standalone_main_wrong_test.go -- +// 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 standalone_main_wrong_test + +import "testing" + +func TestMain(m *testing.Main) { +} +-- standalone_testmain_flag_test.go -- +// Copyright 2019 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 standalone_testmain_flag_test + +import ( + "flag" + "fmt" + "os" + "testing" +) + +func TestMain(m *testing.M) { + // A TestMain should be able to access testing flags if it calls + // flag.Parse without needing to use testing.Init. + flag.Parse() + found := false + flag.VisitAll(func(f *flag.Flag) { + if f.Name == "test.count" { + found = true + } + }) + if !found { + fmt.Println("testing flags not registered") + os.Exit(1) + } + os.Exit(m.Run()) +} +-- standalone_testmain_not_call_os_exit_test.go -- +// Copyright 2020 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 standalone_testmain_not_call_os_exit_test + +import ( + "testing" +) + +func TestWillFail(t *testing.T) { + t.Error("this test will fail.") +} + +func TestMain(m *testing.M) { + defer func() { + recover() + }() + exit := m.Run() + panic(exit) +} diff --git a/src/cmd/go/testdata/script/test_main_archive.txt b/src/cmd/go/testdata/script/test_main_archive.txt new file mode 100644 index 0000000..410d923 --- /dev/null +++ b/src/cmd/go/testdata/script/test_main_archive.txt @@ -0,0 +1,32 @@ +env GO111MODULE=off + +# Test that a main_test of 'package main' imports the package, +# not the installed binary. + +[short] skip + +env GOBIN=$WORK/bin +go test main_test +go install main_test + +go list -f '{{.Stale}}' main_test +stdout false + +go test main_test + +-- main_test/m.go -- +package main + +func F() {} +func main() {} +-- main_test/m_test.go -- +package main_test + +import ( + . "main_test" + "testing" +) + +func Test1(t *testing.T) { + F() +} diff --git a/src/cmd/go/testdata/script/test_main_panic.txt b/src/cmd/go/testdata/script/test_main_panic.txt new file mode 100644 index 0000000..45887c5 --- /dev/null +++ b/src/cmd/go/testdata/script/test_main_panic.txt @@ -0,0 +1,30 @@ +[short] skip +[!race] skip + +! go test -v -race main_panic/testmain_parallel_sub_panic_test.go +! stdout 'DATA RACE' +-- main_panic/testmain_parallel_sub_panic_test.go -- +package testmain_parallel_sub_panic_test + +import "testing" + +func setup() { println("setup()") } +func teardown() { println("teardown()") } +func TestA(t *testing.T) { + t.Run("1", func(t *testing.T) { + t.Run("1", func(t *testing.T) { + t.Parallel() + panic("A/1/1 panics") + }) + t.Run("2", func(t *testing.T) { + t.Parallel() + println("A/1/2 is ok") + }) + }) +} + +func TestMain(m *testing.M) { + setup() + defer teardown() + m.Run() +} \ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_main_twice.txt b/src/cmd/go/testdata/script/test_main_twice.txt new file mode 100644 index 0000000..f32d4fc --- /dev/null +++ b/src/cmd/go/testdata/script/test_main_twice.txt @@ -0,0 +1,27 @@ +[short] skip + +env GOCACHE=$WORK/tmp +go test -v multimain +stdout -count=2 notwithstanding # check tests ran twice + +-- go.mod -- +module multimain + +go 1.16 +-- multimain_test.go -- +package multimain_test + +import "testing" + +func TestMain(m *testing.M) { + // Some users run m.Run multiple times, changing + // some kind of global state between runs. + // This used to work so I guess now it has to keep working. + // See golang.org/issue/23129. + m.Run() + m.Run() +} + +func Test(t *testing.T) { + t.Log("notwithstanding") +} diff --git a/src/cmd/go/testdata/script/test_match_benchmark_labels.txt b/src/cmd/go/testdata/script/test_match_benchmark_labels.txt new file mode 100644 index 0000000..13c4007 --- /dev/null +++ b/src/cmd/go/testdata/script/test_match_benchmark_labels.txt @@ -0,0 +1,18 @@ +# Benchmark labels, file outside gopath +# TODO(matloob): This test was called TestBenchmarkLabelsOutsideGOPATH +# why "OutsideGOPATH"? Does the go command need to be run outside GOPATH? +# Do the files need to exist outside GOPATH? +cp $GOPATH/src/standalone_benchmark_test.go $WORK/tmp/standalone_benchmark_test.go +go test -run '^$' -bench . $WORK/tmp/standalone_benchmark_test.go +stdout '^goos: '$GOOS +stdout '^goarch: '$GOARCH +! stdout '^pkg:' +! stderr '^pkg:' + +-- standalone_benchmark_test.go -- +package standalone_benchmark + +import "testing" + +func Benchmark(b *testing.B) { +} \ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_match_no_benchmarks.txt b/src/cmd/go/testdata/script/test_match_no_benchmarks.txt new file mode 100644 index 0000000..30f4be8 --- /dev/null +++ b/src/cmd/go/testdata/script/test_match_no_benchmarks.txt @@ -0,0 +1,13 @@ +# Matches no benchmarks +go test -run '^$' -bench ThisWillNotMatch standalone_benchmark_test.go +! stdout '^ok.*\[no tests to run\]' +! stderr '^ok.*\[no tests to run\]' +stdout '^ok' + +-- standalone_benchmark_test.go -- +package standalone_benchmark + +import "testing" + +func Benchmark(b *testing.B) { +} \ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_match_no_subtests.txt b/src/cmd/go/testdata/script/test_match_no_subtests.txt new file mode 100644 index 0000000..7abb1eb --- /dev/null +++ b/src/cmd/go/testdata/script/test_match_no_subtests.txt @@ -0,0 +1,12 @@ +# The subtests don't match +go test -run Test/ThisWillNotMatch standalone_sub_test.go +stdout '^ok.*\[no tests to run\]' + +-- standalone_sub_test.go -- +package standalone_sub_test + +import "testing" + +func Test(t *testing.T) { + t.Run("Sub", func(t *testing.T) {}) +} \ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_match_no_subtests_failure.txt b/src/cmd/go/testdata/script/test_match_no_subtests_failure.txt new file mode 100644 index 0000000..b3c5b92 --- /dev/null +++ b/src/cmd/go/testdata/script/test_match_no_subtests_failure.txt @@ -0,0 +1,15 @@ +# Matches no subtests, but parent test still fails +! go test -run TestThatFails/ThisWillNotMatch standalone_fail_sub_test.go +! stdout '^ok.*\[no tests to run\]' +! stderr '^ok.*\[no tests to run\]' +stdout 'FAIL' + +-- standalone_fail_sub_test.go -- +package standalone_fail_sub_test + +import "testing" + +func TestThatFails(t *testing.T) { + t.Run("Sub", func(t *testing.T) {}) + t.Fail() +} \ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_match_no_subtests_parallel.txt b/src/cmd/go/testdata/script/test_match_no_subtests_parallel.txt new file mode 100644 index 0000000..11c734c --- /dev/null +++ b/src/cmd/go/testdata/script/test_match_no_subtests_parallel.txt @@ -0,0 +1,19 @@ +# Matches no subtests, parallel +go test -run Test/Sub/ThisWillNotMatch standalone_parallel_sub_test.go +stdout '^ok.*\[no tests to run\]' + +-- standalone_parallel_sub_test.go -- +package standalone_parallel_sub_test + +import "testing" + +func Test(t *testing.T) { + ch := make(chan bool, 1) + t.Run("Sub", func(t *testing.T) { + t.Parallel() + <-ch + t.Run("Nested", func(t *testing.T) {}) + }) + // Ensures that Sub will finish after its t.Run call already returned. + ch <- true +} diff --git a/src/cmd/go/testdata/script/test_match_no_tests.txt b/src/cmd/go/testdata/script/test_match_no_tests.txt new file mode 100644 index 0000000..1ad2097 --- /dev/null +++ b/src/cmd/go/testdata/script/test_match_no_tests.txt @@ -0,0 +1,11 @@ +# Matches no tests +go test -run ThisWillNotMatch standalone_test.go +stdout '^ok.*\[no tests to run\]' + +-- standalone_test.go -- +package standalone_test + +import "testing" + +func Test(t *testing.T) { +} \ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_match_no_tests_build_failure.txt b/src/cmd/go/testdata/script/test_match_no_tests_build_failure.txt new file mode 100644 index 0000000..e1c9643 --- /dev/null +++ b/src/cmd/go/testdata/script/test_match_no_tests_build_failure.txt @@ -0,0 +1,19 @@ +# Test that when there's a build failure and a -run flag that doesn't match, +# that the error for not matching tests does not override the error for +# the build failure. + +! go test -run ThisWillNotMatch syntaxerror +! stderr '(?m)^ok.*\[no tests to run\]' +stdout 'FAIL' + +-- go.mod -- +module syntaxerror + +go 1.16 +-- x.go -- +package p +-- x_test.go -- +package p + +func f() (x.y, z int) { +} diff --git a/src/cmd/go/testdata/script/test_match_no_tests_with_subtests.txt b/src/cmd/go/testdata/script/test_match_no_tests_with_subtests.txt new file mode 100644 index 0000000..0d94918 --- /dev/null +++ b/src/cmd/go/testdata/script/test_match_no_tests_with_subtests.txt @@ -0,0 +1,12 @@ +# Matches no tests with subtests +go test -run ThisWillNotMatch standalone_sub_test.go +stdout '^ok.*\[no tests to run\]' + +-- standalone_sub_test.go -- +package standalone_sub_test + +import "testing" + +func Test(t *testing.T) { + t.Run("Sub", func(t *testing.T) {}) +} \ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_match_only_benchmarks.txt b/src/cmd/go/testdata/script/test_match_only_benchmarks.txt new file mode 100644 index 0000000..5dfb96e --- /dev/null +++ b/src/cmd/go/testdata/script/test_match_only_benchmarks.txt @@ -0,0 +1,13 @@ +# Matches only benchmarks +go test -run '^$' -bench . standalone_benchmark_test.go +! stdout '^ok.*\[no tests to run\]' +! stderr '^ok.*\[no tests to run\]' +stdout '^ok' + +-- standalone_benchmark_test.go -- +package standalone_benchmark + +import "testing" + +func Benchmark(b *testing.B) { +} \ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_match_only_example.txt b/src/cmd/go/testdata/script/test_match_only_example.txt new file mode 100644 index 0000000..515ccb3 --- /dev/null +++ b/src/cmd/go/testdata/script/test_match_only_example.txt @@ -0,0 +1,31 @@ +[short] skip + +# Check that it's okay for test pattern to match only examples. +go test -run Example example1_test.go +! stderr '^ok.*\[no tests to run\]' +stdout '^ok' + +-- example1_test.go -- +// Copyright 2013 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. + +// Make sure that go test runs Example_Z before Example_A, preserving source order. + +package p + +import "fmt" + +var n int + +func Example_Z() { + n++ + fmt.Println(n) + // Output: 1 +} + +func Example_A() { + n++ + fmt.Println(n) + // Output: 2 +} diff --git a/src/cmd/go/testdata/script/test_match_only_subtests.txt b/src/cmd/go/testdata/script/test_match_only_subtests.txt new file mode 100644 index 0000000..beea895 --- /dev/null +++ b/src/cmd/go/testdata/script/test_match_only_subtests.txt @@ -0,0 +1,14 @@ +# Matches only subtests +go test -run Test/Sub standalone_sub_test.go +! stdout '^ok.*\[no tests to run\]' +! stderr '^ok.*\[no tests to run\]' +stdout '^ok' + +-- standalone_sub_test.go -- +package standalone_sub_test + +import "testing" + +func Test(t *testing.T) { + t.Run("Sub", func(t *testing.T) {}) +} \ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_match_only_subtests_parallel.txt b/src/cmd/go/testdata/script/test_match_only_subtests_parallel.txt new file mode 100644 index 0000000..11872c2 --- /dev/null +++ b/src/cmd/go/testdata/script/test_match_only_subtests_parallel.txt @@ -0,0 +1,21 @@ +# Matches only subtests, parallel +go test -run Test/Sub/Nested standalone_parallel_sub_test.go +! stdout '^ok.*\[no tests to run\]' +! stderr '^ok.*\[no tests to run\]' +stdout '^ok' + +-- standalone_parallel_sub_test.go -- +package standalone_parallel_sub_test + +import "testing" + +func Test(t *testing.T) { + ch := make(chan bool, 1) + t.Run("Sub", func(t *testing.T) { + t.Parallel() + <-ch + t.Run("Nested", func(t *testing.T) {}) + }) + // Ensures that Sub will finish after its t.Run call already returned. + ch <- true +} diff --git a/src/cmd/go/testdata/script/test_match_only_tests.txt b/src/cmd/go/testdata/script/test_match_only_tests.txt new file mode 100644 index 0000000..9185793 --- /dev/null +++ b/src/cmd/go/testdata/script/test_match_only_tests.txt @@ -0,0 +1,13 @@ +# Matches only tests +go test -run Test standalone_test.go +! stdout '^ok.*\[no tests to run\]' +! stderr '^ok.*\[no tests to run\]' +stdout '^ok' + +-- standalone_test.go -- +package standalone_test + +import "testing" + +func Test(t *testing.T) { +} \ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_minus_n.txt b/src/cmd/go/testdata/script/test_minus_n.txt new file mode 100644 index 0000000..9900dbc --- /dev/null +++ b/src/cmd/go/testdata/script/test_minus_n.txt @@ -0,0 +1,14 @@ +# The intent here is to verify that 'go test -n' works without crashing. +# Any test will do. + +go test -n x_test.go + +-- x_test.go -- +package x_test + +import ( + "testing" +) + +func TestEmpty(t *testing.T) { +} diff --git a/src/cmd/go/testdata/script/test_no_run_example.txt b/src/cmd/go/testdata/script/test_no_run_example.txt new file mode 100644 index 0000000..53ac755 --- /dev/null +++ b/src/cmd/go/testdata/script/test_no_run_example.txt @@ -0,0 +1,30 @@ +go test -v norunexample +stdout 'File with non-runnable example was built.' + +-- go.mod -- +module norunexample + +go 1.16 +-- example_test.go -- +package pkg_test + +import "os" + +func init() { + os.Stdout.Write([]byte("File with non-runnable example was built.\n")) +} + +func Example_test() { + // This test will not be run, it has no "Output:" comment. +} +-- test_test.go -- +package pkg + +import ( + "os" + "testing" +) + +func TestBuilt(t *testing.T) { + os.Stdout.Write([]byte("A normal test was executed.\n")) +} diff --git a/src/cmd/go/testdata/script/test_no_tests.txt b/src/cmd/go/testdata/script/test_no_tests.txt new file mode 100644 index 0000000..2d624d1 --- /dev/null +++ b/src/cmd/go/testdata/script/test_no_tests.txt @@ -0,0 +1,15 @@ +# Tests issue #26242 + +go test testnorun +stdout 'testnorun\t\[no test files\]' + +-- go.mod -- +module testnorun + +go 1.16 +-- p.go -- +package p + +func init() { + panic("go test must not link and run test binaries without tests") +} diff --git a/src/cmd/go/testdata/script/test_parallel_number.txt b/src/cmd/go/testdata/script/test_parallel_number.txt new file mode 100644 index 0000000..4eb9794 --- /dev/null +++ b/src/cmd/go/testdata/script/test_parallel_number.txt @@ -0,0 +1,25 @@ +[short] skip + +# go test -parallel -1 shouldn't work +! go test -parallel -1 standalone_parallel_sub_test.go +stdout '-parallel can only be given' + +# go test -parallel 0 shouldn't work +! go test -parallel 0 standalone_parallel_sub_test.go +stdout '-parallel can only be given' + +-- standalone_parallel_sub_test.go -- +package standalone_parallel_sub_test + +import "testing" + +func Test(t *testing.T) { + ch := make(chan bool, 1) + t.Run("Sub", func(t *testing.T) { + t.Parallel() + <-ch + t.Run("Nested", func(t *testing.T) {}) + }) + // Ensures that Sub will finish after its t.Run call already returned. + ch <- true +} diff --git a/src/cmd/go/testdata/script/test_profile.txt b/src/cmd/go/testdata/script/test_profile.txt new file mode 100644 index 0000000..4bfa2cc --- /dev/null +++ b/src/cmd/go/testdata/script/test_profile.txt @@ -0,0 +1,19 @@ +[gccgo] skip 'gccgo has no standard packages' +[short] skip + +# Check go test -cpuprofile creates errors.test +go test -cpuprofile errors.prof errors +exists -exec errors.test$GOEXE + +# Check go test -cpuprofile -o myerrors.test creates errors.test +go test -cpuprofile errors.prof -o myerrors.test$GOEXE errors +exists -exec myerrors.test$GOEXE + +# Check go test -mutexprofile creates errors.test +go test -mutexprofile errors.prof errors +exists -exec errors.test$GOEXE + +# Check go test -mutexprofile -o myerrors.test creates errors.test +go test -mutexprofile errors.prof -o myerrors.test$GOEXE errors +exists -exec myerrors.test$GOEXE + diff --git a/src/cmd/go/testdata/script/test_race.txt b/src/cmd/go/testdata/script/test_race.txt new file mode 100644 index 0000000..2ffea46 --- /dev/null +++ b/src/cmd/go/testdata/script/test_race.txt @@ -0,0 +1,51 @@ +[short] skip +[!race] skip + +go test testrace + +! go test -race testrace +stdout 'FAIL: TestRace' +! stdout 'PASS' +! stderr 'PASS' + +! go test -race testrace -run XXX -bench . +stdout 'FAIL: BenchmarkRace' +! stdout 'PASS' +! stderr 'PASS' + +-- go.mod -- +module testrace + +go 1.16 +-- race_test.go -- +package testrace + +import "testing" + +func TestRace(t *testing.T) { + for i := 0; i < 10; i++ { + c := make(chan int) + x := 1 + go func() { + x = 2 + c <- 1 + }() + x = 3 + <-c + _ = x + } +} + +func BenchmarkRace(b *testing.B) { + for i := 0; i < b.N; i++ { + c := make(chan int) + x := 1 + go func() { + x = 2 + c <- 1 + }() + x = 3 + <-c + _ = x + } +} diff --git a/src/cmd/go/testdata/script/test_race_cover_mode_issue20435.txt b/src/cmd/go/testdata/script/test_race_cover_mode_issue20435.txt new file mode 100644 index 0000000..eacc882 --- /dev/null +++ b/src/cmd/go/testdata/script/test_race_cover_mode_issue20435.txt @@ -0,0 +1,48 @@ +[short] skip +[!race] skip + +# Make sure test is functional. +go test testrace + +# Now, check that -race -covermode=set is not allowed. +! go test -race -covermode=set testrace +stderr '-covermode must be "atomic", not "set", when -race is enabled' +! stdout PASS +! stderr PASS + +-- go.mod -- +module testrace + +go 1.16 +-- race_test.go -- +package testrace + +import "testing" + +func TestRace(t *testing.T) { + for i := 0; i < 10; i++ { + c := make(chan int) + x := 1 + go func() { + x = 2 + c <- 1 + }() + x = 3 + <-c + _ = x + } +} + +func BenchmarkRace(b *testing.B) { + for i := 0; i < b.N; i++ { + c := make(chan int) + x := 1 + go func() { + x = 2 + c <- 1 + }() + x = 3 + <-c + _ = x + } +} diff --git a/src/cmd/go/testdata/script/test_race_install.txt b/src/cmd/go/testdata/script/test_race_install.txt new file mode 100644 index 0000000..8b1f343 --- /dev/null +++ b/src/cmd/go/testdata/script/test_race_install.txt @@ -0,0 +1,18 @@ +[!race] skip +[short] skip + +mkdir $WORKDIR/tmp/pkg +go install -race -pkgdir=$WORKDIR/tmp/pkg std + +# Make sure go test -i -race doesn't rebuild cached packages +go test -race -pkgdir=$WORKDIR/tmp/pkg -i -v empty/pkg +cmp stderr stderr.txt + +-- go.mod -- +module empty + +go 1.16 +-- pkg/pkg.go -- +package p +-- stderr.txt -- +go test: -i flag is deprecated diff --git a/src/cmd/go/testdata/script/test_race_install_cgo.txt b/src/cmd/go/testdata/script/test_race_install_cgo.txt new file mode 100644 index 0000000..3f4eb90 --- /dev/null +++ b/src/cmd/go/testdata/script/test_race_install_cgo.txt @@ -0,0 +1,93 @@ +# Tests Issue #10500 + +[!race] skip + +[!darwin] ! stale cmd/cgo # The darwin builders are spuriously stale; see #33598. + +env GOBIN=$WORK/bin +go install m/mtime m/sametime + +go tool -n cgo +cp stdout cgopath.txt +exec $GOBIN/mtime cgopath.txt # get the mtime of the file whose name is in cgopath.txt +cp stdout cgotime_before.txt + + # For this test, we don't actually care whether 'go test -race -i' succeeds. + # It may fail if GOROOT is read-only (perhaps it was installed as root). + # We only care that it does not overwrite cmd/cgo regardless. +? go test -race -i runtime/race + +exec $GOBIN/mtime cgopath.txt # get the mtime of the file whose name is in cgopath.txt +cp stdout cgotime_after.txt +exec $GOBIN/sametime cgotime_before.txt cgotime_after.txt + +-- go.mod -- +module m + +go 1.16 +-- mtime/mtime.go -- +package main + +import ( + "encoding/json" + "fmt" + "os" + "strings" +) + +func main() { + b, err := os.ReadFile(os.Args[1]) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + filename := strings.TrimSpace(string(b)) + info, err := os.Stat(filename) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + if err := json.NewEncoder(os.Stdout).Encode(info.ModTime()); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} +-- sametime/sametime.go -- +package main + +import ( + "encoding/json" + "fmt" + "os" + "time" +) + + +func main() { + var t1 time.Time + b1, err := os.ReadFile(os.Args[1]) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + if err := json.Unmarshal(b1, &t1); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + var t2 time.Time + b2, err := os.ReadFile(os.Args[2]) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + if err := json.Unmarshal(b2, &t2); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + if !t1.Equal(t2) { + fmt.Fprintf(os.Stderr, "time in %v (%v) is not the same as time in %v (%v)", os.Args[1], t1, os.Args[2], t2) + os.Exit(1) + } +} diff --git a/src/cmd/go/testdata/script/test_rebuildall.txt b/src/cmd/go/testdata/script/test_rebuildall.txt new file mode 100644 index 0000000..38233c1 --- /dev/null +++ b/src/cmd/go/testdata/script/test_rebuildall.txt @@ -0,0 +1,14 @@ +env GO111MODULE=off + +# Regression test for golang.org/issue/6844: +# 'go test -a' should force dependencies in the standard library to be rebuilt. + +[short] skip + +go test -x -a -c testdata/dep_test.go +stderr '^.*[/\\]compile'$GOEXE'["]? (.* )?regexp .*[/\\]regexp\.go' + +-- testdata/dep_test.go -- +package deps + +import _ "testing" diff --git a/src/cmd/go/testdata/script/test_regexps.txt b/src/cmd/go/testdata/script/test_regexps.txt new file mode 100644 index 0000000..2f33080 --- /dev/null +++ b/src/cmd/go/testdata/script/test_regexps.txt @@ -0,0 +1,79 @@ +go test -cpu=1 -run=X/Y -bench=X/Y -count=2 -v testregexp + +# Test the following: + +# TestX is run, twice +stdout -count=2 '^=== RUN TestX$' +stdout -count=2 '^ x_test.go:6: LOG: X running$' + +# TestX/Y is run, twice +stdout -count=2 '^=== RUN TestX/Y$' +stdout -count=2 '^ x_test.go:8: LOG: Y running$' + +# TestXX is run, twice +stdout -count=2 '^=== RUN TestXX$' +stdout -count=2 '^ z_test.go:10: LOG: XX running' + +# TestZ is not run +! stdout '^=== RUN TestZ$' + +# BenchmarkX is run with N=1 once, only to discover what sub-benchmarks it has, +# and should not print a final summary line. +stdout -count=1 '^ x_test.go:13: LOG: X running N=1$' +! stdout '^\s+BenchmarkX: x_test.go:13: LOG: X running N=\d\d+' +! stdout 'BenchmarkX\s+\d+' + +# Same for BenchmarkXX. +stdout -count=1 '^ z_test.go:18: LOG: XX running N=1$' +! stdout '^ z_test.go:18: LOG: XX running N=\d\d+' +! stdout 'BenchmarkXX\s+\d+' + +# BenchmarkX/Y is run in full twice due to -count=2. +# "Run in full" means that it runs for approximately the default benchtime, +# but may cap out at N=1e9. +# We don't actually care what the final iteration count is, but it should be +# a large number, and the last iteration count prints right before the results. +stdout -count=2 '^ x_test.go:15: LOG: Y running N=[1-9]\d{4,}\nBenchmarkX/Y\s+\d+' + +-- go.mod -- +module testregexp + +go 1.16 +-- x_test.go -- +package x + +import "testing" + +func TestX(t *testing.T) { + t.Logf("LOG: X running") + t.Run("Y", func(t *testing.T) { + t.Logf("LOG: Y running") + }) +} + +func BenchmarkX(b *testing.B) { + b.Logf("LOG: X running N=%d", b.N) + b.Run("Y", func(b *testing.B) { + b.Logf("LOG: Y running N=%d", b.N) + }) +} +-- z_test.go -- +package x + +import "testing" + +func TestZ(t *testing.T) { + t.Logf("LOG: Z running") +} + +func TestXX(t *testing.T) { + t.Logf("LOG: XX running") +} + +func BenchmarkZ(b *testing.B) { + b.Logf("LOG: Z running N=%d", b.N) +} + +func BenchmarkXX(b *testing.B) { + b.Logf("LOG: XX running N=%d", b.N) +} diff --git a/src/cmd/go/testdata/script/test_relative_cmdline.txt b/src/cmd/go/testdata/script/test_relative_cmdline.txt new file mode 100644 index 0000000..2f9c80f --- /dev/null +++ b/src/cmd/go/testdata/script/test_relative_cmdline.txt @@ -0,0 +1,50 @@ +# Relative imports in command line package + +# Run tests outside GOPATH. +env GOPATH=$WORK/tmp + +go test ./testimport/p.go ./testimport/p_test.go ./testimport/x_test.go +stdout '^ok' + +-- testimport/p.go -- +package p + +func F() int { return 1 } +-- testimport/p1/p1.go -- +package p1 + +func F() int { return 1 } +-- testimport/p2/p2.go -- +package p2 + +func F() int { return 1 } +-- testimport/p_test.go -- +package p + +import ( + "./p1" + + "testing" +) + +func TestF(t *testing.T) { + if F() != p1.F() { + t.Fatal(F()) + } +} +-- testimport/x_test.go -- +package p_test + +import ( + . "../testimport" + + "./p2" + + "testing" +) + +func TestF1(t *testing.T) { + if F() != p2.F() { + t.Fatal(F()) + } +} \ No newline at end of file diff --git a/src/cmd/go/testdata/script/test_relative_import.txt b/src/cmd/go/testdata/script/test_relative_import.txt new file mode 100644 index 0000000..938a875 --- /dev/null +++ b/src/cmd/go/testdata/script/test_relative_import.txt @@ -0,0 +1,31 @@ +# Relative imports in go test +env GO111MODULE=off # relative import not supported in module mode + +# Run tests outside GOPATH. +env GOPATH=$WORK/tmp + +go test ./testimport +stdout '^ok' + +-- testimport/p.go -- +package p + +func F() int { return 1 } +-- testimport/p1/p1.go -- +package p1 + +func F() int { return 1 } +-- testimport/p_test.go -- +package p + +import ( + "./p1" + + "testing" +) + +func TestF(t *testing.T) { + if F() != p1.F() { + t.Fatal(F()) + } +} diff --git a/src/cmd/go/testdata/script/test_relative_import_dash_i.txt b/src/cmd/go/testdata/script/test_relative_import_dash_i.txt new file mode 100644 index 0000000..b2716d8 --- /dev/null +++ b/src/cmd/go/testdata/script/test_relative_import_dash_i.txt @@ -0,0 +1,32 @@ +# Relative imports in go test -i +env GO111MODULE=off # relative import not supported in module mode + +# Run tests outside GOPATH. +env GOPATH=$WORK/tmp + +# Check that it's safe to pass -i (which installs dependencies in $GOPATH/pkg) to go test. +! stale runtime # don't let test -i overwrite runtime +go test -i ./testimport + +-- testimport/p.go -- +package p + +func F() int { return 1 } +-- testimport/p1/p1.go -- +package p1 + +func F() int { return 1 } +-- testimport/p_test.go -- +package p + +import ( + "./p1" + + "testing" +) + +func TestF(t *testing.T) { + if F() != p1.F() { + t.Fatal(F()) + } +} diff --git a/src/cmd/go/testdata/script/test_source_order.txt b/src/cmd/go/testdata/script/test_source_order.txt new file mode 100644 index 0000000..2865276 --- /dev/null +++ b/src/cmd/go/testdata/script/test_source_order.txt @@ -0,0 +1,54 @@ +[short] skip + +# Control +! go test example2_test.go example1_test.go + +# This test only passes if the source order is preserved +go test example1_test.go example2_test.go + +-- example1_test.go -- +// Copyright 2013 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. + +// Make sure that go test runs Example_Z before Example_A, preserving source order. + +package p + +import "fmt" + +var n int + +func Example_Z() { + n++ + fmt.Println(n) + // Output: 1 +} + +func Example_A() { + n++ + fmt.Println(n) + // Output: 2 +} +-- example2_test.go -- +// Copyright 2013 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. + +// Make sure that go test runs Example_Y before Example_B, preserving source order. + +package p + +import "fmt" + +func Example_Y() { + n++ + fmt.Println(n) + // Output: 3 +} + +func Example_B() { + n++ + fmt.Println(n) + // Output: 4 +} diff --git a/src/cmd/go/testdata/script/test_status.txt b/src/cmd/go/testdata/script/test_status.txt new file mode 100644 index 0000000..aa6ad3c --- /dev/null +++ b/src/cmd/go/testdata/script/test_status.txt @@ -0,0 +1,18 @@ +env GO111MODULE=off + +! go test x y +stdout ^FAIL\s+x +stdout ^ok\s+y +stdout (?-m)FAIL\n$ + +-- x/x_test.go -- +package x + +import "testing" + +func TestNothingJustFail(t *testing.T) { + t.Fail() +} + +-- y/y_test.go -- +package y diff --git a/src/cmd/go/testdata/script/test_syntax_error_says_fail.txt b/src/cmd/go/testdata/script/test_syntax_error_says_fail.txt new file mode 100644 index 0000000..44ff6e2 --- /dev/null +++ b/src/cmd/go/testdata/script/test_syntax_error_says_fail.txt @@ -0,0 +1,25 @@ +# Test that the error message for a syntax error in a test go file +# says FAIL. + +env GO111MODULE=off +! go test syntaxerror +stderr 'x_test.go:' # check that the error is diagnosed +stdout 'FAIL' # check that go test says FAIL + +env GO111MODULE=on +cd syntaxerror +! go test syntaxerror +stderr 'x_test.go:' # check that the error is diagnosed +stdout 'FAIL' # check that go test says FAIL + +-- syntaxerror/go.mod -- +module syntaxerror + +go 1.16 +-- syntaxerror/x.go -- +package p +-- syntaxerror/x_test.go -- +package p + +func f() (x.y, z int) { +} diff --git a/src/cmd/go/testdata/script/test_timeout.txt b/src/cmd/go/testdata/script/test_timeout.txt new file mode 100644 index 0000000..4de4df4 --- /dev/null +++ b/src/cmd/go/testdata/script/test_timeout.txt @@ -0,0 +1,23 @@ +[short] skip +env GO111MODULE=off +cd a + +# If no timeout is set explicitly, 'go test' should set +# -test.timeout to its internal deadline. +go test -v . -- +stdout '10m0s' + +# An explicit -timeout argument should be propagated to -test.timeout. +go test -v -timeout 30m . -- +stdout '30m0s' + +-- a/timeout_test.go -- +package t +import ( + "flag" + "fmt" + "testing" +) +func TestTimeout(t *testing.T) { + fmt.Println(flag.Lookup("test.timeout").Value.String()) +} diff --git a/src/cmd/go/testdata/script/test_vendor.txt b/src/cmd/go/testdata/script/test_vendor.txt new file mode 100644 index 0000000..c6a88b6 --- /dev/null +++ b/src/cmd/go/testdata/script/test_vendor.txt @@ -0,0 +1,57 @@ +# In GOPATH mode, vendored packages can replace std packages. +env GO111MODULE=off +cd vend/hello +go test -v +stdout TestMsgInternal +stdout TestMsgExternal + +# In module mode, they cannot. +env GO111MODULE=on +! go test -mod=vendor +stderr 'undefined: strings.Msg' + +-- vend/hello/go.mod -- +module vend/hello + +go 1.16 +-- vend/hello/hello.go -- +package main + +import ( + "fmt" + "strings" // really ../vendor/strings +) + +func main() { + fmt.Printf("%s\n", strings.Msg) +} +-- vend/hello/hello_test.go -- +package main + +import ( + "strings" // really ../vendor/strings + "testing" +) + +func TestMsgInternal(t *testing.T) { + if strings.Msg != "hello, world" { + t.Fatalf("unexpected msg: %v", strings.Msg) + } +} +-- vend/hello/hellox_test.go -- +package main_test + +import ( + "strings" // really ../vendor/strings + "testing" +) + +func TestMsgExternal(t *testing.T) { + if strings.Msg != "hello, world" { + t.Fatalf("unexpected msg: %v", strings.Msg) + } +} +-- vend/vendor/strings/msg.go -- +package strings + +var Msg = "hello, world" diff --git a/src/cmd/go/testdata/script/test_vet.txt b/src/cmd/go/testdata/script/test_vet.txt new file mode 100644 index 0000000..5af26b5 --- /dev/null +++ b/src/cmd/go/testdata/script/test_vet.txt @@ -0,0 +1,92 @@ +[short] skip + +# Test file +! go test p1_test.go +stderr 'Logf format %d' +go test -vet=off +stdout '^ok' + +# Non-test file +! go test p1.go +stderr 'Printf format %d' +go test -x -vet=shift p1.go +stderr '[\\/]vet.*-shift' +stdout '\[no test files\]' +go test -vet=off p1.go +! stderr '[\\/]vet.*-shift' +stdout '\[no test files\]' + +# Test issue #22890 +go test m/vetcycle +stdout 'm/vetcycle.*\[no test files\]' + +# Test with ... +! go test ./vetfail/... +stderr 'Printf format %d' +stdout 'ok\s+m/vetfail/p2' + +# Check there's no diagnosis of a bad build constraint in vetxonly mode. +# Use -a so that we need to recompute the vet-specific export data for +# vetfail/p1. +go test -a m/vetfail/p2 +! stderr 'invalid.*constraint' + +-- go.mod -- +module m + +go 1.16 +-- p1_test.go -- +package p + +import "testing" + +func Test(t *testing.T) { + t.Logf("%d") // oops +} +-- p1.go -- +package p + +import "fmt" + +func F() { + fmt.Printf("%d") // oops +} +-- vetcycle/p.go -- +package p + +type ( + _ interface{ m(B1) } + A1 interface{ a(D1) } + B1 interface{ A1 } + C1 interface { + B1 /* ERROR issue #18395 */ + } + D1 interface{ C1 } +) + +var _ A1 = C1 /* ERROR cannot use C1 */ (nil) +-- vetfail/p1/p1.go -- +// +build !foo-bar + +package p1 + +import "fmt" + +func F() { + fmt.Printf("%d", "hello") // causes vet error +} +-- vetfail/p2/p2.go -- +package p2 + +import _ "m/vetfail/p1" + +func F() { +} +-- vetfail/p2/p2_test.go -- +package p2 + +import "testing" + +func TestF(t *testing.T) { + F() +} diff --git a/src/cmd/go/testdata/script/test_write_profiles_on_timeout.txt b/src/cmd/go/testdata/script/test_write_profiles_on_timeout.txt new file mode 100644 index 0000000..08e67a4 --- /dev/null +++ b/src/cmd/go/testdata/script/test_write_profiles_on_timeout.txt @@ -0,0 +1,17 @@ +# Tests issue 19394 + +[short] skip + +! go test -cpuprofile cpu.pprof -memprofile mem.pprof -timeout 1ms +grep . cpu.pprof +grep . mem.pprof + +-- go.mod -- +module profiling + +go 1.16 +-- timeout_test.go -- +package timeouttest_test +import "testing" +import "time" +func TestSleep(t *testing.T) { time.Sleep(time.Second) } diff --git a/src/cmd/go/testdata/script/test_xtestonly_works.txt b/src/cmd/go/testdata/script/test_xtestonly_works.txt new file mode 100644 index 0000000..8e150db --- /dev/null +++ b/src/cmd/go/testdata/script/test_xtestonly_works.txt @@ -0,0 +1,27 @@ +[short] skip + +go test xtestonly +! stdout '^ok.*\[no tests to run\]' +stdout '^ok' + +-- go.mod -- +module xtestonly + +go 1.16 +-- f.go -- +package xtestonly + +func F() int { return 42 } +-- f_test.go -- +package xtestonly_test + +import ( + "testing" + "xtestonly" +) + +func TestF(t *testing.T) { + if x := xtestonly.F(); x != 42 { + t.Errorf("f.F() = %d, want 42", x) + } +} diff --git a/src/cmd/go/testdata/script/testing_issue40908.txt b/src/cmd/go/testdata/script/testing_issue40908.txt new file mode 100644 index 0000000..839320e --- /dev/null +++ b/src/cmd/go/testdata/script/testing_issue40908.txt @@ -0,0 +1,25 @@ +[short] skip +[!race] skip + +go test -race testrace + +-- go.mod -- +module testrace + +go 1.16 +-- race_test.go -- +package testrace + +import "testing" + +func TestRace(t *testing.T) { + helperDone := make(chan struct{}) + go func() { + t.Logf("Something happened before cleanup.") + close(helperDone) + }() + + t.Cleanup(func() { + <-helperDone + }) +} diff --git a/src/cmd/go/testdata/script/toolexec.txt b/src/cmd/go/testdata/script/toolexec.txt new file mode 100644 index 0000000..5262341 --- /dev/null +++ b/src/cmd/go/testdata/script/toolexec.txt @@ -0,0 +1,85 @@ +[short] skip + +# Build our simple toolexec program. +go build ./cmd/mytool + +# Build the main package with our toolexec program. For each action, it will +# print the tool's name and the TOOLEXEC_IMPORTPATH value. We expect to compile +# each package once, and link the main package once. +# Don't check the entire output at once, because the order in which the tools +# are run is irrelevant here. +# Finally, note that asm and cgo are run twice. + +go build -toolexec=$PWD/mytool +[amd64] stderr -count=2 '^asm'${GOEXE}' TOOLEXEC_IMPORTPATH=test/main/withasm$' +stderr -count=1 '^compile'${GOEXE}' TOOLEXEC_IMPORTPATH=test/main/withasm$' +[cgo] stderr -count=2 '^cgo'${GOEXE}' TOOLEXEC_IMPORTPATH=test/main/withcgo$' +[cgo] stderr -count=1 '^compile'${GOEXE}' TOOLEXEC_IMPORTPATH=test/main/withcgo$' +stderr -count=1 '^compile'${GOEXE}' TOOLEXEC_IMPORTPATH=test/main$' +stderr -count=1 '^link'${GOEXE}' TOOLEXEC_IMPORTPATH=test/main$' + +-- go.mod -- +module test/main +-- foo.go -- +// Simple package so we can test a program build with -toolexec. +// With a dummy import, to test different TOOLEXEC_IMPORTPATH values. +// Includes dummy uses of cgo and asm, to cover those tools as well. +package main + +import ( + _ "test/main/withasm" + _ "test/main/withcgo" +) + +func main() {} +-- withcgo/withcgo.go -- +package withcgo + +// int fortytwo() +// { +// return 42; +// } +import "C" +-- withcgo/stub.go -- +package withcgo + +// Stub file to ensure we build without cgo too. +-- withasm/withasm.go -- +package withasm + +// Note that we don't need to declare the Add func at all. +-- withasm/withasm_amd64.s -- +TEXT ·Add(SB),$0-24 + MOVQ a+0(FP), AX + ADDQ b+8(FP), AX + MOVQ AX, ret+16(FP) + RET +-- cmd/mytool/main.go -- +package main + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" +) + +func main() { + tool, args := os.Args[1], os.Args[2:] + toolName := filepath.Base(tool) + if len(args) > 0 && args[0] == "-V=full" { + // We can't alter the version output. + } else { + // Print which tool we're running, and on what package. + fmt.Fprintf(os.Stdout, "%s TOOLEXEC_IMPORTPATH=%s\n", toolName, os.Getenv("TOOLEXEC_IMPORTPATH")) + } + + // Simply run the tool. + cmd := exec.Command(tool, args...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} diff --git a/src/cmd/go/testdata/script/vendor_complex.txt b/src/cmd/go/testdata/script/vendor_complex.txt new file mode 100644 index 0000000..9ca94e7 --- /dev/null +++ b/src/cmd/go/testdata/script/vendor_complex.txt @@ -0,0 +1,75 @@ +env GO111MODULE=off + +# 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/src/cmd/go/testdata/script/vendor_gopath_issue11409.txt b/src/cmd/go/testdata/script/vendor_gopath_issue11409.txt new file mode 100644 index 0000000..da52f9a --- /dev/null +++ b/src/cmd/go/testdata/script/vendor_gopath_issue11409.txt @@ -0,0 +1,52 @@ +[!windows] [short] stop 'this test only applies to Windows' +env GO111MODULE=off + +go build run_go.go +exec ./run_go$GOEXE $GOPATH $GOPATH/src/vend/hello +stdout 'hello, world' + +-- run_go.go -- +package main + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" +) + +func changeVolume(s string, f func(s string) string) string { + vol := filepath.VolumeName(s) + return f(vol) + s[len(vol):] +} + +func main() { + gopath := changeVolume(os.Args[1], strings.ToLower) + dir := changeVolume(os.Args[2], strings.ToUpper) + cmd := exec.Command("go", "run", "hello.go") + cmd.Dir = dir + cmd.Env = append(os.Environ(), "GOPATH="+gopath) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +-- vend/hello/hello.go -- +package main + +import ( + "fmt" + "strings" // really ../vendor/strings +) + +func main() { + fmt.Printf("%s\n", strings.Msg) +} +-- vend/vendor/strings/msg.go -- +package strings + +var Msg = "hello, world" diff --git a/src/cmd/go/testdata/script/vendor_import.txt b/src/cmd/go/testdata/script/vendor_import.txt new file mode 100644 index 0000000..df4c27d --- /dev/null +++ b/src/cmd/go/testdata/script/vendor_import.txt @@ -0,0 +1,104 @@ +# Imports +env GO111MODULE=off +go list -f '{{.ImportPath}} {{.Imports}}' 'vend/...' 'vend/vendor/...' 'vend/x/vendor/...' +cmp stdout want_vendor_imports.txt + +-- want_vendor_imports.txt -- +vend [vend/vendor/p r] +vend/dir1 [] +vend/hello [fmt vend/vendor/strings] +vend/subdir [vend/vendor/p r] +vend/x [vend/x/vendor/p vend/vendor/q vend/x/vendor/r vend/dir1 vend/vendor/vend/dir1/dir2] +vend/x/invalid [vend/x/invalid/vendor/foo] +vend/vendor/p [] +vend/vendor/q [] +vend/vendor/strings [] +vend/vendor/vend/dir1/dir2 [] +vend/x/vendor/p [] +vend/x/vendor/p/p [notfound] +vend/x/vendor/r [] +-- vend/bad.go -- +package vend + +import _ "r" +-- vend/dir1/dir1.go -- +package dir1 +-- vend/good.go -- +package vend + +import _ "p" +-- vend/hello/hello.go -- +package main + +import ( + "fmt" + "strings" // really ../vendor/strings +) + +func main() { + fmt.Printf("%s\n", strings.Msg) +} +-- vend/hello/hello_test.go -- +package main + +import ( + "strings" // really ../vendor/strings + "testing" +) + +func TestMsgInternal(t *testing.T) { + if strings.Msg != "hello, world" { + t.Fatalf("unexpected msg: %v", strings.Msg) + } +} +-- vend/hello/hellox_test.go -- +package main_test + +import ( + "strings" // really ../vendor/strings + "testing" +) + +func TestMsgExternal(t *testing.T) { + if strings.Msg != "hello, world" { + t.Fatalf("unexpected msg: %v", strings.Msg) + } +} +-- vend/subdir/bad.go -- +package subdir + +import _ "r" +-- vend/subdir/good.go -- +package subdir + +import _ "p" +-- vend/vendor/p/p.go -- +package p +-- vend/vendor/q/q.go -- +package q +-- vend/vendor/strings/msg.go -- +package strings + +var Msg = "hello, world" +-- vend/vendor/vend/dir1/dir2/dir2.go -- +package dir2 +-- vend/x/invalid/invalid.go -- +package invalid + +import "vend/x/invalid/vendor/foo" +-- vend/x/vendor/p/p/p.go -- +package p + +import _ "notfound" +-- vend/x/vendor/p/p.go -- +package p +-- vend/x/vendor/r/r.go -- +package r +-- vend/x/x.go -- +package x + +import _ "p" +import _ "q" +import _ "r" +import _ "vend/dir1" // not vendored +import _ "vend/dir1/dir2" // vendored diff --git a/src/cmd/go/testdata/script/vendor_import_missing.txt b/src/cmd/go/testdata/script/vendor_import_missing.txt new file mode 100644 index 0000000..8e50dfe --- /dev/null +++ b/src/cmd/go/testdata/script/vendor_import_missing.txt @@ -0,0 +1,7 @@ +# Missing package error message +! go build vend/x/vendor/p/p + +-- vend/x/vendor/p/p/p.go -- +package p + +import _ "notfound" diff --git a/src/cmd/go/testdata/script/vendor_import_wrong.txt b/src/cmd/go/testdata/script/vendor_import_wrong.txt new file mode 100644 index 0000000..73bf595 --- /dev/null +++ b/src/cmd/go/testdata/script/vendor_import_wrong.txt @@ -0,0 +1,20 @@ +# Wrong import path +env GO111MODULE=off +! go build vend/x/invalid +stderr 'must be imported as foo' + +env GO111MODULE= +cd vend/x/invalid +! go build vend/x/invalid +stderr 'must be imported as foo' + +-- vend/x/invalid/go.mod -- +module vend/x/invalid + +go 1.16 + +-- vend/x/invalid/invalid.go -- +package invalid + +import "vend/x/invalid/vendor/foo" + diff --git a/src/cmd/go/testdata/script/vendor_issue12156.txt b/src/cmd/go/testdata/script/vendor_issue12156.txt new file mode 100644 index 0000000..ac95c6d --- /dev/null +++ b/src/cmd/go/testdata/script/vendor_issue12156.txt @@ -0,0 +1,16 @@ +# Tests issue #12156, a former index out of range panic. + +env GO111MODULE=off +env GOPATH=$WORK/gopath/src/testvendor2 # vendor/x is directly in $GOPATH, not in $GOPATH/src +cd $WORK/gopath/src/testvendor2/src/p + +! go build p.go +! stderr panic # Make sure it doesn't panic +stderr 'cannot find package "x"' + +-- testvendor2/src/p/p.go -- +package p + +import "x" +-- testvendor2/vendor/x/x.go -- +package x diff --git a/src/cmd/go/testdata/script/vendor_list_issue11977.txt b/src/cmd/go/testdata/script/vendor_list_issue11977.txt new file mode 100644 index 0000000..ce2e29f --- /dev/null +++ b/src/cmd/go/testdata/script/vendor_list_issue11977.txt @@ -0,0 +1,17 @@ +[!net] skip +[!exec:git] skip +env GO111MODULE=off + +go get -d github.com/rsc/go-get-issue-11864 + +go list -f '{{join .TestImports "\n"}}' github.com/rsc/go-get-issue-11864/t +stdout 'go-get-issue-11864/vendor/vendor.org/p' + +go list -f '{{join .XTestImports "\n"}}' github.com/rsc/go-get-issue-11864/tx +stdout 'go-get-issue-11864/vendor/vendor.org/p' + +go list -f '{{join .XTestImports "\n"}}' github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx2 +stdout 'go-get-issue-11864/vendor/vendor.org/tx2' + +go list -f '{{join .XTestImports "\n"}}' github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx3 +stdout 'go-get-issue-11864/vendor/vendor.org/tx3' diff --git a/src/cmd/go/testdata/script/vendor_resolve.txt b/src/cmd/go/testdata/script/vendor_resolve.txt new file mode 100644 index 0000000..bc8cf0a --- /dev/null +++ b/src/cmd/go/testdata/script/vendor_resolve.txt @@ -0,0 +1,21 @@ +env GO111MODULE=off +! go build p +stderr 'must be imported as x' + +-- p/p.go -- +package p + +import ( + _ "q/y" + _ "q/z" +) +-- q/vendor/x/x.go -- +package x +-- q/y/y.go -- +package y + +import _ "x" +-- q/z/z.go -- +package z + +import _ "q/vendor/x" diff --git a/src/cmd/go/testdata/script/vendor_test_issue11864.txt b/src/cmd/go/testdata/script/vendor_test_issue11864.txt new file mode 100644 index 0000000..cfb43bf --- /dev/null +++ b/src/cmd/go/testdata/script/vendor_test_issue11864.txt @@ -0,0 +1,20 @@ +[!net] skip +[!exec:git] skip +env GO111MODULE=off + +go get github.com/rsc/go-get-issue-11864 + +# build -i should work +go build -i github.com/rsc/go-get-issue-11864 +go build -i github.com/rsc/go-get-issue-11864/t + +# test -i should work like build -i (golang.org/issue/11988) +go test -i github.com/rsc/go-get-issue-11864 +go test -i github.com/rsc/go-get-issue-11864/t + +# test should work too +go test github.com/rsc/go-get-issue-11864 +go test github.com/rsc/go-get-issue-11864/t + +# external tests should observe internal test exports (golang.org/issue/11977) +go test github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx2 diff --git a/src/cmd/go/testdata/script/vendor_test_issue14613.txt b/src/cmd/go/testdata/script/vendor_test_issue14613.txt new file mode 100644 index 0000000..7801e69 --- /dev/null +++ b/src/cmd/go/testdata/script/vendor_test_issue14613.txt @@ -0,0 +1,22 @@ +[!net] skip +[!exec:git] skip +env GO111MODULE=off + +cd $GOPATH + +go get github.com/clsung/go-vendor-issue-14613 +go build -o $WORK/a.out -i github.com/clsung/go-vendor-issue-14613 + +# test folder should work +go test -i github.com/clsung/go-vendor-issue-14613 +go test github.com/clsung/go-vendor-issue-14613 + +# test with specified _test.go should work too +cd $GOPATH/src +go test -i github.com/clsung/go-vendor-issue-14613/vendor_test.go +go test github.com/clsung/go-vendor-issue-14613/vendor_test.go + +# test with imported and not used +go test -i github.com/clsung/go-vendor-issue-14613/vendor/mylibtesttest/myapp/myapp_test.go +! go test github.com/clsung/go-vendor-issue-14613/vendor/mylibtesttest/myapp/myapp_test.go +stderr 'imported and not used:' diff --git a/src/cmd/go/testdata/script/version.txt b/src/cmd/go/testdata/script/version.txt new file mode 100644 index 0000000..8615a4a --- /dev/null +++ b/src/cmd/go/testdata/script/version.txt @@ -0,0 +1,52 @@ +# Without arguments, we just print Go's own version. +go version +stdout '^go version' + +# Flags without files, or paths to misisng files, should error. +! go version missing.exe +! go version -m +stderr 'with arguments' +! go version -v +stderr 'with arguments' + +# Neither of the two flags above should be an issue via GOFLAGS. +env GOFLAGS='-m -v' +go version +stdout '^go version' +env GOFLAGS= + +env GO111MODULE=on +# Skip the builds below if we are running in short mode. +[short] skip + +# Check that 'go version' and 'go version -m' work on a binary built in module mode. +go get -d rsc.io/fortune +go build -o fortune.exe rsc.io/fortune +go version fortune.exe +stdout '^fortune.exe: .+' +go version -m fortune.exe +stdout '^\tpath\trsc.io/fortune' +stdout '^\tmod\trsc.io/fortune\tv1.0.0' + +# Repeat the test with -buildmode=pie. +[!buildmode:pie] stop +go build -buildmode=pie -o external.exe rsc.io/fortune +go version external.exe +stdout '^external.exe: .+' +go version -m external.exe +stdout '^\tpath\trsc.io/fortune' +stdout '^\tmod\trsc.io/fortune\tv1.0.0' + +# Also test PIE with internal linking. +# currently only supported on linux/amd64, linux/arm64 and windows/amd64. +[!linux] [!windows] stop +[!amd64] [!arm64] stop +go build -buildmode=pie -ldflags=-linkmode=internal -o internal.exe rsc.io/fortune +go version internal.exe +stdout '^internal.exe: .+' +go version -m internal.exe +stdout '^\tpath\trsc.io/fortune' +stdout '^\tmod\trsc.io/fortune\tv1.0.0' + +-- go.mod -- +module m diff --git a/src/cmd/go/testdata/script/version_replace.txt b/src/cmd/go/testdata/script/version_replace.txt new file mode 100644 index 0000000..ec98f4e --- /dev/null +++ b/src/cmd/go/testdata/script/version_replace.txt @@ -0,0 +1,33 @@ +[short] skip + +go mod download example.com/printversion@v0.1.0 example.com/printversion@v1.0.0 +go get -d example.com/printversion@v0.1.0 +go install example.com/printversion + +go run example.com/printversion +cmp stdout out.txt + +go version -m $GOPATH/bin/printversion$GOEXE +stdout '^.*[/\\]bin[/\\]printversion'$GOEXE': .*$' +stdout '^ path example.com/printversion$' +stdout '^ mod example.com/printversion v0.1.0$' +stdout '^ => example.com/printversion v1.0.0 h1:.*$' +stdout '^ dep example.com/version v1.0.0$' +stdout '^ => example.com/version v1.0.1 h1:.*$' + +-- go.mod -- +module golang.org/issue/37392 +go 1.14 +require ( + example.com/printversion v0.1.0 +) +replace ( + example.com/printversion => example.com/printversion v1.0.0 + example.com/version v1.0.0 => example.com/version v1.0.1 +) +-- out.txt -- +path is example.com/printversion +main is example.com/printversion v0.1.0 + (replaced by example.com/printversion v1.0.0) +using example.com/version v1.0.0 + (replaced by example.com/version v1.0.1) diff --git a/src/cmd/go/testdata/script/vet.txt b/src/cmd/go/testdata/script/vet.txt new file mode 100644 index 0000000..6573ae3 --- /dev/null +++ b/src/cmd/go/testdata/script/vet.txt @@ -0,0 +1,62 @@ +# Package with external tests +! go vet m/vetpkg +stderr 'Printf' + +# With tags +! go vet -tags tagtest m/vetpkg +stderr 'c\.go.*Printf' + +# With flags on +! go vet -printf m/vetpkg +stderr 'Printf' + +# With flags off +go vet -printf=false m/vetpkg +! stderr . + +# With only test files (tests issue #23395) +go vet m/onlytest +! stderr . + +# With only cgo files (tests issue #24193) +[!cgo] skip +[short] skip +go vet m/onlycgo +! stderr . + +-- go.mod -- +module m + +go 1.16 +-- vetpkg/a_test.go -- +package p_test +-- vetpkg/b.go -- +package p + +import "fmt" + +func f() { + fmt.Printf("%d") +} +-- vetpkg/c.go -- +// +build tagtest + +package p + +import "fmt" + +func g() { + fmt.Printf("%d", 3, 4) +} +-- onlytest/p_test.go -- +package p + +import "testing" + +func TestMe(*testing.T) {} +-- onlycgo/p.go -- +package p + +import "C" + +func F() {} diff --git a/src/cmd/go/testdata/script/vet_asm.txt b/src/cmd/go/testdata/script/vet_asm.txt new file mode 100644 index 0000000..59b35ec --- /dev/null +++ b/src/cmd/go/testdata/script/vet_asm.txt @@ -0,0 +1,32 @@ +env GO111MODULE=off + +# Issue 27665. Verify that "go vet" analyzes non-Go files. + +[!amd64] skip +! go vet -asmdecl a +stderr 'f: invalid MOVW of x' + +# -c flag shows context +! go vet -c=2 -asmdecl a +stderr '...invalid MOVW...' +stderr '1 .*TEXT' +stderr '2 MOVW' +stderr '3 RET' +stderr '4' + +# -json causes success, even with diagnostics and errors. +go vet -json -asmdecl a +stderr '"a": {' +stderr '"asmdecl":' +stderr '"posn": ".*asm.s:2:1",' +stderr '"message": ".*invalid MOVW.*"' + +-- a/a.go -- +package a + +func f(x int8) + +-- a/asm.s -- +TEXT ·f(SB),0,$0-1 + MOVW x+0(FP), AX + RET diff --git a/src/cmd/go/testdata/script/vet_deps.txt b/src/cmd/go/testdata/script/vet_deps.txt new file mode 100644 index 0000000..b2a8f16 --- /dev/null +++ b/src/cmd/go/testdata/script/vet_deps.txt @@ -0,0 +1,34 @@ +env GO111MODULE=off + +# Issue 30296. Verify that "go vet" uses only immediate dependencies. + +# First run fills the cache. +go vet a + +go vet -x a +! stderr 'transitive' + +-- a/a.go -- +package a + +import "b" + +func F() { + b.F() +} + +-- b/b.go -- +package b + +import "transitive" + +func F() { + transitive.F() +} + +-- transitive/c.go -- +package transitive + +func F() { +} + diff --git a/src/cmd/go/testdata/script/vet_flags.txt b/src/cmd/go/testdata/script/vet_flags.txt new file mode 100644 index 0000000..e2e3f5b --- /dev/null +++ b/src/cmd/go/testdata/script/vet_flags.txt @@ -0,0 +1,93 @@ +env GO111MODULE=on + +# Issue 35837: "go vet - " should use the requested +# analyzers, not the default analyzers for 'go test'. +go vet -n -buildtags=false runtime +stderr '-buildtags=false' +! stderr '-unsafeptr=false' + +# Issue 37030: "go vet " without other flags should disable the +# unsafeptr check by default. +go vet -n runtime +stderr '-unsafeptr=false' +! stderr '-unreachable=false' + +# However, it should be enabled if requested explicitly. +go vet -n -unsafeptr runtime +stderr '-unsafeptr' +! stderr '-unsafeptr=false' + +# -unreachable is disabled during test but on during plain vet. +go test -n runtime +stderr '-unreachable=false' + +# A flag terminator should be allowed before the package list. +go vet -n -- . + +[short] stop + +# Analyzer flags should be included from GOFLAGS, and should override +# the defaults. +go vet . +env GOFLAGS='-tags=buggy' +! go vet . +stderr 'possible formatting directive' + +# Enabling one analyzer in GOFLAGS should disable the rest implicitly... +env GOFLAGS='-tags=buggy -unsafeptr' +go vet . + +# ...but enabling one on the command line should not disable the analyzers +# enabled via GOFLAGS. +env GOFLAGS='-tags=buggy -printf' +! go vet -unsafeptr +stderr 'possible formatting directive' + +# Analyzer flags don't exist unless we're running 'go vet', +# and we shouldn't run the vet tool to discover them otherwise. +# (Maybe someday we'll hard-code the analyzer flags for the default vet +# tool to make this work, but not right now.) +env GOFLAGS='-unsafeptr' +! go list . +stderr 'go: parsing \$GOFLAGS: unknown flag -unsafeptr' +env GOFLAGS= + +env GOCACHE=$WORK/gocache + +# "go test" on a user package should by default enable an explicit list of analyzers. +go test -x -run=none . +stderr '[/\\]vet'$GOEXE'["]? .* -errorsas .* ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg' + +# An explicitly-empty -vet argument should imply the default analyzers. +go test -x -vet= -run=none . +stderr '[/\\]vet'$GOEXE'["]? .* -errorsas .* ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg' + +# "go test" on a standard package should by default disable an explicit list. +go test -x -run=none encoding/binary +stderr '[/\\]vet'$GOEXE'["]? -unsafeptr=false -unreachable=false ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg' + +go test -x -vet= -run=none encoding/binary +stderr '[/\\]vet'$GOEXE'["]? -unsafeptr=false -unreachable=false ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg' + +# Both should allow users to override via the -vet flag. +go test -x -vet=unreachable -run=none . +stderr '[/\\]vet'$GOEXE'["]? -unreachable ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg' +go test -x -vet=unreachable -run=none encoding/binary +stderr '[/\\]vet'$GOEXE'["]? -unreachable ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg' + +-- go.mod -- +module example.com/x +-- x.go -- +package x +-- x_test.go -- +package x +-- x_tagged.go -- +// +build buggy + +package x + +import "fmt" + +func init() { + fmt.Sprint("%s") // oops! +} diff --git a/src/cmd/go/testdata/script/vet_internal.txt b/src/cmd/go/testdata/script/vet_internal.txt new file mode 100644 index 0000000..85f7093 --- /dev/null +++ b/src/cmd/go/testdata/script/vet_internal.txt @@ -0,0 +1,71 @@ +env GO111MODULE=off + +# Issue 36173. Verify that "go vet" prints line numbers on load errors. + +! go vet a/a.go +stderr '^package command-line-arguments\n\ta[/\\]a.go:5:3: use of internal package' + +! go vet a/a_test.go +stderr '^package command-line-arguments \(test\)\n\ta[/\\]a_test.go:4:3: use of internal package' + +! go vet a +stderr '^package a\n\ta[/\\]a.go:5:3: use of internal package' + +go vet b/b.go +! stderr 'use of internal package' + +! go vet b/b_test.go +stderr '^package command-line-arguments \(test\)\n\tb[/\\]b_test.go:4:3: use of internal package' + +! go vet depends-on-a/depends-on-a.go +stderr '^package command-line-arguments\n\timports a\n\ta[/\\]a.go:5:3: use of internal package' + +! go vet depends-on-a/depends-on-a_test.go +stderr '^package command-line-arguments \(test\)\n\timports a\n\ta[/\\]a.go:5:3: use of internal package a/x/internal/y not allowed' + +! go vet depends-on-a +stderr '^package depends-on-a\n\timports a\n\ta[/\\]a.go:5:3: use of internal package' + +-- a/a.go -- +// A package with bad imports in both src and test +package a + +import ( + _ "a/x/internal/y" +) + +-- a/a_test.go -- +package a + +import ( + _ "a/x/internal/y" +) + +-- b/b.go -- +// A package with a bad import in test only +package b + +-- b/b_test.go -- +package b + +import ( + _ "a/x/internal/y" +) + +-- depends-on-a/depends-on-a.go -- +// A package that depends on a package with a bad import +package depends + +import ( + _ "a" +) + +-- depends-on-a/depends-on-a_test.go -- +package depends + +import ( + _ "a" +) + +-- a/x/internal/y/y.go -- +package y diff --git a/src/cmd/go/testdata/testterminal18153/terminal_test.go b/src/cmd/go/testdata/testterminal18153/terminal_test.go new file mode 100644 index 0000000..71493ef --- /dev/null +++ b/src/cmd/go/testdata/testterminal18153/terminal_test.go @@ -0,0 +1,39 @@ +// Copyright 2016 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 linux + +// This test is run by src/cmd/dist/test.go (cmd_go_test_terminal), +// and not by cmd/go's tests. This is because this test requires +// that it be called with its stdout and stderr being a terminal. +// dist doesn't run `cmd/go test` against this test directory if +// dist's stdout/stderr aren't terminals. +// +// See issue 18153. + +package p + +import ( + "syscall" + "testing" + "unsafe" +) + +const ioctlReadTermios = syscall.TCGETS + +// isTerminal reports whether fd is a terminal. +func isTerminal(fd uintptr) bool { + var termios syscall.Termios + _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) + return err == 0 +} + +func TestIsTerminal(t *testing.T) { + if !isTerminal(1) { + t.Errorf("stdout is not a terminal") + } + if !isTerminal(2) { + t.Errorf("stderr is not a terminal") + } +} diff --git a/src/cmd/go/testdata/vendormod.txt b/src/cmd/go/testdata/vendormod.txt new file mode 100644 index 0000000..1bdaf2a --- /dev/null +++ b/src/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/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" +-- 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 -- cgit v1.2.3