Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions internal/librariangen/config/repoconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ type ModuleConfig struct {
ModulePathVersion string `yaml:"module_path_version"`
// APIs is the list of APIs within this module (that need overrides).
APIs []*APIConfig `yaml:"apis"`
// DeleteGenerationOutputPaths specifies paths (files or directories) to
// be deleted from the output directory at the end of generation. This is for files
// which it is difficult to prevent from being generated, but which shouldn't appear
// in the repo.
DeleteGenerationOutputPaths []string `yaml:"delete_generation_output_paths"`
}

// APIConfig provides per-API configuration to override defaults,
Expand Down
20 changes: 20 additions & 0 deletions internal/librariangen/generate/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ func Generate(ctx context.Context, cfg *Config) error {
return fmt.Errorf("librariangen: post-processing failed: %w", err)
}
}
if err := deleteOutputPaths(cfg.OutputDir, moduleConfig.DeleteGenerationOutputPaths); err != nil {
return fmt.Errorf("librariangen: failed to delete paths specified in delete_generation_output_paths: %w", err)
}

slog.Debug("librariangen: generate command finished")
return nil
Expand Down Expand Up @@ -280,3 +283,20 @@ func moveFiles(sourceDir, targetDir string) error {
}
return nil
}

// deleteOutputPaths deletes the specified paths, which may be files
// or directories, relative to the output directory. This is an emergency
// escape hatch for situations where files are generated that we don't want
// to include, such as the internal/generated/snippets/storage/internal directory.
// This is configured in repo-config.yaml at the library level, with the key
// delete_generation_output_paths.
func deleteOutputPaths(outputDir string, pathsToDelete []string) error {
for _, path := range pathsToDelete {
// This is so rare that it's useful to be able to validate it easily.
slog.Info("deleting output path", "path", path)
if err := os.RemoveAll(filepath.Join(outputDir, path)); err != nil {
return err
}
}
return nil
}
Comment thread
quartzmo marked this conversation as resolved.
55 changes: 44 additions & 11 deletions internal/librariangen/generate/generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -468,17 +468,50 @@ func TestApplyModuleVersion(t *testing.T) {
if tt.wantErr {
return
}

for _, wantPresent := range tt.wantPresent {
if _, err := os.Stat(filepath.Join(tmpDir, wantPresent)); err != nil {
t.Errorf("wanted present, was absent: %s", wantPresent)
}
}
for _, wantAbsent := range tt.wantAbsent {
if _, err := os.Stat(filepath.Join(tmpDir, wantAbsent)); !os.IsNotExist(err) {
t.Errorf("wanted absent, was missing: %s", wantAbsent)
}
}
assertPresent(t, tmpDir, tt.wantPresent)
assertAbsent(t, tmpDir, tt.wantAbsent)
})
}
}

func TestDeleteOutputPaths(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "apply-module-version-test")
if err != nil {
t.Fatalf("failed to create temp dir: %v", err)
}
// We create file1, file2 and dir1/file3, then delete
// file1 and dir1; only file2 should be left.
if err := os.MkdirAll(filepath.Join(tmpDir, "dir1"), 0755); err != nil {
t.Fatalf("failed to create dir1: %v", err)
}
if err := os.WriteFile(filepath.Join(tmpDir, "file1"), []byte("test"), 0644); err != nil {
t.Fatalf("failed to write file1: %v", err)
}
if err := os.WriteFile(filepath.Join(tmpDir, "file2"), []byte("test"), 0644); err != nil {
t.Fatalf("failed to write file file2: %v", err)
}
if err := os.WriteFile(filepath.Join(tmpDir, "dir1", "file3"), []byte("test"), 0644); err != nil {
t.Fatalf("failed to write file dir1/file3: %v", err)
}
deleteOutputPaths(tmpDir, []string{"file1", "dir1"})
assertPresent(t, tmpDir, []string{"file2"})
assertAbsent(t, tmpDir, []string{"file1", "dir1"})
}
Comment thread
jskeet marked this conversation as resolved.

func assertPresent(t *testing.T, dir string, paths []string) {
t.Helper()
for _, path := range paths {
if _, err := os.Stat(filepath.Join(dir, path)); err != nil {
t.Errorf("wanted present, stat failed: %s", path)
}
}
}

func assertAbsent(t *testing.T, dir string, paths []string) {
t.Helper()
for _, path := range paths {
if _, err := os.Stat(filepath.Join(dir, path)); !os.IsNotExist(err) {
t.Errorf("wanted absent, was present (or stat failed): %s", path)
}
}
}