Update BuildAndPackage

This commit is contained in:
2026-04-09 17:23:00 +02:00
parent 4f8bfc133a
commit 68aea4ba00
5 changed files with 250 additions and 6 deletions
+121
View File
@@ -1,12 +1,15 @@
package topdata
import (
"errors"
"fmt"
"io"
"io/fs"
"os"
"path/filepath"
"slices"
"strings"
"time"
"gitea.westgate.pw/ShadowsOverWestgate/sow-tools/internal/erf"
"gitea.westgate.pw/ShadowsOverWestgate/sow-tools/internal/project"
@@ -19,6 +22,17 @@ const (
)
func BuildPackage(p *project.Project, progress func(string)) (PackageResult, error) {
if progress == nil {
progress = func(string) {}
}
nativeResult, err := packagedBuildResult(p)
if err != nil {
return PackageResult{}, err
}
return packageBuiltTopData(p, nativeResult, progress)
}
func BuildAndPackage(p *project.Project, progress func(string)) (PackageResult, error) {
if progress == nil {
progress = func(string) {}
}
@@ -29,6 +43,13 @@ func BuildPackage(p *project.Project, progress func(string)) (PackageResult, err
return packageBuiltTopData(p, nativeResult, progress)
}
func BuildPackageFromBuild(p *project.Project, nativeResult BuildResult, progress func(string)) (PackageResult, error) {
if progress == nil {
progress = func(string) {}
}
return packageBuiltTopData(p, nativeResult, progress)
}
func packageBuiltTopData(p *project.Project, nativeResult BuildResult, progress func(string)) (PackageResult, error) {
if progress == nil {
progress = func(string) {}
@@ -207,3 +228,103 @@ func copyFile(dst, src string) error {
}
return nil
}
func packagedBuildResult(p *project.Project) (BuildResult, error) {
if !p.HasTopData() {
return BuildResult{}, errors.New("topdata is not configured for this project")
}
buildDir := p.TopDataBuildDir()
output2DA := filepath.Join(buildDir, "2da")
outputTLK := filepath.Join(buildDir, "tlk")
if _, err := os.Stat(output2DA); err != nil {
return BuildResult{}, fmt.Errorf("topdata build output missing: run build-topdata first")
}
if _, err := os.Stat(outputTLK); err != nil {
return BuildResult{}, fmt.Errorf("topdata tlk output missing: run build-topdata first")
}
files2DA, oldest2DA, err := countCompiledFiles(output2DA, ".2da")
if err != nil {
return BuildResult{}, err
}
filesTLK, oldestTLK, err := countCompiledFiles(outputTLK, ".tlk")
if err != nil {
return BuildResult{}, err
}
if files2DA == 0 {
return BuildResult{}, fmt.Errorf("topdata build output missing: run build-topdata first")
}
if filesTLK != 1 {
return BuildResult{}, fmt.Errorf("expected exactly 1 compiled tlk output, found %d", filesTLK)
}
newestSource, newestPath, err := newestTopDataSource(p.TopDataSourceDir())
if err != nil {
return BuildResult{}, err
}
oldestBuild := oldest2DA
if oldestBuild.IsZero() || (!oldestTLK.IsZero() && oldestTLK.Before(oldestBuild)) {
oldestBuild = oldestTLK
}
if !newestSource.IsZero() && !oldestBuild.IsZero() && newestSource.After(oldestBuild) {
return BuildResult{}, fmt.Errorf("topdata build output is older than source file %s; run build-topdata first", newestPath)
}
return BuildResult{
Mode: "native",
Output2DADir: output2DA,
OutputTLKDir: outputTLK,
Files2DA: files2DA,
FilesTLK: filesTLK,
}, nil
}
func countCompiledFiles(dir, extension string) (int, time.Time, error) {
entries, err := os.ReadDir(dir)
if err != nil {
return 0, time.Time{}, fmt.Errorf("read compiled output dir %s: %w", dir, err)
}
count := 0
oldest := time.Time{}
for _, entry := range entries {
if entry.IsDir() || !strings.EqualFold(filepath.Ext(entry.Name()), extension) {
continue
}
info, err := entry.Info()
if err != nil {
return 0, time.Time{}, fmt.Errorf("stat compiled output %s: %w", filepath.Join(dir, entry.Name()), err)
}
count++
if oldest.IsZero() || info.ModTime().Before(oldest) {
oldest = info.ModTime()
}
}
return count, oldest, nil
}
func newestTopDataSource(sourceDir string) (time.Time, string, error) {
newest := time.Time{}
newestPath := ""
err := filepath.WalkDir(sourceDir, func(path string, d fs.DirEntry, walkErr error) error {
if walkErr != nil {
return walkErr
}
if d.IsDir() {
return nil
}
info, err := d.Info()
if err != nil {
return err
}
if newest.IsZero() || info.ModTime().After(newest) {
newest = info.ModTime()
newestPath = path
}
return nil
})
if err != nil {
return time.Time{}, "", fmt.Errorf("scan topdata sources: %w", err)
}
return newest, newestPath, nil
}