Commit 0627fa84 authored by Andrew Gerrand's avatar Andrew Gerrand

misc/makerelease: upload files to Google Cloud Storage

LGTM=bradfitz
R=jasonhall, bradfitz
CC=golang-codereviews
https://golang.org/cl/91700047
parent c038c38a
...@@ -12,13 +12,11 @@ import ( ...@@ -12,13 +12,11 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"compress/gzip" "compress/gzip"
"encoding/base64"
"flag" "flag"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"log" "log"
"mime/multipart"
"net/http" "net/http"
"os" "os"
"os/exec" "os/exec"
...@@ -27,6 +25,9 @@ import ( ...@@ -27,6 +25,9 @@ import (
"regexp" "regexp"
"runtime" "runtime"
"strings" "strings"
"code.google.com/p/goauth2/oauth"
"code.google.com/p/google-api-go-client/storage/v1beta2"
) )
var ( var (
...@@ -40,8 +41,10 @@ var ( ...@@ -40,8 +41,10 @@ var (
includeRace = flag.Bool("race", true, "build race detector packages") includeRace = flag.Bool("race", true, "build race detector packages")
versionOverride = flag.String("version", "", "override version name") versionOverride = flag.String("version", "", "override version name")
staticToolchain = flag.Bool("static", true, "try to build statically linked toolchain (only supported on ELF targets)") staticToolchain = flag.Bool("static", true, "try to build statically linked toolchain (only supported on ELF targets)")
tokenCache = flag.String("token", defaultCacheFile, "Authentication token cache file")
storageBucket = flag.String("bucket", "golang", "Cloud Storage Bucket")
username, password string // for Google Code upload defaultCacheFile = filepath.Join(os.Getenv("HOME"), ".makerelease-request-token")
) )
const ( const (
...@@ -119,6 +122,12 @@ var staticLinkAvailable = []string{ ...@@ -119,6 +122,12 @@ var staticLinkAvailable = []string{
var fileRe = regexp.MustCompile(`^(go[a-z0-9-.]+)\.(src|([a-z0-9]+)-([a-z0-9]+)(?:-([a-z0-9.]+))?)\.(tar\.gz|zip|pkg|msi)$`) var fileRe = regexp.MustCompile(`^(go[a-z0-9-.]+)\.(src|([a-z0-9]+)-([a-z0-9]+)(?:-([a-z0-9.]+))?)\.(tar\.gz|zip|pkg|msi)$`)
// OAuth2-authenticated HTTP client used to make calls to Cloud Storage.
var oauthClient *http.Client
// Builder key as specified in ~/.gobuildkey
var builderKey string
func main() { func main() {
flag.Usage = func() { flag.Usage = func() {
fmt.Fprintf(os.Stderr, "usage: %s [flags] targets...\n", os.Args[0]) fmt.Fprintf(os.Stderr, "usage: %s [flags] targets...\n", os.Args[0])
...@@ -135,7 +144,10 @@ func main() { ...@@ -135,7 +144,10 @@ func main() {
if *upload { if *upload {
if err := readCredentials(); err != nil { if err := readCredentials(); err != nil {
log.Println("readCredentials:", err) log.Fatalln("readCredentials:", err)
}
if err := setupOAuthClient(); err != nil {
log.Fatalln("setupOAuthClient:", err)
} }
} }
for _, targ := range flag.Args() { for _, targ := range flag.Args() {
...@@ -641,121 +653,56 @@ func (b *Build) env() []string { ...@@ -641,121 +653,56 @@ func (b *Build) env() []string {
} }
func (b *Build) Upload(version string, filename string) error { func (b *Build) Upload(version string, filename string) error {
// Prepare upload metadata. svc, err := storage.New(oauthClient)
var labels []string
os_, arch := b.OS, b.Arch
switch b.Arch {
case "386":
arch = "x86 32-bit"
case "amd64":
arch = "x86 64-bit"
}
if arch != "" {
labels = append(labels, "Arch-"+b.Arch)
}
var opsys, ftype string // labels
switch b.OS {
case "linux":
os_ = "Linux"
opsys = "Linux"
case "freebsd":
os_ = "FreeBSD"
opsys = "FreeBSD"
case "darwin":
os_ = "Mac OS X"
opsys = "OSX"
case "netbsd":
os_ = "NetBSD"
opsys = "NetBSD"
case "windows":
os_ = "Windows"
opsys = "Windows"
}
summary := fmt.Sprintf("%s %s (%s)", version, os_, arch)
switch {
case strings.HasSuffix(filename, ".msi"):
ftype = "Installer"
summary += " MSI installer"
case strings.HasSuffix(filename, ".pkg"):
ftype = "Installer"
summary += " PKG installer"
case strings.HasSuffix(filename, ".zip"):
ftype = "Archive"
summary += " ZIP archive"
case strings.HasSuffix(filename, ".tar.gz"):
ftype = "Archive"
summary += " tarball"
}
if b.Source {
ftype = "Source"
summary = fmt.Sprintf("%s (source only)", version)
}
if opsys != "" {
labels = append(labels, "OpSys-"+opsys)
}
if ftype != "" {
labels = append(labels, "Type-"+ftype)
}
if b.Label != "" {
labels = append(labels, b.Label)
}
if *addLabel != "" {
labels = append(labels, *addLabel)
}
// Put "Go" prefix on summary when it doesn't already begin with "go".
if !strings.HasPrefix(strings.ToLower(summary), "go") {
summary = "Go " + summary
}
// Open file to upload.
f, err := os.Open(filename)
if err != nil { if err != nil {
return err return err
} }
defer f.Close()
// Prepare multipart payload. obj := &storage.Object{
body := new(bytes.Buffer) Acl: []*storage.ObjectAccessControl{{Entity: "allUsers", Role: "READER"}},
w := multipart.NewWriter(body) Name: filename,
if err := w.WriteField("summary", summary); err != nil {
return err
}
for _, l := range labels {
if err := w.WriteField("label", l); err != nil {
return err
}
} }
fw, err := w.CreateFormFile("filename", filename) f, err := os.Open(filename)
if err != nil { if err != nil {
return err return err
} }
if _, err = io.Copy(fw, f); err != nil { defer f.Close()
return err _, err = svc.Objects.Insert(*storageBucket, obj).Media(f).Do()
}
if err := w.Close(); err != nil {
return err
}
// Send the file to Google Code.
req, err := http.NewRequest("POST", uploadURL, body)
if err != nil { if err != nil {
return err return err
} }
token := fmt.Sprintf("%s:%s", username, password)
token = base64.StdEncoding.EncodeToString([]byte(token))
req.Header.Set("Authorization", "Basic "+token)
req.Header.Set("Content-type", w.FormDataContentType())
resp, err := http.DefaultTransport.RoundTrip(req) return nil
if err != nil { }
return err
} func setupOAuthClient() error {
if resp.StatusCode/100 != 2 { config := &oauth.Config{
fmt.Fprintln(os.Stderr, "upload failed") ClientId: "999119582588-h7kpj5pcm6d9solh5lgrbusmvvk4m9dn.apps.googleusercontent.com",
defer resp.Body.Close() ClientSecret: "8YLFgOhXIELWbO",
io.Copy(os.Stderr, resp.Body) Scope: storage.DevstorageRead_writeScope,
return fmt.Errorf("upload: %s", resp.Status) AuthURL: "https://accounts.google.com/o/oauth2/auth",
TokenURL: "https://accounts.google.com/o/oauth2/token",
TokenCache: oauth.CacheFile(*tokenCache),
RedirectURL: "oob",
}
transport := &oauth.Transport{Config: config}
if token, err := config.TokenCache.Token(); err != nil {
url := transport.Config.AuthCodeURL("")
fmt.Println("Visit the following URL, obtain an authentication" +
"code, and enter it below.")
fmt.Println(url)
fmt.Print("Enter authentication code: ")
code := ""
if _, err := fmt.Scan(&code); err != nil {
return err
}
if _, err := transport.Exchange(code); err != nil {
return err
}
} else {
transport.Token = token
} }
oauthClient = transport.Client()
return nil return nil
} }
...@@ -785,21 +732,11 @@ func readCredentials() error { ...@@ -785,21 +732,11 @@ func readCredentials() error {
return err return err
} }
defer f.Close() defer f.Close()
r := bufio.NewReader(f) s := bufio.NewScanner(f)
for i := 0; i < 3; i++ { if s.Scan() {
b, _, err := r.ReadLine() builderKey = s.Text()
if err != nil {
return err
}
b = bytes.TrimSpace(b)
switch i {
case 1:
username = string(b)
case 2:
password = string(b)
}
} }
return nil return s.Err()
} }
func cp(dst, src string) error { func cp(dst, src string) error {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment