2020-10-11 14:12:48 +00:00
|
|
|
package z
|
|
|
|
|
|
|
|
import (
|
2020-10-14 23:35:46 +00:00
|
|
|
"os"
|
2020-10-15 21:44:55 +00:00
|
|
|
"sort"
|
2020-10-15 23:58:56 +00:00
|
|
|
"strings"
|
2020-10-11 14:12:48 +00:00
|
|
|
"log"
|
2020-10-11 20:13:56 +00:00
|
|
|
"errors"
|
2020-10-11 14:12:48 +00:00
|
|
|
"encoding/json"
|
|
|
|
"github.com/tidwall/buntdb"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Database struct {
|
|
|
|
DB *buntdb.DB
|
|
|
|
}
|
|
|
|
|
|
|
|
func InitDatabase() (*Database, error) {
|
2020-10-14 23:35:46 +00:00
|
|
|
dbfile, ok := os.LookupEnv("ZEIT_DB")
|
|
|
|
if ok == false || dbfile == "" {
|
|
|
|
return nil, errors.New("please `export ZEIT_DB` to the location the zeit database should be stored at")
|
|
|
|
}
|
|
|
|
|
|
|
|
db, err := buntdb.Open(dbfile)
|
2020-10-11 14:12:48 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
db.CreateIndex("task", "*", buntdb.IndexJSON("task"))
|
|
|
|
db.CreateIndex("project", "*", buntdb.IndexJSON("project"))
|
|
|
|
|
|
|
|
database := Database{db}
|
|
|
|
return &database, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (database *Database) NewID() (string) {
|
|
|
|
id, err := uuid.NewRandom()
|
|
|
|
if err != nil {
|
2020-10-15 21:07:36 +00:00
|
|
|
log.Fatalln("could not generate UUID: %+v", err)
|
2020-10-11 14:12:48 +00:00
|
|
|
}
|
|
|
|
return id.String()
|
|
|
|
}
|
|
|
|
|
2020-10-11 20:13:56 +00:00
|
|
|
func (database *Database) AddEntry(user string, entry Entry, setRunning bool) (string, error) {
|
2020-10-11 14:12:48 +00:00
|
|
|
id := database.NewID()
|
|
|
|
|
|
|
|
entryJson, jsonerr := json.Marshal(entry)
|
|
|
|
if jsonerr != nil {
|
|
|
|
return id, jsonerr
|
|
|
|
}
|
|
|
|
|
|
|
|
dberr := database.DB.Update(func(tx *buntdb.Tx) error {
|
2020-10-11 19:36:08 +00:00
|
|
|
if setRunning == true {
|
2020-10-11 20:13:56 +00:00
|
|
|
_, _, seterr := tx.Set(user + ":status:running", id, nil)
|
2020-10-11 19:36:08 +00:00
|
|
|
if seterr != nil {
|
|
|
|
return seterr
|
|
|
|
}
|
|
|
|
}
|
2020-10-11 20:13:56 +00:00
|
|
|
_, _, seterr := tx.Set(user + ":entry:" + id, string(entryJson), nil)
|
2020-10-11 19:36:08 +00:00
|
|
|
if seterr != nil {
|
|
|
|
return seterr
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2020-10-11 14:12:48 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
return id, dberr
|
|
|
|
}
|
|
|
|
|
2020-10-11 20:13:56 +00:00
|
|
|
func (database *Database) GetEntry(user string, entryId string) (Entry, error) {
|
|
|
|
var entry Entry
|
2020-10-11 19:36:08 +00:00
|
|
|
|
|
|
|
dberr := database.DB.View(func(tx *buntdb.Tx) error {
|
2020-10-11 20:13:56 +00:00
|
|
|
tx.AscendKeys(user + ":entry:" + entryId, func(key, value string) bool {
|
|
|
|
json.Unmarshal([]byte(value), &entry)
|
2020-10-15 21:44:36 +00:00
|
|
|
|
|
|
|
entry.SetIDFromDatabaseKey(key)
|
|
|
|
|
2020-10-11 19:36:08 +00:00
|
|
|
return true
|
|
|
|
})
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
2020-10-11 20:13:56 +00:00
|
|
|
return entry, dberr
|
|
|
|
}
|
|
|
|
|
2020-10-17 20:14:34 +00:00
|
|
|
func (database *Database) UpdateEntry(user string, entry Entry) (string, error) {
|
|
|
|
entryJson, jsonerr := json.Marshal(entry)
|
|
|
|
if jsonerr != nil {
|
|
|
|
return entry.ID, jsonerr
|
|
|
|
}
|
|
|
|
|
|
|
|
dberr := database.DB.Update(func(tx *buntdb.Tx) error {
|
|
|
|
_, _, seerr := tx.Set(user + ":entry:" + entry.ID, string(entryJson), nil)
|
|
|
|
if seerr != nil {
|
|
|
|
return seerr
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
return entry.ID, dberr
|
|
|
|
}
|
|
|
|
|
2020-10-11 20:13:56 +00:00
|
|
|
func (database *Database) FinishEntry(user string, entry Entry) (string, error) {
|
|
|
|
entryJson, jsonerr := json.Marshal(entry)
|
|
|
|
if jsonerr != nil {
|
|
|
|
return entry.ID, jsonerr
|
|
|
|
}
|
|
|
|
|
|
|
|
dberr := database.DB.Update(func(tx *buntdb.Tx) error {
|
|
|
|
runningEntryId, grerr := tx.Get(user + ":status:running")
|
|
|
|
if grerr != nil {
|
2020-10-15 21:07:36 +00:00
|
|
|
return errors.New("no currently running entry found!")
|
2020-10-11 20:13:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if runningEntryId != entry.ID {
|
2020-10-15 21:07:36 +00:00
|
|
|
return errors.New("specified entry is not currently running!")
|
2020-10-11 20:13:56 +00:00
|
|
|
}
|
|
|
|
|
2020-10-14 23:22:20 +00:00
|
|
|
_, _, srerr := tx.Set(user + ":status:running", "", nil)
|
2020-10-11 20:13:56 +00:00
|
|
|
if srerr != nil {
|
|
|
|
return srerr
|
|
|
|
}
|
|
|
|
|
|
|
|
_, _, seerr := tx.Set(user + ":entry:" + entry.ID, string(entryJson), nil)
|
|
|
|
if seerr != nil {
|
|
|
|
return seerr
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
return entry.ID, dberr
|
2020-10-11 19:36:08 +00:00
|
|
|
}
|
|
|
|
|
2020-10-16 00:20:56 +00:00
|
|
|
func (database *Database) EraseEntry(user string, id string) (error) {
|
|
|
|
runningEntryId, err := database.GetRunningEntryId(user)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
dberr := database.DB.Update(func(tx *buntdb.Tx) error {
|
|
|
|
if runningEntryId == id {
|
|
|
|
_, _, seterr := tx.Set(user + ":status:running", "", nil)
|
|
|
|
if seterr != nil {
|
|
|
|
return seterr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_, delerr := tx.Delete(user + ":entry:" + id)
|
|
|
|
if delerr != nil {
|
|
|
|
return delerr
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
return dberr
|
|
|
|
}
|
|
|
|
|
2020-10-11 19:36:08 +00:00
|
|
|
func (database *Database) GetRunningEntryId(user string) (string, error) {
|
|
|
|
var runningId string = ""
|
|
|
|
|
|
|
|
dberr := database.DB.View(func(tx *buntdb.Tx) error {
|
|
|
|
tx.AscendKeys(user + ":status:running", func(key, value string) bool {
|
|
|
|
runningId = value
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
return runningId, dberr
|
|
|
|
}
|
|
|
|
|
2020-10-15 21:44:48 +00:00
|
|
|
func (database *Database) ListEntries(user string) ([]Entry, error) {
|
2020-10-11 14:12:48 +00:00
|
|
|
var entries []Entry
|
|
|
|
|
|
|
|
dberr := database.DB.View(func(tx *buntdb.Tx) error {
|
2020-10-15 21:44:48 +00:00
|
|
|
tx.AscendKeys(user + ":entry:*", func(key, value string) bool {
|
2020-10-11 14:12:48 +00:00
|
|
|
var entry Entry
|
|
|
|
json.Unmarshal([]byte(value), &entry)
|
|
|
|
|
2020-10-15 21:44:36 +00:00
|
|
|
entry.SetIDFromDatabaseKey(key)
|
2020-10-11 14:12:48 +00:00
|
|
|
|
|
|
|
entries = append(entries, entry)
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
2020-10-15 21:44:55 +00:00
|
|
|
sort.Slice(entries, func(i, j int) bool { return entries[i].Begin.Before(entries[j].Begin) })
|
2020-10-11 14:12:48 +00:00
|
|
|
return entries, dberr
|
|
|
|
}
|
2020-10-15 23:58:56 +00:00
|
|
|
|
|
|
|
func (database *Database) GetImportsSHA1List(user string) (map[string]string, error) {
|
|
|
|
var sha1List = make(map[string]string)
|
|
|
|
|
|
|
|
dberr := database.DB.View(func(tx *buntdb.Tx) error {
|
|
|
|
value, err := tx.Get(user + ":imports:sha1", false)
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
sha1Entries := strings.Split(value, ",")
|
|
|
|
|
|
|
|
for _, sha1Entry := range sha1Entries {
|
|
|
|
sha1EntrySplit := strings.Split(sha1Entry, ":")
|
|
|
|
sha1 := sha1EntrySplit[0]
|
|
|
|
id := sha1EntrySplit[1]
|
|
|
|
sha1List[sha1] = id
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
return sha1List, dberr
|
|
|
|
}
|
|
|
|
|
|
|
|
func (database *Database) UpdateImportsSHA1List(user string, sha1List map[string]string) (error) {
|
|
|
|
var sha1Entries []string
|
|
|
|
|
|
|
|
for sha1, id := range sha1List {
|
|
|
|
sha1Entries = append(sha1Entries, sha1 + ":" + id)
|
|
|
|
}
|
|
|
|
|
|
|
|
value := strings.Join(sha1Entries, ",")
|
|
|
|
|
|
|
|
dberr := database.DB.Update(func(tx *buntdb.Tx) error {
|
|
|
|
_, _, seterr := tx.Set(user + ":imports:sha1", value, nil)
|
|
|
|
if seterr != nil {
|
|
|
|
return seterr
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
return dberr
|
|
|
|
}
|
2020-10-17 00:32:53 +00:00
|
|
|
|
|
|
|
func (database *Database) UpdateProject(user string, projectName string, project Project) (error) {
|
|
|
|
projectJson, jsonerr := json.Marshal(project)
|
|
|
|
if jsonerr != nil {
|
|
|
|
return jsonerr
|
|
|
|
}
|
|
|
|
|
2020-10-17 12:14:58 +00:00
|
|
|
projectId := GetIdFromName(projectName)
|
2020-10-17 00:32:53 +00:00
|
|
|
|
|
|
|
dberr := database.DB.Update(func(tx *buntdb.Tx) error {
|
|
|
|
_, _, sperr := tx.Set(user + ":project:" + projectId, string(projectJson), nil)
|
|
|
|
if sperr != nil {
|
|
|
|
return sperr
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
return dberr
|
|
|
|
}
|
|
|
|
|
|
|
|
func (database *Database) GetProject(user string, projectName string) (Project, error) {
|
|
|
|
var project Project
|
2020-10-17 12:14:58 +00:00
|
|
|
projectId := GetIdFromName(projectName)
|
2020-10-17 00:32:53 +00:00
|
|
|
|
|
|
|
dberr := database.DB.View(func(tx *buntdb.Tx) error {
|
|
|
|
value, err := tx.Get(user + ":project:" + projectId, false)
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
json.Unmarshal([]byte(value), &project)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
return project, dberr
|
|
|
|
}
|
2020-10-17 12:17:28 +00:00
|
|
|
|
|
|
|
func (database *Database) UpdateTask(user string, taskName string, task Task) (error) {
|
|
|
|
taskJson, jsonerr := json.Marshal(task)
|
|
|
|
if jsonerr != nil {
|
|
|
|
return jsonerr
|
|
|
|
}
|
|
|
|
|
|
|
|
taskId := GetIdFromName(taskName)
|
|
|
|
|
|
|
|
dberr := database.DB.Update(func(tx *buntdb.Tx) error {
|
|
|
|
_, _, sperr := tx.Set(user + ":task:" + taskId, string(taskJson), nil)
|
|
|
|
if sperr != nil {
|
|
|
|
return sperr
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
return dberr
|
|
|
|
}
|
|
|
|
|
|
|
|
func (database *Database) GetTask(user string, taskName string) (Task, error) {
|
|
|
|
var task Task
|
|
|
|
taskId := GetIdFromName(taskName)
|
|
|
|
|
|
|
|
dberr := database.DB.View(func(tx *buntdb.Tx) error {
|
|
|
|
value, err := tx.Get(user + ":task:" + taskId, false)
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
json.Unmarshal([]byte(value), &task)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
return task, dberr
|
|
|
|
}
|