Skip to content

Commit

Permalink
feat: Add remove functionality (#13)
Browse files Browse the repository at this point in the history
* feat: Add remove functionality

Signed-off-by: Owen Rumney <owen@owenrumney.co.uk>

* feat: Add RemoveAll functionality

Signed-off-by: Owen Rumney <owen@owenrumney.co.uk>
  • Loading branch information
owenrumney authored May 4, 2022
1 parent 959a422 commit 34bba9d
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 0 deletions.
57 changes: 57 additions & 0 deletions dir.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,69 @@ func (d *dir) Open(name string) (fs.File, error) {
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist}
}

func (d *dir) Remove(name string) error {
if name == "" || name == "." {
return nil
}

return d.removePath(name, false)
}

func (d *dir) RemoveAll(name string) error {
if name == "" || name == "." {
return nil
}

return d.removePath(name, true)
}

func (d *dir) Stat() (fs.FileInfo, error) {
d.RLock()
defer d.RUnlock()
return d.info, nil
}

func (d *dir) removePath(name string, recursive bool) error {

parts := strings.Split(name, separator)
if len(parts) == 1 {
d.RLock()
_, ok := d.files[name]
d.RUnlock()
if ok {
delete(d.files, name)
return nil
}

if sub, err := d.getDir(parts[0]); err == nil {
d.RLock()
defer d.RUnlock()
if len(sub.dirs) == 0 && len(sub.files) == 0 {
delete(d.dirs, parts[0])
return nil
} else if recursive {
for _, s := range sub.dirs {
sub.removePath(s.info.name, recursive)
}
for _, f := range sub.files {
sub.removePath(f.info.name, recursive)
}
delete(d.dirs, parts[0])
return nil
}
return fs.ErrInvalid
}
return fs.ErrNotExist
}

sub, err := d.getDir(parts[0])
if err != nil {
return err
}

return sub.removePath(strings.Join(parts[1:], separator), recursive)
}

func (d *dir) getFile(name string) (*file, error) {

parts := strings.Split(name, separator)
Expand Down
10 changes: 10 additions & 0 deletions fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,13 @@ func (m *FS) Glob(pattern string) ([]string, error) {
func (m *FS) WriteLazyFile(path string, opener LazyOpener, perm fs.FileMode) error {
return m.dir.WriteLazyFile(cleanse(path), opener, perm)
}

// Remove deletes a file or directory from the filesystem
func (m *FS) Remove(path string) error {
return m.dir.Remove(cleanse(path))
}

// RemoveAll deletes a file or directory and any children if present from the filesystem
func (m *FS) RemoveAll(path string) error {
return m.dir.RemoveAll(cleanse(path))
}
122 changes: 122 additions & 0 deletions fs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,128 @@ func Test_WriteWhileOpen(t *testing.T) {
assert.Equal(t, "hello world", string(data))
}

func Test_DeleteFile(t *testing.T) {
memfs := New()
err := memfs.WriteFile("test.txt", []byte("hello world"), 0o644)
require.NoError(t, err)

f, err := memfs.Open("test.txt")
require.NoError(t, err)
data, err := ioutil.ReadAll(f)
require.NoError(t, err)
assert.Equal(t, "hello world", string(data))

err = memfs.Remove("test.txt")
require.NoError(t, err)

_, err = memfs.Open("test.txt")
require.Error(t, err)
}

func Test_DeleteNestedFile(t *testing.T) {
memfs := New()
err := memfs.MkdirAll("/some/arbitrary/path", 0o644)
require.NoError(t, err)
err = memfs.WriteFile("/some/arbitrary/path/test.txt", []byte("hello world"), 0o644)
require.NoError(t, err)

f, err := memfs.Open("/some/arbitrary/path/test.txt")
require.NoError(t, err)
data, err := ioutil.ReadAll(f)
require.NoError(t, err)
assert.Equal(t, "hello world", string(data))

err = memfs.Remove("/some/arbitrary/path/test.txt")
require.NoError(t, err)

_, err = memfs.Open("/some/arbitrary/path/test.txt")
require.Error(t, err)
}

func Test_DeleteEmptyDirectory(t *testing.T) {
memfs := New()
err := memfs.MkdirAll("/some/arbitrary/path", 0o644)
require.NoError(t, err)
err = memfs.WriteFile("/some/arbitrary/path/test.txt", []byte("hello world"), 0o644)
require.NoError(t, err)

f, err := memfs.Open("/some/arbitrary/path/test.txt")
require.NoError(t, err)
data, err := ioutil.ReadAll(f)
require.NoError(t, err)
assert.Equal(t, "hello world", string(data))

err = memfs.Remove("/some/arbitrary/path/test.txt")
require.NoError(t, err)

err = memfs.Remove("/some/arbitrary/path")
require.NoError(t, err)

_, err = memfs.Stat("/some/arbitrary/path")
require.Error(t, err)
}

func Test_DeleteNonEmptyDirectoryError(t *testing.T) {
memfs := New()
err := memfs.MkdirAll("/some/arbitrary/path", 0o644)
require.NoError(t, err)
err = memfs.WriteFile("/some/arbitrary/path/test.txt", []byte("hello world"), 0o644)
require.NoError(t, err)

f, err := memfs.Open("/some/arbitrary/path/test.txt")
require.NoError(t, err)
data, err := ioutil.ReadAll(f)
require.NoError(t, err)
assert.Equal(t, "hello world", string(data))

err = memfs.Remove("/some/arbitrary/path")
require.Error(t, err)
}

func Test_DeleteNonEmptyDirectorySuccess(t *testing.T) {
memfs := New()
err := memfs.MkdirAll("/some/arbitrary/path", 0o644)
require.NoError(t, err)
err = memfs.WriteFile("/some/arbitrary/path/test.txt", []byte("hello world"), 0o644)
require.NoError(t, err)
err = memfs.WriteFile("/some/arbitrary/path/test2.txt", []byte("hello world too"), 0o644)
require.NoError(t, err)

f, err := memfs.Open("/some/arbitrary/path/test.txt")
require.NoError(t, err)
data, err := ioutil.ReadAll(f)
require.NoError(t, err)
assert.Equal(t, "hello world", string(data))

err = memfs.Remove("/some/arbitrary/path")
require.Error(t, err)

err = memfs.RemoveAll("/some/arbitrary/path")
require.NoError(t, err)
}

func Test_DeleteNonEmptyDirectorySuccessFromHigherLevel(t *testing.T) {
memfs := New()
err := memfs.MkdirAll("/some/arbitrary/path", 0o644)
require.NoError(t, err)
err = memfs.WriteFile("/some/arbitrary/path/test.txt", []byte("hello world"), 0o644)
require.NoError(t, err)
err = memfs.WriteFile("/some/arbitrary/path/test2.txt", []byte("hello world too"), 0o644)
require.NoError(t, err)

f, err := memfs.Open("/some/arbitrary/path/test.txt")
require.NoError(t, err)
data, err := ioutil.ReadAll(f)
require.NoError(t, err)
assert.Equal(t, "hello world", string(data))

err = memfs.Remove("/some")
require.Error(t, err)

err = memfs.RemoveAll("/some")
require.NoError(t, err)
}

func Test_CloneFS(t *testing.T) {
memfs := New()
require.NoError(t, memfs.WriteFile("file1.txt", []byte("This is the first file"), fs.ModePerm))
Expand Down

0 comments on commit 34bba9d

Please sign in to comment.