1package polyfill
  2
  3import (
  4	"os"
  5	"path/filepath"
  6
  7	"github.com/go-git/go-billy/v5"
  8)
  9
 10// Polyfill is a helper that implements all missing method from billy.Filesystem.
 11type Polyfill struct {
 12	billy.Basic
 13	c capabilities
 14}
 15
 16type capabilities struct{ tempfile, dir, symlink, chroot, chmod bool }
 17
 18// New creates a new filesystem wrapping up 'fs' the intercepts all the calls
 19// made and errors if fs doesn't implement any of the billy interfaces.
 20func New(fs billy.Basic) billy.Filesystem {
 21	if original, ok := fs.(billy.Filesystem); ok {
 22		return original
 23	}
 24
 25	h := &Polyfill{Basic: fs}
 26
 27	_, h.c.tempfile = h.Basic.(billy.TempFile)
 28	_, h.c.dir = h.Basic.(billy.Dir)
 29	_, h.c.symlink = h.Basic.(billy.Symlink)
 30	_, h.c.chroot = h.Basic.(billy.Chroot)
 31	_, h.c.chmod = h.Basic.(billy.Chmod)
 32	return h
 33}
 34
 35func (h *Polyfill) TempFile(dir, prefix string) (billy.File, error) {
 36	if !h.c.tempfile {
 37		return nil, billy.ErrNotSupported
 38	}
 39
 40	return h.Basic.(billy.TempFile).TempFile(dir, prefix)
 41}
 42
 43func (h *Polyfill) ReadDir(path string) ([]os.FileInfo, error) {
 44	if !h.c.dir {
 45		return nil, billy.ErrNotSupported
 46	}
 47
 48	return h.Basic.(billy.Dir).ReadDir(path)
 49}
 50
 51func (h *Polyfill) MkdirAll(filename string, perm os.FileMode) error {
 52	if !h.c.dir {
 53		return billy.ErrNotSupported
 54	}
 55
 56	return h.Basic.(billy.Dir).MkdirAll(filename, perm)
 57}
 58
 59func (h *Polyfill) Symlink(target, link string) error {
 60	if !h.c.symlink {
 61		return billy.ErrNotSupported
 62	}
 63
 64	return h.Basic.(billy.Symlink).Symlink(target, link)
 65}
 66
 67func (h *Polyfill) Readlink(link string) (string, error) {
 68	if !h.c.symlink {
 69		return "", billy.ErrNotSupported
 70	}
 71
 72	return h.Basic.(billy.Symlink).Readlink(link)
 73}
 74
 75func (h *Polyfill) Lstat(path string) (os.FileInfo, error) {
 76	if !h.c.symlink {
 77		return nil, billy.ErrNotSupported
 78	}
 79
 80	return h.Basic.(billy.Symlink).Lstat(path)
 81}
 82
 83func (h *Polyfill) Chroot(path string) (billy.Filesystem, error) {
 84	if !h.c.chroot {
 85		return nil, billy.ErrNotSupported
 86	}
 87
 88	return h.Basic.(billy.Chroot).Chroot(path)
 89}
 90
 91func (h *Polyfill) Chmod(path string, mode os.FileMode) error {
 92	if !h.c.chmod {
 93		return billy.ErrNotSupported
 94	}
 95
 96	return h.Basic.(billy.Chmod).Chmod(path, mode)
 97}
 98
 99func (h *Polyfill) Root() string {
100	if !h.c.chroot {
101		return string(filepath.Separator)
102	}
103
104	return h.Basic.(billy.Chroot).Root()
105}
106
107func (h *Polyfill) Underlying() billy.Basic {
108	return h.Basic
109}
110
111// Capabilities implements the Capable interface.
112func (h *Polyfill) Capabilities() billy.Capability {
113	return billy.Capabilities(h.Basic)
114}