diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 122efc8..5796af7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,7 +5,7 @@ jobs: test: strategy: matrix: - go-version: [1.21.x,1.22.x,1.23.x] + go-version: [1.24.x, oldstable, stable] platform: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.platform }} steps: diff --git a/helper/polyfill/polyfill.go b/helper/polyfill/polyfill.go index 1efce0e..9fe131b 100644 --- a/helper/polyfill/polyfill.go +++ b/helper/polyfill/polyfill.go @@ -13,7 +13,7 @@ type Polyfill struct { c capabilities } -type capabilities struct{ tempfile, dir, symlink, chroot bool } +type capabilities struct{ tempfile, dir, symlink, chroot, chmod bool } // New creates a new filesystem wrapping up 'fs' the intercepts all the calls // made and errors if fs doesn't implement any of the billy interfaces. @@ -28,6 +28,7 @@ func New(fs billy.Basic) billy.Filesystem { _, h.c.dir = h.Basic.(billy.Dir) _, h.c.symlink = h.Basic.(billy.Symlink) _, h.c.chroot = h.Basic.(billy.Chroot) + _, h.c.chmod = h.Basic.(billy.Chmod) return h } @@ -87,6 +88,14 @@ func (h *Polyfill) Chroot(path string) (billy.Filesystem, error) { return h.Basic.(billy.Chroot).Chroot(path) } +func (h *Polyfill) Chmod(path string, mode os.FileMode) error { + if !h.c.chmod { + return billy.ErrNotSupported + } + + return h.Basic.(billy.Chmod).Chmod(path, mode) +} + func (h *Polyfill) Root() string { if !h.c.chroot { return string(filepath.Separator) diff --git a/helper/polyfill/polyfill_test.go b/helper/polyfill/polyfill_test.go index b0df9a7..0e908af 100644 --- a/helper/polyfill/polyfill_test.go +++ b/helper/polyfill/polyfill_test.go @@ -58,6 +58,14 @@ func (s *PolyfillSuite) TestChroot(c *C) { c.Assert(err, Equals, billy.ErrNotSupported) } +func (s *PolyfillSuite) TestChmod(c *C) { + ch, ok := s.Helper.(billy.Chmod) + c.Assert(ok, Equals, true) + + err := ch.Chmod("", 0o444) + c.Assert(err, Equals, billy.ErrNotSupported) +} + func (s *PolyfillSuite) TestRoot(c *C) { c.Assert(s.Helper.Root(), Equals, string(filepath.Separator)) } diff --git a/osfs/os_bound.go b/osfs/os_bound.go index 6f54480..92ebc3d 100644 --- a/osfs/os_bound.go +++ b/osfs/os_bound.go @@ -126,6 +126,14 @@ func (fs *BoundOS) TempFile(dir, prefix string) (billy.File, error) { if err != nil { return nil, err } + + _, err = os.Stat(dir) + if err != nil && os.IsNotExist(err) { + err = os.MkdirAll(dir, defaultDirectoryMode) + if err != nil { + return nil, err + } + } } return tempFile(dir, prefix) diff --git a/osfs/os_bound_test.go b/osfs/os_bound_test.go index ed446a6..8d9ee72 100644 --- a/osfs/os_bound_test.go +++ b/osfs/os_bound_test.go @@ -247,9 +247,10 @@ func TestTempFile(t *testing.T) { g.Expect(f.Close()).ToNot(gomega.HaveOccurred()) f, err = fs.TempFile("/above/cwd", "prefix") - g.Expect(err).To(gomega.HaveOccurred()) - g.Expect(err.Error()).To(gomega.ContainSubstring(fmt.Sprint(dir, filepath.FromSlash("/above/cwd/prefix")))) - g.Expect(f).To(gomega.BeNil()) + g.Expect(err).ToNot(gomega.HaveOccurred()) + g.Expect(f).ToNot(gomega.BeNil()) + g.Expect(f.Name()).To(gomega.HavePrefix(filepath.Join(dir, "/above/cwd", "prefix"))) + g.Expect(f.Close()).ToNot(gomega.HaveOccurred()) tempDir := os.TempDir() // For windows, volume name must be removed. @@ -258,9 +259,10 @@ func TestTempFile(t *testing.T) { } f, err = fs.TempFile(tempDir, "prefix") - g.Expect(err).To(gomega.HaveOccurred()) - g.Expect(err.Error()).To(gomega.ContainSubstring(filepath.Join(dir, tempDir, "prefix"))) - g.Expect(f).To(gomega.BeNil()) + g.Expect(err).ToNot(gomega.HaveOccurred()) + g.Expect(f).ToNot(gomega.BeNil()) + g.Expect(f.Name()).To(gomega.HavePrefix(filepath.Join(dir, tempDir, "prefix"))) + g.Expect(f.Close()).ToNot(gomega.HaveOccurred()) } func TestChroot(t *testing.T) { @@ -1105,10 +1107,10 @@ func TestReadDir(t *testing.T) { g.Expect(dirs).To(gomega.BeNil()) } -func TestInsideBaseDirEval(t*testing.T) { +func TestInsideBaseDirEval(t *testing.T) { g := gomega.NewWithT(t) fs := BoundOS{baseDir: "/"} - b, err := fs.insideBaseDirEval("a") + b, err := fs.insideBaseDirEval("a") g.Expect(b).To(gomega.BeTrue()) g.Expect(err).To(gomega.BeNil()) }