Skip to content

Commit

Permalink
fix(cli): support aspect configure with rules_go under bzlmod (#7217)
Browse files Browse the repository at this point in the history
The rules_go gazelle integration changed in bzlmod such that it now
requires resolving the
[bazel_gazelle_go_repository_config](https://github.com/bazel-contrib/bazel-gazelle/blob/v0.39.1/internal/bzlmod/go_deps.bzl#L653-L672)
repository which contains a cache-able list of the `go_repository`
target data (not the actual targets, just data about them).

With regular gazelle from a `gazelle_binary` target the
`@bazel_gazelle_go_repository_config` repo path is resolved using [a
rule label
attribute](https://github.com/bazel-contrib/bazel-gazelle/blob/v0.39.1/def.bzl#L101-L104)
and [this
hack](https://github.com/bazel-contrib/bazel-gazelle/blob/v0.39.1/internal/go_repository.bzl#L313-L321).
However when we are running gazelle within `aspect configure` we need an
alternate way of resolving this path.

This PR does something similar to the [the go_repository
hack](https://github.com/bazel-contrib/bazel-gazelle/blob/v0.39.1/internal/go_repository.bzl#L313-L321),
except we must launch `bazel info output_base` to get the external
directory.

Fix #760

---

### Changes are visible to end-users: yes

- Searched for relevant documentation and updated as needed: yes
- Breaking change (forces users to change their own code or config): no
- Suggested release notes appear below: yes

The go language in `aspect configure` will now work when rules_go is
under bzlmod.

### Test plan

- Manual testing; please provide instructions so we can reproduce: run
the cli binary on a repo where rules_go is loaded with bzlmod, for
example https://github.com/r0bobo/aspect-cli-issue-760-reproduce

GitOrigin-RevId: aded45cc9e6566447383b193a201255e55e90730
  • Loading branch information
jbedard committed Nov 7, 2024
1 parent 9316744 commit 81fb19d
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 0 deletions.
3 changes: 3 additions & 0 deletions pkg/aspect/configure/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ go_library(
"fix.go",
"fix-update.go",
"gazelle.go",
"go_deps.go",
"metaresolver.go",
"print.go",
"profiler.go",
Expand All @@ -21,7 +22,9 @@ go_library(
"//gazelle/python",
"//pkg/aspect/configure/internal/wspace",
"//pkg/aspecterrors",
"//pkg/bazel",
"//pkg/ioutils",
"//pkg/logger",
"@bazel_gazelle//config:go_default_library",
"@bazel_gazelle//flag:go_default_library",
"@bazel_gazelle//label:go_default_library",
Expand Down
16 changes: 16 additions & 0 deletions pkg/aspect/configure/configure.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,17 @@ func (c *Configure) addDefaultLanguages() {

viper.SetDefault("configure.languages.go", false)
if viper.GetBool("configure.languages.go") {
if os.Getenv(GO_REPOSITORY_CONFIG_ENV) == "" {
goConfigPath, err := determineGoRepositoryConfigPath()
if err != nil {
log.Fatalf("ERROR: unable to determine go_repository config path: %v", err)
}

if goConfigPath != "" {
os.Setenv(GO_REPOSITORY_CONFIG_ENV, goConfigPath)
}
}

c.AddLanguage("go", golang.NewLanguage)
}

Expand Down Expand Up @@ -140,6 +151,11 @@ configure:
fixArgs = append(fixArgs, "--memprofile="+memprofile)
}

go_repo_config := os.Getenv(GO_REPOSITORY_CONFIG_ENV)
if go_repo_config != "" {
fixArgs = append(fixArgs, "--repo_config="+go_repo_config)
}

// Append additional args including specific directories to fix.
fixArgs = append(fixArgs, args...)

Expand Down
82 changes: 82 additions & 0 deletions pkg/aspect/configure/go_deps.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright 2024 Aspect Build Systems, Inc.
*
* 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 configure

import (
"fmt"
"os"
"path"
"strings"

"aspect.build/cli/pkg/bazel"
"aspect.build/cli/pkg/ioutils"
BazelLog "aspect.build/cli/pkg/logger"
)

// The @gazelle go_deps extension name.
// https://github.com/bazel-contrib/bazel-gazelle/blob/v0.39.1/internal/bzlmod/go_deps.bzl#L827
const GO_DEPS_EXTENSION_NAME = "go_deps"

// The repository name for the gazelle repo_config.
// https://github.com/bazel-contrib/bazel-gazelle/blob/v0.39.1/internal/bzlmod/go_deps.bzl#L648-L654
const GO_REPOSITORY_CONFIG_REPO_NAME = "bazel_gazelle_go_repository_config"

// An environment variable to set the full path to the gazelle repo_config
const GO_REPOSITORY_CONFIG_ENV = GO_REPOSITORY_CONFIG_REPO_NAME

// bazel 8 switches the bzlmod separator to "+"
// See https://github.com/bazelbuild/bazel/issues/23127
var BZLMOD_REPO_SEPARATORS = []string{"~", "+"}

func determineGoRepositoryConfigPath() (string, error) {
// TODO(jason): look into a store of previous invocations for relevant logs
bzl := bazel.WorkspaceFromWd

var out strings.Builder
streams := ioutils.Streams{Stdout: &out, Stderr: nil}
if err := bzl.RunCommand(streams, nil, "info", "output_base"); err != nil {
return "", fmt.Errorf("unable to locate output_base: %w", err)
}

outputBase := strings.TrimSpace(out.String())
if outputBase == "" {
return "", fmt.Errorf("unable to locate output_base on path")
}

var goDepsRepoName string
for _, sep := range BZLMOD_REPO_SEPARATORS {
repoName := fmt.Sprintf("gazelle%s%s%s%s%s/WORKSPACE", sep, sep, GO_DEPS_EXTENSION_NAME, sep, GO_REPOSITORY_CONFIG_REPO_NAME)
repoPath := path.Join(outputBase, "external", repoName)

_, err := os.Stat(repoPath)
if err == nil {
goDepsRepoName = repoPath
break
}
}

if goDepsRepoName == "" {
// Assume no matches means rules_go is not being used in bzlmod
// or the gazelle `go_deps` extension is not being used
BazelLog.Infof("No %s found in output_base: %s", GO_REPOSITORY_CONFIG_REPO_NAME, outputBase)
return "", nil
}

BazelLog.Infof("Found %s(s): %v", GO_REPOSITORY_CONFIG_REPO_NAME, goDepsRepoName)

return goDepsRepoName, nil
}

0 comments on commit 81fb19d

Please sign in to comment.