gitlab.com/jfprevost/gitlab-runner-notlscheck@v11.11.4+incompatible/commands/helpers/cache_extractor.go (about)

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