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 }