download.go
func FromURL(src *url.URL, w io.Writer, options Options) error {
	httpClient := getHTTPClient(options)
	var (
		err  error
		resp *http.Response
	)
	downloader := func() error {
		resp, err = httpClient.Get(src.String())
		if err != nil {
			return &retriableError{errors.Wrap(err, "Temporary download error")}
		}
		if resp.StatusCode != http.StatusOK {
			defer func() { _ = resp.Body.Close() }() // #nosec
			return errors.Errorf("received invalid status code: %d (expected %d)", resp.StatusCode, http.StatusOK)
		}
		return nil
	}
	retries := options.Retries
	if retries == 0 {
		retries = 5
	}
	if err = retryAfter(retries, downloader, options.RetryInterval); err != nil {
		return errors.Wrap(err, "download failed")
	}
	defer func() { _ = resp.Body.Close() }() // #nosec

	var (
		validator checksumValidator

		reader io.Reader = resp.Body
	)

	if options.ProgressBars != nil && resp.ContentLength > 0 {
		bar := newProgressBar(resp.ContentLength, options.ProgressBars.MaxWidth, options.ProgressBars.Writer)
		bar.Start()
		reader = bar.NewProxyReader(reader)
		defer func() {
			<-time.After(bar.RefreshRate)
			fmt.Println()
		}()
	}

	validator, reader, err = createValidatorReader(reader, options.ChecksumHash, httpClient, options.Checksum, path.Base(src.Path))
	if err != nil {
		return err
	}

	if _, err = io.Copy(w, reader); err != nil {
		return errors.Wrap(err, "failed to copy contents")
	}

	if !validator.validate() {
		return errors.New("checksum validation failed")
	}

	return nil
}
func FromURL(src *url.URL, w io.Writer, options Options) error {
	httpClient := getHTTPClient(options)
	var (
		err  error
		resp *http.Response
	)
	downloader := func() error {
		resp, err = httpClient.Get(src.String())
		if err != nil {
			return &retriableError{errors.Wrap(err, "Temporary download error")}
		}
		if resp.StatusCode != http.StatusOK {
			defer func() { _ = resp.Body.Close() }() // #nosec
			return errors.Errorf("received invalid status code: %d (expected %d)", resp.StatusCode, http.StatusOK)
		}
		return nil
	}
	retries := options.Retries
	if retries == 0 {
		retries = 5
	}
	if err = retryAfter(retries, downloader, options.RetryInterval); err != nil {
		return errors.Wrap(err, "download failed")
	}
	defer func() { _ = resp.Body.Close() }() // #nosec

	var (
		validator checksumValidator

		reader io.Reader = resp.Body
	)

	if options.ProgressBars != nil && resp.ContentLength > 0 {
		bar := newProgressBar(resp.ContentLength, options.ProgressBars.MaxWidth, options.ProgressBars.Writer)
		bar.Start()
		reader = bar.NewProxyReader(reader)
		defer func() {
			<-time.After(bar.RefreshRate)
			fmt.Println()
		}()
	}

	validator, reader, err = createValidatorReader(reader, options.ChecksumHash, httpClient, options.Checksum, path.Base(src.Path))
	if err != nil {
		return err
	}

	if _, err = io.Copy(w, reader); err != nil {
		return errors.Wrap(err, "failed to copy contents")
	}

	if !validator.validate() {
		return errors.New("checksum validation failed")
	}

	return nil
}
// FromURL downloads the specified `src` URL to `w` writer using
// the specified `Options`.