package migrate import ( "bufio" "fmt" "io" nurl "net/url" "strings" "time" ) // MultiError holds multiple errors. type MultiError struct { Errs []error } // NewMultiError returns an error type holding multiple errors. func NewMultiError(errs ...error) MultiError { compactErrs := make([]error, 0) for _, e := range errs { if e != nil { compactErrs = append(compactErrs, e) } } return MultiError{compactErrs} } // Error implements error. Mulitple errors are concatenated with 'and's. func (m MultiError) Error() string { var strs = make([]string, 0) for _, e := range m.Errs { if len(e.Error()) > 0 { strs = append(strs, e.Error()) } } return strings.Join(strs, " and ") } // suint safely converts int to uint // see https://goo.gl/wEcqof // see https://goo.gl/pai7Dr func suint(n int) uint { if n < 0 { panic(fmt.Sprintf("suint(%v) expects input >= 0", n)) } return uint(n) } // newSlowReader turns an io.ReadCloser into a slow io.ReadCloser. // Use this to simulate a slow internet connection. func newSlowReader(r io.ReadCloser) io.ReadCloser { return &slowReader{ rx: r, reader: bufio.NewReader(r), } } type slowReader struct { rx io.ReadCloser reader *bufio.Reader } func (b *slowReader) Read(p []byte) (n int, err error) { time.Sleep(10 * time.Millisecond) c, err := b.reader.ReadByte() if err != nil { return 0, err } else { copy(p, []byte{c}) return 1, nil } } func (b *slowReader) Close() error { return b.rx.Close() } var errNoScheme = fmt.Errorf("no scheme") // schemeFromUrl returns the scheme from a URL string func schemeFromUrl(url string) (string, error) { u, err := nurl.Parse(url) if err != nil { return "", err } if len(u.Scheme) == 0 { return "", errNoScheme } return u.Scheme, nil }