124 lines
2.7 KiB
Go
124 lines
2.7 KiB
Go
package pipeline
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"slices"
|
|
"time"
|
|
|
|
"aego/asset"
|
|
"aego/core/ids"
|
|
"aego/format/aetext"
|
|
)
|
|
|
|
const (
|
|
graveFile = "graveyard.aetext"
|
|
graveMax = 2000
|
|
graveVersion = 1
|
|
)
|
|
|
|
type Grave struct {
|
|
ID ids.AssetID
|
|
Path string
|
|
Kind asset.ArtifactKind
|
|
When time.Time
|
|
}
|
|
|
|
func (p *Pipeline) bury(id ids.AssetID, path string) {
|
|
g := Grave{ID: id, Path: path, When: time.Now()}
|
|
if e, ok := p.index.Lookup(id); ok {
|
|
g.Kind = e.Kind
|
|
}
|
|
p.graves = slices.DeleteFunc(p.graves, func(x Grave) bool { return x.ID == id })
|
|
p.graves = append(p.graves, g)
|
|
if over := len(p.graves) - graveMax; over > 0 {
|
|
p.graves = slices.Delete(p.graves, 0, over)
|
|
}
|
|
p.gravesDirty = true
|
|
}
|
|
|
|
func (p *Pipeline) Graveyard() []Grave {
|
|
p.mu.RLock()
|
|
defer p.mu.RUnlock()
|
|
out := make([]Grave, 0, len(p.graves))
|
|
for _, g := range p.graves {
|
|
if _, alive := p.byID[g.ID]; !alive {
|
|
out = append(out, g)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func (p *Pipeline) Grave(id ids.AssetID) (Grave, bool) {
|
|
p.mu.RLock()
|
|
defer p.mu.RUnlock()
|
|
if _, alive := p.byID[id]; alive {
|
|
return Grave{}, false
|
|
}
|
|
for i := len(p.graves) - 1; i >= 0; i-- {
|
|
if p.graves[i].ID == id {
|
|
return p.graves[i], true
|
|
}
|
|
}
|
|
return Grave{}, false
|
|
}
|
|
|
|
func (p *Pipeline) gravePath() string {
|
|
return filepath.Join(p.project.CacheDir(), graveFile)
|
|
}
|
|
|
|
func (p *Pipeline) loadGraves() {
|
|
data, err := os.ReadFile(p.gravePath())
|
|
if err != nil {
|
|
return
|
|
}
|
|
doc, err := aetext.Parse(data, graveFile)
|
|
if err != nil || doc.Head != "graveyard" {
|
|
return
|
|
}
|
|
doc.EachBlock("grave", func(n *aetext.Node) {
|
|
id, err := ids.ParseAssetID(n.Label)
|
|
if err != nil {
|
|
return
|
|
}
|
|
g := Grave{ID: id}
|
|
if v, ok := n.Attr("path"); ok {
|
|
g.Path = v.Str
|
|
}
|
|
if v, ok := n.Attr("kind"); ok {
|
|
g.Kind = asset.ArtifactKind(v.Str)
|
|
}
|
|
if v, ok := n.Attr("time"); ok {
|
|
g.When = time.Unix(v.AsInt(), 0)
|
|
}
|
|
p.graves = append(p.graves, g)
|
|
})
|
|
}
|
|
|
|
func (p *Pipeline) saveGraves() error {
|
|
if p.shared || !p.gravesDirty {
|
|
return nil
|
|
}
|
|
root := &aetext.Node{Head: "graveyard", Attrs: []aetext.Field{{Name: "version", Value: aetext.Int(graveVersion)}}}
|
|
for _, g := range p.graves {
|
|
root.Blocks = append(root.Blocks, &aetext.Node{Head: "grave", Label: g.ID.String(), Attrs: []aetext.Field{
|
|
{Name: "path", Value: aetext.String(g.Path)},
|
|
{Name: "kind", Value: aetext.String(string(g.Kind))},
|
|
{Name: "time", Value: aetext.Int(g.When.Unix())},
|
|
}})
|
|
}
|
|
path := p.gravePath()
|
|
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
|
return err
|
|
}
|
|
tmp := path + ".tmp"
|
|
if err := os.WriteFile(tmp, aetext.Write(root), 0o644); err != nil {
|
|
return err
|
|
}
|
|
if err := os.Rename(tmp, path); err != nil {
|
|
return err
|
|
}
|
|
p.gravesDirty = false
|
|
return nil
|
|
}
|