diff --git a/internal/pipeline/build.go b/internal/pipeline/build.go index d1b9dbc..62cccf3 100644 --- a/internal/pipeline/build.go +++ b/internal/pipeline/build.go @@ -857,6 +857,11 @@ func collectGitAssetCreationTimes(p *project.Project) (map[string]time.Time, err } assetsRelPath = filepath.ToSlash(assetsRelPath) + cacheFile := filepath.Join(p.Root, ".git", "asset-creation-times.json") + if cache, err := loadCreationTimeCache(cacheFile, p.Root, assetsRelPath, p.Inventory.AssetFiles); err == nil { + return cache, nil + } + output, err := gitOutput(p.Root, "log", "--diff-filter=A", "--format=%ct", "--name-only", "--", assetsRelPath) if err != nil { return result, nil @@ -892,9 +897,59 @@ func collectGitAssetCreationTimes(p *project.Project) (map[string]time.Time, err } } + _ = saveCreationTimeCache(cacheFile, p.Root, result) return result, nil } +type creationTimeCache struct { + Head string `json:"head"` + Times map[string]int64 `json:"times"` +} + +func loadCreationTimeCache(cacheFile, root, assetsRel string, assetFiles []string) (map[string]time.Time, error) { + data, err := os.ReadFile(cacheFile) + if err != nil { + return nil, err + } + var cache creationTimeCache + if err := json.Unmarshal(data, &cache); err != nil { + return nil, err + } + currentHead, err := gitOutput(root, "rev-parse", "HEAD") + if err != nil { + return nil, err + } + currentHead = strings.TrimSpace(currentHead) + if cache.Head != currentHead { + return nil, fmt.Errorf("cache stale") + } + result := make(map[string]time.Time, len(cache.Times)) + for k, v := range cache.Times { + result[k] = time.Unix(v, 0).UTC() + } + return result, nil +} + +func saveCreationTimeCache(cacheFile, root string, times map[string]time.Time) error { + head, err := gitOutput(root, "rev-parse", "HEAD") + if err != nil { + return err + } + intTimes := make(map[string]int64, len(times)) + for k, v := range times { + intTimes[k] = v.Unix() + } + cache := creationTimeCache{ + Head: strings.TrimSpace(head), + Times: intTimes, + } + data, err := json.Marshal(cache) + if err != nil { + return err + } + return os.WriteFile(cacheFile, data, 0o644) +} + func gitOutput(dir string, args ...string) (string, error) { cmd := exec.Command("git", args...) if dir != "" {