fix(core): keep workspace runtime available

This commit is contained in:
Codex
2026-09-08 13:37:10 +02:00
parent 50c546e42d
commit 818563c408
6 changed files with 192 additions and 24 deletions
@@ -140,7 +140,8 @@ func Render(installation config.Installation) (map[string][]byte, error) {
}, nil
}
// Generate publishes all adapters as one directory generation. A failed replacement restores the
// Generate publishes all adapters as one directory generation. An unchanged generation stays in
// place so active file bind mounts keep their source identity. A failed replacement restores the
// previous directory, so callers never observe a successfully returned mixed generation.
func Generate(installation config.Installation) error {
artifacts, err := Render(installation)
@@ -152,6 +153,17 @@ func Generate(installation config.Installation) error {
if err := os.MkdirAll(parent, 0o755); err != nil {
return fmt.Errorf("create model projection parent: %w", err)
}
info, statErr := os.Lstat(target)
if statErr == nil {
if !info.IsDir() || info.Mode()&os.ModeSymlink != 0 {
return fmt.Errorf("current model projection path is not a regular directory")
}
if projectionMatches(target, artifacts) {
return nil
}
} else if !os.IsNotExist(statErr) {
return fmt.Errorf("inspect current model projection generation: %w", statErr)
}
candidate, err := os.MkdirTemp(parent, ".model-projections-candidate-*")
if err != nil {
return fmt.Errorf("create model projection candidate: %w", err)
@@ -161,19 +173,12 @@ func Generate(installation config.Installation) error {
return err
}
info, statErr := os.Lstat(target)
if os.IsNotExist(statErr) {
if err := renameProjectionDirectory(candidate, target); err != nil {
return fmt.Errorf("publish model projection generation: %w", err)
}
return nil
}
if statErr != nil {
return fmt.Errorf("inspect current model projection generation: %w", statErr)
}
if !info.IsDir() || info.Mode()&os.ModeSymlink != 0 {
return fmt.Errorf("current model projection path is not a regular directory")
}
previous, err := absentTemporaryPath(parent)
if err != nil {
return fmt.Errorf("reserve previous model projection generation: %w", err)
@@ -191,6 +196,21 @@ func Generate(installation config.Installation) error {
return nil
}
func projectionMatches(directory string, artifacts map[string][]byte) bool {
for _, relative := range sortedArtifactPaths(artifacts) {
path := filepath.Join(directory, filepath.FromSlash(relative))
info, err := os.Lstat(path)
if err != nil || !info.Mode().IsRegular() {
return false
}
actual, err := os.ReadFile(path)
if err != nil || !bytes.Equal(actual, artifacts[relative]) {
return false
}
}
return true
}
func writeProjectionCandidate(directory string, artifacts map[string][]byte) error {
if err := os.Chmod(directory, 0o755); err != nil {
return fmt.Errorf("protect model projection candidate: %w", err)
@@ -56,6 +56,50 @@ func TestRenderProducesDeterministicCatalogPiAndComposeProjections(t *testing.T)
}
}
func TestGenerateDoesNotReplaceUnchangedProjection(t *testing.T) {
installation := projectionFixture(t)
if err := Generate(installation); err != nil {
t.Fatalf("Generate() initial error = %v", err)
}
paths := []string{
installation.GeneratedModelCatalogPath(),
installation.GeneratedPiModelsPath(),
installation.GeneratedPiSettingsPath(),
installation.ModelProjectionComposePath(),
}
before := make(map[string]os.FileInfo, len(paths))
for _, path := range paths {
info, err := os.Stat(path)
if err != nil {
t.Fatal(err)
}
before[path] = info
}
originalRename := renameProjectionDirectory
t.Cleanup(func() { renameProjectionDirectory = originalRename })
renames := 0
renameProjectionDirectory = func(oldPath, newPath string) error {
renames++
return os.Rename(oldPath, newPath)
}
if err := Generate(installation); err != nil {
t.Fatalf("Generate() repeated error = %v", err)
}
if renames != 0 {
t.Fatalf("Generate() replaced an unchanged generation with %d renames", renames)
}
for _, path := range paths {
after, err := os.Stat(path)
if err != nil {
t.Fatal(err)
}
if !os.SameFile(before[path], after) {
t.Fatalf("Generate() replaced unchanged artifact %q", path)
}
}
}
func TestGenerateRestoresWholePreviousGenerationWhenPublishFails(t *testing.T) {
installation := projectionFixture(t)
if err := Generate(installation); err != nil {