Move generated file writes into owning adapters
This commit is contained in:
@@ -7,9 +7,6 @@ import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gitea.maximumdirect.net/eric/narratio/internal/fileops"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// RunRequest defines a subprocess invocation.
|
||||
@@ -108,29 +105,6 @@ func Run(ctx context.Context, req RunRequest) (RunResult, error) {
|
||||
return result, fmt.Errorf("command failed to run (%s): %w", diagnostics, joinErrors(outcome.waitErr, outcome.contextErr, outcome.abortErr, cleanupErr))
|
||||
}
|
||||
|
||||
// WriteYAMLAtomic marshals value as YAML and atomically writes it to path.
|
||||
func WriteYAMLAtomic(path string, value any, perm os.FileMode) error {
|
||||
data, err := yaml.Marshal(value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshal yaml for %q: %w", path, err)
|
||||
}
|
||||
if err := WriteFileAtomic(path, data, perm); err != nil {
|
||||
return fmt.Errorf("write yaml %q: %w", path, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteFileAtomic writes bytes through the shared durable replacement primitive.
|
||||
func WriteFileAtomic(path string, data []byte, perm os.FileMode) error {
|
||||
if strings.TrimSpace(path) == "" {
|
||||
return fmt.Errorf("write file: path is required")
|
||||
}
|
||||
if err := fileops.WriteFileAtomic(path, data, perm); err != nil {
|
||||
return fmt.Errorf("write file %q: %w", path, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildDiagnostics(req RunRequest, result RunResult, stderrTail string) string {
|
||||
details := fmt.Sprintf(
|
||||
"executable=%q args=%v cwd=%q timeout=%s exit_code=%d timed_out=%t canceled=%t stdout_log=%q stderr_log=%q",
|
||||
|
||||
@@ -14,8 +14,6 @@ import (
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func TestRunSuccessCapturesStdoutStderr(t *testing.T) {
|
||||
@@ -592,59 +590,6 @@ func TestRunSharedStdoutStderrLogPath(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteYAMLAtomic(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := filepath.Join(dir, "config.generated.yml")
|
||||
|
||||
if err := WriteYAMLAtomic(path, map[string]any{"name": "narratio", "stage": "merge"}, 0o644); err != nil {
|
||||
t.Fatalf("WriteYAMLAtomic() error = %v", err)
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatalf("read yaml: %v", err)
|
||||
}
|
||||
|
||||
var got map[string]any
|
||||
if err := yaml.Unmarshal(data, &got); err != nil {
|
||||
t.Fatalf("yaml unmarshal: %v", err)
|
||||
}
|
||||
if got["name"] != "narratio" {
|
||||
t.Fatalf("name = %#v, want narratio", got["name"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteYAMLAtomicOverwriteNoTempResidue(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := filepath.Join(dir, "config.generated.yml")
|
||||
|
||||
if err := WriteYAMLAtomic(path, map[string]any{"value": "one"}, 0o644); err != nil {
|
||||
t.Fatalf("first write: %v", err)
|
||||
}
|
||||
if err := WriteYAMLAtomic(path, map[string]any{"value": "two"}, 0o644); err != nil {
|
||||
t.Fatalf("second write: %v", err)
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatalf("read yaml: %v", err)
|
||||
}
|
||||
if !strings.Contains(string(data), "two") {
|
||||
t.Fatalf("yaml = %q, want overwritten value", string(data))
|
||||
}
|
||||
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
t.Fatalf("ReadDir() error = %v", err)
|
||||
}
|
||||
for _, entry := range entries {
|
||||
name := entry.Name()
|
||||
if strings.Contains(name, ".tmp-") {
|
||||
t.Fatalf("temp file residue found: %q", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubprocessHelper(t *testing.T) {
|
||||
if os.Getenv("GO_WANT_SUBPROCESS_HELPER") != "1" {
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user