Skip to content

Commit

Permalink
POC - go.mod replace with ModulePath
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanpenner authored and Stefan Penner committed Feb 22, 2024
1 parent 9205f89 commit 45a18bb
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 11 deletions.
16 changes: 13 additions & 3 deletions internal/bzlmod/go_deps.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,7 @@ def _go_deps_impl(module_ctx):
version = new_version,
raw_version = replace.version,
)

if path in root_versions:
if replace != replace.to_path:
# If the root module replaces a Go module with a completely different one, do
Expand Down Expand Up @@ -522,7 +523,6 @@ def _go_deps_impl(module_ctx):
# Do not create a go_repository for a dep shared with the non-isolated instance of
# go_deps.
continue

go_repository_args = {
"name": module.repo_name,
"importpath": path,
Expand All @@ -549,6 +549,13 @@ def _go_deps_impl(module_ctx):
"version": "v" + module.raw_version,
})

# TODO: remove the need for a sentinel value, make it explicit instead
if module.raw_version == "999.999.999":
go_repository_args.update({
"version": None,
"path": module.replace,
})

go_repository(**go_repository_args)

# Create a synthetic WORKSPACE file that lists all Go repositories created
Expand Down Expand Up @@ -593,8 +600,11 @@ def _get_sum_from_module(path, module, sums):
entry = (module.replace, module.raw_version)

if entry not in sums:
# TODO: if no sum exist, this is probably because a go mod tidy was missed
fail("No sum for {}@{} found".format(path, module.raw_version))
if module.raw_version == "999.999.999":
return ""
else:
# TODO: if no sum exist, this is probably because a go mod tidy was missed
fail("No sum for {}@{} found".format(path, module.raw_version))

return sums[entry]

Expand Down
9 changes: 5 additions & 4 deletions internal/bzlmod/go_mod.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -252,10 +252,11 @@ def _parse_replace_directive(state, tokens, path, line_no):
version = _canonicalize_raw_version(tokens[4]),
)
else:
fail(
"{}:{}: replace directive must follow pattern: ".format(path, line_no) +
"'replace from_path from_version => to_path to_version' or " +
"'replace from_path => to_path to_version'",
state["replace"][from_path] = struct(
from_version = None,
to_path = tokens[2],
# TODO: should version be None here? or some sentinel Null value version?
version = _canonicalize_raw_version("999.999.999"),
)

def _tokenize_line(line, path, line_no):
Expand Down
88 changes: 84 additions & 4 deletions internal/go_repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ def _go_repository_impl(ctx):
"-version=" + ctx.attr.version,
"-sum=" + ctx.attr.sum,
]
elif ctx.attr.path:
pass
else:
fail("one of urls, commit, tag, or importpath must be specified")

Expand Down Expand Up @@ -237,6 +239,77 @@ def _go_repository_impl(ctx):

env.update({k: ctx.os.environ[k] for k in env_keys if k in ctx.os.environ})

if ctx.attr.path:
local_path_env = dict(env)
local_path_env["GOSUMDB"] = "off"

# Override external GO111MODULE, because it is needed by module mode, no-op in repository mode
local_path_env["GO111MODULE"] = "on"

if hasattr(ctx, "watch_tree"):
# https://github.com/bazelbuild/bazel/commit/fffa0affebbacf1961a97ef7cd248be64487d480
ctx.watch_tree(ctx.attr.path)
else:
print("""
WARNING: go.mod replace directives to module paths is only supported in bazel 7.1.0-rc1 or later,
Because of this changes to %s will not be detected by bazel in previous versions.""" % ctx.attr.path)

#
# TODO more advance syncing would be a better solution, but for now this is OK.
# purge directory:
command = ["rm", "-rf", "%s/" % ctx.path("")]
result = env_execute(
ctx,
command,
environment = local_path_env,
timeout = _GO_REPOSITORY_TIMEOUT,
)

if result.return_code:
fail(command)

if result.stderr:
print("clear mod: %s", result.stderr)

if result.return_code:
fail(command)

command = ["cp", "-r", "%s/" % ctx.attr.path, ctx.path("")]
result = env_execute(
ctx,
command,
environment = local_path_env,
timeout = _GO_REPOSITORY_TIMEOUT,
)

# use "go mod download" to satisfy the dependencies of this module
if ctx.attr.debug_mode and result.stderr:
print("copy mod: %s", result.stderr)

if result.return_code:
fail(command)

# TODO: this needs to have a go mod with the same go version as the
# project, or it may fail as not all go versions are available
# locally
command = ["go", "mod", "download", "-json", "-modcacherw"]
result = env_execute(
ctx,
command,
environment = local_path_env,
timeout = _GO_REPOSITORY_TIMEOUT,
working_directory = "%s" % ctx.path(""),
)

# use "go mod download" to satisfy the dependencies of this module
if result.stderr:
print("mod download: %s", result.stderr)

if result.return_code:
fail(command)

# use "go mod download" to satisfy the dependencies of this module

if fetch_repo_args:
# Disable sumdb in fetch_repo. In module mode, the sum is a mandatory
# attribute of go_repository, so we don't need to look it up.
Expand All @@ -252,10 +325,12 @@ def _go_repository_impl(ctx):
environment = fetch_repo_env,
timeout = _GO_REPOSITORY_TIMEOUT,
)

if result.stderr:
print("copy_repo: " + result.stderr)

if result.return_code:
fail("failed to fetch %s: %s" % (ctx.name, result.stderr))
if ctx.attr.debug_mode and result.stderr:
print("fetch_repo: " + result.stderr)
fail("%s: %s" % (ctx.name, result.stderr))

# Repositories are fetched. Determine if build file generation is needed.
build_file_names = ctx.attr.build_file_name.split(",")
Expand Down Expand Up @@ -307,7 +382,7 @@ def _go_repository_impl(ctx):
"-repo_config",
repo_config,
]
if ctx.attr.version:
if ctx.attr.version or ctx.attr.path:
cmd.append("-go_repository_module_mode")
if ctx.attr.build_file_name:
cmd.extend(["-build_file_name", ctx.attr.build_file_name])
Expand Down Expand Up @@ -421,6 +496,11 @@ go_repository = repository_rule(
doc = _AUTH_PATTERN_DOC,
),

# Attributes for a module that should be loaded from the local file system.
"path": attr.string(
doc = """ If specified, `go_repository` will load the module from this local directory""",
),

# Attributes for a module that should be downloaded with the Go toolchain.
"version": attr.string(
doc = """If specified, `go_repository` will download the module at this version
Expand Down

0 comments on commit 45a18bb

Please sign in to comment.