Optimization Pass
This commit is contained in:
@@ -56,9 +56,41 @@ func BuildPackage(p *project.Project, progress func(string)) (PackageResult, err
|
||||
}
|
||||
|
||||
func BuildAndPackage(p *project.Project, progress func(string)) (PackageResult, error) {
|
||||
return BuildAndPackageWithOptions(p, BuildAndPackageOptions{}, progress)
|
||||
}
|
||||
|
||||
type BuildAndPackageOptions struct {
|
||||
Force bool
|
||||
}
|
||||
|
||||
func BuildAndPackageWithOptions(p *project.Project, opts BuildAndPackageOptions, progress func(string)) (PackageResult, error) {
|
||||
if progress == nil {
|
||||
progress = func(string) {}
|
||||
}
|
||||
if !opts.Force {
|
||||
incrementalResult, ok, err := currentTopPackageResult(p)
|
||||
if err != nil {
|
||||
return PackageResult{}, err
|
||||
}
|
||||
if ok {
|
||||
progress("Topdata outputs are current; skipping native build and top package refresh.")
|
||||
return incrementalResult, nil
|
||||
}
|
||||
|
||||
nativeResult, ok, err := currentCompiledBuildResult(p)
|
||||
if err != nil {
|
||||
return PackageResult{}, err
|
||||
}
|
||||
if ok {
|
||||
progress("Compiled topdata outputs are current; refreshing sow_top.hak and sow_tlk.tlk only.")
|
||||
return packageBuiltTopData(p, nativeResult, progress)
|
||||
}
|
||||
}
|
||||
|
||||
return buildAndPackageFull(p, progress)
|
||||
}
|
||||
|
||||
func buildAndPackageFull(p *project.Project, progress func(string)) (PackageResult, error) {
|
||||
nativeResult, err := BuildNative(p, progress)
|
||||
if err != nil {
|
||||
return PackageResult{}, err
|
||||
@@ -323,6 +355,109 @@ func packagedBuildResult(p *project.Project) (BuildResult, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func currentCompiledBuildResult(p *project.Project) (BuildResult, bool, error) {
|
||||
nativeResult, err := packagedBuildResult(p)
|
||||
if err == nil {
|
||||
return nativeResult, true, nil
|
||||
}
|
||||
if strings.Contains(err.Error(), "run build-topdata first") {
|
||||
return BuildResult{}, false, nil
|
||||
}
|
||||
return BuildResult{}, false, err
|
||||
}
|
||||
|
||||
func currentTopPackageResult(p *project.Project) (PackageResult, bool, error) {
|
||||
nativeResult, ok, err := currentCompiledBuildResult(p)
|
||||
if err != nil || !ok {
|
||||
return PackageResult{}, ok, err
|
||||
}
|
||||
|
||||
outputHAK := filepath.Join(p.BuildDir(), PackageHAKFileName)
|
||||
outputTLK := filepath.Join(p.BuildDir(), PackageTLKFileName)
|
||||
hakInfo, err := os.Stat(outputHAK)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return PackageResult{}, false, nil
|
||||
}
|
||||
return PackageResult{}, false, fmt.Errorf("stat top package hak %s: %w", outputHAK, err)
|
||||
}
|
||||
tlkInfo, err := os.Stat(outputTLK)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return PackageResult{}, false, nil
|
||||
}
|
||||
return PackageResult{}, false, fmt.Errorf("stat top package tlk %s: %w", outputTLK, err)
|
||||
}
|
||||
|
||||
newestSource, _, err := newestTopDataSource(p.TopDataSourceDir())
|
||||
if err != nil {
|
||||
return PackageResult{}, false, err
|
||||
}
|
||||
newestCompiled, err := newestFileModTime(nativeResult.Output2DADir, ".2da")
|
||||
if err != nil {
|
||||
return PackageResult{}, false, err
|
||||
}
|
||||
compiledTLKInfo, err := os.Stat(compiledTLKOutputPath(p))
|
||||
if err != nil {
|
||||
return PackageResult{}, false, fmt.Errorf("stat compiled tlk output %s: %w", compiledTLKOutputPath(p), err)
|
||||
}
|
||||
if compiledTLKInfo.ModTime().After(newestCompiled) {
|
||||
newestCompiled = compiledTLKInfo.ModTime()
|
||||
}
|
||||
newestInput := newestSource
|
||||
if newestCompiled.After(newestInput) {
|
||||
newestInput = newestCompiled
|
||||
}
|
||||
|
||||
oldestPackage := hakInfo.ModTime()
|
||||
if tlkInfo.ModTime().Before(oldestPackage) {
|
||||
oldestPackage = tlkInfo.ModTime()
|
||||
}
|
||||
if !newestInput.IsZero() && newestInput.After(oldestPackage) {
|
||||
return PackageResult{}, false, nil
|
||||
}
|
||||
|
||||
resources, assetFiles, err := collectTopPackageResources(p, nativeResult.Output2DADir)
|
||||
if err != nil {
|
||||
return PackageResult{}, false, err
|
||||
}
|
||||
return PackageResult{
|
||||
Mode: "incremental-noop",
|
||||
Output2DADir: nativeResult.Output2DADir,
|
||||
OutputTLKDir: nativeResult.OutputTLKDir,
|
||||
OutputHAKPath: outputHAK,
|
||||
OutputTLKPath: outputTLK,
|
||||
Files2DA: nativeResult.Files2DA,
|
||||
FilesTLK: nativeResult.FilesTLK,
|
||||
HAKResources: len(resources),
|
||||
AssetFiles: assetFiles,
|
||||
WikiOutputDir: nativeResult.WikiOutputDir,
|
||||
WikiPages: nativeResult.WikiPages,
|
||||
WikiStatus: nativeResult.WikiStatus,
|
||||
}, true, nil
|
||||
}
|
||||
|
||||
func newestFileModTime(dir, extension string) (time.Time, error) {
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
return time.Time{}, fmt.Errorf("read output dir %s: %w", dir, err)
|
||||
}
|
||||
newest := 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 time.Time{}, fmt.Errorf("stat output %s: %w", filepath.Join(dir, entry.Name()), err)
|
||||
}
|
||||
if newest.IsZero() || info.ModTime().After(newest) {
|
||||
newest = info.ModTime()
|
||||
}
|
||||
}
|
||||
return newest, nil
|
||||
}
|
||||
|
||||
func countCompiledFiles(dir, extension string) (int, time.Time, error) {
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user