| Index: go/src/infra/tools/cipd/fetcher.go
|
| diff --git a/go/src/infra/tools/cipd/fetcher.go b/go/src/infra/tools/cipd/fetcher.go
|
| deleted file mode 100644
|
| index 43a0d13982f4a8b85554bc3c3d6645476f1d8cba..0000000000000000000000000000000000000000
|
| --- a/go/src/infra/tools/cipd/fetcher.go
|
| +++ /dev/null
|
| @@ -1,217 +0,0 @@
|
| -// Copyright 2014 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -package cipd
|
| -
|
| -import (
|
| - "fmt"
|
| - "io"
|
| - "io/ioutil"
|
| - "net/http"
|
| - "os"
|
| - "path/filepath"
|
| - "time"
|
| -
|
| - "infra/libs/logging"
|
| -)
|
| -
|
| -// FetchInstanceOptions contains parameters for FetchInstance function.
|
| -type FetchInstanceOptions struct {
|
| - // ServiceURL is root URL of the backend service, or "" to use default service.
|
| - ServiceURL string
|
| - // Client is http.Client to use to make requests, default is http.DefaultClient.
|
| - Client *http.Client
|
| - // Log is a logger to use for logs, default is logging.DefaultLogger.
|
| - Log logging.Logger
|
| -
|
| - // PackageName is a name of the package to fetch.
|
| - PackageName string
|
| - // InstanceID identifies an instance of the package to fetch.
|
| - InstanceID string
|
| - // Output is where to write the fetched data to. Must be nil when used with FetchAndDeployInstance.
|
| - Output io.WriteSeeker
|
| -}
|
| -
|
| -// FetchInstance downloads package instance file from the repository.
|
| -func FetchInstance(options FetchInstanceOptions) (err error) {
|
| - // Fill in default options.
|
| - if options.ServiceURL == "" {
|
| - options.ServiceURL = DefaultServiceURL()
|
| - }
|
| - if options.Client == nil {
|
| - options.Client = http.DefaultClient
|
| - }
|
| - if options.Log == nil {
|
| - options.Log = logging.DefaultLogger
|
| - }
|
| - log := options.Log
|
| - remote := newRemoteService(options.Client, options.ServiceURL, log)
|
| -
|
| - // Logs the error before returning it.
|
| - defer func() {
|
| - if err != nil {
|
| - log.Errorf("cipd: failed to fetch %s (%s)", options.PackageName, err)
|
| - }
|
| - }()
|
| -
|
| - // Grab fetch URL.
|
| - log.Infof("cipd: resolving %s:%s", options.PackageName, options.InstanceID)
|
| - fetchInfo, err := remote.fetchInstance(options.PackageName, options.InstanceID)
|
| - if err != nil {
|
| - return
|
| - }
|
| -
|
| - // reportProgress print fetch progress, throttling the reports rate.
|
| - var prevProgress int64 = 1000
|
| - var prevReportTs time.Time
|
| - reportProgress := func(read int64, total int64) {
|
| - now := time.Now()
|
| - progress := read * 100 / total
|
| - if progress < prevProgress || read == total || now.Sub(prevReportTs) > 5*time.Second {
|
| - log.Infof("cipd: fetching %s: %d%%", options.InstanceID, progress)
|
| - prevReportTs = now
|
| - prevProgress = progress
|
| - }
|
| - }
|
| -
|
| - // download is a separate function to be able to use deferred close.
|
| - download := func(out io.WriteSeeker, src io.ReadCloser, totalLen int64) error {
|
| - defer src.Close()
|
| - log.Infof("cipd: fetching %s (%.1f Mb)", options.InstanceID, float32(totalLen)/1024.0/1024.0)
|
| - reportProgress(0, totalLen)
|
| - _, err := io.Copy(out, &readerWithProgress{
|
| - reader: src,
|
| - callback: func(read int64) { reportProgress(read, totalLen) },
|
| - })
|
| - if err == nil {
|
| - log.Infof("cipd: successfully fetched %s", options.InstanceID)
|
| - }
|
| - return err
|
| - }
|
| -
|
| - // Download the actual data (several attempts).
|
| - maxAttempts := 10
|
| - for attempt := 0; attempt < maxAttempts; attempt++ {
|
| - // Rewind output to zero offset.
|
| - _, err = options.Output.Seek(0, os.SEEK_SET)
|
| - if err != nil {
|
| - return
|
| - }
|
| -
|
| - // Send the request.
|
| - log.Infof("cipd: initiating the fetch")
|
| - var req *http.Request
|
| - var resp *http.Response
|
| - req, err = http.NewRequest("GET", fetchInfo.FetchURL, nil)
|
| - if err != nil {
|
| - return
|
| - }
|
| - req.Header.Set("User-Agent", userAgent())
|
| - resp, err = options.Client.Do(req)
|
| - if err != nil {
|
| - return
|
| - }
|
| -
|
| - // Transient error, retry.
|
| - if resp.StatusCode == 408 || resp.StatusCode >= 500 {
|
| - resp.Body.Close()
|
| - log.Warningf("cipd: transient HTTP error %d while fetching the file", resp.StatusCode)
|
| - continue
|
| - }
|
| -
|
| - // Fatal error, abort.
|
| - if resp.StatusCode >= 400 {
|
| - resp.Body.Close()
|
| - return fmt.Errorf("Server replied with HTTP code %d", resp.StatusCode)
|
| - }
|
| -
|
| - // Try to fetch.
|
| - err = download(options.Output, resp.Body, resp.ContentLength)
|
| - if err != nil {
|
| - log.Warningf("cipd: transient error fetching the file: %s", err)
|
| - continue
|
| - }
|
| -
|
| - // Success.
|
| - err = nil
|
| - return
|
| - }
|
| -
|
| - err = fmt.Errorf("All %d fetch attempts failed", maxAttempts)
|
| - return
|
| -}
|
| -
|
| -// FetchAndDeployInstance fetches the package instance and deploys it into
|
| -// a site root. It doesn't check whether the instance is already deployed.
|
| -// options.Output field is not used and must be set to nil.
|
| -func FetchAndDeployInstance(root string, options FetchInstanceOptions) error {
|
| - // Be paranoid.
|
| - err := ValidatePackageName(options.PackageName)
|
| - if err != nil {
|
| - return err
|
| - }
|
| - err = ValidateInstanceID(options.InstanceID)
|
| - if err != nil {
|
| - return err
|
| - }
|
| -
|
| - // This field is not supported.
|
| - if options.Output != nil {
|
| - return fmt.Errorf("Passed non-nil Output to FetchAndDeployInstance")
|
| - }
|
| -
|
| - // Use temp file for storing package file. Delete it when done.
|
| - var instance PackageInstance
|
| - tempPath := filepath.Join(root, siteServiceDir, "tmp")
|
| - err = os.MkdirAll(tempPath, 0777)
|
| - if err != nil {
|
| - return err
|
| - }
|
| - f, err := ioutil.TempFile(tempPath, options.InstanceID)
|
| - if err != nil {
|
| - return err
|
| - }
|
| - defer func() {
|
| - // Instance takes ownership of the file, no need to close it separately.
|
| - if instance == nil {
|
| - f.Close()
|
| - }
|
| - os.Remove(f.Name())
|
| - }()
|
| -
|
| - // Fetch the package data to the provided storage.
|
| - options.Output = f
|
| - err = FetchInstance(options)
|
| - if err != nil {
|
| - return err
|
| - }
|
| -
|
| - // Open the instance, verify the instance ID.
|
| - instance, err = OpenInstance(f, options.InstanceID)
|
| - if err != nil {
|
| - return err
|
| - }
|
| - defer instance.Close()
|
| -
|
| - // Deploy it. 'defer' will take care of removing the temp file if needed.
|
| - _, err = DeployInstance(root, instance)
|
| - return err
|
| -}
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -
|
| -// readerWithProgress is io.Reader that calls callback whenever something is
|
| -// read from it.
|
| -type readerWithProgress struct {
|
| - reader io.Reader
|
| - total int64
|
| - callback func(total int64)
|
| -}
|
| -
|
| -func (r *readerWithProgress) Read(p []byte) (int, error) {
|
| - n, err := r.reader.Read(p)
|
| - r.total += int64(n)
|
| - r.callback(r.total)
|
| - return n, err
|
| -}
|
|
|