Build in /tmp and immediately discard
This commit is contained in:
+16
-2
@@ -180,6 +180,7 @@ func runBuildModule(ctx context) error {
|
||||
|
||||
type buildHAKOptions struct {
|
||||
filteredHAKs []string
|
||||
filteredArchives []string
|
||||
planOnly bool
|
||||
}
|
||||
|
||||
@@ -205,7 +206,10 @@ func runBuildHAKs(ctx context) error {
|
||||
if opts.planOnly {
|
||||
result, err = pipeline.PlanHAKsWithProgress(p, progress)
|
||||
} else {
|
||||
result, err = pipeline.BuildHAKsWithProgress(p, progress)
|
||||
result, err = pipeline.BuildHAKsWithOptions(p, pipeline.BuildHAKOptions{
|
||||
Progress: progress,
|
||||
ArchiveNames: opts.filteredArchives,
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -230,13 +234,19 @@ func parseBuildHAKArgs(args []string) (buildHAKOptions, error) {
|
||||
arg := args[index]
|
||||
switch arg {
|
||||
case "-h", "--help":
|
||||
return opts, errors.New("usage: build-haks [--hak <hak-name> ...] [--plan-only]")
|
||||
return opts, errors.New("usage: build-haks [--hak <hak-name> ...] [--archive <archive-name> ...] [--plan-only]")
|
||||
case "--hak":
|
||||
index++
|
||||
if index >= len(args) {
|
||||
return opts, errors.New("--hak requires a value")
|
||||
}
|
||||
opts.filteredHAKs = append(opts.filteredHAKs, args[index])
|
||||
case "--archive":
|
||||
index++
|
||||
if index >= len(args) {
|
||||
return opts, errors.New("--archive requires a value")
|
||||
}
|
||||
opts.filteredArchives = append(opts.filteredArchives, args[index])
|
||||
case "--plan-only":
|
||||
opts.planOnly = true
|
||||
default:
|
||||
@@ -244,6 +254,10 @@ func parseBuildHAKArgs(args []string) (buildHAKOptions, error) {
|
||||
opts.filteredHAKs = append(opts.filteredHAKs, value)
|
||||
continue
|
||||
}
|
||||
if value, ok := parseInlineFlagValue(arg, "--archive"); ok {
|
||||
opts.filteredArchives = append(opts.filteredArchives, value)
|
||||
continue
|
||||
}
|
||||
return opts, fmt.Errorf("unknown build-haks argument %q", arg)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,11 @@ type hakChunk struct {
|
||||
|
||||
type ProgressFunc func(string)
|
||||
|
||||
type BuildHAKOptions struct {
|
||||
Progress ProgressFunc
|
||||
ArchiveNames []string
|
||||
}
|
||||
|
||||
func Build(p *project.Project) (BuildResult, error) {
|
||||
var topPackage topdata.PackageResult
|
||||
var err error
|
||||
@@ -145,6 +150,10 @@ func BuildHAKsWithProgress(p *project.Project, progress ProgressFunc) (BuildResu
|
||||
return buildHAKs(p, progress)
|
||||
}
|
||||
|
||||
func BuildHAKsWithOptions(p *project.Project, opts BuildHAKOptions) (BuildResult, error) {
|
||||
return planOrBuildHAKs(p, opts.Progress, true, opts.ArchiveNames)
|
||||
}
|
||||
|
||||
func PlanHAKs(p *project.Project) (BuildResult, error) {
|
||||
return planHAKs(p, nil)
|
||||
}
|
||||
@@ -154,14 +163,14 @@ func PlanHAKsWithProgress(p *project.Project, progress ProgressFunc) (BuildResul
|
||||
}
|
||||
|
||||
func buildHAKs(p *project.Project, progress ProgressFunc) (BuildResult, error) {
|
||||
return planOrBuildHAKs(p, progress, true)
|
||||
return planOrBuildHAKs(p, progress, true, nil)
|
||||
}
|
||||
|
||||
func planHAKs(p *project.Project, progress ProgressFunc) (BuildResult, error) {
|
||||
return planOrBuildHAKs(p, progress, false)
|
||||
return planOrBuildHAKs(p, progress, false, nil)
|
||||
}
|
||||
|
||||
func planOrBuildHAKs(p *project.Project, progress ProgressFunc, writeArchives bool) (BuildResult, error) {
|
||||
func planOrBuildHAKs(p *project.Project, progress ProgressFunc, writeArchives bool, archiveNames []string) (BuildResult, error) {
|
||||
preserveExistingHAKs := envBool("SOW_BUILD_HAKS_KEEP_EXISTING")
|
||||
|
||||
progressf(progress, "Validating project...")
|
||||
@@ -189,6 +198,10 @@ func planOrBuildHAKs(p *project.Project, progress ProgressFunc, writeArchives bo
|
||||
if err != nil {
|
||||
return BuildResult{}, err
|
||||
}
|
||||
chunks, err = filterHAKChunksByName(chunks, archiveNames)
|
||||
if err != nil {
|
||||
return BuildResult{}, err
|
||||
}
|
||||
progressf(progress, "Resolving module HAK order...")
|
||||
moduleHakOrder, err := resolveModuleHAKOrder(p, chunks)
|
||||
if err != nil {
|
||||
@@ -274,6 +287,50 @@ func planOrBuildHAKs(p *project.Project, progress ProgressFunc, writeArchives bo
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func filterHAKChunksByName(chunks []hakChunk, archiveNames []string) ([]hakChunk, error) {
|
||||
if len(archiveNames) == 0 {
|
||||
return chunks, nil
|
||||
}
|
||||
|
||||
wanted := make(map[string]struct{}, len(archiveNames))
|
||||
for _, name := range archiveNames {
|
||||
trimmed := strings.TrimSpace(strings.ToLower(name))
|
||||
if trimmed == "" {
|
||||
continue
|
||||
}
|
||||
wanted[trimmed] = struct{}{}
|
||||
}
|
||||
if len(wanted) == 0 {
|
||||
return chunks, nil
|
||||
}
|
||||
|
||||
filtered := make([]hakChunk, 0, len(wanted))
|
||||
found := make(map[string]struct{}, len(wanted))
|
||||
for _, chunk := range chunks {
|
||||
key := strings.ToLower(strings.TrimSpace(chunk.Name))
|
||||
if _, ok := wanted[key]; !ok {
|
||||
continue
|
||||
}
|
||||
filtered = append(filtered, chunk)
|
||||
found[key] = struct{}{}
|
||||
}
|
||||
|
||||
var missing []string
|
||||
for _, name := range archiveNames {
|
||||
key := strings.TrimSpace(strings.ToLower(name))
|
||||
if key == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := found[key]; !ok {
|
||||
missing = append(missing, name)
|
||||
}
|
||||
}
|
||||
if len(missing) > 0 {
|
||||
return nil, fmt.Errorf("unknown hak archive(s): %s", strings.Join(missing, ", "))
|
||||
}
|
||||
return filtered, nil
|
||||
}
|
||||
|
||||
func progressf(progress ProgressFunc, message string) {
|
||||
if progress != nil {
|
||||
progress(message)
|
||||
|
||||
@@ -3,6 +3,7 @@ package pipeline
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -935,7 +936,6 @@ func TestBuildSplitsMultipleHAKGroupsDeterministically(t *testing.T) {
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
`)
|
||||
mustWriteFile(t, filepath.Join(root, "src", "module", "module.ifo.json"), `{
|
||||
"file_type": "IFO ",
|
||||
@@ -1039,6 +1039,87 @@ func TestBuildSplitsMultipleHAKGroupsDeterministically(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildHAKsWithOptionsBuildsSingleArchiveByName(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
mustMkdir(t, filepath.Join(root, "src"))
|
||||
mustMkdir(t, filepath.Join(root, "src", "module"))
|
||||
mustMkdir(t, filepath.Join(root, "assets", "core"))
|
||||
mustMkdir(t, filepath.Join(root, "build"))
|
||||
|
||||
mustWriteFile(t, filepath.Join(root, "nwn-tool.json"), `{
|
||||
"module": {
|
||||
"name": "Test Module",
|
||||
"resref": "testmod"
|
||||
},
|
||||
"paths": {
|
||||
"source": "src",
|
||||
"assets": "assets",
|
||||
"build": "build"
|
||||
},
|
||||
"haks": [
|
||||
{
|
||||
"name": "core",
|
||||
"priority": 1,
|
||||
"max_bytes": 310,
|
||||
"split": true,
|
||||
"include": ["core/**"]
|
||||
}
|
||||
]
|
||||
}
|
||||
`)
|
||||
mustWriteFile(t, filepath.Join(root, "src", "module", "module.ifo.json"), `{
|
||||
"file_type": "IFO ",
|
||||
"file_version": "V3.2",
|
||||
"root": {
|
||||
"struct_type": 0,
|
||||
"fields": [
|
||||
{
|
||||
"label": "Mod_Name",
|
||||
"type": "CExoString",
|
||||
"value": "Test Module"
|
||||
},
|
||||
{
|
||||
"label": "Mod_HakList",
|
||||
"type": "List",
|
||||
"value": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
`)
|
||||
mustWriteFile(t, filepath.Join(root, "assets", "core", "a.tga"), strings.Repeat("a", 80))
|
||||
mustWriteFile(t, filepath.Join(root, "assets", "core", "b.tga"), strings.Repeat("b", 80))
|
||||
mustWriteFile(t, filepath.Join(root, "assets", "core", "c.tga"), strings.Repeat("c", 80))
|
||||
|
||||
p, err := project.Load(root)
|
||||
if err != nil {
|
||||
t.Fatalf("load project: %v", err)
|
||||
}
|
||||
if err := p.ValidateLayout(); err != nil {
|
||||
t.Fatalf("validate layout: %v", err)
|
||||
}
|
||||
if err := p.Scan(); err != nil {
|
||||
t.Fatalf("scan: %v", err)
|
||||
}
|
||||
|
||||
result, err := BuildHAKsWithOptions(p, BuildHAKOptions{ArchiveNames: []string{"core_02"}})
|
||||
if err != nil {
|
||||
t.Fatalf("build filtered haks: %v", err)
|
||||
}
|
||||
if len(result.HAKPaths) != 1 {
|
||||
t.Fatalf("expected 1 hak output, got %d", len(result.HAKPaths))
|
||||
}
|
||||
if got := filepath.Base(result.HAKPaths[0]); got != "core_02.hak" {
|
||||
t.Fatalf("unexpected hak output %q", got)
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(root, "build", "core_01.hak")); !errors.Is(err, os.ErrNotExist) {
|
||||
t.Fatalf("expected core_01.hak to be absent, got err=%v", err)
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(root, "build", "core.hak")); !errors.Is(err, os.ErrNotExist) {
|
||||
t.Fatalf("expected unsplit core.hak to be absent, got err=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildExcludesOptionalHAKsFromModuleOrder(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
mustMkdir(t, filepath.Join(root, "src"))
|
||||
|
||||
Reference in New Issue
Block a user