Skip to content

Instantly share code, notes, and snippets.

@imjasonh
Created December 12, 2012 18:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save imjasonh/4270274 to your computer and use it in GitHub Desktop.
Save imjasonh/4270274 to your computer and use it in GitHub Desktop.
Script to copy your GitHub Downloads to Google Cloud Storage
/*
First go to https://code.google.com/apis/console, create a project, enable Cloud Storage in the "Services"
tab. Enable billing and create a bucket via the online browser. Then, run this script.
Usage:
$ go build main.go -o copy_downloads && chmod +x copy_downloads && ./copy_downloads \
--repo=SomeGitHubUser/AndARepo
--bucket=google-storage-bucket-that-i-own
(Alternately, the build script is available at http://www.imjasonh.com/copy_downloads)
When you run this, a browser window will pop up requesting authorization to
write to your bucket, and when you accept the script will start copying.
*/
package main
import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/http/httptest"
"os/exec"
"time"
"code.google.com/p/goauth2/oauth"
"code.google.com/p/google-api-go-client/storage/v1beta1"
)
var (
githubRepo = flag.String("repo", "", "GitHub repo to fetch downloads for")
storageBucket = flag.String("bucket", "", "Google Storage bucket to copy to")
)
var googleConfig = &oauth.Config{
ClientId: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
Scope: storage.DevstorageFull_controlScope,
AuthURL: "https://accounts.google.com/o/oauth2/auth",
TokenURL: "https://accounts.google.com/o/oauth2/token",
}
type downloads []download
type download struct {
HtmlUrl string `json:"html_url"`
Name string
}
func main() {
flag.Parse()
if *githubRepo == "" {
log.Fatalln("GitHub repo is required")
return
}
if *storageBucket == "" {
log.Fatalln("Google Cloud Storage bucket is required")
return
}
resp, err := http.Get("https://api.github.com/repos/" + *githubRepo + "/downloads")
if err != nil {
log.Fatalln(err)
return
}
var downloads downloads
if err = json.NewDecoder(resp.Body).Decode(&downloads); err != nil {
data, _ := ioutil.ReadAll(resp.Body)
log.Fatalln(err, data)
return
}
if len(downloads) == 0 {
log.Println("No downloads in repo " + *githubRepo)
return
}
log.Println("# downloads to copy:", len(downloads))
googleToken := tokenFromWeb(googleConfig)
transport := &oauth.Transport{
Token: googleToken,
Config: googleConfig,
Transport: http.DefaultTransport,
}
service, err := storage.New(transport.Client())
if err != nil {
log.Fatalln(err)
return
}
for _, d := range downloads {
log.Println("Copying", d.HtmlUrl)
resp, err = http.Get(d.HtmlUrl)
if err != nil {
log.Fatalln(err)
return
}
if _, err := service.Objects.Insert(*storageBucket, &storage.Object{Name: d.Name}).Media(resp.Body).Do(); err != nil {
log.Fatalln("Failed to upload", err.Error())
return
}
if _, err = service.ObjectAccessControls.Insert(*storageBucket, d.Name, &storage.ObjectAccessControl{
Entity: "allUsers",
Role: "READER",
}).Do(); err != nil {
log.Fatalln("Failed to set ACL", err.Error())
return
}
url := "https://storage.googleapis.com/" + *storageBucket + "/" + d.Name
log.Println("Done:", url)
}
}
// Copied from OAuth sample app
func tokenFromWeb(config *oauth.Config) *oauth.Token {
ch := make(chan string)
randState := fmt.Sprintf("st%d", time.Now())
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
if req.URL.Path == "/favicon.ico" {
http.Error(rw, "", 404)
return
}
if req.FormValue("state") != randState {
log.Printf("State doesn't match: req = %#v", req)
http.Error(rw, "", 500)
return
}
if code := req.FormValue("code"); code != "" {
fmt.Fprintf(rw, "<h1>Success</h1>You can close this window now.")
rw.(http.Flusher).Flush()
ch <- code
return
}
log.Printf("no code")
http.Error(rw, "", 500)
}))
defer ts.Close()
config.RedirectURL = ts.URL
authUrl := config.AuthCodeURL(randState)
go openUrl(authUrl)
log.Printf("Authorize this app at: %s", authUrl)
code := <-ch
t := &oauth.Transport{
Config: config,
Transport: http.DefaultTransport,
}
_, err := t.Exchange(code)
if err != nil {
log.Fatalf("Token exchange error: %v", err)
}
return t.Token
}
func openUrl(url string) {
try := []string{"xdg-open", "google-chrome", "open"}
for _, bin := range try {
err := exec.Command(bin, url).Run()
if err == nil {
return
}
}
log.Printf("Error opening URL in browser.")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment