func WithTransport(t *http.Transport) Opts {
	return func(r *retryable) {
		r.httpClient = &http.Client{Transport: t}
	}
}
WithTransport uses a specific http transport with retryable requests
package retryable
import (
	"bytes"
	"context"
	"sync"
	_ "crypto/sha256"
	_ "crypto/sha512"
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"time"
	digest "github.com/opencontainers/go-digest"
	"github.com/sirupsen/logrus"
)
type Retryable interface {
	DoRequest(ctx context.Context, method string, u []url.URL, opts ...OptsReq) (Response, error)
	BackoffClear()
	BackoffUntil() time.Time
}
type Response interface {
	io.ReadCloser
	HTTPResponse() *http.Response
	HTTPResponses() ([]*http.Response, error)
}
type Auth interface {
	AddScope(host, scope string) error
	HandleResponse(*http.Response) error
	UpdateRequest(*http.Request) error
}
type Opts func(*retryable)
type OptsReq func(*request)
type retryable struct {
	httpClient    *http.Client
	auth          Auth
	rootCAPool    [][]byte
	limit         int
	delayInit     time.Duration
	delayMax      time.Duration
	backoffNeeded bool
	backoffCur    int
	backoffUntil  time.Time
	log           *logrus.Logger
	useragent     string
	mu            sync.Mutex
}
var defaultDelayInit, _ = time.ParseDuration("1s")
var defaultDelayMax, _ = time.ParseDuration("30s")
var defaultLimit = 3
func NewRetryable(opts ...Opts) Retryable {
	r := &retryable{
		httpClient: &http.Client{},
		limit:      defaultLimit,
		delayInit:  defaultDelayInit,
		delayMax:   defaultDelayMax,
		log:        &logrus.Logger{Out: ioutil.Discard},
		rootCAPool: [][]byte{},
	}
	for _, opt := range opts {
		opt(r)
	}
	if len(r.rootCAPool) > 0 {
		var tlsc *tls.Config
		if r.httpClient.Transport == nil {
			r.httpClient.Transport = &http.Transport{}
		}
		t, ok := r.httpClient.Transport.(*http.Transport)
		if ok {
			if t.TLSClientConfig != nil {
				tlsc = t.TLSClientConfig.Clone()
			} else {
				tlsc = &tls.Config{}
			}
			if tlsc.RootCAs == nil {
				rootPool, err := x509.SystemCertPool()
				if err != nil {
					r.log.WithFields(logrus.Fields{
						"err": err,
					}).Warn("Failed to load system cert pool")
				}
				tlsc.RootCAs = rootPool
			}
			for _, ca := range r.rootCAPool {
				if ok := tlsc.RootCAs.AppendCertsFromPEM(ca); !ok {
					r.log.WithFields(logrus.Fields{
						"cert": string(ca),
					}).Warn("Failed to load root certificate")
				}
			}
			t.TLSClientConfig = tlsc
			r.httpClient.Transport = t
		}
	}
	return r
}
func WithAuth(auth Auth) Opts {
	return func(r *retryable) {
		r.auth = auth
	}
}
func WithCerts(certs [][]byte) Opts {
	return func(r *retryable) {
		for _, c := range certs {
			r.rootCAPool = append(r.rootCAPool, c)
		}
	}
}
func WithCertFiles(files []string) Opts {
	return func(r *retryable) {
		for _, f := range files {
			c, err := ioutil.ReadFile(f)
			if err != nil {
				r.log.WithFields(logrus.Fields{
					"err":  err,
					"file": f,
				}).Warn("Failed to read certificate")
			} else {
				r.rootCAPool = append(r.rootCAPool, c)
			}
		}
	}
}
func WithDelay(delayInit time.Duration, delayMax time.Duration) Opts {
	return func(r *retryable) {
		if delayInit > 0 {
			r.delayInit = delayInit
		}
		if delayMax > r.delayInit {
			r.delayMax = delayMax
		} else if delayMax > 0 {
			r.delayMax = r.delayInit
		} else {
			r.delayMax = r.delayInit * 30
		}
	}
}
func WithHTTPClient(h *http.Client) Opts {
	return func(r *retryable) {
		r.httpClient = h
	}
}
func WithLimit(l int) Opts {
	return func(r *retryable) {
		if l > 0 {
			r.limit = l
		}
	}
}
func WithLog(log *logrus.Logger) Opts {
	return func(r *retryable) {
		r.log = log
	}
}