2015-04-07 08:20:55 +00:00
|
|
|
package bolt
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2015-04-10 16:14:02 +00:00
|
|
|
"encoding/binary"
|
2015-04-07 08:20:55 +00:00
|
|
|
"strconv"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/boltdb/bolt"
|
|
|
|
"github.com/drone/drone/common"
|
|
|
|
)
|
|
|
|
|
2015-04-15 05:04:38 +00:00
|
|
|
// Build gets the specified build number for the
|
|
|
|
// named repository and build number.
|
|
|
|
func (db *DB) Build(repo string, build int) (*common.Build, error) {
|
2015-04-07 08:20:55 +00:00
|
|
|
build_ := &common.Build{}
|
|
|
|
key := []byte(repo + "/" + strconv.Itoa(build))
|
2015-04-10 19:52:33 +00:00
|
|
|
|
|
|
|
err := db.View(func(t *bolt.Tx) error {
|
|
|
|
return get(t, bucketBuild, key, build_)
|
|
|
|
})
|
|
|
|
|
2015-04-07 08:20:55 +00:00
|
|
|
return build_, err
|
|
|
|
}
|
|
|
|
|
2015-04-15 05:04:38 +00:00
|
|
|
// BuildList gets a list of recent builds for the
|
2015-04-07 08:20:55 +00:00
|
|
|
// named repository.
|
2015-04-15 05:04:38 +00:00
|
|
|
func (db *DB) BuildList(repo string) ([]*common.Build, error) {
|
2015-04-11 06:11:41 +00:00
|
|
|
// TODO (bradrydzewski) we can do this more efficiently
|
|
|
|
var builds []*common.Build
|
2015-04-15 05:04:38 +00:00
|
|
|
build, err := db.BuildLast(repo)
|
2015-04-11 06:11:41 +00:00
|
|
|
if err == ErrKeyNotFound {
|
|
|
|
return builds, nil
|
|
|
|
} else if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = db.View(func(t *bolt.Tx) error {
|
|
|
|
pos := build.Number - 25
|
|
|
|
if pos < 1 {
|
|
|
|
pos = 1
|
|
|
|
}
|
|
|
|
for i := pos; i <= build.Number; i++ {
|
|
|
|
key := []byte(repo + "/" + strconv.Itoa(i))
|
|
|
|
build := &common.Build{}
|
|
|
|
err = get(t, bucketBuild, key, build)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
builds = append(builds, build)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
return builds, err
|
2015-04-07 08:20:55 +00:00
|
|
|
}
|
|
|
|
|
2015-04-15 05:04:38 +00:00
|
|
|
// BuildLast gets the last executed build for the
|
2015-04-07 08:20:55 +00:00
|
|
|
// named repository.
|
2015-04-15 05:04:38 +00:00
|
|
|
func (db *DB) BuildLast(repo string) (*common.Build, error) {
|
2015-04-11 05:22:55 +00:00
|
|
|
key := []byte(repo)
|
|
|
|
build := &common.Build{}
|
|
|
|
err := db.View(func(t *bolt.Tx) error {
|
|
|
|
raw := t.Bucket(bucketBuildSeq).Get(key)
|
2015-04-11 22:46:30 +00:00
|
|
|
if raw == nil {
|
|
|
|
return ErrKeyNotFound
|
|
|
|
}
|
2015-04-11 05:22:55 +00:00
|
|
|
num := binary.LittleEndian.Uint32(raw)
|
|
|
|
key = []byte(repo + "/" + strconv.FormatUint(uint64(num), 10))
|
|
|
|
return get(t, bucketBuild, key, build)
|
|
|
|
})
|
|
|
|
return build, err
|
2015-04-07 08:20:55 +00:00
|
|
|
}
|
|
|
|
|
2015-04-15 05:04:38 +00:00
|
|
|
// SetBuild inserts or updates a build for the named
|
|
|
|
// repository. The build number is incremented and
|
|
|
|
// assigned to the provided build.
|
|
|
|
func (db *DB) SetBuild(repo string, build *common.Build) error {
|
|
|
|
repokey := []byte(repo)
|
|
|
|
build.Updated = time.Now().UTC().Unix()
|
|
|
|
|
|
|
|
return db.Update(func(t *bolt.Tx) error {
|
|
|
|
|
|
|
|
if build.Number == 0 {
|
|
|
|
raw, err := raw(t, bucketBuildSeq, repokey)
|
|
|
|
|
|
|
|
var next_seq uint32
|
|
|
|
switch err {
|
|
|
|
case ErrKeyNotFound:
|
|
|
|
next_seq = 1
|
|
|
|
case nil:
|
|
|
|
next_seq = 1 + binary.LittleEndian.Uint32(raw)
|
|
|
|
default:
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// covert our seqno to raw value
|
|
|
|
raw = make([]byte, 4) // TODO(benschumacher) replace magic number 4 (uint32)
|
|
|
|
binary.LittleEndian.PutUint32(raw, next_seq)
|
|
|
|
err = t.Bucket(bucketBuildSeq).Put(repokey, raw)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// fill out the build structure
|
|
|
|
build.Number = int(next_seq)
|
|
|
|
build.Created = time.Now().UTC().Unix()
|
|
|
|
}
|
|
|
|
|
|
|
|
key := []byte(repo + "/" + strconv.Itoa(build.Number))
|
|
|
|
return update(t, bucketBuild, key, build)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Status returns the status for the given repository
|
|
|
|
// and build number.
|
|
|
|
func (db *DB) Status(repo string, build int, status string) (*common.Status, error) {
|
2015-04-07 08:20:55 +00:00
|
|
|
status_ := &common.Status{}
|
|
|
|
key := []byte(repo + "/" + strconv.Itoa(build) + "/" + status)
|
2015-04-10 19:52:33 +00:00
|
|
|
|
|
|
|
err := db.Update(func(t *bolt.Tx) error {
|
|
|
|
return update(t, bucketBuildStatus, key, status)
|
|
|
|
})
|
|
|
|
|
2015-04-07 08:20:55 +00:00
|
|
|
return status_, err
|
|
|
|
}
|
|
|
|
|
2015-04-15 05:04:38 +00:00
|
|
|
// StatusList returned a list of all build statues for
|
|
|
|
// the given repository and build number.
|
|
|
|
func (db *DB) StatusList(repo string, build int) ([]*common.Status, error) {
|
2015-04-07 08:20:55 +00:00
|
|
|
// TODO (bradrydzewski) explore efficiency of cursor vs index
|
|
|
|
|
|
|
|
statuses := []*common.Status{}
|
|
|
|
err := db.View(func(tx *bolt.Tx) error {
|
|
|
|
c := tx.Bucket(bucketBuildStatus).Cursor()
|
|
|
|
prefix := []byte(repo + "/" + strconv.Itoa(build) + "/")
|
|
|
|
for k, v := c.Seek(prefix); bytes.HasPrefix(k, prefix); k, v = c.Next() {
|
|
|
|
status := &common.Status{}
|
|
|
|
if err := decode(v, status); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
statuses = append(statuses, status)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
return statuses, err
|
|
|
|
}
|
|
|
|
|
2015-04-15 05:04:38 +00:00
|
|
|
// SetStatus inserts a new build status for the
|
2015-04-07 08:20:55 +00:00
|
|
|
// named repository and build number. If the status already
|
|
|
|
// exists an error is returned.
|
2015-04-15 05:04:38 +00:00
|
|
|
func (db *DB) SetStatus(repo string, build int, status *common.Status) error {
|
2015-04-07 08:20:55 +00:00
|
|
|
key := []byte(repo + "/" + strconv.Itoa(build) + "/" + status.Context)
|
2015-04-10 19:52:33 +00:00
|
|
|
|
|
|
|
return db.Update(func(t *bolt.Tx) error {
|
|
|
|
return update(t, bucketBuildStatus, key, status)
|
|
|
|
})
|
2015-04-07 08:20:55 +00:00
|
|
|
}
|