1package deps 2 3import ( 4 "crypto/sha256" 5 "encoding/hex" 6 "fmt" 7 "io" 8 "net/http" 9 "os" 10 "path" 11) 12 13func fetchIntoFile(url string, file *os.File) error { 14 resp, err := http.Get(url) 15 if err != nil { 16 return err 17 } 18 defer resp.Body.Close() 19 _, err = io.Copy(file, resp.Body) 20 return err 21} 22 23func fileSHA256(file *os.File) (string, error) { 24 file.Seek(0, 0) 25 hasher := sha256.New() 26 if _, err := io.Copy(hasher, file); err != nil { 27 return "", nil 28 } 29 return hex.EncodeToString(hasher.Sum(nil)), nil 30} 31 32// FetchURL fetches the specified URL into the specified file path, and returns 33// the SHA-256 hash of the file fetched. 34func FetchURL(url string, path string) (string, error) { 35 file, err := os.Create(path) 36 if err != nil { 37 return "", err 38 } 39 defer file.Close() 40 41 if err = fetchIntoFile(url, file); err != nil { 42 os.Remove(path) 43 return "", err 44 } 45 46 checksum, err := fileSHA256(file) 47 if err != nil { 48 os.Remove(path) 49 return "", err 50 } 51 52 return checksum, nil 53} 54 55// FetchEntry retrieves an existing WORKSPACE file entry into a specified directory, 56// verifies its checksum, and then returns the full path to the resulting file. 57func FetchEntry(entry *Entry, dir string) (string, error) { 58 filename := path.Join(dir, entry.SHA256+".tar.gz") 59 checksum, err := FetchURL(entry.URL, filename) 60 if err != nil { 61 return "", err 62 } 63 64 if checksum != entry.SHA256 { 65 os.Remove(filename) 66 return "", fmt.Errorf("SHA-256 mismatch: expected %s, got %s", entry.SHA256, checksum) 67 } 68 69 return filename, nil 70} 71