forked from mystiq/dex
120 lines
2.7 KiB
Go
120 lines
2.7 KiB
Go
|
package testserver
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"io/ioutil"
|
||
|
"log"
|
||
|
"net/http"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"runtime"
|
||
|
"strings"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
awsBaseURL = "https://s3.amazonaws.com/cockroach/cockroach"
|
||
|
latestSuffix = "LATEST"
|
||
|
localBinaryPath = "/var/tmp"
|
||
|
finishedFileMode = 0555
|
||
|
)
|
||
|
|
||
|
func binaryName() string {
|
||
|
return fmt.Sprintf("cockroach.%s-%s", runtime.GOOS, runtime.GOARCH)
|
||
|
}
|
||
|
|
||
|
func binaryNameWithSha(sha string) string {
|
||
|
return fmt.Sprintf("%s.%s", binaryName(), sha)
|
||
|
}
|
||
|
|
||
|
func binaryPath(sha string) string {
|
||
|
return filepath.Join(localBinaryPath, binaryNameWithSha(sha))
|
||
|
}
|
||
|
|
||
|
func latestMarkerURL() string {
|
||
|
return fmt.Sprintf("%s/%s.%s", awsBaseURL, binaryName(), latestSuffix)
|
||
|
}
|
||
|
|
||
|
func binaryURL(sha string) string {
|
||
|
return fmt.Sprintf("%s/%s.%s", awsBaseURL, binaryName(), sha)
|
||
|
}
|
||
|
|
||
|
func findLatestSha() (string, error) {
|
||
|
markerURL := latestMarkerURL()
|
||
|
marker, err := http.Get(markerURL)
|
||
|
if err != nil {
|
||
|
return "", fmt.Errorf("could not download %s: %s", markerURL)
|
||
|
}
|
||
|
if marker.StatusCode == 404 {
|
||
|
return "", fmt.Errorf("for 404 from GET %s: make sure OS and ARCH are supported",
|
||
|
markerURL)
|
||
|
} else if marker.StatusCode != 200 {
|
||
|
return "", fmt.Errorf("bad response got GET %s: %d (%s)",
|
||
|
markerURL, marker.StatusCode, marker.Status)
|
||
|
}
|
||
|
|
||
|
defer marker.Body.Close()
|
||
|
body, err := ioutil.ReadAll(marker.Body)
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
return strings.TrimSpace(string(body)), nil
|
||
|
}
|
||
|
|
||
|
func downloadFile(url, filePath string) error {
|
||
|
output, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0200)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("error creating %s: %s", filePath, "-", err)
|
||
|
}
|
||
|
defer output.Close()
|
||
|
|
||
|
log.Printf("downloading %s to %s, this may take some time", url, filePath)
|
||
|
|
||
|
response, err := http.Get(url)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("error downloading %s: %s", url, err)
|
||
|
}
|
||
|
defer response.Body.Close()
|
||
|
if response.StatusCode != 200 {
|
||
|
return fmt.Errorf("error downloading %s: %d (%s)", url, response.StatusCode, response.Status)
|
||
|
}
|
||
|
|
||
|
_, err = io.Copy(output, response.Body)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("problem downloading %s to %s: %s", url, filePath, err)
|
||
|
}
|
||
|
|
||
|
// Download was successful, add the rw bits.
|
||
|
return os.Chmod(filePath, finishedFileMode)
|
||
|
}
|
||
|
|
||
|
func downloadLatestBinary() (string, error) {
|
||
|
sha, err := findLatestSha()
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
|
||
|
localFile := binaryPath(sha)
|
||
|
for {
|
||
|
finfo, err := os.Stat(localFile)
|
||
|
if err != nil {
|
||
|
// File does not exist: download it.
|
||
|
break
|
||
|
}
|
||
|
// File already present: check mode.
|
||
|
if finfo.Mode().Perm() == finishedFileMode {
|
||
|
return localFile, nil
|
||
|
}
|
||
|
time.Sleep(time.Millisecond * 10)
|
||
|
}
|
||
|
|
||
|
err = downloadFile(binaryURL(sha), localFile)
|
||
|
if err != nil {
|
||
|
_ = os.Remove(localFile)
|
||
|
return "", err
|
||
|
}
|
||
|
|
||
|
return localFile, nil
|
||
|
}
|