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 26, 2024
1 parent 847cae4 commit 8f7c963
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 13 deletions.
16 changes: 13 additions & 3 deletions internal/bzlmod/go_deps.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,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 @@ -599,7 +600,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 @@ -626,6 +626,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 @@ -670,8 +677,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
69 changes: 65 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,58 @@ 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"):
print("hi")
# 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)

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 +306,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 +363,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 +477,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
5 changes: 3 additions & 2 deletions repository.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ git_repository(
go_repository(<a href="#go_repository-name">name</a>, <a href="#go_repository-auth_patterns">auth_patterns</a>, <a href="#go_repository-build_config">build_config</a>, <a href="#go_repository-build_directives">build_directives</a>, <a href="#go_repository-build_external">build_external</a>, <a href="#go_repository-build_extra_args">build_extra_args</a>,
<a href="#go_repository-build_file_generation">build_file_generation</a>, <a href="#go_repository-build_file_name">build_file_name</a>, <a href="#go_repository-build_file_proto_mode">build_file_proto_mode</a>, <a href="#go_repository-build_naming_convention">build_naming_convention</a>,
<a href="#go_repository-build_tags">build_tags</a>, <a href="#go_repository-canonical_id">canonical_id</a>, <a href="#go_repository-commit">commit</a>, <a href="#go_repository-debug_mode">debug_mode</a>, <a href="#go_repository-importpath">importpath</a>, <a href="#go_repository-patch_args">patch_args</a>, <a href="#go_repository-patch_cmds">patch_cmds</a>,
<a href="#go_repository-patch_tool">patch_tool</a>, <a href="#go_repository-patches">patches</a>, <a href="#go_repository-remote">remote</a>, <a href="#go_repository-replace">replace</a>, <a href="#go_repository-repo_mapping">repo_mapping</a>, <a href="#go_repository-sha256">sha256</a>, <a href="#go_repository-strip_prefix">strip_prefix</a>, <a href="#go_repository-sum">sum</a>, <a href="#go_repository-tag">tag</a>,
<a href="#go_repository-type">type</a>, <a href="#go_repository-urls">urls</a>, <a href="#go_repository-vcs">vcs</a>, <a href="#go_repository-version">version</a>)
<a href="#go_repository-patch_tool">patch_tool</a>, <a href="#go_repository-patches">patches</a>, <a href="#go_repository-path">path</a>, <a href="#go_repository-remote">remote</a>, <a href="#go_repository-replace">replace</a>, <a href="#go_repository-repo_mapping">repo_mapping</a>, <a href="#go_repository-sha256">sha256</a>, <a href="#go_repository-strip_prefix">strip_prefix</a>, <a href="#go_repository-sum">sum</a>,
<a href="#go_repository-tag">tag</a>, <a href="#go_repository-type">type</a>, <a href="#go_repository-urls">urls</a>, <a href="#go_repository-vcs">vcs</a>, <a href="#go_repository-version">version</a>)
</pre>

`go_repository` downloads a Go project and generates build files with Gazelle
Expand Down Expand Up @@ -189,6 +189,7 @@ go_repository(
| <a id="go_repository-patch_cmds"></a>patch_cmds | Commands to run in the repository after patches are applied. | List of strings | optional | `[]` |
| <a id="go_repository-patch_tool"></a>patch_tool | The patch tool used to apply `patches`. If this is specified, Bazel will use the specifed patch tool instead of the Bazel-native patch implementation. | String | optional | `""` |
| <a id="go_repository-patches"></a>patches | A list of patches to apply to the repository after gazelle runs. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="go_repository-path"></a>path | If specified, `go_repository` will load the module from this local directory | String | optional | `""` |
| <a id="go_repository-remote"></a>remote | The VCS location where the repository should be downloaded from. This is usually inferred from `importpath`, but you can set `remote` to download from a private repository or a fork. | String | optional | `""` |
| <a id="go_repository-replace"></a>replace | A replacement for the module named by `importpath`. The module named by `replace` will be downloaded at `version` and verified with `sum`.<br><br>NOTE: There is no `go_repository` equivalent to file path `replace` directives. Use `local_repository` instead. | String | optional | `""` |
| <a id="go_repository-repo_mapping"></a>repo_mapping | A dictionary from local repository name to global repository name. This allows controls over workspace dependency resolution for dependencies of this repository.<p>For example, an entry `"@foo": "@bar"` declares that, for any time this repository depends on `@foo` (such as a dependency on `@foo//some:target`, it should actually resolve that dependency within globally-declared `@bar` (`@bar//some:target`). | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | required | |
Expand Down

0 comments on commit 8f7c963

Please sign in to comment.