github.com/alloyci/alloy-runner@v1.0.1-0.20180222164613-925503ccafd6/commands/helpers/cache_extractor.go (about)

     1  package helpers
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"io/ioutil"
     7  	"net/http"
     8  	"os"
     9  	"path/filepath"
    10  	"time"
    11  
    12  	"github.com/Sirupsen/logrus"
    13  	"github.com/urfave/cli"
    14  
    15  	"gitlab.com/gitlab-org/gitlab-runner/common"
    16  	"gitlab.com/gitlab-org/gitlab-runner/helpers/archives"
    17  	"gitlab.com/gitlab-org/gitlab-runner/helpers/formatter"
    18  	"gitlab.com/gitlab-org/gitlab-runner/helpers/url"
    19  )
    20  
    21  type CacheExtractorCommand struct {
    22  	retryHelper
    23  	File    string `long:"file" description:"The file containing your cache artifacts"`
    24  	URL     string `long:"url" description:"URL of remote cache resource"`
    25  	Timeout int    `long:"timeout" description:"Overall timeout for cache downloading request (in minutes)"`
    26  
    27  	client *CacheClient
    28  }
    29  
    30  func (c *CacheExtractorCommand) getClient() *CacheClient {
    31  	if c.client == nil {
    32  		c.client = NewCacheClient(c.Timeout)
    33  	}
    34  
    35  	return c.client
    36  }
    37  
    38  func (c *CacheExtractorCommand) download() (bool, error) {
    39  	os.MkdirAll(filepath.Dir(c.File), 0700)
    40  
    41  	file, err := ioutil.TempFile(filepath.Dir(c.File), "cache")
    42  	if err != nil {
    43  		return false, err
    44  	}
    45  	defer file.Close()
    46  	defer os.Remove(file.Name())
    47  
    48  	resp, err := c.getClient().Get(c.URL)
    49  	if err != nil {
    50  		return true, err
    51  	}
    52  	defer resp.Body.Close()
    53  
    54  	if resp.StatusCode == http.StatusNotFound {
    55  		return false, os.ErrNotExist
    56  	} else if resp.StatusCode/100 != 2 {
    57  		// Retry on server errors
    58  		retry := resp.StatusCode/100 == 5
    59  		return retry, fmt.Errorf("Received: %s", resp.Status)
    60  	}
    61  
    62  	fi, _ := os.Lstat(c.File)
    63  	date, _ := time.Parse(http.TimeFormat, resp.Header.Get("Last-Modified"))
    64  	if fi != nil && !date.After(fi.ModTime()) {
    65  		logrus.Infoln(filepath.Base(c.File), "is up to date")
    66  		return false, nil
    67  	}
    68  
    69  	logrus.Infoln("Downloading", filepath.Base(c.File), "from", url_helpers.CleanURL(c.URL))
    70  	_, err = io.Copy(file, resp.Body)
    71  	if err != nil {
    72  		return true, err
    73  	}
    74  	os.Chtimes(file.Name(), time.Now(), date)
    75  
    76  	err = os.Rename(file.Name(), c.File)
    77  	if err != nil {
    78  		return false, err
    79  	}
    80  	return false, nil
    81  }
    82  
    83  func (c *CacheExtractorCommand) Execute(context *cli.Context) {
    84  	formatter.SetRunnerFormatter()
    85  
    86  	if len(c.File) == 0 {
    87  		logrus.Fatalln("Missing cache file")
    88  	}
    89  
    90  	if c.URL != "" {
    91  		err := c.doRetry(c.download)
    92  		if err != nil {
    93  			logrus.Fatalln(err)
    94  		}
    95  	}
    96  
    97  	err := archives.ExtractZipFile(c.File)
    98  	if err != nil && !os.IsNotExist(err) {
    99  		logrus.Fatalln(err)
   100  	}
   101  }
   102  
   103  func init() {
   104  	common.RegisterCommand2("cache-extractor", "download and extract cache artifacts (internal)", &CacheExtractorCommand{
   105  		retryHelper: retryHelper{
   106  			Retry:     2,
   107  			RetryTime: time.Second,
   108  		},
   109  	})
   110  }