示例#1
0
文件: handler.go 项目: felixanya/go
// commitHandler retrieves commit data or records a new commit.
//
// For GET requests it returns a Commit value for the specified
// packagePath and hash.
//
// For POST requests it reads a JSON-encoded Commit value from the request
// body and creates a new Commit entity. It also updates the "tip" Tag for
// each new commit at tip.
//
// This handler is used by a gobuilder process in -commit mode.
func commitHandler(r *http.Request) (interface{}, error) {
	c := appengine.NewContext(r)
	com := new(Commit)

	if r.Method == "GET" {
		com.PackagePath = r.FormValue("packagePath")
		com.Hash = r.FormValue("hash")
		if err := datastore.Get(c, com.Key(c), com); err != nil {
			return nil, fmt.Errorf("getting Commit: %v", err)
		}
		return com, nil
	}
	if r.Method != "POST" {
		return nil, errBadMethod(r.Method)
	}

	// POST request
	defer r.Body.Close()
	if err := json.NewDecoder(r.Body).Decode(com); err != nil {
		return nil, fmt.Errorf("decoding Body: %v", err)
	}
	if len(com.Desc) > maxDatastoreStringLen {
		com.Desc = com.Desc[:maxDatastoreStringLen]
	}
	if err := com.Valid(); err != nil {
		return nil, fmt.Errorf("validating Commit: %v", err)
	}
	defer cache.Tick(c)
	tx := func(c appengine.Context) error {
		return addCommit(c, com)
	}
	return nil, datastore.RunInTransaction(c, tx, nil)
}
示例#2
0
// perfResultHandler records a becnhmarking result.
func perfResultHandler(r *http.Request) (interface{}, error) {
	defer r.Body.Close()
	if r.Method != "POST" {
		return nil, errBadMethod(r.Method)
	}

	req := new(PerfRequest)
	if err := json.NewDecoder(r.Body).Decode(req); err != nil {
		return nil, fmt.Errorf("decoding Body: %v", err)
	}

	c := contextForRequest(r)
	defer cache.Tick(c)

	// store the text files if supplied
	for i, a := range req.Artifacts {
		hash, err := PutLog(c, a.Body)
		if err != nil {
			return nil, fmt.Errorf("putting Log: %v", err)
		}
		req.Artifacts[i].Body = hash
	}
	tx := func(c appengine.Context) error {
		return addPerfResult(c, r, req)
	}
	return nil, datastore.RunInTransaction(c, tx, nil)
}
示例#3
0
func initHandler(w http.ResponseWriter, r *http.Request) {
	d := dashboardForRequest(r)
	c := d.Context(appengine.NewContext(r))
	defer cache.Tick(c)
	for _, p := range d.Packages {
		err := datastore.Get(c, p.Key(c), new(Package))
		if _, ok := err.(*datastore.ErrFieldMismatch); ok {
			// Some fields have been removed, so it's okay to ignore this error.
			err = nil
		}
		if err == nil {
			continue
		} else if err != datastore.ErrNoSuchEntity {
			logErr(w, r, err)
			return
		}
		if _, err := datastore.Put(c, p.Key(c), p); err != nil {
			logErr(w, r, err)
			return
		}
	}

	// Create secret key.
	key.Secret(c)

	fmt.Fprint(w, "OK")
}
示例#4
0
// resultHandler records a build result.
// It reads a JSON-encoded Result value from the request body,
// creates a new Result entity, and updates the relevant Commit entity.
// If the Log field is not empty, resultHandler creates a new Log entity
// and updates the LogHash field before putting the Commit entity.
func resultHandler(r *http.Request) (interface{}, error) {
	if r.Method != "POST" {
		return nil, errBadMethod(r.Method)
	}

	// For now, the gccgo builders are using the old stuff.
	// TODO(adg,cmang): remove this exception when gccgo is updated.
	if dashboardForRequest(r) != gccgoDash {
		v, _ := strconv.Atoi(r.FormValue("version"))
		if v != builderVersion {
			return nil, fmt.Errorf("rejecting POST from builder; need version %v", builderVersion)
		}
	}

	c := contextForRequest(r)
	res := new(Result)
	defer r.Body.Close()
	if err := json.NewDecoder(r.Body).Decode(res); err != nil {
		return nil, fmt.Errorf("decoding Body: %v", err)
	}
	if err := res.Valid(); err != nil {
		return nil, fmt.Errorf("validating Result: %v", err)
	}
	defer cache.Tick(c)
	// store the Log text if supplied
	if len(res.Log) > 0 {
		hash, err := PutLog(c, res.Log)
		if err != nil {
			return nil, fmt.Errorf("putting Log: %v", err)
		}
		res.LogHash = hash
	}
	tx := func(c appengine.Context) error {
		// check Package exists
		if _, err := GetPackage(c, res.PackagePath); err != nil {
			return fmt.Errorf("GetPackage: %v", err)
		}
		// put Result
		if _, err := datastore.Put(c, res.Key(c), res); err != nil {
			return fmt.Errorf("putting Result: %v", err)
		}
		// add Result to Commit
		com := &Commit{PackagePath: res.PackagePath, Hash: res.Hash}
		if err := com.AddResult(c, res); err != nil {
			return fmt.Errorf("AddResult: %v", err)
		}
		// Send build failure notifications, if necessary.
		// Note this must run after the call AddResult, which
		// populates the Commit's ResultData field.
		return notifyOnFailure(c, com, res.Builder)
	}
	return nil, datastore.RunInTransaction(c, tx, nil)
}
示例#5
0
文件: init.go 项目: joninvski/go
func initHandler(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	defer cache.Tick(c)
	for _, p := range defaultPackages {
		if err := datastore.Get(c, p.Key(c), new(Package)); err == nil {
			continue
		} else if err != datastore.ErrNoSuchEntity {
			logErr(w, r, err)
			return
		}
		if _, err := datastore.Put(c, p.Key(c), p); err != nil {
			logErr(w, r, err)
			return
		}
	}
	fmt.Fprint(w, "OK")
}
示例#6
0
文件: init.go 项目: rdterner/build
func initHandler(w http.ResponseWriter, r *http.Request) {
	d := dashboardForRequest(r)
	c := d.Context(appengine.NewContext(r))
	defer cache.Tick(c)
	for _, p := range d.Packages {
		err := datastore.Get(c, p.Key(c), new(Package))
		if _, ok := err.(*datastore.ErrFieldMismatch); ok {
			// Some fields have been removed, so it's okay to ignore this error.
			err = nil
		}
		if err == nil {
			continue
		} else if err != datastore.ErrNoSuchEntity {
			logErr(w, r, err)
			return
		}
		p.NextNum = 1 // So we can add the first commit.
		if _, err := datastore.Put(c, p.Key(c), p); err != nil {
			logErr(w, r, err)
			return
		}
	}

	// Create secret key.
	key.Secret(c)

	// Create dummy config values.
	initConfig(c)

	// Populate Go 1.4 tag. This is for bootstrapping the new feature of
	// building sub-repos against the stable release.
	// TODO(adg): remove this after Go 1.5 is released, at which point the
	// build system will pick up on the new release tag automatically.
	t := &Tag{
		Kind: "release",
		Name: "release-branch.go1.4",
		Hash: "883bc6ed0ea815293fe6309d66f967ea60630e87", // Go 1.4.2
	}
	if _, err := datastore.Put(c, t.Key(c), t); err != nil {
		logErr(w, r, err)
		return
	}

	fmt.Fprint(w, "OK")
}
示例#7
0
文件: handler.go 项目: 4honor/obdi
// commitHandler retrieves commit data or records a new commit.
//
// For GET requests it returns a Commit value for the specified
// packagePath and hash.
//
// For POST requests it reads a JSON-encoded Commit value from the request
// body and creates a new Commit entity. It also updates the "tip" Tag for
// each new commit at tip.
//
// This handler is used by a gobuilder process in -commit mode.
func commitHandler(r *http.Request) (interface{}, error) {
	c := contextForRequest(r)
	com := new(Commit)

	if r.Method == "GET" {
		com.PackagePath = r.FormValue("packagePath")
		com.Hash = r.FormValue("hash")
		if err := datastore.Get(c, com.Key(c), com); err != nil {
			return nil, fmt.Errorf("getting Commit: %v", err)
		}
		// Strip potentially large and unnecessary fields.
		com.ResultData = nil
		com.PerfResults = nil
		return com, nil
	}
	if r.Method != "POST" {
		return nil, errBadMethod(r.Method)
	}
	if !isMasterKey(c, r.FormValue("key")) {
		return nil, errors.New("can only POST commits with master key")
	}

	// POST request
	body, err := ioutil.ReadAll(r.Body)
	r.Body.Close()
	if err != nil {
		return nil, fmt.Errorf("reading Body: %v", err)
	}
	if !bytes.Contains(body, needsBenchmarkingBytes) {
		c.Warningf("old builder detected at %v", r.RemoteAddr)
		return nil, fmt.Errorf("rejecting old builder request, body does not contain %s: %q", needsBenchmarkingBytes, body)
	}
	if err := json.Unmarshal(body, com); err != nil {
		return nil, fmt.Errorf("unmarshaling body %q: %v", body, err)
	}
	com.Desc = limitStringLength(com.Desc, maxDatastoreStringLen)
	if err := com.Valid(); err != nil {
		return nil, fmt.Errorf("validating Commit: %v", err)
	}
	defer cache.Tick(c)
	tx := func(c appengine.Context) error {
		return addCommit(c, com)
	}
	return nil, datastore.RunInTransaction(c, tx, nil)
}
示例#8
0
// tagHandler records a new tag. It reads a JSON-encoded Tag value from the
// request body and updates the Tag entity for the Kind of tag provided.
//
// This handler is used by a gobuilder process in -commit mode.
func tagHandler(r *http.Request) (interface{}, error) {
	if r.Method != "POST" {
		return nil, errBadMethod(r.Method)
	}

	t := new(Tag)
	defer r.Body.Close()
	if err := json.NewDecoder(r.Body).Decode(t); err != nil {
		return nil, err
	}
	if err := t.Valid(); err != nil {
		return nil, err
	}
	c := contextForRequest(r)
	defer cache.Tick(c)
	_, err := datastore.Put(c, t.Key(c), t)
	return nil, err
}
示例#9
0
// clearResultsHandler purges the last commitsPerPage results for the given builder.
// It optionally takes a comma-separated list of specific hashes to clear.
func clearResultsHandler(r *http.Request) (interface{}, error) {
	if r.Method != "POST" {
		return nil, errBadMethod(r.Method)
	}
	builder := r.FormValue("builder")
	if builder == "" {
		return nil, errors.New("must specify a builder")
	}
	clearAll := r.FormValue("hash") == ""
	hash := strings.Split(r.FormValue("hash"), ",")

	c := contextForRequest(r)
	defer cache.Tick(c)
	pkg := (&Package{}).Key(c) // TODO(adg): support clearing sub-repos
	err := datastore.RunInTransaction(c, func(c appengine.Context) error {
		var coms []*Commit
		keys, err := datastore.NewQuery("Commit").
			Ancestor(pkg).
			Order("-Num").
			Limit(commitsPerPage).
			GetAll(c, &coms)
		if err != nil {
			return err
		}
		var rKeys []*datastore.Key
		for _, com := range coms {
			if !(clearAll || contains(hash, com.Hash)) {
				continue
			}
			r := com.Result(builder, "")
			if r == nil {
				continue
			}
			com.RemoveResult(r)
			rKeys = append(rKeys, r.Key(c))
		}
		_, err = datastore.PutMulti(c, keys, coms)
		if err != nil {
			return err
		}
		return datastore.DeleteMulti(c, rKeys)
	}, nil)
	return nil, err
}
示例#10
0
// resultHandler records a build result.
// It reads a JSON-encoded Result value from the request body,
// creates a new Result entity, and updates the relevant Commit entity.
// If the Log field is not empty, resultHandler creates a new Log entity
// and updates the LogHash field before putting the Commit entity.
func resultHandler(r *http.Request) (interface{}, error) {
	if r.Method != "POST" {
		return nil, errBadMethod(r.Method)
	}

	c := contextForRequest(r)
	res := new(Result)
	defer r.Body.Close()
	if err := json.NewDecoder(r.Body).Decode(res); err != nil {
		return nil, fmt.Errorf("decoding Body: %v", err)
	}
	if err := res.Valid(); err != nil {
		return nil, fmt.Errorf("validating Result: %v", err)
	}
	defer cache.Tick(c)
	// store the Log text if supplied
	if len(res.Log) > 0 {
		hash, err := PutLog(c, res.Log)
		if err != nil {
			return nil, fmt.Errorf("putting Log: %v", err)
		}
		res.LogHash = hash
	}
	tx := func(c appengine.Context) error {
		// check Package exists
		if _, err := GetPackage(c, res.PackagePath); err != nil {
			return fmt.Errorf("GetPackage: %v", err)
		}
		// put Result
		if _, err := datastore.Put(c, res.Key(c), res); err != nil {
			return fmt.Errorf("putting Result: %v", err)
		}
		// add Result to Commit
		com := &Commit{PackagePath: res.PackagePath, Hash: res.Hash}
		if err := com.AddResult(c, res); err != nil {
			return fmt.Errorf("AddResult: %v", err)
		}
		// Send build failure notifications, if necessary.
		// Note this must run after the call AddResult, which
		// populates the Commit's ResultData field.
		return notifyOnFailure(c, com, res.Builder)
	}
	return nil, datastore.RunInTransaction(c, tx, nil)
}
示例#11
0
// UpdatePerfConfig updates the PerfConfig entity with results of benchmarking.
// Returns whether it's a benchmark that we have not yet seem on the builder.
func UpdatePerfConfig(c appengine.Context, r *http.Request, req *PerfRequest) (newBenchmark bool, err error) {
	pc, err := GetPerfConfig(c, r)
	if err != nil {
		return false, err
	}

	modified := false
	add := func(arr *[]string, str string) {
		for _, s := range *arr {
			if s == str {
				return
			}
		}
		*arr = append(*arr, str)
		modified = true
		return
	}

	BenchProcs := strings.Split(req.Benchmark, "-")
	benchmark := BenchProcs[0]
	procs := "1"
	if len(BenchProcs) > 1 {
		procs = BenchProcs[1]
	}

	add(&pc.BuilderBench, req.Builder+"|"+benchmark)
	newBenchmark = modified
	add(&pc.BuilderProcs, req.Builder+"|"+procs)
	for _, m := range req.Metrics {
		add(&pc.BenchMetric, benchmark+"|"+m.Type)
	}

	if modified {
		if _, err := datastore.Put(c, PerfConfigKey(c), pc); err != nil {
			return false, fmt.Errorf("putting PerfConfig: %v", err)
		}
		cache.Tick(c)
	}
	return newBenchmark, nil
}
示例#12
0
// commitHandler retrieves commit data or records a new commit.
//
// For GET requests it returns a Commit value for the specified
// packagePath and hash.
//
// For POST requests it reads a JSON-encoded Commit value from the request
// body and creates a new Commit entity. It also updates the "tip" Tag for
// each new commit at tip.
//
// This handler is used by a gobuilder process in -commit mode.
func commitHandler(r *http.Request) (interface{}, error) {
	c := contextForRequest(r)
	com := new(Commit)

	if r.Method == "GET" {
		com.PackagePath = r.FormValue("packagePath")
		com.Hash = r.FormValue("hash")
		if err := datastore.Get(c, com.Key(c), com); err != nil {
			return nil, fmt.Errorf("getting Commit: %v", err)
		}
		// Strip potentially large and unnecessary fields.
		com.ResultData = nil
		com.PerfResults = nil
		return com, nil
	}
	if r.Method != "POST" {
		return nil, errBadMethod(r.Method)
	}
	if !isMasterKey(c, r.FormValue("key")) {
		return nil, errors.New("can only POST commits with master key")
	}

	// POST request
	defer r.Body.Close()
	if err := json.NewDecoder(r.Body).Decode(com); err != nil {
		return nil, fmt.Errorf("decoding Body: %v", err)
	}
	com.Desc = limitStringLength(com.Desc, maxDatastoreStringLen)
	if err := com.Valid(); err != nil {
		return nil, fmt.Errorf("validating Commit: %v", err)
	}
	defer cache.Tick(c)
	tx := func(c appengine.Context) error {
		return addCommit(c, com)
	}
	return nil, datastore.RunInTransaction(c, tx, nil)
}
示例#13
0
// commitHandler retrieves commit data or records a new commit.
//
// For GET requests it returns a Commit value for the specified
// packagePath and hash.
//
// For POST requests it reads a JSON-encoded Commit value from the request
// body and creates a new Commit entity. It also updates the "tip" Tag for
// each new commit at tip.
//
// This handler is used by a gobuilder process in -commit mode.
func commitHandler(r *http.Request) (interface{}, error) {
	c := contextForRequest(r)
	com := new(Commit)

	if r.Method == "GET" {
		com.PackagePath = r.FormValue("packagePath")
		com.Hash = r.FormValue("hash")
		err := datastore.Get(c, com.Key(c), com)
		if com.Num == 0 && com.Desc == "" {
			// Perf builder might have written an incomplete Commit.
			// Pretend it doesn't exist, so that we can get complete details.
			err = datastore.ErrNoSuchEntity
		}
		if err != nil {
			if err == datastore.ErrNoSuchEntity {
				// This error string is special.
				// The commit watcher expects it.
				// Do not change it.
				return nil, errors.New("Commit not found")
			}
			return nil, fmt.Errorf("getting Commit: %v", err)
		}
		if com.Num == 0 {
			// Corrupt state which shouldn't happen but does.
			// Return an error so builders' commit loops will
			// be willing to retry submitting this commit.
			return nil, errors.New("in datastore with zero Num")
		}
		if com.Desc == "" || com.User == "" {
			// Also shouldn't happen, but at least happened
			// once on a single commit when trying to fix data
			// in the datastore viewer UI?
			return nil, errors.New("missing field")
		}
		// Strip potentially large and unnecessary fields.
		com.ResultData = nil
		com.PerfResults = nil
		return com, nil
	}
	if r.Method != "POST" {
		return nil, errBadMethod(r.Method)
	}
	if !isMasterKey(c, r.FormValue("key")) {
		return nil, errors.New("can only POST commits with master key")
	}

	// For now, the commit watcher doesn't support gccgo.
	// TODO(adg,cmang): remove this exception when gccgo is supported.
	if dashboardForRequest(r) != gccgoDash {
		v, _ := strconv.Atoi(r.FormValue("version"))
		if v != watcherVersion {
			return nil, fmt.Errorf("rejecting POST from commit watcher; need version %v", watcherVersion)
		}
	}

	// POST request
	body, err := ioutil.ReadAll(r.Body)
	r.Body.Close()
	if err != nil {
		return nil, fmt.Errorf("reading Body: %v", err)
	}
	if !bytes.Contains(body, needsBenchmarkingBytes) {
		c.Warningf("old builder detected at %v", r.RemoteAddr)
		return nil, fmt.Errorf("rejecting old builder request, body does not contain %s: %q", needsBenchmarkingBytes, body)
	}
	if err := json.Unmarshal(body, com); err != nil {
		return nil, fmt.Errorf("unmarshaling body %q: %v", body, err)
	}
	com.Desc = limitStringLength(com.Desc, maxDatastoreStringLen)
	if err := com.Valid(); err != nil {
		return nil, fmt.Errorf("validating Commit: %v", err)
	}
	defer cache.Tick(c)
	tx := func(c appengine.Context) error {
		return addCommit(c, com)
	}
	return nil, datastore.RunInTransaction(c, tx, nil)
}