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 }