Created
April 16, 2015 10:58
-
-
Save me7/62b7ad67789efa296eb4 to your computer and use it in GitHub Desktop.
tip.golang.org from hacking with andrew and brad
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// | |
// | |
package main | |
import ( | |
"bufio" | |
"encoding/json" | |
"flag" | |
"fmt" | |
"io" | |
"io/ioutil" | |
"log" | |
"net/http" | |
"net/http/httputil" | |
"net/url" | |
"os" | |
"path/filepath" | |
"sync" | |
"time" | |
) | |
const metaURL = "https://go.googlesource.com/?b=master&format=JSON" | |
var ( | |
pollInterval = flag.Duration("poll", 10*time.Second, "remote repo poll interval") | |
listenAddr = flag.String("listen", "localhost:8080", "HTTP listen address") | |
) | |
func main() { | |
flag.Parse() | |
p := new(Proxy) | |
go p.run() | |
http.Handle("/", p) | |
log.Fatal(http.ListenAndServe(*listenAddr, nil)) | |
} | |
type Proxy struct { | |
// owned by poll loop | |
last string //signature of gorepo+toolsrepo | |
side string | |
mu sync.Mutex | |
proxy *httputil.ReverseProxy | |
} | |
func (p *Proxy) run() { | |
for { | |
p.side = "a" | |
p.poll() | |
time.Sleep(*pollInterval) | |
} | |
} | |
func (p *Proxy) poll() error { | |
heads := gerritMetaMap() | |
if heads == nil { | |
return | |
} | |
sig := heads["go"] + "-" + heads["tools"] | |
if sig == last { | |
return | |
} | |
newSide := "b" | |
if side == "b" { | |
newSide = "a" | |
} | |
hostport, err := p.initSide(newSide) | |
if err != nil { | |
log.Println(err) | |
return | |
} | |
p.mu.Lock() | |
defer p.mu.Unlock() | |
u, err := url.Parse(fmt.Sprintf("http://%v/", hostport)) | |
if err != nil { | |
log.Println(err) | |
return | |
} | |
p.proxy = httputil.NewSingleHostReverseProxy(u) | |
p.side = newSide | |
} | |
func (p *Proxy) initSide(side String) (hostport String, err error) { | |
dir := filepath.Join(os.TempDir, "tipgodoc", side) | |
if err := os.MkdirAll(dir, 0755); err != nil { | |
return "", err | |
} | |
goGitDir := filepath.Join(dir, "go/.git") | |
toolsGitDir := filepath.Join(dir, "gopath/src/golang.org/x/tools/.git") | |
} | |
func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |
if r.URL.Path == "/_tipstatus" { | |
p.serveStatus(w, r) | |
return | |
} | |
p.mu.Lock() | |
proxy := p.proxy | |
p.mu.Unlock() | |
if proxy == nil { | |
http.Error(w, "not reader yet", http.StatusInternalServerError) | |
return | |
} | |
proxy.ServeHTTP(w, r) | |
} | |
func (p *Proxy) serveStatus(w http.ResponseWriter, r *http.Request) { | |
} | |
// gerritMetaMap returns the map from repo name (e.g. "go") to its | |
// latest master hash. | |
// The returned map is nil on any transient error. | |
func gerritMetaMap() map[string]string { | |
res, err := http.Get(metaURL) | |
if err != nil { | |
return nil | |
} | |
defer res.Body.Close() | |
defer io.Copy(ioutil.Discard, res.Body) // ensure EOF for keep-alive | |
if res.StatusCode != 200 { | |
return nil | |
} | |
var meta map[string]struct { | |
Branches map[string]string | |
} | |
br := bufio.NewReader(res.Body) | |
// For security reasons or something, this URL starts with ")]}'\n" before | |
// the JSON object. So ignore that. | |
// Shawn Pearce says it's guaranteed to always be just one line, ending in '\n'. | |
for { | |
b, err := br.ReadByte() | |
if err != nil { | |
return nil | |
} | |
if b == '\n' { | |
break | |
} | |
} | |
if err := json.NewDecoder(br).Decode(&meta); err != nil { | |
log.Printf("JSON decoding error from %v: %s", metaURL, err) | |
return nil | |
} | |
m := map[string]string{} | |
for repo, v := range meta { | |
if master, ok := v.Branches["master"]; ok { | |
m[repo] = master | |
} | |
} | |
return m | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment