goose: use marker functions instead of comments
To avoid making this CL too large, I did not migrate the existing goose comments through the repository. This will be addressed in a subsequent CL. Reviewed-by: Tuo Shan <shantuo@google.com>
This commit is contained in:
113
README.md
113
README.md
@@ -13,34 +13,27 @@ might have hand-written.
|
||||
### Defining Providers
|
||||
|
||||
The primary mechanism in goose is the **provider**: a function that can
|
||||
produce a value, annotated with the special `goose:provide` directive. These
|
||||
functions are otherwise ordinary Go code.
|
||||
produce a value. These functions are ordinary Go code.
|
||||
|
||||
```go
|
||||
package foobarbaz
|
||||
|
||||
type Foo int
|
||||
|
||||
// goose:provide
|
||||
|
||||
// ProvideFoo returns a Foo.
|
||||
func ProvideFoo() Foo {
|
||||
return 42
|
||||
}
|
||||
```
|
||||
|
||||
Providers are always part of a **provider set**: if there is no provider set
|
||||
named on the `//goose:provide` line, then the provider is added to the provider
|
||||
set with the same name as the function (`ProvideFoo`, in this case).
|
||||
|
||||
Providers can specify dependencies with parameters:
|
||||
|
||||
```go
|
||||
package foobarbaz
|
||||
|
||||
type Bar int
|
||||
// ...
|
||||
|
||||
// goose:provide SuperSet
|
||||
type Bar int
|
||||
|
||||
// ProvideBar returns a Bar: a negative Foo.
|
||||
func ProvideBar(foo Foo) Bar {
|
||||
@@ -58,9 +51,9 @@ import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
type Baz int
|
||||
// ...
|
||||
|
||||
// goose:provide SuperSet
|
||||
type Baz int
|
||||
|
||||
// ProvideBaz returns a value if Bar is not zero.
|
||||
func ProvideBaz(ctx context.Context, bar Bar) (Baz, error) {
|
||||
@@ -71,23 +64,36 @@ func ProvideBaz(ctx context.Context, bar Bar) (Baz, error) {
|
||||
}
|
||||
```
|
||||
|
||||
Provider sets can import other provider sets. To add the `ProvideFoo` set to
|
||||
`SuperSet`:
|
||||
Providers can be grouped in **provider sets**. To add these providers to a new
|
||||
set called `SuperSet`, use the `goose.NewSet` function:
|
||||
|
||||
```go
|
||||
// goose:import SuperSet ProvideFoo
|
||||
package foobarbaz
|
||||
|
||||
import (
|
||||
// ...
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
// ...
|
||||
|
||||
var SuperSet = goose.NewSet(ProvideFoo, ProvideBar, ProvideBaz)
|
||||
```
|
||||
|
||||
You can also import provider sets in another package, provided that you have a
|
||||
Go import for the package:
|
||||
You can also add other provider sets into a provider set.
|
||||
|
||||
```go
|
||||
// goose:import SuperSet "example.com/some/other/pkg".OtherSet
|
||||
```
|
||||
package foobarbaz
|
||||
|
||||
A provider set reference is an optional import qualifier (either a package name
|
||||
or a quoted import path, as seen above) ending with a dot, followed by the
|
||||
provider set name.
|
||||
import (
|
||||
// ...
|
||||
"example.com/some/other/pkg"
|
||||
)
|
||||
|
||||
// ...
|
||||
|
||||
var MegaSet = goose.NewSet(SuperSet, pkg.OtherSet)
|
||||
```
|
||||
|
||||
### Injectors
|
||||
|
||||
@@ -95,32 +101,34 @@ An application wires up these providers with an **injector**: a function that
|
||||
calls providers in dependency order. With goose, you write the injector's
|
||||
signature, then goose generates the function's body.
|
||||
|
||||
An injector is declared by writing a function declaration without a body in a
|
||||
file guarded by a `gooseinject` build tag. Let's say that the above providers
|
||||
were defined in a package called `example.com/foobarbaz`. The following would
|
||||
declare an injector to obtain a `Baz`:
|
||||
An injector is declared by writing a function declaration whose body is a call
|
||||
to `panic()` with a call to `goose.Use` as its argument. Let's say that the
|
||||
above providers were defined in a package called `example.com/foobarbaz`. The
|
||||
following would declare an injector to obtain a `Baz`:
|
||||
|
||||
```go
|
||||
//+build gooseinject
|
||||
// +build gooseinject
|
||||
|
||||
// ^ build tag makes sure the stub is not built in the final build
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"codename/goose"
|
||||
"example.com/foobarbaz"
|
||||
)
|
||||
|
||||
// goose:use foobarbaz.SuperSet
|
||||
|
||||
func initializeApp(ctx context.Context) (foobarbaz.Baz, error)
|
||||
func initializeApp(ctx context.Context) (foobarbaz.Baz, error) {
|
||||
panic(goose.Use(foobarbaz.MegaSet))
|
||||
}
|
||||
```
|
||||
|
||||
Like providers, injectors can be parameterized on inputs (which then get sent to
|
||||
providers) and can return errors. Each `goose:use` directive specifies a
|
||||
provider set to use in the injection. An injector can have one or more
|
||||
`goose:use` directives. `goose:use` directives use the same syntax as
|
||||
`goose:import` to reference provider sets.
|
||||
providers) and can return errors. Arguments to `goose.Use` are the same as
|
||||
`goose.NewSet`: they form a provider set. This is the provider set that gets
|
||||
used during code generation for that injector.
|
||||
|
||||
You can generate the injector by invoking goose in the package directory:
|
||||
|
||||
@@ -164,7 +172,7 @@ func initializeApp(ctx context.Context) (foobarbaz.Baz, error) {
|
||||
```
|
||||
|
||||
As you can see, the output is very close to what a developer would write
|
||||
themselves. Further, there is no dependency on goose at runtime: all of the
|
||||
themselves. Further, there is little dependency on goose at runtime: all of the
|
||||
written code is just normal Go code, and can be used without goose.
|
||||
|
||||
[`go generate`]: https://blog.golang.org/generate
|
||||
@@ -228,19 +236,21 @@ func (b *Bar) Foo() string {
|
||||
return string(*b)
|
||||
}
|
||||
|
||||
//goose:provide BarFooer
|
||||
func provideBar() *Bar {
|
||||
func ProvideBar() *Bar {
|
||||
b := new(Bar)
|
||||
*b = "Hello, World!"
|
||||
return b
|
||||
}
|
||||
|
||||
//goose:bind BarFooer Fooer *Bar
|
||||
var BarFooer = goose.NewSet(
|
||||
ProvideBar,
|
||||
goose.Bind(Fooer(nil), (*Bar)(nil)))
|
||||
```
|
||||
|
||||
The syntax is provider set name, interface type, and finally the concrete type.
|
||||
An interface binding does not necessarily need to have a provider in the same
|
||||
set that provides the concrete type.
|
||||
The first argument to `goose.Bind` is a nil value for the interface type and the
|
||||
second argument is a zero value of the concrete type. An interface binding does
|
||||
not necessarily need to have a provider in the same set that provides the
|
||||
concrete type.
|
||||
|
||||
[type identity]: https://golang.org/ref/spec#Type_identity
|
||||
[return concrete types]: https://github.com/golang/go/wiki/CodeReviewComments#interfaces
|
||||
@@ -256,32 +266,31 @@ following providers:
|
||||
type Foo int
|
||||
type Bar int
|
||||
|
||||
//goose:provide Foo
|
||||
|
||||
func provideFoo() Foo {
|
||||
func ProvideFoo() Foo {
|
||||
// ...
|
||||
}
|
||||
|
||||
//goose:provide Bar
|
||||
|
||||
func provideBar() Bar {
|
||||
func ProvideBar() Bar {
|
||||
// ...
|
||||
}
|
||||
|
||||
//goose:provide
|
||||
|
||||
type FooBar struct {
|
||||
Foo Foo
|
||||
Bar Bar
|
||||
}
|
||||
|
||||
var Set = goose.NewSet(
|
||||
ProvideFoo,
|
||||
ProvideBar,
|
||||
FooBar{})
|
||||
```
|
||||
|
||||
A generated injector for `FooBar` would look like this:
|
||||
|
||||
```go
|
||||
func injectFooBar() FooBar {
|
||||
foo := provideFoo()
|
||||
bar := provideBar()
|
||||
foo := ProvideFoo()
|
||||
bar := ProvideBar()
|
||||
fooBar := FooBar{
|
||||
Foo: foo,
|
||||
Bar: bar,
|
||||
@@ -300,8 +309,6 @@ this to either return an aggregated cleanup function to the caller or to clean
|
||||
up the resource if a later provider returns an error.
|
||||
|
||||
```go
|
||||
//goose:provide
|
||||
|
||||
func provideFile(log Logger, path Path) (*os.File, func(), error) {
|
||||
f, err := os.Open(string(path))
|
||||
if err != nil {
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"codename/goose/internal/goose"
|
||||
@@ -71,9 +72,9 @@ func generate(pkg string) error {
|
||||
|
||||
// show runs the show subcommand.
|
||||
//
|
||||
// Given one or more packages, show will find all the declared provider
|
||||
// sets and print what other provider sets it imports and what outputs
|
||||
// it can produce, given possible inputs.
|
||||
// Given one or more packages, show will find all the provider sets
|
||||
// declared as top-level variables and print what other provider sets it
|
||||
// imports and what outputs it can produce, given possible inputs.
|
||||
func show(pkgs ...string) error {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
@@ -89,11 +90,12 @@ func show(pkgs ...string) error {
|
||||
}
|
||||
sort.Slice(keys, func(i, j int) bool {
|
||||
if keys[i].ImportPath == keys[j].ImportPath {
|
||||
return keys[i].Name < keys[j].Name
|
||||
return keys[i].VarName < keys[j].VarName
|
||||
}
|
||||
return keys[i].ImportPath < keys[j].ImportPath
|
||||
})
|
||||
// ANSI color codes.
|
||||
// TODO(light): Possibly use github.com/fatih/color?
|
||||
const (
|
||||
reset = "\x1b[0m"
|
||||
redBold = "\x1b[0;1;31m"
|
||||
@@ -116,7 +118,7 @@ func show(pkgs ...string) error {
|
||||
switch v := v.(type) {
|
||||
case *goose.Provider:
|
||||
out[types.TypeString(t, nil)] = v.Pos
|
||||
case goose.IfaceBinding:
|
||||
case *goose.IfaceBinding:
|
||||
out[types.TypeString(t, nil)] = v.Pos
|
||||
default:
|
||||
panic("unreachable")
|
||||
@@ -134,19 +136,19 @@ func show(pkgs ...string) error {
|
||||
type outGroup struct {
|
||||
name string
|
||||
inputs *typeutil.Map // values are not important
|
||||
outputs *typeutil.Map // values are either *goose.Provider or goose.IfaceBinding
|
||||
outputs *typeutil.Map // values are either *goose.Provider or *goose.IfaceBinding
|
||||
}
|
||||
|
||||
// gather flattens a provider set into outputs grouped by the inputs
|
||||
// required to create them. As it flattens the provider set, it records
|
||||
// the visited provider sets as imports.
|
||||
// the visited named provider sets as imports.
|
||||
func gather(info *goose.Info, key goose.ProviderSetID) (_ []outGroup, imports map[string]struct{}) {
|
||||
hash := typeutil.MakeHasher()
|
||||
// Map types to providers and bindings.
|
||||
pm := new(typeutil.Map)
|
||||
pm.SetHasher(hash)
|
||||
next := []goose.ProviderSetID{key}
|
||||
visited := make(map[goose.ProviderSetID]struct{})
|
||||
next := []*goose.ProviderSet{info.Sets[key]}
|
||||
visited := make(map[*goose.ProviderSet]struct{})
|
||||
imports = make(map[string]struct{})
|
||||
for len(next) > 0 {
|
||||
curr := next[len(next)-1]
|
||||
@@ -155,18 +157,17 @@ func gather(info *goose.Info, key goose.ProviderSetID) (_ []outGroup, imports ma
|
||||
continue
|
||||
}
|
||||
visited[curr] = struct{}{}
|
||||
if curr != key {
|
||||
imports[curr.String()] = struct{}{}
|
||||
if curr.Name != "" && !(curr.PkgPath == key.ImportPath && curr.Name == key.VarName) {
|
||||
imports[formatProviderSetName(curr.PkgPath, curr.Name)] = struct{}{}
|
||||
}
|
||||
set := info.All[curr]
|
||||
for _, p := range set.Providers {
|
||||
for _, p := range curr.Providers {
|
||||
pm.Set(p.Out, p)
|
||||
}
|
||||
for _, b := range set.Bindings {
|
||||
for _, b := range curr.Bindings {
|
||||
pm.Set(b.Iface, b)
|
||||
}
|
||||
for _, imp := range set.Imports {
|
||||
next = append(next, imp.ProviderSetID)
|
||||
for _, imp := range curr.Imports {
|
||||
next = append(next, imp)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +239,7 @@ func gather(info *goose.Info, key goose.ProviderSetID) (_ []outGroup, imports ma
|
||||
inputs: in,
|
||||
outputs: out,
|
||||
})
|
||||
case goose.IfaceBinding:
|
||||
case *goose.IfaceBinding:
|
||||
i, ok := inputVisited.At(p.Provided).(int)
|
||||
if !ok {
|
||||
stk = append(stk, curr, p.Provided)
|
||||
@@ -327,3 +328,8 @@ func sortSet(set interface{}) []string {
|
||||
sort.Strings(a)
|
||||
return a
|
||||
}
|
||||
|
||||
func formatProviderSetName(importPath, varName string) string {
|
||||
// Since varName is an identifier, it doesn't make sense to quote.
|
||||
return strconv.Quote(importPath) + "." + varName
|
||||
}
|
||||
38
goose.go
Normal file
38
goose.go
Normal file
@@ -0,0 +1,38 @@
|
||||
// Package goose contains directives for goose code generation.
|
||||
package goose
|
||||
|
||||
// ProviderSet is a marker type that collects a group of providers.
|
||||
type ProviderSet struct{}
|
||||
|
||||
// NewSet creates a new provider set that includes the providers in
|
||||
// its arguments. Each argument is either an exported function value,
|
||||
// an exported struct (zero) value, or a call to Bind.
|
||||
func NewSet(...interface{}) ProviderSet {
|
||||
return ProviderSet{}
|
||||
}
|
||||
|
||||
// Use is placed in the body of an injector function to declare the
|
||||
// providers to use. Its arguments are the same as NewSet. Its return
|
||||
// value is an error message that can be sent to panic.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// func injector(ctx context.Context) (*sql.DB, error) {
|
||||
// panic(Use(otherpkg.Foo, myProviderFunc, goose.Bind()))
|
||||
// }
|
||||
func Use(...interface{}) string {
|
||||
return "implementation not generated, run goose"
|
||||
}
|
||||
|
||||
// A Binding maps an interface to a concrete type.
|
||||
type Binding struct{}
|
||||
|
||||
// Bind declares that a concrete type should be used to satisfy a
|
||||
// dependency on iface.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// var MySet = goose.NewSet(goose.Bind(MyInterface(nil), new(MyStruct)))
|
||||
func Bind(iface, to interface{}) Binding {
|
||||
return Binding{}
|
||||
}
|
||||
@@ -42,7 +42,7 @@ type call struct {
|
||||
|
||||
// solve finds the sequence of calls required to produce an output type
|
||||
// with an optional set of provided inputs.
|
||||
func solve(mc *providerSetCache, out types.Type, given []types.Type, sets []symref) ([]call, error) {
|
||||
func solve(fset *token.FileSet, out types.Type, given []types.Type, set *ProviderSet) ([]call, error) {
|
||||
for i, g := range given {
|
||||
for _, h := range given[:i] {
|
||||
if types.Identical(g, h) {
|
||||
@@ -50,7 +50,7 @@ func solve(mc *providerSetCache, out types.Type, given []types.Type, sets []symr
|
||||
}
|
||||
}
|
||||
}
|
||||
providers, err := buildProviderMap(mc, sets)
|
||||
providers, err := buildProviderMap(fset, set)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -61,7 +61,7 @@ func solve(mc *providerSetCache, out types.Type, given []types.Type, sets []symr
|
||||
for i, g := range given {
|
||||
if p := providers.At(g); p != nil {
|
||||
pp := p.(*Provider)
|
||||
return nil, fmt.Errorf("input of %s conflicts with provider %s at %s", types.TypeString(g, nil), pp.Name, mc.fset.Position(pp.Pos))
|
||||
return nil, fmt.Errorf("input of %s conflicts with provider %s at %s", types.TypeString(g, nil), pp.Name, fset.Position(pp.Pos))
|
||||
}
|
||||
index.Set(g, i)
|
||||
}
|
||||
@@ -135,88 +135,70 @@ func solve(mc *providerSetCache, out types.Type, given []types.Type, sets []symr
|
||||
return calls, nil
|
||||
}
|
||||
|
||||
func buildProviderMap(mc *providerSetCache, sets []symref) (*typeutil.Map, error) {
|
||||
type nextEnt struct {
|
||||
to symref
|
||||
|
||||
from symref
|
||||
pos token.Pos
|
||||
}
|
||||
func buildProviderMap(fset *token.FileSet, set *ProviderSet) (*typeutil.Map, error) {
|
||||
type binding struct {
|
||||
IfaceBinding
|
||||
pset symref
|
||||
from symref
|
||||
*IfaceBinding
|
||||
set *ProviderSet
|
||||
}
|
||||
|
||||
pm := new(typeutil.Map) // to *providerInfo
|
||||
providerMap := new(typeutil.Map) // to *Provider
|
||||
setMap := new(typeutil.Map) // to *ProviderSet, for error messages
|
||||
var bindings []binding
|
||||
visited := make(map[symref]struct{})
|
||||
var next []nextEnt
|
||||
for _, ref := range sets {
|
||||
next = append(next, nextEnt{to: ref})
|
||||
}
|
||||
visited := make(map[*ProviderSet]struct{})
|
||||
next := []*ProviderSet{set}
|
||||
for len(next) > 0 {
|
||||
curr := next[0]
|
||||
copy(next, next[1:])
|
||||
next = next[:len(next)-1]
|
||||
if _, skip := visited[curr.to]; skip {
|
||||
if _, skip := visited[curr]; skip {
|
||||
continue
|
||||
}
|
||||
visited[curr.to] = struct{}{}
|
||||
pset, err := mc.get(curr.to)
|
||||
if err != nil {
|
||||
if !curr.pos.IsValid() {
|
||||
return nil, err
|
||||
visited[curr] = struct{}{}
|
||||
for _, p := range curr.Providers {
|
||||
if providerMap.At(p.Out) != nil {
|
||||
return nil, bindingConflictError(fset, p.Pos, p.Out, setMap.At(p.Out).(*ProviderSet))
|
||||
}
|
||||
return nil, fmt.Errorf("%v: %v", mc.fset.Position(curr.pos), err)
|
||||
providerMap.Set(p.Out, p)
|
||||
setMap.Set(p.Out, curr)
|
||||
}
|
||||
for _, p := range pset.Providers {
|
||||
if prev := pm.At(p.Out); prev != nil {
|
||||
pos := mc.fset.Position(p.Pos)
|
||||
typ := types.TypeString(p.Out, nil)
|
||||
prevPos := mc.fset.Position(prev.(*Provider).Pos)
|
||||
if curr.from.importPath == "" {
|
||||
// Provider set is imported directly by injector.
|
||||
return nil, fmt.Errorf("%v: multiple bindings for %s (added by injector, previous binding at %v)", pos, typ, prevPos)
|
||||
}
|
||||
return nil, fmt.Errorf("%v: multiple bindings for %s (imported by %v, previous binding at %v)", pos, typ, curr.from, prevPos)
|
||||
}
|
||||
pm.Set(p.Out, p)
|
||||
}
|
||||
for _, b := range pset.Bindings {
|
||||
for _, b := range curr.Bindings {
|
||||
bindings = append(bindings, binding{
|
||||
IfaceBinding: b,
|
||||
pset: curr.to,
|
||||
from: curr.from,
|
||||
set: curr,
|
||||
})
|
||||
}
|
||||
for _, imp := range pset.Imports {
|
||||
next = append(next, nextEnt{to: imp.symref(), from: curr.to, pos: imp.Pos})
|
||||
for _, imp := range curr.Imports {
|
||||
next = append(next, imp)
|
||||
}
|
||||
}
|
||||
// Validate that bindings have their concrete type provided in the set.
|
||||
// TODO(light): Move this validation up into provider set creation.
|
||||
for _, b := range bindings {
|
||||
if prev := pm.At(b.Iface); prev != nil {
|
||||
pos := mc.fset.Position(b.Pos)
|
||||
typ := types.TypeString(b.Iface, nil)
|
||||
// TODO(light): Error message for conflicting with another interface binding will point at provider instead of binding.
|
||||
prevPos := mc.fset.Position(prev.(*Provider).Pos)
|
||||
if b.from.importPath == "" {
|
||||
// Provider set is imported directly by injector.
|
||||
return nil, fmt.Errorf("%v: multiple bindings for %s (added by injector, previous binding at %v)", pos, typ, prevPos)
|
||||
}
|
||||
return nil, fmt.Errorf("%v: multiple bindings for %s (imported by %v, previous binding at %v)", pos, typ, b.from, prevPos)
|
||||
if providerMap.At(b.Iface) != nil {
|
||||
return nil, bindingConflictError(fset, b.Pos, b.Iface, setMap.At(b.Iface).(*ProviderSet))
|
||||
}
|
||||
concrete := pm.At(b.Provided)
|
||||
concrete := providerMap.At(b.Provided)
|
||||
if concrete == nil {
|
||||
pos := mc.fset.Position(b.Pos)
|
||||
pos := fset.Position(b.Pos)
|
||||
typ := types.TypeString(b.Provided, nil)
|
||||
if b.from.importPath == "" {
|
||||
// Concrete provider is imported directly by injector.
|
||||
return nil, fmt.Errorf("%v: no binding for %s", pos, typ)
|
||||
}
|
||||
return nil, fmt.Errorf("%v: no binding for %s (imported by %v)", pos, typ, b.from)
|
||||
return nil, fmt.Errorf("%v: no binding for %s", pos, typ)
|
||||
}
|
||||
pm.Set(b.Iface, concrete)
|
||||
providerMap.Set(b.Iface, concrete)
|
||||
setMap.Set(b.Iface, b.set)
|
||||
}
|
||||
return pm, nil
|
||||
return providerMap, nil
|
||||
}
|
||||
|
||||
// bindingConflictError creates a new error describing multiple bindings
|
||||
// for the same output type.
|
||||
func bindingConflictError(fset *token.FileSet, pos token.Pos, typ types.Type, prevSet *ProviderSet) error {
|
||||
position := fset.Position(pos)
|
||||
typString := types.TypeString(typ, nil)
|
||||
if prevSet.Name == "" {
|
||||
prevPosition := fset.Position(prevSet.Pos)
|
||||
return fmt.Errorf("%v: multiple bindings for %s (previous binding at %v)",
|
||||
position, typString, prevPosition)
|
||||
}
|
||||
return fmt.Errorf("%v: multiple bindings for %s (previous binding in %q.%s)",
|
||||
position, typString, prevSet.PkgPath, prevSet.Name)
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/format"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"sort"
|
||||
"strconv"
|
||||
@@ -22,8 +22,24 @@ import (
|
||||
// Generate performs dependency injection for a single package,
|
||||
// returning the gofmt'd Go source code.
|
||||
func Generate(bctx *build.Context, wd string, pkg string) ([]byte, error) {
|
||||
conf := newLoaderConfig(bctx, wd, true)
|
||||
mainPkg, err := bctx.Import(pkg, wd, build.FindOnly)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load: %v", err)
|
||||
}
|
||||
// TODO(light): Stop errors from printing to stderr.
|
||||
conf := &loader.Config{
|
||||
Build: new(build.Context),
|
||||
Cwd: wd,
|
||||
TypeCheckFuncBodies: func(path string) bool {
|
||||
return path == mainPkg.ImportPath
|
||||
},
|
||||
}
|
||||
*conf.Build = *bctx
|
||||
n := len(conf.Build.BuildTags)
|
||||
// TODO(light): Only apply gooseinject build tag on main package.
|
||||
conf.Build.BuildTags = append(conf.Build.BuildTags[:n:n], "gooseinject")
|
||||
conf.Import(pkg)
|
||||
|
||||
prog, err := conf.Load()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load: %v", err)
|
||||
@@ -34,47 +50,23 @@ func Generate(bctx *build.Context, wd string, pkg string) ([]byte, error) {
|
||||
}
|
||||
pkgInfo := prog.InitialPackages()[0]
|
||||
g := newGen(prog, pkgInfo.Pkg.Path())
|
||||
r := newImportResolver(conf, prog.Fset)
|
||||
mc := newProviderSetCache(prog, r)
|
||||
oc := newObjectCache(prog)
|
||||
for _, f := range pkgInfo.Files {
|
||||
if !isInjectFile(f) {
|
||||
continue
|
||||
}
|
||||
fileScope := pkgInfo.Scopes[f]
|
||||
groups := parseFile(prog.Fset, f)
|
||||
for _, decl := range f.Decls {
|
||||
fn, ok := decl.(*ast.FuncDecl)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
var dg directiveGroup
|
||||
for _, dg = range groups {
|
||||
if dg.decl == decl {
|
||||
break
|
||||
}
|
||||
useCall := isInjector(&pkgInfo.Info, fn)
|
||||
if useCall == nil {
|
||||
continue
|
||||
}
|
||||
if dg.decl != decl {
|
||||
dg = directiveGroup{}
|
||||
}
|
||||
var sets []symref
|
||||
for _, d := range dg.dirs {
|
||||
if d.kind != "use" {
|
||||
return nil, fmt.Errorf("%v: cannot use %s directive on inject function", prog.Fset.Position(d.pos), d.kind)
|
||||
}
|
||||
args := d.args()
|
||||
if len(args) == 0 {
|
||||
return nil, fmt.Errorf("%v: goose:use must have at least one provider set reference", prog.Fset.Position(d.pos))
|
||||
}
|
||||
for _, arg := range args {
|
||||
ref, err := parseSymbolRef(r, arg, fileScope, g.currPackage, d.pos)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%v: %v", prog.Fset.Position(d.pos), err)
|
||||
}
|
||||
sets = append(sets, ref)
|
||||
}
|
||||
set, err := oc.processNewSet(pkgInfo, useCall)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%v: %v", prog.Fset.Position(fn.Pos()), err)
|
||||
}
|
||||
sig := pkgInfo.ObjectOf(fn.Name).Type().(*types.Signature)
|
||||
if err := g.inject(mc, fn.Name.Name, sig, sets); err != nil {
|
||||
if err := g.inject(prog.Fset, fn.Name.Name, sig, set); err != nil {
|
||||
return nil, fmt.Errorf("%v: %v", prog.Fset.Position(fn.Pos()), err)
|
||||
}
|
||||
}
|
||||
@@ -89,23 +81,6 @@ func Generate(bctx *build.Context, wd string, pkg string) ([]byte, error) {
|
||||
return fmtSrc, nil
|
||||
}
|
||||
|
||||
func newLoaderConfig(bctx *build.Context, wd string, inject bool) *loader.Config {
|
||||
// TODO(light): Stop errors from printing to stderr.
|
||||
conf := &loader.Config{
|
||||
Build: bctx,
|
||||
ParserMode: parser.ParseComments,
|
||||
Cwd: wd,
|
||||
TypeCheckFuncBodies: func(string) bool { return false },
|
||||
}
|
||||
if inject {
|
||||
conf.Build = new(build.Context)
|
||||
*conf.Build = *bctx
|
||||
n := len(conf.Build.BuildTags)
|
||||
conf.Build.BuildTags = append(conf.Build.BuildTags[:n:n], "gooseinject")
|
||||
}
|
||||
return conf
|
||||
}
|
||||
|
||||
// gen is the generator state.
|
||||
type gen struct {
|
||||
currPackage string
|
||||
@@ -150,7 +125,7 @@ func (g *gen) frame() []byte {
|
||||
}
|
||||
|
||||
// inject emits the code for an injector.
|
||||
func (g *gen) inject(mc *providerSetCache, name string, sig *types.Signature, sets []symref) error {
|
||||
func (g *gen) inject(fset *token.FileSet, name string, sig *types.Signature, set *ProviderSet) error {
|
||||
results := sig.Results()
|
||||
var returnsCleanup, returnsErr bool
|
||||
switch results.Len() {
|
||||
@@ -184,7 +159,7 @@ func (g *gen) inject(mc *providerSetCache, name string, sig *types.Signature, se
|
||||
for i := 0; i < params.Len(); i++ {
|
||||
given[i] = params.At(i).Type()
|
||||
}
|
||||
calls, err := solve(mc, outType, given, sets)
|
||||
calls, err := solve(fset, outType, given, set)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -29,13 +29,19 @@ func TestGoose(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// The marker function package source is needed to have the test cases
|
||||
// type check. loadTestCase places this file at the well-known import path.
|
||||
gooseGo, err := ioutil.ReadFile(filepath.Join("..", "..", "goose.go"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tests := make([]*testCase, 0, len(testdataEnts))
|
||||
for _, ent := range testdataEnts {
|
||||
name := ent.Name()
|
||||
if !ent.IsDir() || strings.HasPrefix(name, ".") || strings.HasPrefix(name, "_") {
|
||||
continue
|
||||
}
|
||||
test, err := loadTestCase(filepath.Join(testRoot, name))
|
||||
test, err := loadTestCase(filepath.Join(testRoot, name), gooseGo)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -227,7 +233,7 @@ type testCase struct {
|
||||
// out.txt file containing the expected output, or the magic string "ERROR"
|
||||
// if this test should cause generation to fail
|
||||
// ... any Go files found recursively placed under GOPATH/src/...
|
||||
func loadTestCase(root string) (*testCase, error) {
|
||||
func loadTestCase(root string, gooseGoSrc []byte) (*testCase, error) {
|
||||
name := filepath.Base(root)
|
||||
pkg, err := ioutil.ReadFile(filepath.Join(root, "pkg"))
|
||||
if err != nil {
|
||||
@@ -242,7 +248,9 @@ func loadTestCase(root string) (*testCase, error) {
|
||||
wantError = true
|
||||
out = nil
|
||||
}
|
||||
goFiles := make(map[string][]byte)
|
||||
goFiles := map[string][]byte{
|
||||
"codename/goose/goose.go": gooseGoSrc,
|
||||
}
|
||||
err = filepath.Walk(root, func(src string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,37 +0,0 @@
|
||||
package goose
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDirectiveArgs(t *testing.T) {
|
||||
tests := []struct {
|
||||
line string
|
||||
args []string
|
||||
}{
|
||||
{"", []string{}},
|
||||
{" \t ", []string{}},
|
||||
{"foo", []string{"foo"}},
|
||||
{"foo bar", []string{"foo", "bar"}},
|
||||
{" foo \t bar ", []string{"foo", "bar"}},
|
||||
{"foo \"bar \t baz\" fido", []string{"foo", "\"bar \t baz\"", "fido"}},
|
||||
{"foo \"bar \t baz\".quux fido", []string{"foo", "\"bar \t baz\".quux", "fido"}},
|
||||
}
|
||||
eq := func(a, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i := range a {
|
||||
if a[i] != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
for _, test := range tests {
|
||||
got := (directive{line: test.line}).args()
|
||||
if !eq(got, test.args) {
|
||||
t.Errorf("directive{line: %q}.args() = %q; want %q", test.line, got, test.args)
|
||||
}
|
||||
}
|
||||
}
|
||||
12
internal/goose/testdata/Chain/foo/foo.go
vendored
12
internal/goose/testdata/Chain/foo/foo.go
vendored
@@ -1,6 +1,10 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(injectFooBar())
|
||||
@@ -9,12 +13,14 @@ func main() {
|
||||
type Foo int
|
||||
type FooBar int
|
||||
|
||||
//goose:provide Set
|
||||
var Set = goose.NewSet(
|
||||
provideFoo,
|
||||
provideFooBar)
|
||||
|
||||
func provideFoo() Foo {
|
||||
return 41
|
||||
}
|
||||
|
||||
//goose:provide Set
|
||||
func provideFooBar(foo Foo) FooBar {
|
||||
return FooBar(foo) + 1
|
||||
}
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
package main
|
||||
|
||||
//goose:use Set
|
||||
import (
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
func injectFooBar() FooBar
|
||||
func injectFooBar() FooBar {
|
||||
panic(goose.Use(Set))
|
||||
}
|
||||
|
||||
6
internal/goose/testdata/Cleanup/foo/foo.go
vendored
6
internal/goose/testdata/Cleanup/foo/foo.go
vendored
@@ -1,6 +1,8 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
bar, cleanup := injectBar()
|
||||
@@ -12,14 +14,12 @@ func main() {
|
||||
type Foo int
|
||||
type Bar int
|
||||
|
||||
//goose:provide Foo
|
||||
func provideFoo() (*Foo, func()) {
|
||||
foo := new(Foo)
|
||||
*foo = 42
|
||||
return foo, func() { *foo = 0 }
|
||||
}
|
||||
|
||||
//goose:provide Bar
|
||||
func provideBar(foo *Foo) (*Bar, func()) {
|
||||
bar := new(Bar)
|
||||
*bar = 77
|
||||
|
||||
9
internal/goose/testdata/Cleanup/foo/goose.go
vendored
9
internal/goose/testdata/Cleanup/foo/goose.go
vendored
@@ -2,7 +2,10 @@
|
||||
|
||||
package main
|
||||
|
||||
//goose:use Foo
|
||||
//goose:use Bar
|
||||
import (
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
func injectBar() (*Bar, func())
|
||||
func injectBar() (*Bar, func()) {
|
||||
panic(goose.Use(provideFoo, provideBar))
|
||||
}
|
||||
|
||||
11
internal/goose/testdata/EmptyVar/foo/foo.go
vendored
Normal file
11
internal/goose/testdata/EmptyVar/foo/foo.go
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(injectedMessage())
|
||||
}
|
||||
|
||||
var myFakeSet struct{}
|
||||
11
internal/goose/testdata/EmptyVar/foo/goose.go
vendored
Normal file
11
internal/goose/testdata/EmptyVar/foo/goose.go
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
//+build gooseinject
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
func injectedMessage() string {
|
||||
panic(goose.Use(myFakeSet))
|
||||
}
|
||||
@@ -3,7 +3,8 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
_ "foo"
|
||||
"codename/goose"
|
||||
"foo"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -16,11 +17,12 @@ func (b *Bar) Foo() string {
|
||||
return string(*b)
|
||||
}
|
||||
|
||||
//goose:provide
|
||||
func provideBar() *Bar {
|
||||
b := new(Bar)
|
||||
*b = "Hello, World!"
|
||||
return b
|
||||
}
|
||||
|
||||
//goose:bind provideBar "foo".Fooer *Bar
|
||||
var Set = goose.NewSet(
|
||||
provideBar,
|
||||
goose.Bind(foo.Fooer(nil), (*Bar)(nil)))
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
|
||||
package main
|
||||
|
||||
import "foo"
|
||||
import (
|
||||
"codename/goose"
|
||||
"foo"
|
||||
)
|
||||
|
||||
//goose:use provideBar
|
||||
|
||||
func injectFooer() foo.Fooer
|
||||
func injectFooer() foo.Fooer {
|
||||
panic(goose.Use(Set))
|
||||
}
|
||||
|
||||
12
internal/goose/testdata/InjectInput/foo/foo.go
vendored
12
internal/goose/testdata/InjectInput/foo/foo.go
vendored
@@ -1,6 +1,10 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(injectFooBar(40))
|
||||
@@ -10,12 +14,14 @@ type Foo int
|
||||
type Bar int
|
||||
type FooBar int
|
||||
|
||||
//goose:provide Set
|
||||
var Set = goose.NewSet(
|
||||
provideBar,
|
||||
provideFooBar)
|
||||
|
||||
func provideBar() Bar {
|
||||
return 2
|
||||
}
|
||||
|
||||
//goose:provide Set
|
||||
func provideFooBar(foo Foo, bar Bar) FooBar {
|
||||
return FooBar(foo) + FooBar(bar)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
package main
|
||||
|
||||
//goose:use Set
|
||||
import (
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
func injectFooBar(foo Foo) FooBar
|
||||
func injectFooBar(foo Foo) FooBar {
|
||||
panic(goose.Use(Set))
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// I'm on the fence as to whether this should be an error (versus an
|
||||
@@ -12,12 +16,14 @@ func main() {
|
||||
type Foo int
|
||||
type Bar int
|
||||
|
||||
//goose:provide Set
|
||||
var Set = goose.NewSet(
|
||||
provideFoo,
|
||||
provideBar)
|
||||
|
||||
func provideFoo() Foo {
|
||||
return -888
|
||||
}
|
||||
|
||||
//goose:provide Set
|
||||
func provideBar(foo Foo) Bar {
|
||||
return 2
|
||||
}
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
package main
|
||||
|
||||
//goose:use Set
|
||||
import (
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
func injectBar(foo Foo) Bar
|
||||
func injectBar(foo Foo) Bar {
|
||||
panic(goose.Use(Set))
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(injectFooer().Foo())
|
||||
@@ -16,11 +20,12 @@ func (b *Bar) Foo() string {
|
||||
return string(*b)
|
||||
}
|
||||
|
||||
//goose:provide
|
||||
func provideBar() *Bar {
|
||||
b := new(Bar)
|
||||
*b = "Hello, World!"
|
||||
return b
|
||||
}
|
||||
|
||||
//goose:bind provideBar Fooer *Bar
|
||||
var Set = goose.NewSet(
|
||||
provideBar,
|
||||
goose.Bind(Fooer(nil), (*Bar)(nil)))
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
package main
|
||||
|
||||
//goose:use provideBar
|
||||
import (
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
func injectFooer() Fooer
|
||||
func injectFooer() Fooer {
|
||||
panic(goose.Use(Set))
|
||||
}
|
||||
|
||||
@@ -28,8 +28,6 @@ func (b *Bar) Foo() string {
|
||||
return string(*b)
|
||||
}
|
||||
|
||||
//goose:provide
|
||||
//goose:bind provideBar Fooer *Bar
|
||||
func provideBar() *Bar {
|
||||
mu.Lock()
|
||||
provideBarCalls++
|
||||
@@ -44,7 +42,6 @@ var (
|
||||
provideBarCalls int
|
||||
)
|
||||
|
||||
//goose:provide
|
||||
func provideFooBar(fooer Fooer, bar *Bar) FooBar {
|
||||
return FooBar{fooer, bar}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
|
||||
package main
|
||||
|
||||
//goose:use provideBar
|
||||
//goose:use provideFooBar
|
||||
import (
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
func injectFooBar() FooBar
|
||||
func injectFooBar() FooBar {
|
||||
panic(goose.Use(
|
||||
provideBar,
|
||||
provideFooBar,
|
||||
goose.Bind(Fooer(nil), (*Bar)(nil))))
|
||||
}
|
||||
|
||||
14
internal/goose/testdata/MissingUse/foo/foo.go
vendored
14
internal/goose/testdata/MissingUse/foo/foo.go
vendored
@@ -1,14 +0,0 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Println(injectedMessage())
|
||||
}
|
||||
|
||||
//goose:provide Set
|
||||
|
||||
// provideMessage provides a friendly user greeting.
|
||||
func provideMessage() string {
|
||||
return "Hello, World!"
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
//+build gooseinject
|
||||
|
||||
package main
|
||||
|
||||
func injectedMessage() string
|
||||
22
internal/goose/testdata/MultiImport/foo/foo.go
vendored
22
internal/goose/testdata/MultiImport/foo/foo.go
vendored
@@ -1,22 +0,0 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Println(injectFooBar())
|
||||
}
|
||||
|
||||
type Foo int
|
||||
type FooBar int
|
||||
|
||||
//goose:provide Foo
|
||||
func provideFoo() Foo {
|
||||
return 41
|
||||
}
|
||||
|
||||
//goose:provide FooBar
|
||||
func provideFooBar(foo Foo) FooBar {
|
||||
return FooBar(foo) + 1
|
||||
}
|
||||
|
||||
//goose:import Set Foo FooBar
|
||||
@@ -1,7 +0,0 @@
|
||||
//+build gooseinject
|
||||
|
||||
package main
|
||||
|
||||
//goose:use Set
|
||||
|
||||
func injectFooBar() FooBar
|
||||
1
internal/goose/testdata/MultiImport/out.txt
vendored
1
internal/goose/testdata/MultiImport/out.txt
vendored
@@ -1 +0,0 @@
|
||||
42
|
||||
1
internal/goose/testdata/MultiImport/pkg
vendored
1
internal/goose/testdata/MultiImport/pkg
vendored
@@ -1 +0,0 @@
|
||||
foo
|
||||
20
internal/goose/testdata/MultiUse/foo/foo.go
vendored
20
internal/goose/testdata/MultiUse/foo/foo.go
vendored
@@ -1,20 +0,0 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Println(injectFooBar())
|
||||
}
|
||||
|
||||
type Foo int
|
||||
type FooBar int
|
||||
|
||||
//goose:provide Foo
|
||||
func provideFoo() Foo {
|
||||
return 41
|
||||
}
|
||||
|
||||
//goose:provide FooBar
|
||||
func provideFooBar(foo Foo) FooBar {
|
||||
return FooBar(foo) + 1
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
//+build gooseinject
|
||||
|
||||
package main
|
||||
|
||||
//goose:use Foo FooBar
|
||||
|
||||
func injectFooBar() FooBar
|
||||
1
internal/goose/testdata/MultiUse/out.txt
vendored
1
internal/goose/testdata/MultiUse/out.txt
vendored
@@ -1 +0,0 @@
|
||||
42
|
||||
1
internal/goose/testdata/MultiUse/pkg
vendored
1
internal/goose/testdata/MultiUse/pkg
vendored
@@ -1 +0,0 @@
|
||||
foo
|
||||
@@ -17,8 +17,6 @@ func main() {
|
||||
fmt.Println(c)
|
||||
}
|
||||
|
||||
//goose:provide
|
||||
|
||||
func provide(ctx stdcontext.Context) (context, error) {
|
||||
return context{}, nil
|
||||
}
|
||||
|
||||
@@ -4,8 +4,10 @@ package main
|
||||
|
||||
import (
|
||||
stdcontext "context"
|
||||
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
//goose:use provide
|
||||
|
||||
func inject(context stdcontext.Context, err struct{}) (context, error)
|
||||
func inject(context stdcontext.Context, err struct{}) (context, error) {
|
||||
panic(goose.Use(provide))
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@ func main() {
|
||||
fmt.Println(injectedMessage())
|
||||
}
|
||||
|
||||
//goose:provide
|
||||
|
||||
// provideMessage provides a friendly user greeting.
|
||||
func provideMessage() string {
|
||||
return "Hello, World!"
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
package main
|
||||
|
||||
//goose:use provideMessage
|
||||
import (
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
func injectedMessage() string
|
||||
func injectedMessage() string {
|
||||
panic(goose.Use(provideMessage))
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ func (b Bar) Foo() string {
|
||||
return string(b)
|
||||
}
|
||||
|
||||
//goose:provide
|
||||
func provideBar() Bar {
|
||||
return "Hello, World!"
|
||||
}
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
package main
|
||||
|
||||
//goose:use provideBar
|
||||
import (
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
func injectFooer() Fooer
|
||||
func injectFooer() Fooer {
|
||||
panic(goose.Use(provideBar))
|
||||
}
|
||||
|
||||
@@ -17,8 +17,6 @@ func main() {
|
||||
fmt.Println(c)
|
||||
}
|
||||
|
||||
//goose:provide
|
||||
|
||||
func provide(ctx stdcontext.Context) (context, error) {
|
||||
return context{}, nil
|
||||
}
|
||||
|
||||
@@ -4,11 +4,13 @@ package main
|
||||
|
||||
import (
|
||||
stdcontext "context"
|
||||
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
// The notable characteristic of this test is that there are no
|
||||
// parameter names on the inject stub.
|
||||
|
||||
//goose:use provide
|
||||
|
||||
func inject(stdcontext.Context, struct{}) (context, error)
|
||||
func inject(stdcontext.Context, struct{}) (context, error) {
|
||||
panic(goose.Use(provide))
|
||||
}
|
||||
|
||||
@@ -25,14 +25,12 @@ type Foo int
|
||||
type Bar int
|
||||
type Baz int
|
||||
|
||||
//goose:provide Foo
|
||||
func provideFoo() (*Foo, func()) {
|
||||
foo := new(Foo)
|
||||
*foo = 42
|
||||
return foo, func() { *foo = 0; cleanedFoo = true }
|
||||
}
|
||||
|
||||
//goose:provide Bar
|
||||
func provideBar(foo *Foo) (*Bar, func(), error) {
|
||||
bar := new(Bar)
|
||||
*bar = 77
|
||||
@@ -45,7 +43,6 @@ func provideBar(foo *Foo) (*Bar, func(), error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
//goose:provide Baz
|
||||
func provideBaz(bar *Bar) (Baz, error) {
|
||||
return 0, errors.New("bork!")
|
||||
}
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
package main
|
||||
|
||||
//goose:use Foo
|
||||
//goose:use Bar
|
||||
//goose:use Baz
|
||||
import (
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
func injectBaz() (Baz, func(), error)
|
||||
func injectBaz() (Baz, func(), error) {
|
||||
panic(goose.Use(provideFoo, provideBar, provideBaz))
|
||||
}
|
||||
|
||||
1
internal/goose/testdata/PkgImport/bar/bar.go
vendored
1
internal/goose/testdata/PkgImport/bar/bar.go
vendored
@@ -2,7 +2,6 @@ package bar
|
||||
|
||||
type Bar int
|
||||
|
||||
//goose:provide Bar
|
||||
func ProvideBar() Bar {
|
||||
return 1
|
||||
}
|
||||
|
||||
10
internal/goose/testdata/PkgImport/foo/foo.go
vendored
10
internal/goose/testdata/PkgImport/foo/foo.go
vendored
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"bar"
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -13,14 +14,15 @@ func main() {
|
||||
type Foo int
|
||||
type FooBar int
|
||||
|
||||
//goose:provide Set
|
||||
var Set = goose.NewSet(
|
||||
provideFoo,
|
||||
bar.ProvideBar,
|
||||
provideFooBar)
|
||||
|
||||
func provideFoo() Foo {
|
||||
return 41
|
||||
}
|
||||
|
||||
//goose:import Set "bar".Bar
|
||||
|
||||
//goose:provide Set
|
||||
func provideFooBar(foo Foo, barVal bar.Bar) FooBar {
|
||||
return FooBar(foo) + FooBar(barVal)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
package main
|
||||
|
||||
//goose:use Set
|
||||
import (
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
func injectFooBar() FooBar
|
||||
func injectFooBar() FooBar {
|
||||
panic(goose.Use(Set))
|
||||
}
|
||||
|
||||
13
internal/goose/testdata/ReturnError/foo/foo.go
vendored
13
internal/goose/testdata/ReturnError/foo/foo.go
vendored
@@ -1,8 +1,12 @@
|
||||
package main
|
||||
|
||||
import "errors"
|
||||
import "fmt"
|
||||
import "strings"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
func main() {
|
||||
foo, err := injectFoo()
|
||||
@@ -16,7 +20,8 @@ func main() {
|
||||
|
||||
type Foo int
|
||||
|
||||
//goose:provide Set
|
||||
func provideFoo() (Foo, error) {
|
||||
return 42, errors.New("there is no Foo")
|
||||
}
|
||||
|
||||
var Set = goose.NewSet(provideFoo)
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
package main
|
||||
|
||||
//goose:use Set
|
||||
import (
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
func injectFoo() (Foo, error)
|
||||
func injectFoo() (Foo, error) {
|
||||
panic(goose.Use(Set))
|
||||
}
|
||||
|
||||
14
internal/goose/testdata/Struct/foo/foo.go
vendored
14
internal/goose/testdata/Struct/foo/foo.go
vendored
@@ -1,6 +1,10 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fb := injectFooBar()
|
||||
@@ -10,18 +14,20 @@ func main() {
|
||||
type Foo int
|
||||
type Bar int
|
||||
|
||||
//goose:provide Set
|
||||
type FooBar struct {
|
||||
Foo Foo
|
||||
Bar Bar
|
||||
}
|
||||
|
||||
//goose:provide Set
|
||||
func provideFoo() Foo {
|
||||
return 41
|
||||
}
|
||||
|
||||
//goose:provide Set
|
||||
func provideBar() Bar {
|
||||
return 1
|
||||
}
|
||||
|
||||
var Set = goose.NewSet(
|
||||
FooBar{},
|
||||
provideFoo,
|
||||
provideBar)
|
||||
|
||||
8
internal/goose/testdata/Struct/foo/goose.go
vendored
8
internal/goose/testdata/Struct/foo/goose.go
vendored
@@ -2,6 +2,10 @@
|
||||
|
||||
package main
|
||||
|
||||
//goose:use Set
|
||||
import (
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
func injectFooBar() FooBar
|
||||
func injectFooBar() FooBar {
|
||||
panic(goose.Use(Set))
|
||||
}
|
||||
|
||||
14
internal/goose/testdata/StructPointer/foo/foo.go
vendored
14
internal/goose/testdata/StructPointer/foo/foo.go
vendored
@@ -1,6 +1,10 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fb := injectFooBar()
|
||||
@@ -10,18 +14,20 @@ func main() {
|
||||
type Foo int
|
||||
type Bar int
|
||||
|
||||
//goose:provide Set
|
||||
type FooBar struct {
|
||||
Foo Foo
|
||||
Bar Bar
|
||||
}
|
||||
|
||||
//goose:provide Set
|
||||
func provideFoo() Foo {
|
||||
return 41
|
||||
}
|
||||
|
||||
//goose:provide Set
|
||||
func provideBar() Bar {
|
||||
return 1
|
||||
}
|
||||
|
||||
var Set = goose.NewSet(
|
||||
FooBar{},
|
||||
provideFoo,
|
||||
provideBar)
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
package main
|
||||
|
||||
//goose:use Set
|
||||
import (
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
func injectFooBar() *FooBar
|
||||
func injectFooBar() *FooBar {
|
||||
panic(goose.Use(Set))
|
||||
}
|
||||
|
||||
14
internal/goose/testdata/TwoDeps/foo/foo.go
vendored
14
internal/goose/testdata/TwoDeps/foo/foo.go
vendored
@@ -1,6 +1,10 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(injectFooBar())
|
||||
@@ -10,17 +14,19 @@ type Foo int
|
||||
type Bar int
|
||||
type FooBar int
|
||||
|
||||
//goose:provide Set
|
||||
func provideFoo() Foo {
|
||||
return 40
|
||||
}
|
||||
|
||||
//goose:provide Set
|
||||
func provideBar() Bar {
|
||||
return 2
|
||||
}
|
||||
|
||||
//goose:provide Set
|
||||
func provideFooBar(foo Foo, bar Bar) FooBar {
|
||||
return FooBar(foo) + FooBar(bar)
|
||||
}
|
||||
|
||||
var Set = goose.NewSet(
|
||||
provideFoo,
|
||||
provideBar,
|
||||
provideFooBar)
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
package main
|
||||
|
||||
//goose:use Set
|
||||
import (
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
func injectFooBar() FooBar
|
||||
func injectFooBar() FooBar {
|
||||
panic(goose.Use(Set))
|
||||
}
|
||||
|
||||
9
internal/goose/testdata/Vendor/foo/goose.go
vendored
9
internal/goose/testdata/Vendor/foo/goose.go
vendored
@@ -3,9 +3,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "bar"
|
||||
"bar"
|
||||
"codename/goose"
|
||||
)
|
||||
|
||||
//goose:use "bar".Message
|
||||
|
||||
func injectedMessage() string
|
||||
func injectedMessage() string {
|
||||
panic(goose.Use(bar.ProvideMessage))
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// Package bar is the vendored copy of bar which contains the real provider.
|
||||
package bar
|
||||
|
||||
//goose:provide Message
|
||||
|
||||
// ProvideMessage provides a friendly user greeting.
|
||||
func ProvideMessage() string {
|
||||
return "Hello, World!"
|
||||
|
||||
Reference in New Issue
Block a user