diff --git a/cmd/wire/main.go b/cmd/wire/main.go index fa37e51d..a6d7bfe0 100644 --- a/cmd/wire/main.go +++ b/cmd/wire/main.go @@ -101,6 +101,7 @@ type genCmd struct { headerFile string prefixFileName string tags string + mode string } func (*genCmd) Name() string { return "gen" } @@ -119,6 +120,7 @@ func (cmd *genCmd) SetFlags(f *flag.FlagSet) { f.StringVar(&cmd.headerFile, "header_file", "", "path to file to insert as a header in wire_gen.go") f.StringVar(&cmd.prefixFileName, "output_file_prefix", "", "string to prepend to output file names.") f.StringVar(&cmd.tags, "tags", "", "append build tags to the default wirebuild") + f.StringVar(&cmd.mode, "mod", "mod", "the build mode to use in the 'go run' command added to the generated header.") } func (cmd *genCmd) Execute(ctx context.Context, f *flag.FlagSet, args ...interface{}) subcommands.ExitStatus { @@ -135,6 +137,7 @@ func (cmd *genCmd) Execute(ctx context.Context, f *flag.FlagSet, args ...interfa opts.PrefixOutputFile = cmd.prefixFileName opts.Tags = cmd.tags + opts.Mode = cmd.mode outs, errs := wire.Generate(ctx, wd, os.Environ(), packages(f), opts) if len(errs) > 0 { diff --git a/internal/wire/testdata/ModeOverride/foo/foo.go b/internal/wire/testdata/ModeOverride/foo/foo.go new file mode 100644 index 00000000..67bc8a3e --- /dev/null +++ b/internal/wire/testdata/ModeOverride/foo/foo.go @@ -0,0 +1,29 @@ +// Copyright 2019 The Wire Authors +// +// 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(injectFoo()) +} + +type Foo int + +func provideFoo() Foo { + return 41 +} diff --git a/internal/wire/testdata/ModeOverride/foo/wire.go b/internal/wire/testdata/ModeOverride/foo/wire.go new file mode 100644 index 00000000..957f1770 --- /dev/null +++ b/internal/wire/testdata/ModeOverride/foo/wire.go @@ -0,0 +1,26 @@ +// Copyright 2019 The Wire Authors +// +// 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 ( + "github.com/google/wire" +) + +func injectFoo() Foo { + wire.Build(provideFoo) + return Foo(0) +} diff --git a/internal/wire/testdata/ModeOverride/mode b/internal/wire/testdata/ModeOverride/mode new file mode 100644 index 00000000..3b3ccd2f --- /dev/null +++ b/internal/wire/testdata/ModeOverride/mode @@ -0,0 +1 @@ +readonly diff --git a/internal/wire/testdata/ModeOverride/pkg b/internal/wire/testdata/ModeOverride/pkg new file mode 100644 index 00000000..f7a5c8ce --- /dev/null +++ b/internal/wire/testdata/ModeOverride/pkg @@ -0,0 +1 @@ +example.com/foo diff --git a/internal/wire/testdata/ModeOverride/want/program_out.txt b/internal/wire/testdata/ModeOverride/want/program_out.txt new file mode 100644 index 00000000..87523dd7 --- /dev/null +++ b/internal/wire/testdata/ModeOverride/want/program_out.txt @@ -0,0 +1 @@ +41 diff --git a/internal/wire/testdata/ModeOverride/want/wire_gen.go b/internal/wire/testdata/ModeOverride/want/wire_gen.go new file mode 100644 index 00000000..be173264 --- /dev/null +++ b/internal/wire/testdata/ModeOverride/want/wire_gen.go @@ -0,0 +1,14 @@ +// Code generated by Wire. DO NOT EDIT. + +//go:generate go run -mod=readonly github.com/google/wire/cmd/wire gen -mod=readonly +//go:build !wireinject +// +build !wireinject + +package main + +// Injectors from wire.go: + +func injectFoo() Foo { + foo := provideFoo() + return foo +} diff --git a/internal/wire/testdata/ModeUnset/foo/foo.go b/internal/wire/testdata/ModeUnset/foo/foo.go new file mode 100644 index 00000000..67bc8a3e --- /dev/null +++ b/internal/wire/testdata/ModeUnset/foo/foo.go @@ -0,0 +1,29 @@ +// Copyright 2019 The Wire Authors +// +// 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(injectFoo()) +} + +type Foo int + +func provideFoo() Foo { + return 41 +} diff --git a/internal/wire/testdata/ModeUnset/foo/wire.go b/internal/wire/testdata/ModeUnset/foo/wire.go new file mode 100644 index 00000000..957f1770 --- /dev/null +++ b/internal/wire/testdata/ModeUnset/foo/wire.go @@ -0,0 +1,26 @@ +// Copyright 2019 The Wire Authors +// +// 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 ( + "github.com/google/wire" +) + +func injectFoo() Foo { + wire.Build(provideFoo) + return Foo(0) +} diff --git a/internal/wire/testdata/ModeUnset/mode b/internal/wire/testdata/ModeUnset/mode new file mode 100644 index 00000000..4eb25b6e --- /dev/null +++ b/internal/wire/testdata/ModeUnset/mode @@ -0,0 +1 @@ +unset diff --git a/internal/wire/testdata/ModeUnset/pkg b/internal/wire/testdata/ModeUnset/pkg new file mode 100644 index 00000000..f7a5c8ce --- /dev/null +++ b/internal/wire/testdata/ModeUnset/pkg @@ -0,0 +1 @@ +example.com/foo diff --git a/internal/wire/testdata/ModeUnset/want/program_out.txt b/internal/wire/testdata/ModeUnset/want/program_out.txt new file mode 100644 index 00000000..87523dd7 --- /dev/null +++ b/internal/wire/testdata/ModeUnset/want/program_out.txt @@ -0,0 +1 @@ +41 diff --git a/internal/wire/testdata/ModeUnset/want/wire_gen.go b/internal/wire/testdata/ModeUnset/want/wire_gen.go new file mode 100644 index 00000000..2fc3e80a --- /dev/null +++ b/internal/wire/testdata/ModeUnset/want/wire_gen.go @@ -0,0 +1,14 @@ +// Code generated by Wire. DO NOT EDIT. + +//go:generate go run github.com/google/wire/cmd/wire gen -mod=unset +//go:build !wireinject +// +build !wireinject + +package main + +// Injectors from wire.go: + +func injectFoo() Foo { + foo := provideFoo() + return foo +} diff --git a/internal/wire/wire.go b/internal/wire/wire.go index 5cedeb1a..5e45f92e 100644 --- a/internal/wire/wire.go +++ b/internal/wire/wire.go @@ -66,6 +66,7 @@ type GenerateOptions struct { Header []byte PrefixOutputFile string Tags string + Mode string } // Generate performs dependency injection for the packages that match the given @@ -88,6 +89,10 @@ func Generate(ctx context.Context, wd string, env []string, patterns []string, o if len(errs) > 0 { return nil, errs } + validatedMode, err := validateMode(opts.Mode) + if err != nil { + return nil, []error{err} + } generated := make([]GenerateResult, len(pkgs)) for i, pkg := range pkgs { generated[i].PkgPath = pkg.PkgPath @@ -104,7 +109,7 @@ func Generate(ctx context.Context, wd string, env []string, patterns []string, o continue } copyNonInjectorDecls(g, injectorFiles, pkg.TypesInfo) - goSrc := g.frame(opts.Tags) + goSrc := g.frame(opts.Tags, validatedMode) if len(opts.Header) > 0 { goSrc = append(opts.Header, goSrc...) } @@ -134,6 +139,23 @@ func detectOutputDir(paths []string) (string, error) { return dir, nil } +// validateMode ensures that the value for mode is a value that can be expected by 'go build' +func validateMode(mode string) (string, error) { + // To maintain backwards compatibility, if mode is blank we can + // default to "mod" here for now + if mode == "" { + return "mod", nil + } + + // These are the modes defined by the 'mod' flag in + // https://pkg.go.dev/cmd/go#hdr-Compile_packages_and_dependencies + if mode != "unset" && mode != "mod" && mode != "vendor" && mode != "readonly" { + return "", fmt.Errorf("Invalid build mode: %s", mode) + } + + return mode, nil +} + // generateInjectors generates the injectors for a given package. func generateInjectors(g *gen, pkg *packages.Package) (injectorFiles []*ast.File, _ []error) { oc := newObjectCache([]*packages.Package{pkg}) @@ -258,16 +280,31 @@ func newGen(pkg *packages.Package) *gen { } // frame bakes the built up source body into an unformatted Go source file. -func (g *gen) frame(tags string) []byte { +func (g *gen) frame(tags, mode string) []byte { if g.buf.Len() == 0 { return nil } var buf bytes.Buffer + suffix := "" + if len(tags) > 0 || (len(mode) > 0 && mode != "mod") { + suffix = " gen" + } + + if len(mode) > 0 && mode != "mod" { + suffix += fmt.Sprintf(" -mod=%s", mode) + } + if len(tags) > 0 { - tags = fmt.Sprintf(" gen -tags \"%s\"", tags) + suffix += fmt.Sprintf(" -tags \"%s\"", tags) } + buf.WriteString("// Code generated by Wire. DO NOT EDIT.\n\n") - buf.WriteString("//go:generate go run -mod=mod github.com/google/wire/cmd/wire" + tags + "\n") + + if mode == "unset" { + buf.WriteString("//go:generate go run github.com/google/wire/cmd/wire" + suffix + "\n") + } else { + buf.WriteString("//go:generate go run -mod=" + mode + " github.com/google/wire/cmd/wire" + suffix + "\n") + } buf.WriteString("//+build !wireinject\n\n") buf.WriteString("package ") buf.WriteString(g.pkg.Name) diff --git a/internal/wire/wire_test.go b/internal/wire/wire_test.go index 6389ac6d..7f63bb0e 100644 --- a/internal/wire/wire_test.go +++ b/internal/wire/wire_test.go @@ -88,7 +88,7 @@ func TestWire(t *testing.T) { t.Fatal(err) } wd := filepath.Join(gopath, "src", "example.com") - gens, errs := Generate(ctx, wd, append(os.Environ(), "GOPATH="+gopath), []string{test.pkg}, &GenerateOptions{Header: test.header}) + gens, errs := Generate(ctx, wd, append(os.Environ(), "GOPATH="+gopath), []string{test.pkg}, &GenerateOptions{Header: test.header, Mode: test.mode}) var gen GenerateResult if len(gens) > 1 { t.Fatalf("got %d generated files, want 0 or 1", len(gens)) @@ -427,6 +427,7 @@ type testCase struct { name string pkg string header []byte + mode string goFiles map[string][]byte wantProgramOutput []byte wantWireOutput []byte @@ -470,6 +471,7 @@ func loadTestCase(root string, wireGoSrc []byte) (*testCase, error) { return nil, fmt.Errorf("load test case %s: %v", name, err) } header, _ := ioutil.ReadFile(filepath.Join(root, "header")) + mode, _ := ioutil.ReadFile(filepath.Join(root, "mode")) var wantProgramOutput []byte var wantWireOutput []byte wireErrb, err := ioutil.ReadFile(filepath.Join(root, "want", "wire_errs.txt")) @@ -521,6 +523,7 @@ func loadTestCase(root string, wireGoSrc []byte) (*testCase, error) { name: name, pkg: string(bytes.TrimSpace(pkg)), header: header, + mode: string(bytes.TrimSpace(mode)), goFiles: goFiles, wantWireOutput: wantWireOutput, wantProgramOutput: wantProgramOutput,