1
0
mirror of https://github.com/golang/go synced 2024-11-22 04:34:39 -07:00

dashboard: update to go1beta

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/5624056
This commit is contained in:
Andrew Gerrand 2012-02-06 09:26:32 +11:00
parent c06bd52a2e
commit 22185aed74
9 changed files with 78 additions and 77 deletions

View File

@ -6,7 +6,7 @@
application: golang-org application: golang-org
version: build version: build
runtime: go runtime: go
api_version: 3 api_version: go1beta
handlers: handlers:
- url: /static - url: /static

View File

@ -8,11 +8,12 @@ import (
"bytes" "bytes"
"compress/gzip" "compress/gzip"
"crypto/sha1" "crypto/sha1"
"errors"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"os"
"strings" "strings"
"time"
"appengine" "appengine"
"appengine/datastore" "appengine/datastore"
@ -41,7 +42,7 @@ func (p *Package) Key(c appengine.Context) *datastore.Key {
} }
// LastCommit returns the most recent Commit for this Package. // LastCommit returns the most recent Commit for this Package.
func (p *Package) LastCommit(c appengine.Context) (*Commit, os.Error) { func (p *Package) LastCommit(c appengine.Context) (*Commit, error) {
var commits []*Commit var commits []*Commit
_, err := datastore.NewQuery("Commit"). _, err := datastore.NewQuery("Commit").
Ancestor(p.Key(c)). Ancestor(p.Key(c)).
@ -58,7 +59,7 @@ func (p *Package) LastCommit(c appengine.Context) (*Commit, os.Error) {
} }
// GetPackage fetches a Package by path from the datastore. // GetPackage fetches a Package by path from the datastore.
func GetPackage(c appengine.Context, path string) (*Package, os.Error) { func GetPackage(c appengine.Context, path string) (*Package, error) {
p := &Package{Path: path} p := &Package{Path: path}
err := datastore.Get(c, p.Key(c), p) err := datastore.Get(c, p.Key(c), p)
if err == datastore.ErrNoSuchEntity { if err == datastore.ErrNoSuchEntity {
@ -80,7 +81,7 @@ type Commit struct {
User string User string
Desc string `datastore:",noindex"` Desc string `datastore:",noindex"`
Time datastore.Time Time time.Time
// ResultData is the Data string of each build Result for this Commit. // ResultData is the Data string of each build Result for this Commit.
// For non-Go commits, only the Results for the current Go tip, weekly, // For non-Go commits, only the Results for the current Go tip, weekly,
@ -100,19 +101,19 @@ func (com *Commit) Key(c appengine.Context) *datastore.Key {
return datastore.NewKey(c, "Commit", key, 0, p.Key(c)) return datastore.NewKey(c, "Commit", key, 0, p.Key(c))
} }
func (c *Commit) Valid() os.Error { func (c *Commit) Valid() error {
if !validHash(c.Hash) { if !validHash(c.Hash) {
return os.NewError("invalid Hash") return errors.New("invalid Hash")
} }
if c.ParentHash != "" && !validHash(c.ParentHash) { // empty is OK if c.ParentHash != "" && !validHash(c.ParentHash) { // empty is OK
return os.NewError("invalid ParentHash") return errors.New("invalid ParentHash")
} }
return nil return nil
} }
// AddResult adds the denormalized Reuslt data to the Commit's Result field. // AddResult adds the denormalized Reuslt data to the Commit's Result field.
// It must be called from inside a datastore transaction. // It must be called from inside a datastore transaction.
func (com *Commit) AddResult(c appengine.Context, r *Result) os.Error { func (com *Commit) AddResult(c appengine.Context, r *Result) error {
if err := datastore.Get(c, com.Key(c), com); err != nil { if err := datastore.Get(c, com.Key(c), com); err != nil {
return fmt.Errorf("getting Commit: %v", err) return fmt.Errorf("getting Commit: %v", err)
} }
@ -192,12 +193,12 @@ func (r *Result) Key(c appengine.Context) *datastore.Key {
return datastore.NewKey(c, "Result", key, 0, p.Key(c)) return datastore.NewKey(c, "Result", key, 0, p.Key(c))
} }
func (r *Result) Valid() os.Error { func (r *Result) Valid() error {
if !validHash(r.Hash) { if !validHash(r.Hash) {
return os.NewError("invalid Hash") return errors.New("invalid Hash")
} }
if r.PackagePath != "" && !validHash(r.GoHash) { if r.PackagePath != "" && !validHash(r.GoHash) {
return os.NewError("invalid GoHash") return errors.New("invalid GoHash")
} }
return nil return nil
} }
@ -214,7 +215,7 @@ type Log struct {
CompressedLog []byte CompressedLog []byte
} }
func (l *Log) Text() ([]byte, os.Error) { func (l *Log) Text() ([]byte, error) {
d, err := gzip.NewReader(bytes.NewBuffer(l.CompressedLog)) d, err := gzip.NewReader(bytes.NewBuffer(l.CompressedLog))
if err != nil { if err != nil {
return nil, fmt.Errorf("reading log data: %v", err) return nil, fmt.Errorf("reading log data: %v", err)
@ -226,14 +227,14 @@ func (l *Log) Text() ([]byte, os.Error) {
return b, nil return b, nil
} }
func PutLog(c appengine.Context, text string) (hash string, err os.Error) { func PutLog(c appengine.Context, text string) (hash string, err error) {
h := sha1.New() h := sha1.New()
io.WriteString(h, text) io.WriteString(h, text)
b := new(bytes.Buffer) b := new(bytes.Buffer)
z, _ := gzip.NewWriterLevel(b, gzip.BestCompression) z, _ := gzip.NewWriterLevel(b, gzip.BestCompression)
io.WriteString(z, text) io.WriteString(z, text)
z.Close() z.Close()
hash = fmt.Sprintf("%x", h.Sum()) hash = fmt.Sprintf("%x", h.Sum(nil))
key := datastore.NewKey(c, "Log", hash, 0, nil) key := datastore.NewKey(c, "Log", hash, 0, nil)
_, err = datastore.Put(c, key, &Log{b.Bytes()}) _, err = datastore.Put(c, key, &Log{b.Bytes()})
return return
@ -252,29 +253,29 @@ func (t *Tag) Key(c appengine.Context) *datastore.Key {
return datastore.NewKey(c, "Tag", t.Kind, 0, p.Key(c)) return datastore.NewKey(c, "Tag", t.Kind, 0, p.Key(c))
} }
func (t *Tag) Valid() os.Error { func (t *Tag) Valid() error {
if t.Kind != "weekly" && t.Kind != "release" && t.Kind != "tip" { if t.Kind != "weekly" && t.Kind != "release" && t.Kind != "tip" {
return os.NewError("invalid Kind") return errors.New("invalid Kind")
} }
if !validHash(t.Hash) { if !validHash(t.Hash) {
return os.NewError("invalid Hash") return errors.New("invalid Hash")
} }
return nil return nil
} }
// Commit returns the Commit that corresponds with this Tag. // Commit returns the Commit that corresponds with this Tag.
func (t *Tag) Commit(c appengine.Context) (*Commit, os.Error) { func (t *Tag) Commit(c appengine.Context) (*Commit, error) {
com := &Commit{Hash: t.Hash} com := &Commit{Hash: t.Hash}
err := datastore.Get(c, com.Key(c), com) err := datastore.Get(c, com.Key(c), com)
return com, err return com, err
} }
// GetTag fetches a Tag by name from the datastore. // GetTag fetches a Tag by name from the datastore.
func GetTag(c appengine.Context, tag string) (*Tag, os.Error) { func GetTag(c appengine.Context, tag string) (*Tag, error) {
t := &Tag{Kind: tag} t := &Tag{Kind: tag}
if err := datastore.Get(c, t.Key(c), t); err != nil { if err := datastore.Get(c, t.Key(c), t); err != nil {
if err == datastore.ErrNoSuchEntity { if err == datastore.ErrNoSuchEntity {
return nil, os.NewError("tag not found: " + tag) return nil, errors.New("tag not found: " + tag)
} }
return nil, err return nil, err
} }
@ -286,11 +287,11 @@ func GetTag(c appengine.Context, tag string) (*Tag, os.Error) {
// Packages returns packages of the specified kind. // Packages returns packages of the specified kind.
// Kind must be one of "external" or "subrepo". // Kind must be one of "external" or "subrepo".
func Packages(c appengine.Context, kind string) ([]*Package, os.Error) { func Packages(c appengine.Context, kind string) ([]*Package, error) {
switch kind { switch kind {
case "external", "subrepo": case "external", "subrepo":
default: default:
return nil, os.NewError(`kind must be one of "external" or "subrepo"`) return nil, errors.New(`kind must be one of "external" or "subrepo"`)
} }
var pkgs []*Package var pkgs []*Package
q := datastore.NewQuery("Package").Filter("Kind=", kind) q := datastore.NewQuery("Package").Filter("Kind=", kind)

View File

@ -6,10 +6,11 @@ package build
import ( import (
"crypto/hmac" "crypto/hmac"
"crypto/md5"
"encoding/json"
"errors"
"fmt" "fmt"
"http" "net/http"
"json"
"os"
"appengine" "appengine"
"appengine/datastore" "appengine/datastore"
@ -28,7 +29,7 @@ const commitsPerPage = 30
// each new commit at tip. // each new commit at tip.
// //
// This handler is used by a gobuilder process in -commit mode. // This handler is used by a gobuilder process in -commit mode.
func commitHandler(r *http.Request) (interface{}, os.Error) { func commitHandler(r *http.Request) (interface{}, error) {
c := appengine.NewContext(r) c := appengine.NewContext(r)
com := new(Commit) com := new(Commit)
@ -56,7 +57,7 @@ func commitHandler(r *http.Request) (interface{}, os.Error) {
return nil, fmt.Errorf("validating Commit: %v", err) return nil, fmt.Errorf("validating Commit: %v", err)
} }
defer cache.Tick(c) defer cache.Tick(c)
tx := func(c appengine.Context) os.Error { tx := func(c appengine.Context) error {
return addCommit(c, com) return addCommit(c, com)
} }
return nil, datastore.RunInTransaction(c, tx, nil) return nil, datastore.RunInTransaction(c, tx, nil)
@ -64,7 +65,7 @@ func commitHandler(r *http.Request) (interface{}, os.Error) {
// addCommit adds the Commit entity to the datastore and updates the tip Tag. // addCommit adds the Commit entity to the datastore and updates the tip Tag.
// It must be run inside a datastore transaction. // It must be run inside a datastore transaction.
func addCommit(c appengine.Context, com *Commit) os.Error { func addCommit(c appengine.Context, com *Commit) error {
var tc Commit // temp value so we don't clobber com var tc Commit // temp value so we don't clobber com
err := datastore.Get(c, com.Key(c), &tc) err := datastore.Get(c, com.Key(c), &tc)
if err != datastore.ErrNoSuchEntity { if err != datastore.ErrNoSuchEntity {
@ -94,7 +95,7 @@ func addCommit(c appengine.Context, com *Commit) os.Error {
return fmt.Errorf("testing for parent Commit: %v", err) return fmt.Errorf("testing for parent Commit: %v", err)
} }
if n == 0 { if n == 0 {
return os.NewError("parent commit not found") return errors.New("parent commit not found")
} }
} }
// update the tip Tag if this is the Go repo // update the tip Tag if this is the Go repo
@ -115,7 +116,7 @@ func addCommit(c appengine.Context, com *Commit) os.Error {
// request body and updates the Tag entity for the Kind of tag provided. // request body and updates the Tag entity for the Kind of tag provided.
// //
// This handler is used by a gobuilder process in -commit mode. // This handler is used by a gobuilder process in -commit mode.
func tagHandler(r *http.Request) (interface{}, os.Error) { func tagHandler(r *http.Request) (interface{}, error) {
if r.Method != "POST" { if r.Method != "POST" {
return nil, errBadMethod(r.Method) return nil, errBadMethod(r.Method)
} }
@ -143,7 +144,7 @@ type Todo struct {
// todoHandler returns the next action to be performed by a builder. // todoHandler returns the next action to be performed by a builder.
// It expects "builder" and "kind" query parameters and returns a *Todo value. // It expects "builder" and "kind" query parameters and returns a *Todo value.
// Multiple "kind" parameters may be specified. // Multiple "kind" parameters may be specified.
func todoHandler(r *http.Request) (interface{}, os.Error) { func todoHandler(r *http.Request) (interface{}, error) {
c := appengine.NewContext(r) c := appengine.NewContext(r)
now := cache.Now(c) now := cache.Now(c)
key := "build-todo-" + r.Form.Encode() key := "build-todo-" + r.Form.Encode()
@ -151,7 +152,7 @@ func todoHandler(r *http.Request) (interface{}, os.Error) {
if cache.Get(r, now, key, &todo) { if cache.Get(r, now, key, &todo) {
return todo, nil return todo, nil
} }
var err os.Error var err error
builder := r.FormValue("builder") builder := r.FormValue("builder")
for _, kind := range r.Form["kind"] { for _, kind := range r.Form["kind"] {
var data interface{} var data interface{}
@ -183,7 +184,7 @@ func todoHandler(r *http.Request) (interface{}, os.Error) {
// If provided with non-empty packagePath and goHash args, it scans the first // If provided with non-empty packagePath and goHash args, it scans the first
// 20 Commits in Num-descending order for the specified packagePath and // 20 Commits in Num-descending order for the specified packagePath and
// returns the first that doesn't have a Result for this builder and goHash. // returns the first that doesn't have a Result for this builder and goHash.
func buildTodo(c appengine.Context, builder, packagePath, goHash string) (interface{}, os.Error) { func buildTodo(c appengine.Context, builder, packagePath, goHash string) (interface{}, error) {
p, err := GetPackage(c, packagePath) p, err := GetPackage(c, packagePath)
if err != nil { if err != nil {
return nil, err return nil, err
@ -251,7 +252,7 @@ func buildTodo(c appengine.Context, builder, packagePath, goHash string) (interf
// packagesHandler returns a list of the non-Go Packages monitored // packagesHandler returns a list of the non-Go Packages monitored
// by the dashboard. // by the dashboard.
func packagesHandler(r *http.Request) (interface{}, os.Error) { func packagesHandler(r *http.Request) (interface{}, error) {
kind := r.FormValue("kind") kind := r.FormValue("kind")
c := appengine.NewContext(r) c := appengine.NewContext(r)
now := cache.Now(c) now := cache.Now(c)
@ -273,7 +274,7 @@ func packagesHandler(r *http.Request) (interface{}, os.Error) {
// creates a new Result entity, and updates the relevant Commit entity. // creates a new Result entity, and updates the relevant Commit entity.
// If the Log field is not empty, resultHandler creates a new Log entity // If the Log field is not empty, resultHandler creates a new Log entity
// and updates the LogHash field before putting the Commit entity. // and updates the LogHash field before putting the Commit entity.
func resultHandler(r *http.Request) (interface{}, os.Error) { func resultHandler(r *http.Request) (interface{}, error) {
if r.Method != "POST" { if r.Method != "POST" {
return nil, errBadMethod(r.Method) return nil, errBadMethod(r.Method)
} }
@ -296,7 +297,7 @@ func resultHandler(r *http.Request) (interface{}, os.Error) {
} }
res.LogHash = hash res.LogHash = hash
} }
tx := func(c appengine.Context) os.Error { tx := func(c appengine.Context) error {
// check Package exists // check Package exists
if _, err := GetPackage(c, res.PackagePath); err != nil { if _, err := GetPackage(c, res.PackagePath); err != nil {
return fmt.Errorf("GetPackage: %v", err) return fmt.Errorf("GetPackage: %v", err)
@ -338,7 +339,7 @@ func logHandler(w http.ResponseWriter, r *http.Request) {
w.Write(b) w.Write(b)
} }
type dashHandler func(*http.Request) (interface{}, os.Error) type dashHandler func(*http.Request) (interface{}, error)
type dashResponse struct { type dashResponse struct {
Response interface{} Response interface{}
@ -349,7 +350,7 @@ type dashResponse struct {
// the request has an unsuitable method. // the request has an unsuitable method.
type errBadMethod string type errBadMethod string
func (e errBadMethod) String() string { func (e errBadMethod) Error() string {
return "bad method: " + string(e) return "bad method: " + string(e)
} }
@ -363,14 +364,14 @@ func AuthHandler(h dashHandler) http.HandlerFunc {
// request body when calling r.FormValue. // request body when calling r.FormValue.
r.Form = r.URL.Query() r.Form = r.URL.Query()
var err os.Error var err error
var resp interface{} var resp interface{}
// Validate key query parameter for POST requests only. // Validate key query parameter for POST requests only.
key := r.FormValue("key") key := r.FormValue("key")
builder := r.FormValue("builder") builder := r.FormValue("builder")
if r.Method == "POST" && !validKey(c, key, builder) { if r.Method == "POST" && !validKey(c, key, builder) {
err = os.NewError("invalid key: " + key) err = errors.New("invalid key: " + key)
} }
// Call the original HandlerFunc and return the response. // Call the original HandlerFunc and return the response.
@ -382,7 +383,7 @@ func AuthHandler(h dashHandler) http.HandlerFunc {
dashResp := &dashResponse{Response: resp} dashResp := &dashResponse{Response: resp}
if err != nil { if err != nil {
c.Errorf("%v", err) c.Errorf("%v", err)
dashResp.Error = err.String() dashResp.Error = err.Error()
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err = json.NewEncoder(w).Encode(dashResp); err != nil { if err = json.NewEncoder(w).Encode(dashResp); err != nil {
@ -394,7 +395,7 @@ func AuthHandler(h dashHandler) http.HandlerFunc {
func keyHandler(w http.ResponseWriter, r *http.Request) { func keyHandler(w http.ResponseWriter, r *http.Request) {
builder := r.FormValue("builder") builder := r.FormValue("builder")
if builder == "" { if builder == "" {
logErr(w, r, os.NewError("must supply builder in query string")) logErr(w, r, errors.New("must supply builder in query string"))
return return
} }
c := appengine.NewContext(r) c := appengine.NewContext(r)
@ -433,12 +434,12 @@ func validKey(c appengine.Context, key, builder string) bool {
} }
func builderKey(c appengine.Context, builder string) string { func builderKey(c appengine.Context, builder string) string {
h := hmac.NewMD5([]byte(secretKey(c))) h := hmac.New(md5.New, []byte(secretKey(c)))
h.Write([]byte(builder)) h.Write([]byte(builder))
return fmt.Sprintf("%x", h.Sum()) return fmt.Sprintf("%x", h.Sum(nil))
} }
func logErr(w http.ResponseWriter, r *http.Request, err os.Error) { func logErr(w http.ResponseWriter, r *http.Request, err error) {
appengine.NewContext(r).Errorf("Error: %v", err) appengine.NewContext(r).Errorf("Error: %v", err)
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
fmt.Fprint(w, "Error: ", err) fmt.Fprint(w, "Error: ", err)

View File

@ -6,7 +6,7 @@ package build
import ( import (
"fmt" "fmt"
"http" "net/http"
"appengine" "appengine"
"appengine/datastore" "appengine/datastore"

View File

@ -55,7 +55,7 @@ func secretKey(c appengine.Context) string {
datastore.Put(c, theKey.Key(c), &theKey.BuilderKey) datastore.Put(c, theKey.Key(c), &theKey.BuilderKey)
return theKey.Secret return theKey.Secret
} }
panic("cannot load builder key: " + err.String()) panic("cannot load builder key: " + err.Error())
} }
return theKey.Secret return theKey.Secret

View File

@ -10,10 +10,9 @@ import (
"appengine/delay" "appengine/delay"
"appengine/mail" "appengine/mail"
"bytes" "bytes"
"encoding/gob"
"fmt" "fmt"
"gob" "text/template"
"os"
"template"
) )
const ( const (
@ -30,7 +29,7 @@ const (
// //
// This must be run in a datastore transaction, and the provided *Commit must // This must be run in a datastore transaction, and the provided *Commit must
// have been retrieved from the datastore within that transaction. // have been retrieved from the datastore within that transaction.
func notifyOnFailure(c appengine.Context, com *Commit, builder string) os.Error { func notifyOnFailure(c appengine.Context, com *Commit, builder string) error {
// TODO(adg): implement notifications for packages // TODO(adg): implement notifications for packages
if com.PackagePath != "" { if com.PackagePath != "" {
return nil return nil
@ -73,7 +72,7 @@ func notifyOnFailure(c appengine.Context, com *Commit, builder string) os.Error
broken = com broken = com
} }
} }
var err os.Error var err error
if broken != nil && !broken.FailNotificationSent { if broken != nil && !broken.FailNotificationSent {
c.Infof("%s is broken commit; notifying", broken.Hash) c.Infof("%s is broken commit; notifying", broken.Hash)
sendFailMailLater.Call(c, broken, builder) // add task to queue sendFailMailLater.Call(c, broken, builder) // add task to queue
@ -84,7 +83,7 @@ func notifyOnFailure(c appengine.Context, com *Commit, builder string) os.Error
} }
// firstMatch executes the query q and loads the first entity into v. // firstMatch executes the query q and loads the first entity into v.
func firstMatch(c appengine.Context, q *datastore.Query, v interface{}) os.Error { func firstMatch(c appengine.Context, q *datastore.Query, v interface{}) error {
t := q.Limit(1).Run(c) t := q.Limit(1).Run(c)
_, err := t.Next(v) _, err := t.Next(v)
if err == datastore.Done { if err == datastore.Done {
@ -96,7 +95,9 @@ func firstMatch(c appengine.Context, q *datastore.Query, v interface{}) os.Error
var ( var (
sendFailMailLater = delay.Func("sendFailMail", sendFailMail) sendFailMailLater = delay.Func("sendFailMail", sendFailMail)
sendFailMailTmpl = template.Must( sendFailMailTmpl = template.Must(
template.New("notify").Funcs(tmplFuncs).ParseFile("build/notify.txt"), template.New("notify.txt").
Funcs(template.FuncMap(tmplFuncs)).
ParseFiles("build/notify.txt"),
) )
) )

View File

@ -10,15 +10,15 @@ import (
"appengine" "appengine"
"appengine/datastore" "appengine/datastore"
"bytes" "bytes"
"encoding/json"
"errors"
"fmt" "fmt"
"http"
"http/httptest"
"io" "io"
"json" "net/http"
"os" "net/http/httptest"
"net/url"
"strings" "strings"
"time" "time"
"url"
) )
func init() { func init() {
@ -41,14 +41,14 @@ var testPackages = []*Package{
testPackage, testPackage,
} }
var tCommitTime = time.Seconds() - 60*60*24*7 var tCommitTime = time.Now().Add(-time.Hour * 24 * 7)
func tCommit(hash, parentHash string) *Commit { func tCommit(hash, parentHash string) *Commit {
tCommitTime += 60 * 60 * 12 // each commit should have a different time tCommitTime.Add(time.Hour) // each commit should have a different time
return &Commit{ return &Commit{
Hash: hash, Hash: hash,
ParentHash: parentHash, ParentHash: parentHash,
Time: datastore.Time(tCommitTime * 1e6), Time: tCommitTime,
User: "adg", User: "adg",
Desc: "change description", Desc: "change description",
} }
@ -233,9 +233,9 @@ func testHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "PASS") fmt.Fprint(w, "PASS")
} }
func nukeEntities(c appengine.Context, kinds []string) os.Error { func nukeEntities(c appengine.Context, kinds []string) error {
if !appengine.IsDevAppServer() { if !appengine.IsDevAppServer() {
return os.NewError("can't nuke production data") return errors.New("can't nuke production data")
} }
var keys []*datastore.Key var keys []*datastore.Key
for _, kind := range kinds { for _, kind := range kinds {

View File

@ -9,14 +9,13 @@ package build
import ( import (
"bytes" "bytes"
"exp/template/html" "errors"
"http" "html/template"
"os" "net/http"
"regexp" "regexp"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
"template"
"appengine" "appengine"
"appengine/datastore" "appengine/datastore"
@ -25,7 +24,6 @@ import (
func init() { func init() {
http.HandleFunc("/", uiHandler) http.HandleFunc("/", uiHandler)
html.Escape(uiTemplate)
} }
// uiHandler draws the build status page. // uiHandler draws the build status page.
@ -96,7 +94,7 @@ type Pagination struct {
// goCommits gets a slice of the latest Commits to the Go repository. // goCommits gets a slice of the latest Commits to the Go repository.
// If page > 0 it paginates by commitsPerPage. // If page > 0 it paginates by commitsPerPage.
func goCommits(c appengine.Context, page int) ([]*Commit, os.Error) { func goCommits(c appengine.Context, page int) ([]*Commit, error) {
q := datastore.NewQuery("Commit"). q := datastore.NewQuery("Commit").
Ancestor((&Package{}).Key(c)). Ancestor((&Package{}).Key(c)).
Order("-Time"). Order("-Time").
@ -140,7 +138,7 @@ type PackageState struct {
} }
// TagStateByName fetches the results for all Go subrepos at the specified Tag. // TagStateByName fetches the results for all Go subrepos at the specified Tag.
func TagStateByName(c appengine.Context, name string) (*TagState, os.Error) { func TagStateByName(c appengine.Context, name string) (*TagState, error) {
tag, err := GetTag(c, name) tag, err := GetTag(c, name)
if err != nil { if err != nil {
return nil, err return nil, err
@ -173,7 +171,7 @@ type uiTemplateData struct {
} }
var uiTemplate = template.Must( var uiTemplate = template.Must(
template.New("ui").Funcs(tmplFuncs).ParseFile("build/ui.html"), template.New("ui.html").Funcs(tmplFuncs).ParseFiles("build/ui.html"),
) )
var tmplFuncs = template.FuncMap{ var tmplFuncs = template.FuncMap{
@ -293,13 +291,13 @@ func shortUser(user string) string {
var repoRe = regexp.MustCompile(`^code\.google\.com/p/([a-z0-9\-]+)(\.[a-z0-9\-]+)?$`) var repoRe = regexp.MustCompile(`^code\.google\.com/p/([a-z0-9\-]+)(\.[a-z0-9\-]+)?$`)
// repoURL returns the URL of a change at a Google Code repository or subrepo. // repoURL returns the URL of a change at a Google Code repository or subrepo.
func repoURL(hash, packagePath string) (string, os.Error) { func repoURL(hash, packagePath string) (string, error) {
if packagePath == "" { if packagePath == "" {
return "https://code.google.com/p/go/source/detail?r=" + hash, nil return "https://code.google.com/p/go/source/detail?r=" + hash, nil
} }
m := repoRe.FindStringSubmatch(packagePath) m := repoRe.FindStringSubmatch(packagePath)
if m == nil { if m == nil {
return "", os.NewError("unrecognized package: " + packagePath) return "", errors.New("unrecognized package: " + packagePath)
} }
url := "https://code.google.com/p/" + m[1] + "/source/detail?r=" + hash url := "https://code.google.com/p/" + m[1] + "/source/detail?r=" + hash
if len(m) > 2 { if len(m) > 2 {

View File

@ -6,7 +6,7 @@ package cache
import ( import (
"fmt" "fmt"
"http" "net/http"
"time" "time"
"appengine" "appengine"
@ -19,7 +19,7 @@ const (
expiry = 600 // 10 minutes expiry = 600 // 10 minutes
) )
func newTime() uint64 { return uint64(time.Seconds()) << 32 } func newTime() uint64 { return uint64(time.Now().Unix()) << 32 }
// Now returns the current logical datastore time to use for cache lookups. // Now returns the current logical datastore time to use for cache lookups.
func Now(c appengine.Context) uint64 { func Now(c appengine.Context) uint64 {