From 2b3f3c56c60ca91f2bad30dad88ce6157b7e6932 Mon Sep 17 00:00:00 2001 From: Ahmed Semih Ozmekik Date: Mon, 26 Oct 2026 18:31:18 +0300 Subject: [PATCH] fix: check the target directory before cutting When the target directory did not exist, the cut failed with "cannot extract from package "base-files": target directory does not exist", which pointed at the first package being extracted rather than at the directory, and only after the packages were fetched. Check the target directory at the start of slicer.Run and return an error that names it, also covering the case where the path exists but is not a directory. The check in the tarball package is kept, as that package has its own API. Fixes #234. --- internal/slicer/slicer.go | 12 ++++++++++++ internal/slicer/slicer_test.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/internal/slicer/slicer.go b/internal/slicer/slicer.go index ce791162..51d8e195 100644 --- a/internal/slicer/slicer.go +++ b/internal/slicer/slicer.go @@ -90,6 +90,18 @@ func Run(options *RunOptions) error { targetDir = filepath.Join(dir, targetDir) } + // Check the target directory before fetching any packages, so that the + // error names it instead of surfacing later while extracting a package. + targetInfo, err := os.Stat(targetDir) + if os.IsNotExist(err) { + return fmt.Errorf("target directory does not exist: %s", targetDir) + } else if err != nil { + return err + } + if !targetInfo.IsDir() { + return fmt.Errorf("target is not a directory: %s", targetDir) + } + pkgArchive, err := selectPkgArchives(options.Archives, options.Selection) if err != nil { return err diff --git a/internal/slicer/slicer_test.go b/internal/slicer/slicer_test.go index d6ef9ca0..f5d24c19 100644 --- a/internal/slicer/slicer_test.go +++ b/internal/slicer/slicer_test.go @@ -634,6 +634,40 @@ var slicerTests = []slicerTest{{ opts.TargetDir, err = filepath.Rel(dir, opts.TargetDir) c.Assert(err, IsNil) }, +}, { + summary: "Target directory must exist", + slices: []setup.SliceKey{{"test-package", "myslice"}}, + release: map[string]string{ + "slices/mydir/test-package.yaml": ` + package: test-package + slices: + myslice: + contents: + /dir/file: + `, + }, + hackopt: func(c *C, opts *slicer.RunOptions) { + opts.TargetDir = filepath.Join(opts.TargetDir, "missing") + }, + error: `target directory does not exist: .*/missing`, +}, { + summary: "Target directory must be a directory", + slices: []setup.SliceKey{{"test-package", "myslice"}}, + release: map[string]string{ + "slices/mydir/test-package.yaml": ` + package: test-package + slices: + myslice: + contents: + /dir/file: + `, + }, + hackopt: func(c *C, opts *slicer.RunOptions) { + opts.TargetDir = filepath.Join(opts.TargetDir, "file") + err := os.WriteFile(opts.TargetDir, nil, 0644) + c.Assert(err, IsNil) + }, + error: `target is not a directory: .*/file`, }, { summary: "Can list parent directories of normal paths", slices: []setup.SliceKey{{"test-package", "myslice"}},