Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix gopackagesdriver for Go 1.18 by replicating stdlib and add test for stdliblist.go #3153

Closed
wants to merge 10 commits into from

Conversation

xytan0056
Copy link
Contributor

What type of PR is this?

This PR addresses comments for #3083

What does this PR do? Why is it needed?
It fixes go list invocations from bazel for go1.18, where std library uses go:embed
see #3083

Which issues(s) does this PR fix?

Fixes #3080

Other notes for review
updated the patch in our repo with this patch

  1. verified that the targets that failed without the patch can build successfully
  2. verified a rebuild of all our repo behaved as expected

abhinav and others added 6 commits May 11, 2022 23:47
The stdliblist operation that the gopackagesdriver relies on fails on
Go 1.18rc1 with the following error:

```
external/go_sdk/src/crypto/elliptic/p256_asm.go:24:12: pattern p256_asm_table.bin: cannot embed irregular file p256_asm_table.bin
```

We see this failure because Bazel builds a symlink tree of the GOROOT run
`go list` with. However, since [CL 380475][1], the Go standard library uses
`go:embed` to embed a file in `crypto/elliptic`, but `go:embed` does not
support symlinks.

[1]: https://go.dev/cl/380475

Fix this by having stdliblist copy the relevant portions of the GOROOT to
run `go list` with. This matches [what the stdlib action does][2].

[2]: https://github.com/bazelbuild/rules_go/blob/e9a7054ff11a520e3b8aceb76a3ba44bb8da4c94/go/tools/builders/stdlib.go#L54-L57

Resolves bazel-contrib#3080
Add a dependency on `GoStdLib._list_json` to the stdlib test.
This ensures that we can successfully build the JSON data needed by the
gopackagesdriver.
The prior version of this fix was incomplete because it generated
incorrect relative paths.

For example, before a path would be:

    __BAZEL_OUTPUT_BASE__/external/go_sdk/src/archive/tar/common.go

But with the prior version of this change.

    __BAZEL_OUTPUT_BASE__/src/archive/tar/common.go

It would drop the external/go_sdk from the path because the flattening
logic in stdliblist makes these relative to the execRoot.

We cannot overwrite external/go_sdk in execRoot because that's a path
controlled by Bazel.

Instead, create a parallel external/go_sdk under a new directory "root",
and flatten paths relative to that.
recover tests/core/stdlib/stdlib_files.bzl
@xytan0056 xytan0056 force-pushed the tanx/stdliblist branch 5 times, most recently from 4a99e93 to 32b5803 Compare May 13, 2022 23:24
@xytan0056 xytan0056 changed the title tanx/stdliblist Fix gopackagesdriver for Go 1.18 by replicating stdlib and add test for stdliblist.go May 13, 2022
@linzhp linzhp self-assigned this May 14, 2022
return "", err
}

if err := replicate(goroot, newGoRoot, replicatePaths("src", "pkg/tool", "pkg/include")); err != nil {
Copy link
Contributor Author

@xytan0056 xytan0056 May 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"pkg/tool" is needed because go list would fail without it

Use --sandbox_debug to see verbose messages from the sandbox
go: no such tool "compile"
go: no such tool "compile"
go: no such tool "compile"
go: no such tool "compile"
go: no such tool "compile"
stdliblist: error running subcommand external/go_sdk/bin/go: exit status 2

maybe because the subcommand tool list needs non-empty ToolDir, which is expected to be at pkg/tool

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good finding. Yes, go list needs to call compile. Can you add comments to explain this finding?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


func Test_stdliblist(t *testing.T) {
testDir := t.TempDir()
f, _ := ioutil.TempFile(testDir, "*")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to create a temp file in a temp dir. outJSON = filepath.Join(testDir, "out.json") should be enough

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}
test_args := []string{
fmt.Sprintf("-out=%s", f.Name()),
fmt.Sprintf("-sdk=%s", "go_sdk"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you pass the absolute path to go_sdk here? It should be available in $TEST_SRCDIR/external/go_sdk. With the absolute path, you don't need to pass -wd, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-sdk passed by go.sdk.root_file.dirname in stdlib.bzl, which is a relative path. See below comment

Comment on lines 21 to 22
// since -sdk is assumed to be a relative path to execRoot
// (go.sdk.root_file.dirname), thus setting wd to
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can make-sdk to take either relative path to current directory (execRoot in bazel action) or an absolute path?

Copy link
Contributor Author

@xytan0056 xytan0056 May 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-sdk is passed as relative path in stdlib.bazl, and stdliblist.go has this assumption too.
Also it looks like we can't get absolute path easily #1273

https://github.com/xytan0056/rules_go/blob/8b0dde29fb0dd2a7a7b35d6e06a43093f8716bc2/go/private/actions/stdlib.bzl#L55-L58

I also tried go.root, which is also a relative path
image

Copy link
Contributor Author

@xytan0056 xytan0056 May 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually -sdk needs to be a relative path, because during cloning, I'd prefer to retain the same relative path of the original go_sdk, i.e. /old/root/rel_go_sdk/src/package -> /new/root/rel_go_sdk/src/package

It cannot be an absolute path, because if so, the only way to get rel_go_sdk from goroot is filepath.Rel(".", env.go_sdk), but this doesn't work for tests:
consider the following test file structure

/a/b/c/runfiles
/a/b/c/runfiles/go_sdk <- data files
/a/b/c/runfiles/workspace <- where test is run with rundir being "." in go_test rule

the relative path of go_sdk is ../go_sdk;
Let's make cloneBase := /tmp/123;
Then in order to retain the same relative path ,newGoRoot becomes /tmp/123/../go_sdk, which is /tmp/go_sdk;
Then go list under newGoRoot returns pkg.Dir being /tmp/go_sdk/src/package, which does not share a prefix with cloneBase and thus cannot be replaced with __BAZEL_OUTBASE_LABEL__

func labelledPath(cloneBase, p string) string {
        // ../go_sdk/src/package 
	dir, _ := filepath.Rel(cloneBase, p) 

        // __BAZEL_OUTPUT_BASE__/../go_sdk/src/package => go_sdk/src/package (wrong)
	return filepath.Join("__BAZEL_OUTPUT_BASE__", dir)  
}

The culprit here is .. in the relative path. Instead of maniplulating the path, a simple way is to set rundir=".." in the go_test rule, so that all assumptions naturally fall into places.

Another finding is the relative path has to be external/go_sdk, matching the original, otherwise our internal targets will fail. This is a perfect indicator to use goenv.sdk as relative path.

However if I take "absolute path" approach with hardcoded "external/go_sdk" #3157, it fails reproducibility test.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just cloning from /old/root/external/go_sdk to /new/root/external/go_sdk?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never mind. xytan0056#1

# -sdk in stdliblist needs to be a relative path, otherwise it breaks
# assumptions of cloning go_sdk, thus we need to set up the test in a
# way that go_sdk is under the directory where test is run.
rundir = "..",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is an easy way to avoid having to break assumption of go_sdk to be absolute path.
by setting it this way, the structure will become

/a/b/c/runfiles/   <- this will be where the test is run with rundir being ..
    go_sdk         <- this will be where the data files are
    workspace      <- this will be where the test is run with rundir being . 

then naturally go_sdk is the relative path.

@xytan0056
Copy link
Contributor Author

xytan0056 commented May 18, 2022

close in favor of #3157

@xytan0056 xytan0056 closed this May 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Go package driver doesn't work with Go 1.18
3 participants