src-d / go-git

Project has been moved to: https://github.com/go-git/go-git
https://github.com/go-git/go-git
Apache License 2.0
4.9k stars 540 forks source link

Timeout is only exposed at a client level, and not on per request level. #1150

Open NonLogicalDev opened 5 years ago

NonLogicalDev commented 5 years ago

Context:

At the moment Fetch/Clone options do not include Timeout as a parameter that can be set, and niether respect Context deadline when issuing ssh/http requests.

Suggestions

It would be great to be able to override timeout on a per request basis as opposed to only having it set globally.

Either as a parameter:

    repo, err := git.Clone(memory.NewStorage(), nil, &git.CloneOptions{
        NoCheckout: true,
        Timeout:  5 * time.Second,
        URL:        URL,
    })

Or as a context with a deadline:

    ctx, _ := context.WithDeadline(context.Background(), 5 * time.Second)
    repo, err := git.CloneContext(ctx, memory.NewStorage(), nil, &git.CloneOptions{
        NoCheckout: true,
        Timeout:  5 * time.Second,
        URL:        URL,
    })

Furthermore it would be great to be able to set the Transport on a per request basis.

    repo, err := git.Clone(memory.NewStorage(), nil, &git.CloneOptions{
        NoCheckout: true,
        Transport:  tssh.NewClient(*ssh.ClientConfig{
            Timeout: 5 * time.Second,
            //.....
        })
        URL:        URL,
    })

It would also be great to have instead of top level functions, or complimentary to them a git.Client type with the same functionality exposed. This way if multiple threads / workers are using git Client they could all have a personal instance, with personal configuration.

gcl := git.ClientInstance(map[string]transport.Transport{...})
gcl.Clone(...)

Hacky Workaround

Currently the only workaround I was able to come up with is defining a wrapper type for AuthMethod:

type SSHAuthWithTimeout struct {
    Auth    tssh.AuthMethod
    Timeout time.Duration
}

func (s SSHAuthWithTimeout) ClientConfig() (*ssh.ClientConfig, error) {
    config, err := s.Auth.ClientConfig()
    if err != nil {
        return nil, err
    }
    config.Timeout = s.Timeout
    return config, nil
}

func (s SSHAuthWithTimeout) String() string {
    return s.Auth.String()
}

func (s SSHAuthWithTimeout) Name() string {
    return s.Auth.Name()
}

And then calling clone like this:

    agent, err := tssh.NewSSHAgentAuth("<user>")

    repo, err := git.Clone(memory.NewStorage(), nil, &git.CloneOptions{
        Auth: SSHAuthWithTimeout{Auth: agent, Timeout: 3 * time.Second},
        URL:  URL,
    })