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 {
|
type buildHAKOptions struct {
|
||||||
filteredHAKs []string
|
filteredHAKs []string
|
||||||
|
filteredArchives []string
|
||||||
planOnly bool
|
planOnly bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,7 +206,10 @@ func runBuildHAKs(ctx context) error {
|
|||||||
if opts.planOnly {
|
if opts.planOnly {
|
||||||
result, err = pipeline.PlanHAKsWithProgress(p, progress)
|
result, err = pipeline.PlanHAKsWithProgress(p, progress)
|
||||||
} else {
|
} else {
|
||||||
result, err = pipeline.BuildHAKsWithProgress(p, progress)
|
result, err = pipeline.BuildHAKsWithOptions(p, pipeline.BuildHAKOptions{
|
||||||
|
Progress: progress,
|
||||||
|
ArchiveNames: opts.filteredArchives,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -230,13 +234,19 @@ func parseBuildHAKArgs(args []string) (buildHAKOptions, error) {
|
|||||||
arg := args[index]
|
arg := args[index]
|
||||||
switch arg {
|
switch arg {
|
||||||
case "-h", "--help":
|
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":
|
case "--hak":
|
||||||
index++
|
index++
|
||||||
if index >= len(args) {
|
if index >= len(args) {
|
||||||
return opts, errors.New("--hak requires a value")
|
return opts, errors.New("--hak requires a value")
|
||||||
}
|
}
|
||||||
opts.filteredHAKs = append(opts.filteredHAKs, args[index])
|
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":
|
case "--plan-only":
|
||||||
opts.planOnly = true
|
opts.planOnly = true
|
||||||
default:
|
default:
|
||||||
@@ -244,6 +254,10 @@ func parseBuildHAKArgs(args []string) (buildHAKOptions, error) {
|
|||||||
opts.filteredHAKs = append(opts.filteredHAKs, value)
|
opts.filteredHAKs = append(opts.filteredHAKs, value)
|
||||||
continue
|
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)
|
return opts, fmt.Errorf("unknown build-haks argument %q", arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,11 @@ type hakChunk struct {
|
|||||||
|
|
||||||
type ProgressFunc func(string)
|
type ProgressFunc func(string)
|
||||||
|
|
||||||
|
type BuildHAKOptions struct {
|
||||||
|
Progress ProgressFunc
|
||||||
|
ArchiveNames []string
|
||||||
|
}
|
||||||
|
|
||||||
func Build(p *project.Project) (BuildResult, error) {
|
func Build(p *project.Project) (BuildResult, error) {
|
||||||
var topPackage topdata.PackageResult
|
var topPackage topdata.PackageResult
|
||||||
var err error
|
var err error
|
||||||
@@ -145,6 +150,10 @@ func BuildHAKsWithProgress(p *project.Project, progress ProgressFunc) (BuildResu
|
|||||||
return buildHAKs(p, progress)
|
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) {
|
func PlanHAKs(p *project.Project) (BuildResult, error) {
|
||||||
return planHAKs(p, nil)
|
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) {
|
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) {
|
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")
|
preserveExistingHAKs := envBool("SOW_BUILD_HAKS_KEEP_EXISTING")
|
||||||
|
|
||||||
progressf(progress, "Validating project...")
|
progressf(progress, "Validating project...")
|
||||||
@@ -189,6 +198,10 @@ func planOrBuildHAKs(p *project.Project, progress ProgressFunc, writeArchives bo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return BuildResult{}, err
|
return BuildResult{}, err
|
||||||
}
|
}
|
||||||
|
chunks, err = filterHAKChunksByName(chunks, archiveNames)
|
||||||
|
if err != nil {
|
||||||
|
return BuildResult{}, err
|
||||||
|
}
|
||||||
progressf(progress, "Resolving module HAK order...")
|
progressf(progress, "Resolving module HAK order...")
|
||||||
moduleHakOrder, err := resolveModuleHAKOrder(p, chunks)
|
moduleHakOrder, err := resolveModuleHAKOrder(p, chunks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -274,6 +287,50 @@ func planOrBuildHAKs(p *project.Project, progress ProgressFunc, writeArchives bo
|
|||||||
return result, nil
|
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) {
|
func progressf(progress ProgressFunc, message string) {
|
||||||
if progress != nil {
|
if progress != nil {
|
||||||
progress(message)
|
progress(message)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package pipeline
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -935,7 +936,6 @@ func TestBuildSplitsMultipleHAKGroupsDeterministically(t *testing.T) {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
`)
|
`)
|
||||||
mustWriteFile(t, filepath.Join(root, "src", "module", "module.ifo.json"), `{
|
mustWriteFile(t, filepath.Join(root, "src", "module", "module.ifo.json"), `{
|
||||||
"file_type": "IFO ",
|
"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) {
|
func TestBuildExcludesOptionalHAKsFromModuleOrder(t *testing.T) {
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
mustMkdir(t, filepath.Join(root, "src"))
|
mustMkdir(t, filepath.Join(root, "src"))
|
||||||
|
|||||||
Reference in New Issue
Block a user