Log Refactor
This commit is contained in:
@@ -28,6 +28,8 @@ type BuildResult struct {
|
||||
Manifest string
|
||||
AutogenManifestPaths []string
|
||||
CreditsArtifactPaths []string
|
||||
CreditsSummary CreditsRefreshSummary
|
||||
HAKSummary HAKArchiveSummary
|
||||
Resources int
|
||||
HAKAssets int
|
||||
TopPackageHAK string
|
||||
@@ -35,6 +37,35 @@ type BuildResult struct {
|
||||
TopPackageFiles int
|
||||
}
|
||||
|
||||
type CreditsRefreshSummary struct {
|
||||
ScannedDirs []string
|
||||
TrackCount int
|
||||
ArtifactPaths []string
|
||||
GeneratedPaths []string
|
||||
InventoryPath string
|
||||
ChangedFiles int
|
||||
Mappings []MusicFileMapping
|
||||
}
|
||||
|
||||
type MusicFileMapping struct {
|
||||
Source string
|
||||
Output string
|
||||
}
|
||||
|
||||
type HAKArchiveSummary struct {
|
||||
Total int
|
||||
Reused int
|
||||
Written int
|
||||
Actions []HAKArchiveAction
|
||||
}
|
||||
|
||||
type HAKArchiveAction struct {
|
||||
Name string
|
||||
AssetCount int
|
||||
Reused bool
|
||||
OutputPath string
|
||||
}
|
||||
|
||||
type BuildManifest struct {
|
||||
ModuleHAKs []string `json:"module_haks"`
|
||||
HAKs []BuildManifestHAK `json:"haks"`
|
||||
@@ -220,6 +251,7 @@ func planOrBuildHAKs(p *project.Project, progress ProgressFunc, writeArchives bo
|
||||
|
||||
result = BuildResult{HAKAssets: len(assetResources)}
|
||||
result.CreditsArtifactPaths = append(result.CreditsArtifactPaths, musicAssets.Artifacts...)
|
||||
result.CreditsSummary = musicAssets.Summary
|
||||
if err := writeAutogenManifestOutputs(progress, autogenManifests); err != nil {
|
||||
return BuildResult{}, err
|
||||
}
|
||||
@@ -298,6 +330,7 @@ func planOrBuildHAKs(p *project.Project, progress ProgressFunc, writeArchives bo
|
||||
|
||||
progressf(progress, "Reusing unchanged generated HAKs where possible...")
|
||||
|
||||
result.HAKSummary.Total = len(chunks)
|
||||
result.HAKPaths = make([]string, 0, len(chunks))
|
||||
for index, chunk := range chunks {
|
||||
hakPath := p.HAKArchivePath(chunk.Name)
|
||||
@@ -307,8 +340,10 @@ func planOrBuildHAKs(p *project.Project, progress ProgressFunc, writeArchives bo
|
||||
return BuildResult{}, err
|
||||
}
|
||||
if reused {
|
||||
result.HAKSummary.Reused++
|
||||
progressf(progress, fmt.Sprintf("Reusing HAK %d/%d: %s (%d assets)", index+1, len(chunks), chunk.Name, len(chunk.Assets)))
|
||||
} else {
|
||||
result.HAKSummary.Written++
|
||||
progressf(progress, fmt.Sprintf("Writing HAK %d/%d: %s (%d assets)", index+1, len(chunks), chunk.Name, len(chunk.Assets)))
|
||||
hakOutput, err := os.Create(hakPath)
|
||||
if err != nil {
|
||||
@@ -323,6 +358,12 @@ func planOrBuildHAKs(p *project.Project, progress ProgressFunc, writeArchives bo
|
||||
}
|
||||
}
|
||||
|
||||
result.HAKSummary.Actions = append(result.HAKSummary.Actions, HAKArchiveAction{
|
||||
Name: chunk.Name,
|
||||
AssetCount: len(chunk.Assets),
|
||||
Reused: reused,
|
||||
OutputPath: hakPath,
|
||||
})
|
||||
result.HAKPaths = append(result.HAKPaths, hakPath)
|
||||
}
|
||||
progressf(progress, "Cleaning stale generated HAKs...")
|
||||
|
||||
+92
-25
@@ -49,6 +49,7 @@ type preparedMusicAssets struct {
|
||||
SkipSourceRel map[string]struct{}
|
||||
Artifacts []string
|
||||
TempRoots []string
|
||||
Summary CreditsRefreshSummary
|
||||
}
|
||||
|
||||
type musicMetadata struct {
|
||||
@@ -111,11 +112,12 @@ func prepareMusicAssets(p *project.Project) (*preparedMusicAssets, error) {
|
||||
SkipSourceRel: make(map[string]struct{}),
|
||||
}
|
||||
if len(dirSources) == 0 {
|
||||
artifactPaths, err := writeCreditsArtifacts(p, nil)
|
||||
writeResult, err := writeCreditsArtifacts(p, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.Artifacts = artifactPaths
|
||||
result.Artifacts = writeResult.Artifacts
|
||||
result.Summary = writeResult.Summary
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -217,28 +219,30 @@ func prepareMusicAssets(p *project.Project) (*preparedMusicAssets, error) {
|
||||
generatedByDir[dir] = entries
|
||||
}
|
||||
|
||||
artifactPaths, err := writeCreditsArtifacts(p, generatedByDir)
|
||||
writeResult, err := writeCreditsArtifacts(p, generatedByDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.Artifacts = artifactPaths
|
||||
writeResult.Summary.ScannedDirs = append(writeResult.Summary.ScannedDirs, dirs...)
|
||||
writeResult.Summary.TrackCount = len(result.Generated)
|
||||
result.Artifacts = writeResult.Artifacts
|
||||
result.Summary = writeResult.Summary
|
||||
sort.Slice(result.Generated, func(i, j int) bool {
|
||||
return compareResourceKeys(result.Generated[i].Resource, result.Generated[j].Resource) < 0
|
||||
})
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func writeCreditsArtifacts(p *project.Project, generatedByDir map[string][]creditsEntry) ([]string, error) {
|
||||
creditsRoot := filepath.Join(p.Root, ".cache", "credits")
|
||||
if err := os.RemoveAll(creditsRoot); err != nil {
|
||||
return nil, fmt.Errorf("reset credits dir: %w", err)
|
||||
}
|
||||
if err := os.MkdirAll(creditsRoot, 0o755); err != nil {
|
||||
return nil, fmt.Errorf("create credits dir: %w", err)
|
||||
}
|
||||
type creditsArtifactWriteResult struct {
|
||||
Artifacts []string
|
||||
Summary CreditsRefreshSummary
|
||||
}
|
||||
|
||||
func writeCreditsArtifacts(p *project.Project, generatedByDir map[string][]creditsEntry) (creditsArtifactWriteResult, error) {
|
||||
creditsRoot := filepath.Join(p.Root, ".cache", "credits")
|
||||
sources := make([]creditsSource, 0)
|
||||
artifacts := make([]string, 0)
|
||||
desiredFiles := make(map[string][]byte)
|
||||
summary := CreditsRefreshSummary{}
|
||||
if generatedByDir != nil {
|
||||
dirs := make([]string, 0, len(generatedByDir))
|
||||
for dir := range generatedByDir {
|
||||
@@ -257,13 +261,14 @@ func writeCreditsArtifacts(p *project.Project, generatedByDir map[string][]credi
|
||||
return strings.ToLower(entries[i].OutputFile) < strings.ToLower(entries[j].OutputFile)
|
||||
})
|
||||
outputPath := filepath.Join(creditsRoot, filepath.FromSlash(dir), "CREDITS.md")
|
||||
if err := os.MkdirAll(filepath.Dir(outputPath), 0o755); err != nil {
|
||||
return nil, fmt.Errorf("create generated credits dir: %w", err)
|
||||
desiredFiles[outputPath] = []byte(renderCreditsMarkdown(entries))
|
||||
summary.GeneratedPaths = append(summary.GeneratedPaths, outputPath)
|
||||
for _, entry := range entries {
|
||||
summary.Mappings = append(summary.Mappings, MusicFileMapping{
|
||||
Source: entry.OriginalFile,
|
||||
Output: entry.OutputFile,
|
||||
})
|
||||
}
|
||||
if err := os.WriteFile(outputPath, []byte(renderCreditsMarkdown(entries)), 0o644); err != nil {
|
||||
return nil, fmt.Errorf("write generated credits %s: %w", outputPath, err)
|
||||
}
|
||||
artifacts = append(artifacts, outputPath)
|
||||
sources = append(sources, creditsSource{
|
||||
Path: filepath.ToSlash(outputPath),
|
||||
Kind: "generated_music",
|
||||
@@ -298,21 +303,83 @@ func writeCreditsArtifacts(p *project.Project, generatedByDir map[string][]credi
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return creditsArtifactWriteResult{}, err
|
||||
}
|
||||
|
||||
sort.Slice(sources, func(i, j int) bool { return sources[i].Path < sources[j].Path })
|
||||
inventoryPath := filepath.Join(creditsRoot, "credits.json")
|
||||
payload, err := json.MarshalIndent(creditsInventory{Sources: sources}, "", " ")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("marshal credits inventory: %w", err)
|
||||
return creditsArtifactWriteResult{}, fmt.Errorf("marshal credits inventory: %w", err)
|
||||
}
|
||||
payload = append(payload, '\n')
|
||||
if err := os.WriteFile(inventoryPath, payload, 0o644); err != nil {
|
||||
return nil, fmt.Errorf("write credits inventory: %w", err)
|
||||
desiredFiles[inventoryPath] = payload
|
||||
if err := os.MkdirAll(creditsRoot, 0o755); err != nil {
|
||||
return creditsArtifactWriteResult{}, fmt.Errorf("create credits dir: %w", err)
|
||||
}
|
||||
artifacts = append(artifacts, inventoryPath)
|
||||
return artifacts, nil
|
||||
changedFiles, err := syncGeneratedCreditsArtifacts(creditsRoot, desiredFiles)
|
||||
if err != nil {
|
||||
return creditsArtifactWriteResult{}, err
|
||||
}
|
||||
artifacts := make([]string, 0, len(desiredFiles))
|
||||
for path := range desiredFiles {
|
||||
artifacts = append(artifacts, path)
|
||||
}
|
||||
sort.Strings(artifacts)
|
||||
summary.ArtifactPaths = append(summary.ArtifactPaths, artifacts...)
|
||||
summary.InventoryPath = inventoryPath
|
||||
summary.ChangedFiles = changedFiles
|
||||
return creditsArtifactWriteResult{
|
||||
Artifacts: artifacts,
|
||||
Summary: summary,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func syncGeneratedCreditsArtifacts(root string, desiredFiles map[string][]byte) (int, error) {
|
||||
changedFiles := 0
|
||||
existingFiles := make(map[string]struct{})
|
||||
if err := filepath.WalkDir(root, func(path string, d os.DirEntry, walkErr error) error {
|
||||
if walkErr != nil {
|
||||
if os.IsNotExist(walkErr) {
|
||||
return nil
|
||||
}
|
||||
return walkErr
|
||||
}
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
existingFiles[path] = struct{}{}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return 0, fmt.Errorf("scan credits dir: %w", err)
|
||||
}
|
||||
|
||||
for path, content := range desiredFiles {
|
||||
current, err := os.ReadFile(path)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return 0, fmt.Errorf("read credits artifact %s: %w", path, err)
|
||||
}
|
||||
if err == nil && string(current) == string(content) {
|
||||
delete(existingFiles, path)
|
||||
continue
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
||||
return 0, fmt.Errorf("create generated credits dir: %w", err)
|
||||
}
|
||||
if err := os.WriteFile(path, content, 0o644); err != nil {
|
||||
return 0, fmt.Errorf("write credits artifact %s: %w", path, err)
|
||||
}
|
||||
changedFiles++
|
||||
delete(existingFiles, path)
|
||||
}
|
||||
|
||||
for path := range existingFiles {
|
||||
if err := os.Remove(path); err != nil && !os.IsNotExist(err) {
|
||||
return 0, fmt.Errorf("remove stale credits artifact %s: %w", path, err)
|
||||
}
|
||||
changedFiles++
|
||||
}
|
||||
return changedFiles, nil
|
||||
}
|
||||
|
||||
func cleanupPreparedMusicAssets(prepared *preparedMusicAssets) error {
|
||||
|
||||
@@ -2685,6 +2685,17 @@ func TestBuildHAKsConvertsMusicSourcesAndWritesCreditsArtifacts(t *testing.T) {
|
||||
if _, err := os.Stat(filepath.Join(root, ".cache", "music")); !os.IsNotExist(err) {
|
||||
t.Fatalf("expected temporary music staging to be cleaned, got err=%v", err)
|
||||
}
|
||||
|
||||
secondResult, err := BuildHAKs(p)
|
||||
if err != nil {
|
||||
t.Fatalf("build haks second pass: %v", err)
|
||||
}
|
||||
if secondResult.CreditsSummary.ChangedFiles != 0 {
|
||||
t.Fatalf("expected second credits refresh to be unchanged, got %d changed files", secondResult.CreditsSummary.ChangedFiles)
|
||||
}
|
||||
if secondResult.CreditsSummary.TrackCount != 1 {
|
||||
t.Fatalf("expected one tracked music conversion, got %d", secondResult.CreditsSummary.TrackCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUniqueMusicNameHandlesShortStemCollisions(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user