Skip to content

Commit 752ad5e

Browse files
committed
Use bazel's downloader for Go modules when possible
1 parent 3e438c8 commit 752ad5e

File tree

3 files changed

+88
-4
lines changed

3 files changed

+88
-4
lines changed

cmd/fetch_repo/main.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ package main
2727
import (
2828
"flag"
2929
"log"
30+
"os"
3031

32+
"golang.org/x/mod/sumdb/dirhash"
3133
"golang.org/x/tools/go/vcs"
3234
)
3335

@@ -70,7 +72,19 @@ func main() {
7072
}
7173

7274
if *no_fetch {
73-
// Nothing to do
75+
if *sum != "" {
76+
repoSum, err := dirhash.HashDir(*dest, *importpath+"@"+*version, dirhash.Hash1)
77+
if err != nil {
78+
log.Fatalf("failed computing sum: %v", err)
79+
}
80+
81+
if repoSum != *sum {
82+
if goModCache := os.Getenv("GOMODCACHE"); goModCache != "" {
83+
log.Fatalf("resulting module with sum %s; expected sum %s, Please try clearing your module cache directory %q", repoSum, *sum, goModCache)
84+
}
85+
log.Fatalf("resulting module with sum %s; expected sum %s", repoSum, *sum)
86+
}
87+
}
7488
} else if *path != "" {
7589
if *importpath != "" {
7690
log.Fatal("-importpath must not be set")

internal/go_repository.bzl

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,56 @@ Authorization: Bearer RANDOM-TOKEN
117117
# We can't disable timeouts on Bazel, but we can set them to large values.
118118
_GO_REPOSITORY_TIMEOUT = 86400
119119

120+
def _escape_go_module_path(module_path):
121+
"""Escapes a Go module path according to the Go proxy protocol."""
122+
result = ""
123+
for c in module_path.elems():
124+
if "A" <= c and c <= "Z":
125+
result += "!" + c.lower()
126+
else:
127+
result += c
128+
return result
129+
130+
def _get_goproxy_url_for_module(env, module_path):
131+
"""Return proxy URL to be used for module_path, or None if no proxy will be used."""
132+
goproxy = env.get("GOPROXY", "")
133+
goprivate = env.get("GOPRIVATE", "")
134+
gonoproxy = env.get("GONOPROXY", "")
135+
136+
if goproxy == "off":
137+
return None
138+
139+
def matches_pattern(pattern, module_path):
140+
pat = pattern.strip()
141+
if not pat:
142+
return False
143+
if pat.endswith("/..."):
144+
return module_path.startswith(pat[:-4])
145+
if "*" in pat:
146+
return pat.replace("*", "") in module_path
147+
return module_path.startswith(pat)
148+
149+
for pat in goprivate.split(",") + gonoproxy.split(","):
150+
if matches_pattern(pat, module_path):
151+
return None
152+
153+
if not goproxy:
154+
return "https://proxy.golang.org"
155+
156+
idx = goproxy.find(",")
157+
if idx != -1:
158+
goproxy = goproxy[:idx]
159+
160+
if goproxy == "direct":
161+
return None
162+
163+
return goproxy
164+
120165
def _go_repository_impl(ctx):
121166
# TODO(#549): vcs repositories are not cached and still need to be fetched.
122167
# Download the repository or module.
123168
fetch_repo_args = None
169+
sum_args = []
124170
gazelle_path = None
125171

126172
is_module_extension_repo = bool(ctx.attr.internal_only_do_not_use_apparent_name)
@@ -137,6 +183,7 @@ def _go_repository_impl(ctx):
137183
gazelle_path = ctx.path(Label(_gazelle))
138184
watch(ctx, gazelle_path)
139185

186+
can_use_direct_download = False
140187
reproducible = False
141188
if ctx.attr.local_path:
142189
if hasattr(ctx, "watch_tree"):
@@ -204,14 +251,15 @@ def _go_repository_impl(ctx):
204251
else:
205252
fail("if version is specified, sum must also be")
206253
reproducible = True
254+
can_use_direct_download = True
207255

208256
fetch_path = ctx.attr.replace if ctx.attr.replace else ctx.attr.importpath
257+
sum_args = ["-sum=" + ctx.attr.sum]
209258
fetch_repo_args = [
210259
"-dest=" + str(ctx.path("")),
211260
"-importpath=" + fetch_path,
212261
"-version=" + ctx.attr.version,
213-
"-sum=" + ctx.attr.sum,
214-
]
262+
] + sum_args
215263
else:
216264
fail("one of urls, commit, tag, or version must be specified")
217265

@@ -286,6 +334,28 @@ def _go_repository_impl(ctx):
286334
# Override external GO111MODULE, because it is needed by module mode, no-op in repository mode
287335
fetch_repo_env["GO111MODULE"] = "on"
288336

337+
if can_use_direct_download:
338+
module = ctx.attr.replace if ctx.attr.replace else ctx.attr.importpath
339+
proxy_url = _get_goproxy_url_for_module(env, module)
340+
341+
if proxy_url:
342+
result = ctx.download_and_extract(
343+
url = "%s/%s/@v/%s.zip" % (
344+
proxy_url,
345+
_escape_go_module_path(module),
346+
ctx.attr.version,
347+
),
348+
sha256 = ctx.attr.sha256,
349+
canonical_id = ctx.attr.canonical_id,
350+
stripPrefix = module + "@" + ctx.attr.version,
351+
type = ctx.attr.type,
352+
auth = use_netrc(read_user_netrc(ctx), ctx.attr.urls, ctx.attr.auth_patterns),
353+
allow_fail = True,
354+
)
355+
if result.success:
356+
# All we need to do now is verify the sum!
357+
fetch_repo_args = ["-no-fetch"] + fetch_repo_args
358+
289359
result = env_execute(
290360
ctx,
291361
[fetch_repo] + fetch_repo_args,

internal/go_repository_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ go_repository(
180180
}
181181

182182
func TestModcacheRW(t *testing.T) {
183-
if err := bazel_testing.RunBazel("query", "@errors_go_mod//:go_default_library"); err != nil {
183+
if err := bazel_testing.RunBazel("query", "--repo_env=GOPROXY=direct", "@errors_go_mod//:go_default_library"); err != nil {
184184
t.Fatal(err)
185185
}
186186
out, err := bazel_testing.BazelOutput("info", "output_base")

0 commit comments

Comments
 (0)