Skip to content

Commit

Permalink
[Feature] go.mod & go.work FilePath ReplaceDirective support
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanpenner committed May 1, 2024
1 parent c26571e commit 2da0494
Show file tree
Hide file tree
Showing 27 changed files with 404 additions and 67 deletions.
2 changes: 2 additions & 0 deletions cmd/fetch_repo/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ go_library(
"fetch_repo.go",
"go_mod_download.go",
"module.go",
"path.go",
"vcs.go",
],
importpath = "github.com/bazelbuild/bazel-gazelle/cmd/fetch_repo",
Expand Down Expand Up @@ -40,6 +41,7 @@ filegroup(
"fetch_repo_test.go",
"go_mod_download.go",
"module.go",
"path.go",
"vcs.go",
],
visibility = ["//visibility:public"],
Expand Down
31 changes: 28 additions & 3 deletions cmd/fetch_repo/fetch_repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
var (
// Common flags
importpath = flag.String("importpath", "", "Go importpath to the repository fetch")
path = flag.String("path", "", "absolute or relative path to a local go module")
dest = flag.String("dest", "", "destination directory")

// Repository flags
Expand All @@ -54,17 +55,41 @@ func main() {
log.SetPrefix("fetch_repo: ")

flag.Parse()
if *importpath == "" {
log.Fatal("-importpath must be set")

if *importpath == "" && *path == "" {
log.Fatal("-importpath or -path must be set")
}

if *dest == "" {
log.Fatal("-dest must be set")
}
if flag.NArg() != 0 {
log.Fatal("fetch_repo does not accept positional arguments")
}

if *version != "" {
if *path != "" {
if *importpath != "" {
log.Fatal("-importpath must not be set")
}
if *remote != "" {
log.Fatal("-remote must not be set in module path mode")
}
if *cmd != "" {
log.Fatal("-vcs must not be set in module path mode")
}
if *rev != "" {
log.Fatal("-rev must not be set in module path mode")
}
if *version != "" {
log.Fatal("-version must not be set in module path mode")
}
if *sum != "" {
log.Fatal("-sum must not be set in module path mode")
}
if err := moduleFromPath(*path, *dest); err != nil {
log.Fatal(err)
}
} else if *version != "" {
if *remote != "" {
log.Fatal("-remote must not be set in module mode")
}
Expand Down
6 changes: 3 additions & 3 deletions cmd/fetch_repo/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ package main

import (
"fmt"
"golang.org/x/mod/sumdb/dirhash"
"os"

"golang.org/x/mod/sumdb/dirhash"
)

func fetchModule(dest, importpath, version, sum string) error {
Expand All @@ -33,7 +34,6 @@ func fetchModule(dest, importpath, version, sum string) error {
// so we create a dummy module in the current directory (which should be
// empty).
w, err := os.OpenFile("go.mod", os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o666)

if err != nil {
return fmt.Errorf("error creating temporary go.mod: %v", err)
}
Expand All @@ -46,7 +46,7 @@ func fetchModule(dest, importpath, version, sum string) error {
return fmt.Errorf("error closing temporary go.mod: %v", err)
}

var dl = GoModDownloadResult{}
dl := GoModDownloadResult{}
err = runGoModDownload(&dl, dest, importpath, version)
os.Remove("go.mod")
if err != nil {
Expand Down
37 changes: 37 additions & 0 deletions cmd/fetch_repo/path.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/* Copyright 2019 The Bazel Authors. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
"fmt"
"os/exec"
)

func moduleFromPath(from string, dest string) error {
err := copyTree(dest, from)
if err != nil {
return err
}

cmd := exec.Command(findGoPath(), "mod", "download", "-json", "-modcacherw")
cmd.Dir = dest

output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("error running '%v': %v in %s. Output: %s", cmd.Args, err, dest, string(output))
}
return nil
}
3 changes: 3 additions & 0 deletions internal/bzlmod/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ bzl_library(
name = "go_mod",
srcs = ["go_mod.bzl"],
visibility = ["//:__subpackages__"],
deps = [
":semver",
],
)

bzl_library(
Expand Down
48 changes: 36 additions & 12 deletions internal/bzlmod/go_deps.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ load(
"DEFAULT_BUILD_FILE_GENERATION_BY_PATH",
"DEFAULT_DIRECTIVES_BY_PATH",
)
load(":go_mod.bzl", "deps_from_go_mod", "parse_go_work", "sums_from_go_mod", "sums_from_go_work")
load(":semver.bzl", "semver")
load(":go_mod.bzl", "deps_from_go_mod", "go_work_from_label", "sums_from_go_mod", "sums_from_go_work")
load(":semver.bzl", "semver", "COMPARES_HIGHEST_SENTINEL")
load(
":utils.bzl",
"drop_nones",
Expand Down Expand Up @@ -83,12 +83,6 @@ _GAZELLE_ATTRS = {
),
}

def go_work_from_label(module_ctx, go_work_label):
"""Loads deps from a go.work file"""
go_work_path = module_ctx.path(go_work_label)
go_work_content = module_ctx.read(go_work_path)
return parse_go_work(go_work_content, go_work_label)

def _fail_on_non_root_overrides(module_ctx, module, tag_class):
if module.is_root:
return
Expand Down Expand Up @@ -299,6 +293,10 @@ def check_for_version_conflict(version, previous, module_tag, module_name_to_go_
# version is the same, skip because we won't error
return

if hasattr(module_tag, "local_path"):
# overrides are not considered for version conflicts
return

# When using go.work, duplicate dependency versions are possible.
# This can cause issues, so we fail with a hopefully actionable error.
current_label = module_tag._parent_label
Expand Down Expand Up @@ -435,7 +433,10 @@ def _go_deps_impl(module_ctx):
]

if module.is_root or getattr(module_ctx, "is_isolated", False):
replace_map.update(go_mod_replace_map)
# for the replace_map, first in wins
for mod_path, mod in go_mod_replace_map.items():
if not mod_path in replace_map:
replace_map[mod_path] = mod
else:
# Register this Bazel module as providing the specified Go module. It participates
# in version resolution using its registry version, which uses a relaxed variant of
Expand Down Expand Up @@ -507,10 +508,21 @@ def _go_deps_impl(module_ctx):
paths[module_tag.path] = struct(version = version, module_tag = module_tag)

if module_tag.path not in module_resolutions or version > module_resolutions[module_tag.path].version:
to_path = None
local_path = None

if module_tag.path in replace_map:
replacement = replace_map[module_tag.path]

to_path = replacement.to_path
local_path = replacement.local_path

module_resolutions[module_tag.path] = struct(
repo_name = _repo_name(module_tag.path),
version = version,
raw_version = raw_version,
to_path = to_path,
local_path = local_path,
)

_fail_on_unmatched_overrides(archive_overrides.keys(), module_resolutions, "archive_overrides")
Expand Down Expand Up @@ -574,7 +586,6 @@ def _go_deps_impl(module_ctx):
resolved_version = module_resolutions[path].raw_version,
),
)

for path, module in module_resolutions.items():
if hasattr(module, "module_name"):
# Do not create a go_repository for a Go module provided by a bazel_dep.
Expand All @@ -585,7 +596,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 @@ -605,6 +615,12 @@ def _go_deps_impl(module_ctx):
"patches": _get_patches(path, archive_overrides),
"patch_args": _get_patch_args(path, archive_overrides),
})
elif module.local_path:
go_repository_args.update({
# the version is now meaningless
"version": None,
"local_path": module.local_path,
})
else:
go_repository_args.update({
"sum": _get_sum_from_module(path, module, sums),
Expand Down Expand Up @@ -659,7 +675,11 @@ def _get_sum_from_module(path, module, sums):
entry = (module.replace, module.raw_version)

if entry not in sums:
fail("No sum for {}@{} found. You may need to run: bazel run @rules_go//go -- mod tidy".format(path, module.raw_version))
if module.raw_version == COMPARES_HIGHEST_SENTINEL:
# replacement have no sums, so we can skip this
return None
elif module.local_path== None:
fail("No sum for {}@{} from {} found. You may need to run: bazel run @rules_go//go -- mod tidy".format(path, module.raw_version, "parent-label-todo")) #module.parent_label))

return sums[entry]

Expand Down Expand Up @@ -706,6 +726,10 @@ _module_tag = tag_class(
),
"build_naming_convention": attr.string(doc = """Removed, do not use""", default = ""),
"build_file_proto_mode": attr.string(doc = """Removed, do not use""", default = ""),
"local_path": attr.string(
doc = """For when a module is replaced by one residing in a local directory path """,
mandatory = False,
),
},
)

Expand Down
Loading

0 comments on commit 2da0494

Please sign in to comment.