wire: handle build tags with relative paths correctly (google/go-cloud#188)

5cfd0141dd95acd1a98a1b7f6de5b8b304077634 worked correctly with
absolute import paths, but would fail with relative import paths
(most commonly when passing "." in the default invocation of
gowire). This commit introduces test infrastructure to allow
relative import paths to be given as test inputs, along with a test
case that addresses the regression.
This commit is contained in:
Ross Light
2018-07-11 09:21:23 -07:00
parent 0b7bb585fd
commit 777c1c4331
8 changed files with 122 additions and 13 deletions

View File

@@ -0,0 +1,23 @@
// Copyright 2018 Google LLC
//
// 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
//
// https://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.
//+build !wireinject
// Package bar includes both wireinject and non-wireinject variants.
package bar
import "github.com/google/go-cloud/wire"
// Set provides a friendly user greeting.
var Set = wire.NewSet(wire.Value("Hello, World!"))

View File

@@ -0,0 +1,22 @@
// Copyright 2018 Google LLC
//
// 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
//
// https://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.
//+build wireinject
package bar
import "github.com/google/go-cloud/wire"
// Set provides an unfriendly user greeting.
var Set = wire.NewSet(wire.Value("Bah humbug! This is the wrong variant!"))

View File

@@ -0,0 +1,21 @@
// Copyright 2018 Google LLC
//
// 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
//
// https://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"
func main() {
fmt.Println(injectedMessage())
}

View File

@@ -0,0 +1,28 @@
// Copyright 2018 Google LLC
//
// 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
//
// https://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.
//+build wireinject
package main
import (
"bar"
"github.com/google/go-cloud/wire"
)
func injectedMessage() string {
wire.Build(bar.Set)
return ""
}

View File

@@ -0,0 +1 @@
Hello, World!

View File

@@ -0,0 +1 @@
./foo

View File

@@ -51,18 +51,21 @@ func Generate(bctx *build.Context, wd string, pkg string) ([]byte, []error) {
return path == mainPkg.ImportPath return path == mainPkg.ImportPath
}, },
FindPackage: func(bctx *build.Context, importPath, fromDir string, mode build.ImportMode) (*build.Package, error) { FindPackage: func(bctx *build.Context, importPath, fromDir string, mode build.ImportMode) (*build.Package, error) {
if importPath == mainPkg.ImportPath { // Optimistically try to load in the package with normal build tags.
// Load in the generated package with the wireinject build tag pkg, err := bctx.Import(importPath, fromDir, mode)
// to pick up the injector template. The imported packages
// should be imported as normal. Since the *build.Context is // If this is the generated package, then load it in with the
// shared between calls to FindPackage, this uses a copy. // wireinject build tag to pick up the injector template. Since
// the *build.Context is shared between calls to FindPackage, this
// uses a copy.
if pkg != nil && pkg.ImportPath == mainPkg.ImportPath {
bctx2 := new(build.Context) bctx2 := new(build.Context)
*bctx2 = *bctx *bctx2 = *bctx
n := len(bctx2.BuildTags) n := len(bctx2.BuildTags)
bctx2.BuildTags = append(bctx2.BuildTags[:n:n], "wireinject") bctx2.BuildTags = append(bctx2.BuildTags[:n:n], "wireinject")
bctx = bctx2 pkg, err = bctx2.Import(importPath, fromDir, mode)
} }
return bctx.Import(importPath, fromDir, mode) return pkg, err
}, },
} }
conf.Import(pkg) conf.Import(pkg)

View File

@@ -34,10 +34,6 @@ import (
) )
func TestWire(t *testing.T) { func TestWire(t *testing.T) {
wd, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
const testRoot = "testdata" const testRoot = "testdata"
testdataEnts, err := ioutil.ReadDir(testRoot) // ReadDir sorts by name. testdataEnts, err := ioutil.ReadDir(testRoot) // ReadDir sorts by name.
if err != nil { if err != nil {
@@ -61,6 +57,7 @@ func TestWire(t *testing.T) {
} }
tests = append(tests, test) tests = append(tests, test)
} }
wd := filepath.Join(magicGOPATH(), "src")
t.Run("Generate", func(t *testing.T) { t.Run("Generate", func(t *testing.T) {
if _, err := os.Stat(filepath.Join(build.Default.GOROOT, "bin", "go")); err != nil { if _, err := os.Stat(filepath.Join(build.Default.GOROOT, "bin", "go")); err != nil {
@@ -70,6 +67,8 @@ func TestWire(t *testing.T) {
test := test test := test
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
t.Parallel() t.Parallel()
// Run gowire from a fake build context.
bctx := test.buildContext() bctx := test.buildContext()
gen, errs := Generate(bctx, wd, test.pkg) gen, errs := Generate(bctx, wd, test.pkg)
if len(gen) > 0 { if len(gen) > 0 {
@@ -93,6 +92,14 @@ func TestWire(t *testing.T) {
t.Fatal("wirego succeeded; want error") t.Fatal("wirego succeeded; want error")
} }
// Find the absolute import path, since test.pkg may be a relative
// import path.
genPkg, err := bctx.Import(test.pkg, wd, build.FindOnly)
if err != nil {
t.Fatal(err)
}
// Run a `go build` with the generated output.
gopath, err := ioutil.TempDir("", "wire_test") gopath, err := ioutil.TempDir("", "wire_test")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@@ -102,7 +109,7 @@ func TestWire(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
if len(gen) > 0 { if len(gen) > 0 {
genPath := filepath.Join(gopath, "src", filepath.FromSlash(test.pkg), "wire_gen.go") genPath := filepath.Join(gopath, "src", filepath.FromSlash(genPkg.ImportPath), "wire_gen.go")
if err := ioutil.WriteFile(genPath, gen, 0666); err != nil { if err := ioutil.WriteFile(genPath, gen, 0666); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -118,9 +125,12 @@ func TestWire(t *testing.T) {
BuildTags: bctx.BuildTags, BuildTags: bctx.BuildTags,
ReleaseTags: bctx.ReleaseTags, ReleaseTags: bctx.ReleaseTags,
} }
if err := runGo(realBuildCtx, "build", "-o", testExePath, test.pkg); err != nil { if err := runGo(realBuildCtx, "build", "-o", testExePath, genPkg.ImportPath); err != nil {
t.Fatal("build:", err) t.Fatal("build:", err)
} }
// Run the resulting program and compare its output to the expected
// output.
out, err := exec.Command(testExePath).Output() out, err := exec.Command(testExePath).Output()
if err != nil { if err != nil {
t.Error("run compiled program:", err) t.Error("run compiled program:", err)