ci-platforms / darwin amd64 smoke (push) Skipped
ci / build (amd64, linux, ubuntu-24.04) (push) Failing after 15m28s
ci / release (push) Skipped
ci-platforms / windows amd64 smoke (push) Skipped
ci-platforms / darwin arm64 smoke (push) Skipped
ci / checks (push) Successful in 7m47s
147 lines
4.2 KiB
Go
147 lines
4.2 KiB
Go
package pipeline
|
|
|
|
import (
|
|
"bytes"
|
|
"slices"
|
|
"strings"
|
|
|
|
"aego/core/errs"
|
|
"aego/core/ids"
|
|
"aego/core/log"
|
|
"aego/project"
|
|
)
|
|
|
|
func (p *Pipeline) MetaOf(id ids.AssetID) (Meta, bool) {
|
|
p.mu.RLock()
|
|
defer p.mu.RUnlock()
|
|
r := p.byID[id]
|
|
if r == nil || r.meta == nil {
|
|
return Meta{}, false
|
|
}
|
|
m := *r.meta
|
|
m.Settings = r.meta.Settings.Clone()
|
|
m.Subs = slices.Clone(r.meta.Subs)
|
|
return m, true
|
|
}
|
|
|
|
// SetSubs writes the cells of a sliced sheet into its meta; the next import turns them into sprite assets (D339).
|
|
func (p *Pipeline) SetSubs(id ids.AssetID, subs []SubAsset) error {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
if p.shared {
|
|
return errs.New(errs.AssetBadMeta, "another process holds the asset index, slice the sheet there")
|
|
}
|
|
r := p.byID[id]
|
|
if r == nil || r.meta == nil {
|
|
return errs.New(errs.AssetNotFound, "the asset is not in the project", log.F("asset", id.String()))
|
|
}
|
|
m := *r.meta
|
|
m.Subs = slices.Clone(subs)
|
|
if err := project.WriteAtomic(p.abs(r.path)+MetaSuffix, WriteMeta(&m)); err != nil {
|
|
return errs.Wrap(err, errs.VFSIO, "cannot write "+r.path+MetaSuffix).With(log.F("path", r.path))
|
|
}
|
|
r.meta, r.derived, r.dup, r.key = &m, false, "", ""
|
|
p.metas[r.path+MetaSuffix] = true
|
|
p.rev++
|
|
return nil
|
|
}
|
|
|
|
func (p *Pipeline) SetSettings(id ids.AssetID, s Settings) error {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
if p.shared {
|
|
return errs.New(errs.AssetBadMeta, "another process holds the asset index, change the import settings there")
|
|
}
|
|
r := p.byID[id]
|
|
if r == nil || r.meta == nil {
|
|
return errs.New(errs.AssetNotFound, "the asset is not in the project", log.F("asset", id.String()))
|
|
}
|
|
m := *r.meta
|
|
m.Settings = s.Clone()
|
|
m.Subs = slices.Clone(r.meta.Subs)
|
|
if err := project.WriteAtomic(p.abs(r.path)+MetaSuffix, WriteMeta(&m)); err != nil {
|
|
return errs.Wrap(err, errs.VFSIO, "cannot write "+r.path+MetaSuffix).With(log.F("path", r.path))
|
|
}
|
|
r.meta, r.derived, r.dup, r.key = &m, false, "", ""
|
|
p.metas[r.path+MetaSuffix] = true
|
|
p.rev++
|
|
return nil
|
|
}
|
|
|
|
// ReloadMetadata reconciles a sidecar already atomically saved by the common
|
|
// document/file transaction. It never writes the sidecar or invents frame IDs.
|
|
func (p *Pipeline) ReloadMetadata(id ids.AssetID) (*Batch, error) {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
if p.shared {
|
|
return nil, errs.New(errs.AssetBadMeta, "another process holds the asset index")
|
|
}
|
|
r := p.byID[id]
|
|
if r == nil || r.meta == nil {
|
|
return nil, errs.New(errs.AssetNotFound, "metadata source is not in this project")
|
|
}
|
|
if err := p.reloadMetadata(r); err != nil {
|
|
return nil, err
|
|
}
|
|
list := []ids.AssetID{id}
|
|
list = append(list, p.dependents(id)...)
|
|
// CacheSalters include indirect frame dependencies and private channel metadata.
|
|
for source, record := range p.byID {
|
|
if source != id {
|
|
if _, ok := record.importer.(CacheSalter); ok && !slices.Contains(list, source) {
|
|
list = append(list, source)
|
|
}
|
|
}
|
|
}
|
|
slices.SortFunc(list, func(a, b ids.AssetID) int { return strings.Compare(p.byID[a].path, p.byID[b].path) })
|
|
return p.importIDs(list...)
|
|
}
|
|
|
|
func (p *Pipeline) reloadMetadata(r *record) error {
|
|
data, err := p.read(r.path + MetaSuffix)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
m, err := ParseMeta(data, r.path+MetaSuffix)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if m.ID != r.id {
|
|
return errs.New(errs.AssetBadMeta, "saving metadata cannot replace the source AssetID")
|
|
}
|
|
if m.Importer != "" && m.Importer != r.importer.ID() {
|
|
return errs.New(errs.AssetBadMeta, "metadata importer does not match the source")
|
|
}
|
|
m.Importer = r.importer.ID()
|
|
for key, value := range r.importer.Defaults() {
|
|
if _, ok := m.Settings[key]; !ok {
|
|
m.Settings[key] = value
|
|
}
|
|
}
|
|
seen := map[ids.AssetID]bool{m.ID: true}
|
|
for _, sub := range m.Subs {
|
|
if sub.ID.IsZero() || seen[sub.ID] {
|
|
return errs.New(errs.AssetBadMeta, "frame AssetIDs must be distinct and nonzero")
|
|
}
|
|
if other, ok := p.pathOf(sub.ID); ok && other != r.path+SubSep+sub.Name {
|
|
own := false
|
|
for _, old := range r.meta.Subs {
|
|
own = own || old.ID == sub.ID
|
|
}
|
|
if !own {
|
|
return errs.New(errs.AssetBadMeta, "frame AssetID belongs to another source")
|
|
}
|
|
}
|
|
seen[sub.ID] = true
|
|
}
|
|
if bytes.Equal(WriteMeta(r.meta), WriteMeta(m)) {
|
|
return nil
|
|
}
|
|
r.meta, r.key, r.derived = m, "", false
|
|
if r.group != "" {
|
|
p.groupKey[r.group] = ""
|
|
}
|
|
p.rev++
|
|
return nil
|
|
}
|