Compile-time Dependency Injection for Go

Wire: Automated Initialization in Go

Build Status godoc Coverage

Wire is a code generation tool that automates connecting components using dependency injection. Dependencies between components are represented in Wire as function parameters, encouraging explicit initialization instead of global variables. Because Wire operates without runtime state or reflection, code written to be used with Wire is useful even for hand-written initialization.

For an overview, see the introductory blog post.

Installing

Install Wire by running:

go get github.com/google/wire/cmd/wire

and ensuring that $GOPATH/bin is added to your $PATH.

Documentation

Project status

As of version v0.3.0, Wire is beta and is considered feature complete. It works well for the tasks it was designed to perform, and we prefer to keep it as simple as possible.

We'll not be accepting new features at this time, but will gladly accept bug reports and fixes.

Community

For questions, please use GitHub Discussions.

This project is covered by the Go Code of Conduct.

Owner
Google
Google ❤️ Open Source
Google
Comments
  • wire: test flakes on Travis with

    wire: test flakes on Travis with "failed to cache compiled Go files"

    Describe the bug

    The Wire tests fail intermittently on Travis with an error like:

            wire_test.go:96: go [list -e -json -compiled -test=false -export=false -deps=true -tags=wireinject -- example.com/foo]: exit status 1: go: finding github.com/google/go-cloud v0.2.0
                go build runtime/internal/atomic: failed to cache compiled Go files
    

    To Reproduce

    This is an intermittent failure, but I've only seen it on Travis. Uncertain what the triggers are.

    Expected behavior

    Wire tests should pass.

    /cc @vangent, who I believe hit this failure before, but I can't find evidence of it.

  • Problem running wire from tutorial

    Problem running wire from tutorial

    Describe the bug

    I can not get the wire command to work. Started off with the tutorial, made a directory in ~/go/src/test and copied the main.go and wire.go files from the _tutorial directory. Ran go get github.com/google/wire/cmd/wire then proceeded to run wire, here is the output:

    16:53 $
    ✔ ~/go/src/test
    16:53 $ ls
    main.go	wire.go
    ✔ ~/go/src/test
    16:53 $ cat main.go
    // Copyright 2018 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.
    
    // The greeter binary simulates an event with greeters greeting guests.
    package main
    
    import (
    	"errors"
    	"fmt"
    	"os"
    	"time"
    )
    
    // Message is what greeters will use to greet guests.
    type Message string
    
    // NewMessage creates a default Message.
    func NewMessage(phrase string) Message {
    	return Message(phrase)
    }
    
    // NewGreeter initializes a Greeter. If the current epoch time is an even
    // number, NewGreeter will create a grumpy Greeter.
    func NewGreeter(m Message) Greeter {
    	var grumpy bool
    	if time.Now().Unix()%2 == 0 {
    		grumpy = true
    	}
    	return Greeter{Message: m, Grumpy: grumpy}
    }
    
    // Greeter is the type charged with greeting guests.
    type Greeter struct {
    	Grumpy  bool
    	Message Message
    }
    
    // Greet produces a greeting for guests.
    func (g Greeter) Greet() Message {
    	if g.Grumpy {
    		return Message("Go away!")
    	}
    	return g.Message
    }
    
    // NewEvent creates an event with the specified greeter.
    func NewEvent(g Greeter) (Event, error) {
    	if g.Grumpy {
    		return Event{}, errors.New("could not create event: event greeter is grumpy")
    	}
    	return Event{Greeter: g}, nil
    }
    
    // Event is a gathering with greeters.
    type Event struct {
    	Greeter Greeter
    }
    
    // Start ensures the event starts with greeting all guests.
    func (e Event) Start() {
    	msg := e.Greeter.Greet()
    	fmt.Println(msg)
    }
    
    func main() {
    	e, err := InitializeEvent("hi there!")
    	if err != nil {
    		fmt.Printf("failed to create event: %s\n", err)
    		os.Exit(2)
    	}
    	e.Start()
    }
    ✔ ~/go/src/test
    16:53 $ cat wire.go
    //+build wireinject
    
    // The build tag makes sure the stub is not built in the final build.
    package main
    
    import "github.com/google/wire"
    
    // InitializeEvent creates an Event. It will error if the Event is staffed with
    // a grumpy greeter.
    func InitializeEvent(phrase string) (Event, error) {
    	wire.Build(NewEvent, NewGreeter, NewMessage)
    	return Event{}, nil
    }
    ✔ ~/go/src/test
    16:53 $ wire
    packages not found
    wire: generate failed
    ✘-1 ~/go/src/test
    16:53 $
    

    I then tried to run wire from the downloaded repo:

    16:51 $
    ✔ ~/go/src/github.com/google/wire/_tutorial [v0.2.1|✚ 1…1]
    16:54 $ ls
    README.md	main.go		wire.go
    ✔ ~/go/src/github.com/google/wire/_tutorial [v0.2.1|✚ 1…1]
    16:54 $ wire
    packages not found
    wire: generate failed
    ✘-1 ~/go/src/github.com/google/wire/_tutorial [v0.2.1|✚ 1…1]
    16:54 $
    

    To Reproduce

    go get -u github.com/google/wire
    cd ~/go/src/github.com/google/wire
    git co v0.2.1
    cd _tutorial
    rm wire_gen.go
    wire
    

    16:51 $ ✔ ~/go/src/github.com/google/wire/_tutorial [v0.2.1|✚ 1…1] 16:54 $ ls README.md main.go wire.go ✔ ~/go/src/github.com/google/wire/_tutorial [v0.2.1|✚ 1…1] 16:54 $ wire packages not found wire: generate failed ✘-1 ~/go/src/github.com/google/wire/_tutorial [v0.2.1|✚ 1…1] 16:54 $

    
    ## Expected behavior
    
    wire_gen.go will be generated.
    
    ### Version
    
    v0.2.1
    
    ### Additional context
    
    I tried this with master before resorting to v0.2.1 and I got the same error both times. I really want to try this out in my project. Any help would be awesome.
    
    GOPATH=/Users/kortm/go
    go version: `version go1.11.1 darwin/amd64`
    
    
  • `go:generate wire` in generated files should be optional

    `go:generate wire` in generated files should be optional

    Is your feature request related to a problem? Please describe.

    We generate a lot of files with wire and we would like to use a single execution of wire to do that. When wire writes out go:generate instructions into files it generates, it makes it hard for us remove those commands and generate the wire files on our own.

    Describe the solution you'd like

    I propose adding a flag such as --no-go-generate to the cli, which, when set omits the go:generate line from https://github.com/google/wire/blob/f285c073b52078f165ca19f3ceb192f0f50f3934/internal/wire/wire.go#L253.

    Describe alternatives you've considered

    For now we can work around this issue by removing the line after running wire.

    Additional context

  • Update dependencies to support Generics

    Update dependencies to support Generics

    Hello! First of all, thanks for this project. It is very helpful and makes dependency injection a breeze.

    We've experience some problems working with wire and generics (as I think other people has experienced too according to #354)

    I dont know for sure if these changes added full support for generics but I've managed to fix all the issues I had in my projects.

    Mainly, I had to update the dependencies to use golang.org/x/[email protected]

    The main issue was here: https://github.com/golang/tools/blob/master/go/ast/astutil/rewrite.go#L255 that was included in this commit

    this is a version adapted from the tutorial that works only with the updated version:

    // main.go
    package main
    
    import (
    	"errors"
    	"fmt"
    	"os"
    	"time"
    )
    
    // Message is what greeters will use to greet guests.
    type Message string
    
    type Resolver[K comparable, V any] struct {
    	store map[K]V
    }
    
    func NewResolver[K comparable, V any]() Resolver[K, V] {
    	return Resolver[K, V]{
    		store: map[K]V{},
    	}
    }
    
    func (o Resolver[K, V]) Resolve(key K) (V, error) {
    	val, exists := o.store[key]
    	if !exists {
    		return val, errors.New("not found")
    	}
    
    	return val, nil
    }
    
    func (o Resolver[K, V]) Add(key K, val V) {
    	o.store[key] = val
    }
    
    // NewMessage creates a default Message.
    func NewMessage(phrase string) Message {
    	return Message(phrase)
    }
    
    // NewGreeter initializes a Greeter. If the current epoch time is an even
    // number, NewGreeter will create a grumpy Greeter.
    func NewGreeter(m Resolver[bool, Message]) Greeter {
    	var grumpy bool
    	if time.Now().Unix()%2 == 0 {
    		grumpy = true
    	}
    	return Greeter{MessageResolver: m, Grumpy: grumpy}
    }
    
    // Greeter is the type charged with greeting guests.
    type Greeter struct {
    	Grumpy          bool
    	MessageResolver Resolver[bool, Message]
    }
    
    // Greet produces a greeting for guests.
    func (g Greeter) Greet() Message {
    	m, err := g.MessageResolver.Resolve(g.Grumpy)
    	if err != nil {
    		return Message("not found")
    	}
    	return m
    }
    
    // NewEvent creates an event with the specified greeter.
    func NewEvent(g Greeter) (Event, error) {
    	if g.Grumpy {
    		return Event{}, errors.New("could not create event: event greeter is grumpy")
    	}
    	return Event{Greeter: g}, nil
    }
    
    // Event is a gathering with greeters.
    type Event struct {
    	Greeter Greeter
    }
    
    // Start ensures the event starts with greeting all guests.
    func (e Event) Start() {
    	msg := e.Greeter.Greet()
    	fmt.Println(msg)
    }
    
    func main() {
    	e, err := InitializeEvent("hi there!")
    	if err != nil {
    		fmt.Printf("failed to create event: %s\n", err)
    		os.Exit(2)
    	}
    	e.Start()
    }
    
    // wire.go
    package main
    
    import "github.com/google/wire"
    
    func getMessageResolver() Resolver[bool, Message] {
    	r := NewResolver[bool, Message]()
    	r.Add(false, Message("happy false"))
    	r.Add(true, Message("grumpy true"))
    	return r
    }
    
    // InitializeEvent creates an Event. It will error if the Event is staffed with
    // a grumpy greeter.
    func InitializeEvent(phrase string) (Event, error) {
    	wire.Build(NewEvent, NewGreeter, getMessageResolver)
    	return Event{}, nil
    }
    
  • Changing installation Commands

    Changing installation Commands

    go get: installing executables with 'go get' in module mode is deprecated. To adjust and download dependencies of the current module, use 'go get -d'. To install using requirements of the current module, use 'go install'. To install ignoring the current module, use 'go install' with a version, like 'go install example.com/cmd@latest'. For more information, see https://golang.org/doc/go-get-install-deprecation or run 'go help get' or 'go help install'.

  • wire: wire.FieldsOf() to inject the values from fields of a struct

    wire: wire.FieldsOf() to inject the values from fields of a struct

    Pretty new to wire, so forgive me if I am asking the wrong questions.

    As far as I understand, wire.Value() allows to specify a value to be injected. If I have a struct, the fields of which must be injected rather than the value of the struct itself, would I have to use wire.Value() for each field of the struct?

    Would it make sense to add something like wire.FieldValues(), which injects the fields of the struct that is specified rather than the struct itself?

  • fix: run wire with -mod=mod

    fix: run wire with -mod=mod

    fixed the issue when using wire with Go module.

    go run github.com/google/wire/cmd/wire gen
    /go/pkg/mod/github.com/google/[email protected]/cmd/wire/main.go:34:2: missing go.sum entry for module providing package github.com/google/subcommands (imported by github.com/google/wire/cmd/wire); to add:
            go get github.com/google/wire/cmd/[email protected]
    

    Close: https://github.com/google/wire/issues/299, https://github.com/google/wire/pull/342

  • Get error message

    Get error message "undefined: InitializeEvent " in tutorial

    Describe the bug

    I had copy tutorial code and run "wire" in ternimal. After getting "wire_gen" file, i ran "go run main.go" or "go build main.go" and it alway show a error message.

    # command-line-arguments
    .\main.go:77:12: undefined: InitializeEvent"  
    

    Am i loss any step or params during wire?

    Version

    go 1.13.4 wire v0.3.0

    Additional context

    main code

    package main
    
    // Copyright 2018 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.
    
    // The greeter binary simulates an event with greeters greeting guests.
    import (
    	"errors"
    	"fmt"
    	"os"
    	"time"
    )
    
    // Message is what greeters will use to greet guests.
    type Message string
    
    // NewMessage creates a default Message.
    func NewMessage(phrase string) Message {
    	return Message(phrase)
    }
    
    // NewGreeter initializes a Greeter. If the current epoch time is an even
    // number, NewGreeter will create a grumpy Greeter.
    func NewGreeter(m Message) Greeter {
    	var grumpy bool
    	if time.Now().Unix()%2 == 0 {
    		grumpy = true
    	}
    	return Greeter{Message: m, Grumpy: grumpy}
    }
    
    // Greeter is the type charged with greeting guests.
    type Greeter struct {
    	Grumpy  bool
    	Message Message
    }
    
    // Greet produces a greeting for guests.
    func (g Greeter) Greet() Message {
    	if g.Grumpy {
    		return Message("Go away!")
    	}
    	return g.Message
    }
    
    // NewEvent creates an event with the specified greeter.
    func NewEvent(g Greeter) (Event, error) {
    	if g.Grumpy {
    		return Event{}, errors.New("could not create event: event greeter is grumpy")
    	}
    	return Event{Greeter: g}, nil
    }
    
    // Event is a gathering with greeters.
    type Event struct {
    	Greeter Greeter
    }
    
    // Start ensures the event starts with greeting all guests.
    func (e Event) Start() {
    	msg := e.Greeter.Greet()
    	fmt.Println(msg)
    }
    
    func main() {
    	e, err := InitializeEvent("hi there!")
    	if err != nil {
    		fmt.Printf("failed to create event: %s\n", err)
    		os.Exit(2)
    	}
    	e.Start()
    }
    

    wire.go

    //+build wireinject
    
    // The build tag makes sure the stub is not built in the final build.
    package main
    
    import "github.com/google/wire"
    
    // InitializeEvent creates an Event. It will error if the Event is staffed with
    // a grumpy greeter.
    func InitializeEvent(phrase string) (Event, error) {
    	wire.Build(NewEvent, NewGreeter, NewMessage)
    	return Event{}, nil
    }
    
  • wire: don't work with go modules [go v.1.11.1]

    wire: don't work with go modules [go v.1.11.1]

    When I run the wire command, I get the following:

    ...
    /home/terminator/.gvm/pkgsets/go1.11.1/global/pkg/mod/github.com/ory/[email protected]+incompatible/dockertest.go:13:2: could not import github.com/cenkalti/backoff (cannot find package "github.com/cenkalti/backoff" in any of:
                    /home/terminator/.gvm/gos/go1.11.1/src/github.com/cenkalti/backoff (from $GOROOT)
                    /home/terminator/.gvm/pkgsets/go1.11.1/global/src/github.com/cenkalti/backoff (from $GOPATH))
    ...
    and many many other dependencies...
    

    wire looks at GOPATH and GOROOT instead of modules dir, what am I doing wrong?

  • missing go.sum entry after ran go mod tidy

    missing go.sum entry after ran go mod tidy

    You can use go bug to have a cool, automatically filled out bug template, or fill out the template below.

    Describe the bug

    Following docs, after initial command wire, then after go mod tidy, subsequent go generate ./... reports:

    /go/pkg/mod/github.com/google/[email protected]/cmd/wire/main.go:34:2: missing go.sum entry for module providing package github.com/google/subcommands (imported by github.com/google/wire/cmd/wire); to add:
            go get github.com/google/wire/cmd/[email protected]
    /go/pkg/mod/github.com/google/[email protected]/cmd/wire/main.go:36:2: missing go.sum entry for module providing package github.com/pmezard/go-difflib/difflib (imported by github.com/google/wire/cmd/wire); to add:
            go get github.com/google/wire/cmd/[email protected]
    /go/pkg/mod/github.com/google/[email protected]/internal/wire/copyast.go:21:2: missing go.sum entry for module providing package golang.org/x/tools/go/ast/astutil (imported by github.com/google/wire/internal/wire); to add:
            go get github.com/google/wire/internal/[email protected]
    /go/pkg/mod/github.com/google/[email protected]/internal/wire/parse.go:30:2: missing go.sum entry for module providing package golang.org/x/tools/go/packages (imported by github.com/google/wire/internal/wire); to add:
            go get github.com/google/wire/internal/[email protected]
    /go/pkg/mod/github.com/google/[email protected]/internal/wire/analyze.go:26:2: missing go.sum entry for module providing package golang.org/x/tools/go/types/typeutil (imported by github.com/google/wire/cmd/wire); to add:
            go get github.com/google/wire/cmd/[email protected]
    wire_gen.go:3: running "go": exit status 1
    

    To Reproduce

    I use this command to reproduce the problem:

    docker build - <<EOF
    FROM golang
    WORKDIR /myproject
    RUN go mod init myproject
    
    RUN echo '// +build wireinject' >> wire.go
    RUN echo 'package main' >> wire.go
    RUN echo 'import ("strings"; "github.com/google/wire")' >> wire.go
    RUN echo 'func initReader(s string) *strings.Reader {' >> wire.go
    RUN echo '	panic(wire.Build(strings.NewReader))' >> wire.go
    RUN echo '}' >> wire.go
    
    RUN go get github.com/google/wire/cmd/wire
    RUN wire
    RUN cat wire_gen.go
    RUN go mod tidy
    RUN cat go.mod
    RUN go generate ./...
    EOF
    

    Expected behavior

    go generate ./... should run without error

    Version

    go 1.16
    
    github.com/google/wire v0.5.0
    

    Additional context

    Following the error message and run the suggest go get commands fixes the problem. But as soon as I run go mod tidy, go generate ./... reports error

  • Add goreportcard.com badge

    Add goreportcard.com badge

    It is one requirement of the pull request to add wire library to list https://github.com/avelino/awesome-go

    https://github.com/avelino/awesome-go/pull/2965

    https://github.com/avelino/awesome-go/blob/master/CONTRIBUTING.md

    https://github.com/avelino/awesome-go/blob/master/.github/PULL_REQUEST_TEMPLATE.md

  • wire `sync.Map`  throw error

    wire `sync.Map` throw error

    You can use go bug to have a cool, automatically filled out bug template, or fill out the template below.

    Describe the bug

    exec: "wire ./..." , not support sync.Map , throw error:

    cannot use (func(key, value interface{}) bool literal) (value of type func(key interface{}, value interface{}) bool) as func(key invalid type, value invalid type) bool value in argument to v.Range
    
    

    Version

    go version: 1.19.2 , wire: v0.5.0

  • Calling wire.Build with a provider set from a structure variable (For modular buildings)

    Calling wire.Build with a provider set from a structure variable (For modular buildings)

    Describe the bug

    I am trying to build a module system to allow some packages to provide their ProviderSets, along with other package settings. This means having a structure to be filled by each package, then after processing and composing modules, the idea is to have a global module with an aggregation of the required Wire Providers, Bindings, etc.

    In the end, instead of passing a single variable with the provider set, we pass a member from a structure variable to the wire.Build call.

    Example:

    wire.Build(module.ProviderSet)
    

    instead of

    wire.Build(providerSet)
    

    But instead of getting the code generated as expected, I got

    internal/wiring/wire.go|32 col 19| unknown pattern
    internal/wiring/wire_gen.go|3| running "go": exit status 1
    

    To Reproduce

    The following code reproduces the issue

    //go:build wireinject
    
    package wiring
    
    import (
    	"github.com/google/wire"
    )
    
    // ClockProvider is a test struct
    type ClockProvider struct{}
    
    // This is a Provider function / Constuctor for ClockProvider
    func NewProvider() *ClockProvider {
    	return &ClockProvider{}
    }
    
    // This is a mock of a Module Structure that can
    // hold a module settings, providers, default values, etc.
    type Module struct {
    	Set           wire.ProviderSet
    	DefaultValues []string
    }
    
    // This is a sample module instance
    var myModule = Module{
    	Set:           wire.NewSet(NewProvider),
    	DefaultValues: []string{"Value 1", "Value 2"},
    }
    
    // To be generated
    func GetClockProvider() (*ClockProvider, error) {
    	panic(wire.Build(myModule.Set))
    }
    

    Expected behavior

    The generated code should be the same as the one providing a single variable.

    Version

    • github.com/google/wire v0.5.0
    • go version go1.19.2 linux/amd64
  • function generated by Wire_gen.go

    function generated by Wire_gen.go "Cannot find declaration to go to" by Golang JetBrains but still run success

    I have main

    package main
    
    func main() {
    
    
    	c, _ := ProviderCCCCCC()
    	c.View()
    	c.B().Show()
    	c.A().Show()
    	c.View()
    
    }
    

    i have wire.go :

    //go:build wireinject
    // +build wireinject
    
    package main
    
    import (
    	"database/sql"
    	"github.com/google/wire"
    	"google.golang.org/grpc"
    	"net"
    	"wire_best_practice/b"
    	"wire_best_practice/c"
    	"wire_best_practice/repo"
    	"wire_best_practice/rpci"
    	"wire_best_practice/service"
    )
    
    func NewListener() (net.Listener, error) {
    	return net.Listen("tcp4", "0.0.0.0:5000")
    }
    
    func NewGRPCServer() *grpc.Server {
    	return grpc.NewServer()
    }
    
    func DBConn() (*sql.DB, error) {
    	return sql.Open("mysql", "127.0.0.1:3306")
    }
    
    func initApp() (*App, error) {
    	wire.Build(
    		rpci.New,
    		NewListener,
    		NewGRPCServer,
    		repo.Provider,
    		DBConn,
    		service.Provider,
    		wire.Struct(new(App), "*"),
    	)
    
    	return &App{}, nil
    }
    
    func ProviderB() (b.BInterface, error) {
    	wire.Build(
    		b.ProviderB,
    	)
    
    	return &b.B{}, nil
    }
    
    func ProviderCCCCCC() (c.CInterface, error) {
    	wire.Build(
    		c.ProviderC,
    	)
    
    	return &c.C{}, nil
    }
    

    and wire_gen.go

    // Code generated by Wire. DO NOT EDIT.
    
    //go:generate go run github.com/google/wire/cmd/wire
    //go:build !wireinject
    // +build !wireinject
    
    package main
    
    import (
    	"database/sql"
    	"google.golang.org/grpc"
    	"net"
    	"wire_best_practice/a"
    	"wire_best_practice/b"
    	"wire_best_practice/c"
    	"wire_best_practice/repo"
    	"wire_best_practice/rpci"
    	"wire_best_practice/service"
    )
    
    // Injectors from wire.go:
    
    func initApp() (*App, error) {
    	listener, err := NewListener()
    	if err != nil {
    		return nil, err
    	}
    	server := NewGRPCServer()
    	db, err := DBConn()
    	if err != nil {
    		return nil, err
    	}
    	repoDB := repo.New(db)
    	serviceService := service.New(repoDB)
    	rpciServer := rpci.New(serviceService, server)
    	app := &App{
    		listener: listener,
    		gsrv:     server,
    		rpcImpl:  rpciServer,
    	}
    	return app, nil
    }
    
    func ProviderB() (b.BInterface, error) {
    	a2 := a.NewA2()
    	bB := b.NewB(a2)
    	return bB, nil
    }
    
    func ProviderCCCCCC() (c.CInterface, error) {
    	a2 := a.NewA2()
    	bB := b.NewB(a2)
    	cC := c.NewC(bB, a2)
    	return cC, nil
    }
    
    // wire.go:
    
    func NewListener() (net.Listener, error) {
    	return net.Listen("tcp4", "0.0.0.0:5000")
    }
    
    func NewGRPCServer() *grpc.Server {
    	return grpc.NewServer()
    }
    
    func DBConn() (*sql.DB, error) {
    	return sql.Open("mysql", "127.0.0.1:3306")
    }
    
    

    every run success but, JetBrain Ide show error "Cannot find declaration to go to" in file wire_gen.go. Is there any way for this problem . Thanks all.

  • Support for concurrent initialization

    Support for concurrent initialization

    Is your feature request related to a problem? Please describe.

    Our service has a few dozen dependencies of various complexity. As part of initializing some of them, we'll 'ping' the API in question so that the service can fail fast if something is wrong (e.g. auth or some other configuration). Doing all of these serially means our service takes several seconds to start up, which is noticeable when using 'serverless' systems that scale down to zero, like GCP's Cloud Run.

    Describe the solution you'd like

    I'd like wire to generate code that parallelizes initialization when possible, e.g.:

    func initializeBaz(ctx context.Context) foobarbaz.Baz {
        fooChan, barChan := [...]
        go func() { fooChan <- foobarbaz.ProvideFoo() }
        go func() { barChan <- foobarbaz.ProvideBar() }
        return foobarbaz.ProvideBaz(ctx, <-fooChan, <-barChan)
    }
    

    (Note: I recognize this contrived example ignores nested things and error-handling, which make this slightly more complicated)

    And tangentially, but usefully, each provider could be wrapped in a sync.Once and cached.

    Describe alternatives you've considered

    The caching can be built into the provider itself by doing something like:

    var onceFoo sync.Once
    var fooVal Foo
    func ProvideFoo() Foo {
      onceFoo.Do(provideFoo)
      return fooVal
    }
    

    But the async/concurrent bit can't be done natively, as far as I know.

  • Missed receiver in generated inject method

    Missed receiver in generated inject method

    What version of Go are you using (go version)?

    $ go version
    go version go1.17.2 darwin/amd64
    

    Does this issue reproduce with the latest release?

    yes

    What operating system and processor architecture are you using (go env)?

    go env Output
    $ go env
    GO111MODULE="on"
    GOARCH="amd64"
    GOBIN=""
    GOCACHE="/Users/simbapeng/Library/Caches/go-build"
    GOENV="/Users/simbapeng/Library/Application Support/go/env"
    GOEXE=""
    GOEXPERIMENT=""
    GOFLAGS=""
    GOHOSTARCH="amd64"
    GOHOSTOS="darwin"
    GOINSECURE=""
    GOMODCACHE="/Users/simbapeng/go/pkg/mod"
    GONOPROXY="git.trustasia.cn/*"
    GONOSUMDB="git.trustasia.cn/*"
    GOOS="darwin"
    GOPATH="/Users/simbapeng/go"
    GOPRIVATE="git.trustasia.cn/*"
    GOPROXY="https://goproxy.cn,direct"
    GOROOT="/usr/local/Cellar/go/1.17.2/libexec"
    GOSUMDB="sum.golang.org"
    GOTMPDIR=""
    GOTOOLDIR="/usr/local/Cellar/go/1.17.2/libexec/pkg/tool/darwin_amd64"
    GOVCS=""
    GOVERSION="go1.17.2"
    GCCGO="gccgo"
    AR="ar"
    CC="clang"
    CXX="clang++"
    CGO_ENABLED="1"
    GOMOD="/Users/simbapeng/Project/gendemo/go.mod"
    CGO_CFLAGS="-g -O2"
    CGO_CPPFLAGS=""
    CGO_CXXFLAGS="-g -O2"
    CGO_FFLAGS="-g -O2"
    CGO_LDFLAGS="-g -O2"
    PKG_CONFIG="pkg-config"
    GOGCCFLAGS="-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/t0/tw9t0q2j7_z5lvxgdx_4chtm0000gn/T/go-build3502256362=/tmp/go-build -gno-record-gcc-switches -fno-common"
    GOROOT/bin/go version: go version go1.17.2 darwin/amd64
    GOROOT/bin/go tool compile -V: compile version go1.17.2
    uname -v: Darwin Kernel Version 21.6.0: Sat Jun 18 17:07:25 PDT 2022; root:xnu-8020.140.41~1/RELEASE_X86_64
    ProductName:	macOS
    ProductVersion:	12.5
    BuildVersion:	21G72
    lldb --version: lldb-1316.0.9.46
    Apple Swift version 5.6.1 (swiftlang-5.6.0.323.66 clang-1316.0.20.12)
    

    What did you do?

    //go:build wireinject
    // +build wireinject
    
    package main
    
    import (
    	"io"
    	"os"
    
    	"github.com/google/wire"
    )
    
    type foo struct{}
    type bar struct{}
    
    func (foo) injectWriter() io.Writer {
    	wire.Build(wire.InterfaceValue(new(io.Writer), os.Stdout))
    	return nil
    }
    
    func (bar) injectWriter() io.Writer {
    	wire.Build(wire.InterfaceValue(new(io.Writer), os.Stderr))
    	return nil
    }
    
    

    What did you expect to see?

    package main
    
    import (
    	"io"
    	"os"
    )
    
    // Injectors from main.go:
    
    func (foo) injectWriter() io.Writer {
    	writer := _wireFileValue
    	return writer
    }
    
    var (
    	_wireFileValue = os.Stdout
    )
    
    func (bar) injectWriter() io.Writer {
    	writer := _wireOsFileValue
    	return writer
    }
    
    var (
    	_wireOsFileValue = os.Stderr
    )
    
    // main.go:
    
    type foo struct{}
    
    type bar struct{}
    
    

    What did you see instead?

    Wire generates broken code. It generates function without receiver.

    package main
    
    import (
    	"io"
    	"os"
    )
    
    // Injectors from main.go:
    
    func injectWriter() io.Writer {
    	writer := _wireFileValue
    	return writer
    }
    
    var (
    	_wireFileValue = os.Stdout
    )
    
    func injectWriter() io.Writer {
    	writer := _wireOsFileValue
    	return writer
    }
    
    var (
    	_wireOsFileValue = os.Stderr
    )
    
    // main.go:
    
    type foo struct{}
    
    type bar struct{}
    
An additive dependency injection container for Golang.

Alice Alice is an additive dependency injection container for Golang. Philosophy Design philosophy behind Alice: The application components should not

Oct 16, 2022
🛠 A full-featured dependency injection container for go programming language.

DI Dependency injection for Go programming language. Tutorial | Examples | Advanced features Dependency injection is one form of the broader technique

Dec 31, 2022
A reflection based dependency injection toolkit for Go.

⚒️ dig A reflection based dependency injection toolkit for Go. Good for: Powering an application framework, e.g. Fx. Resolving the object graph during

Jan 1, 2023
Go Dependency Injection Framework

Dingo Dependency injection for go Hello Dingo Dingo works very very similiar to Guice Basically one binds implementations/factories to interfaces, whi

Dec 25, 2022
A dependency injection based application framework for Go.

?? Fx An application framework for Go that: Makes dependency injection easy. Eliminates the need for global state and func init(). Installation We rec

Jan 3, 2023
Simple Dependency Injection Container
Simple Dependency Injection Container

?? gocontainer gocontainer - Dependency Injection Container ?? ABOUT Contributors: Rafał Lorenz Want to contribute ? Feel free to send pull requests!

Sep 27, 2022
Simple and yet powerful Dependency Injection for Go
Simple and yet powerful Dependency Injection for Go

goioc/di: Dependency Injection Why DI in Go? Why IoC at all? I've been using Dependency Injection in Java for nearly 10 years via Spring Framework. I'

Dec 28, 2022
Dependency Injection and Inversion of Control package

Linker Linker is Dependency Injection and Inversion of Control package. It supports the following features: Components registry Automatic dependency i

Sep 27, 2022
Strict Runtime Dependency Injection for Golang

wire Wire is runtime depedency injection/wiring for golang. It's designed to be strict to avoid your go application running without proper dependency

Sep 27, 2022
Generated dependency injection containers in go (golang)
Generated dependency injection containers in go (golang)

Generation of dependency injection containers for go programs (golang). Dingo is a code generator. It generates dependency injection containers based

Dec 22, 2022
A dependency injection library that is focused on clean API and flexibility

Dependency injection DI is a dependency injection library that is focused on clean API and flexibility. DI has two types of top-level abstractions: Co

Oct 13, 2022
golang-runtime-di is a framework for runtime dependency injection in go

golang-runtime-di description golang-runtime-di is a framework for runtime dependency injection in go. usage quickstart add it to your go.mod: go get

Aug 1, 2022
Golang PE injection on windows

GoPEInjection Golang PE injection on windows See: https://malwareunicorn.org/workshops/peinjection.html Based on Cryptowall's PE injection technique.

Jan 6, 2023
two scripts written in golang that will help you recognize dependency confusion.
two scripts written in golang that will help you recognize dependency confusion.

two scripts written in golang that will help you recognize dependency confusion.

Mar 3, 2022
Compile-time Dependency Injection for Go

Wire: Automated Initialization in Go Wire is a code generation tool that automates connecting components using dependency injection. Dependencies betw

Jan 2, 2023
How we can run unit tests in parallel mode with failpoint injection taking effect and without injection race

This is a simple demo to show how we can run unit tests in parallel mode with failpoint injection taking effect and without injection race. The basic

Oct 31, 2021
Write your SQL queries in raw files with all benefits of modern IDEs, use them in an easy way inside your application with all the profit of compile time constants

About qry is a general purpose library for storing your raw database queries in .sql files with all benefits of modern IDEs, instead of strings and co

Dec 25, 2022
Completely type-safe compile-time mock generator for Go

Mockc Mockc is a completely type-safe compile-time mock generator for Go. You can use it just by writing the mock generators with mockc.Implement() or

Aug 25, 2022
hiboot is a high performance web and cli application framework with dependency injection support

Hiboot - web/cli application framework About Hiboot is a cloud native web and cli application framework written in Go. Hiboot is not trying to reinven

Nov 20, 2022
An additive dependency injection container for Golang.

Alice Alice is an additive dependency injection container for Golang. Philosophy Design philosophy behind Alice: The application components should not

Oct 16, 2022