Put initial prototype code under version control
parent
f734ccfeee
commit
3a83607a2d
@ -0,0 +1,156 @@
|
|||||||
|
package job
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StringSlice sort.StringSlice
|
||||||
|
|
||||||
|
type Job struct {
|
||||||
|
Id uint
|
||||||
|
Archived bool
|
||||||
|
Customer string
|
||||||
|
Name string
|
||||||
|
Taxa []string
|
||||||
|
Tags sort.StringSlice
|
||||||
|
Watching sort.StringSlice
|
||||||
|
Notified map[string]time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewJob(id uint, customer string, name string) *Job {
|
||||||
|
job := &Job{
|
||||||
|
Id: id,
|
||||||
|
Archived: false,
|
||||||
|
Customer: customer,
|
||||||
|
Name: name,
|
||||||
|
Taxa: sort.StringSlice{},
|
||||||
|
Tags: sort.StringSlice{},
|
||||||
|
Watching: sort.StringSlice{},
|
||||||
|
Notified: map[string]time.Time{},
|
||||||
|
}
|
||||||
|
return job
|
||||||
|
}
|
||||||
|
|
||||||
|
func union(slices ...sort.StringSlice) sort.StringSlice {
|
||||||
|
set := map[string]bool{}
|
||||||
|
for _, slice := range slices {
|
||||||
|
for _, key := range slice {
|
||||||
|
set[key] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
keys := make(sort.StringSlice, len(set))
|
||||||
|
i := 0
|
||||||
|
for key, _ := range set {
|
||||||
|
keys[i] = key
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
keys.Sort()
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
|
||||||
|
func (job *Job) AddTaxa(taxa ...string) {
|
||||||
|
job.Taxa = append(job.Taxa, taxa...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (job *Job) AddTags(tags ...string) {
|
||||||
|
job.Tags = union(job.Tags, tags)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (job *Job) Watch(who ...string) {
|
||||||
|
job.Watching = union(job.Watching, who)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (job *Job) Notify(who ...string) {
|
||||||
|
for _, user := range who {
|
||||||
|
job.Notified[user] = time.Now()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (job *Job) Shard() string {
|
||||||
|
upper := job.Id / 1000
|
||||||
|
return fmt.Sprintf("%dxxx", upper)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (job *Job) Path() string {
|
||||||
|
return fmt.Sprintf("Jobs/%s/%d", job.Shard(), job.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (job *Job) TaxonomyDirectories() sort.StringSlice {
|
||||||
|
n := len(job.Taxa)
|
||||||
|
parts := make([][]string, (n*n+n)/2)
|
||||||
|
|
||||||
|
// e.g. [x,y,z] -> [[x], [x, y], [x, y, z]]
|
||||||
|
for i := range job.Taxa {
|
||||||
|
parts[i] = job.Taxa[0 : i+1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// e.g. [[x], [x, y], [x, y, z]] -> [[y], [y, z]] + [[z]]
|
||||||
|
k := n
|
||||||
|
for i := 1; i < n; i++ {
|
||||||
|
for j := i; j < n; j++ {
|
||||||
|
parts[k] = job.Taxa[i : j+1]
|
||||||
|
k++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dirs := make([]string, k)
|
||||||
|
upper := job.Id / 1000
|
||||||
|
for i, part := range parts {
|
||||||
|
dirs[i] = fmt.Sprintf("Customers/%s/%s/• Jobs/%dxxx", job.Customer, strings.Join(part, "/"), upper)
|
||||||
|
}
|
||||||
|
return dirs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (job *Job) CustomerDirectory() string {
|
||||||
|
return fmt.Sprintf("Customers/%s/• Jobs/%s", job.Customer, job.Shard())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (job *Job) SymlinkDirectories() sort.StringSlice {
|
||||||
|
customer := sort.StringSlice{job.CustomerDirectory()}
|
||||||
|
taxonomy := job.TaxonomyDirectories()
|
||||||
|
|
||||||
|
return union(customer, taxonomy)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (job *Job) AllDirectories() sort.StringSlice {
|
||||||
|
original := sort.StringSlice{job.Path()}
|
||||||
|
symlinks := job.SymlinkDirectories()
|
||||||
|
|
||||||
|
return union(original, symlinks)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (job *Job) Description() string {
|
||||||
|
return fmt.Sprintf("%d | %s | %s", job.Id, strings.Join(job.Taxa, " ▶ "), job.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (job *Job) Create(where string) error {
|
||||||
|
for _, dir := range job.AllDirectories() {
|
||||||
|
err := os.MkdirAll(where+"/"+dir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
original := job.Path()
|
||||||
|
description := job.Description()
|
||||||
|
for _, dir := range job.SymlinkDirectories() {
|
||||||
|
err := os.Remove(where + "/" + dir + "/." + description)
|
||||||
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = os.Symlink(where+"/"+original, where+"/"+dir+"/."+description)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = os.Rename(where+"/"+dir+"/."+description, where+"/"+dir+"/"+description)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
Reference in New Issue