Skip to content
Open
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
1 change: 1 addition & 0 deletions .nextchanges/cli/template-skip-dir-not-created.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
`bundle init` no longer creates an empty directory when a template's `{{skip}}` directive names a directory that the template walk had already visited.
18 changes: 17 additions & 1 deletion libs/template/renderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,8 +372,24 @@ func (r *renderer) persistToDisk(ctx context.Context, out filer.Filer) error {
continue
}

// A {{skip}} directive can name a directory the walk has already
// visited, because the directive lives in a file processed later.
// walk() only tests the patterns known when it reaches a directory, so
// re-test the accumulated set here; otherwise the directory is created
// even though it was explicitly skipped. This leaves directories whose
// files merely happened to be skipped untouched, since those patterns
// match the files rather than the directory itself.
match, err := isSkipped(dir, r.skipPatterns)
if err != nil {
return err
}
if match {
log.Infof(r.ctx, "skipping directory: %s", dir)
continue
}

// Check if directory already exists (may have been created during file writes)
_, err := out.Stat(ctx, dir)
_, err = out.Stat(ctx, dir)
if err == nil {
// Directory already exists, nothing to do
continue
Expand Down
26 changes: 26 additions & 0 deletions libs/template/renderer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -631,3 +631,29 @@ func TestRendererSubTemplateInPath(t *testing.T) {
assert.Equal(t, "my_directory/my_file", f.RelPath())
}
}

// A {{skip}} directive can name a directory that the BFS walk has already
// visited, because the directive lives in a file processed later. The
// directory must still not be created: the walk records visited directories
// before any later file can skip them, so the skip patterns have to be applied
// again when directories are materialized.
func TestRendererSkipDirectoryVisitedBeforeSkipDirective(t *testing.T) {
ctx := t.Context()
ctx = cmdctx.SetWorkspaceClient(ctx, nil)
tmpDir := t.TempDir()

helpers := loadHelpers(ctx)
r, err := newRenderer(ctx, nil, helpers, os.DirFS("."), "./testdata/skip-dir-after-visit/template", "./testdata/skip-dir-after-visit/library")
require.NoError(t, err)

err = r.walk()
require.NoError(t, err)

out, err := filer.NewLocalClient(tmpDir)
require.NoError(t, err)
err = r.persistToDisk(ctx, out)
require.NoError(t, err)

assert.NoDirExists(t, filepath.Join(tmpDir, "dir1"))
assert.FileExists(t, filepath.Join(tmpDir, "dir2", "file2"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This file is skipped by dir2, so dir1 must not be created
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
I should be the only file created

{{skip "../dir1"}}{{skip "../dir1/*"}}