Skip to content

Commit b5144ff

Browse files
committed
filesystem: add 'ReadDirRecursive()'
Add the 'ReadDirRecursive()' function to 'FileSystem' to facilitate easy lookup of filesystem entries at a fixed depth from the root. In later commits, this will be used to look up routes in the bundle server under the 'reporoot' on the filesystem. 'ReadDirRecursive()' takes three arguments: * 'path': the root directory into which we want to recurse * 'depth': the number of times to recurse into 'path'. A depth of 0 will return nothing, a depth of 1 will return all entries inside 'path', a depth of 2 will return all entries inside the subdirectories of 'path', etc. * 'strictDepth': a flag indicating whether to return only entries that are *exactly 'depth' levels beneath 'path'. If 'false', 'ReadDirRecursive()' will also include files and empty directories at depths less than 'depth'. For example, consider the following directory tree: . ├── another-dir/ │ └── testfile ├── myfile ├── org/ │ └── repo/ │ ├── deeper/ │ └── repofile └── too-shallow/ 'ReadDirRecursive(".", 2, true)' will return: - ./another-dir/testfile - ./org/repo/ Whereas 'ReadDirRecursive(".", 2, false)' will return: - ./another-dir/testfile - ./myfile - ./org/repo/ - ./too-shallow/ Signed-off-by: Victoria Dye <[email protected]>
1 parent 3783a2b commit b5144ff

File tree

2 files changed

+77
-0
lines changed

2 files changed

+77
-0
lines changed

internal/common/filesystem.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010
"path"
1111
"path/filepath"
1212
"syscall"
13+
14+
"github.com/github/git-bundle-server/internal/utils"
1315
)
1416

1517
const (
@@ -35,6 +37,29 @@ func (l *lockFile) Rollback() error {
3537
return os.Remove(l.lockFilename)
3638
}
3739

40+
type ReadDirEntry interface {
41+
Path() string
42+
fs.DirEntry
43+
}
44+
45+
type fsEntry struct {
46+
root string
47+
fs.DirEntry
48+
}
49+
50+
func (e *fsEntry) Path() string {
51+
return filepath.Join(e.root, e.Name())
52+
}
53+
54+
func mapDirEntry(root string) func(fs.DirEntry) ReadDirEntry {
55+
return func(e fs.DirEntry) ReadDirEntry {
56+
return &fsEntry{
57+
root: root,
58+
DirEntry: e,
59+
}
60+
}
61+
}
62+
3863
type FileSystem interface {
3964
GetLocalExecutable(name string) (string, error)
4065

@@ -43,6 +68,15 @@ type FileSystem interface {
4368
WriteLockFileFunc(filename string, writeFunc func(io.Writer) error) (LockFile, error)
4469
DeleteFile(filename string) (bool, error)
4570
ReadFileLines(filename string) ([]string, error)
71+
72+
// ReadDirRecursive recurses into a given directory ('path') up to 'depth'
73+
// levels deep. If 'strictDepth' is true, only the entries at *exactly* the
74+
// given depth are returned (if any). If 'strictDepth' is false, though, the
75+
// results will also include any files or empty directories for a depth <
76+
// 'depth'.
77+
//
78+
// If 'depth' is <= 0, ReadDirRecursive returns an empty list.
79+
ReadDirRecursive(path string, depth int, strictDepth bool) ([]ReadDirEntry, error)
4680
}
4781

4882
type fileSystem struct{}
@@ -173,3 +207,41 @@ func (f *fileSystem) ReadFileLines(filename string) ([]string, error) {
173207

174208
return l, nil
175209
}
210+
211+
func (f *fileSystem) ReadDirRecursive(path string, depth int, strictDepth bool) ([]ReadDirEntry, error) {
212+
if depth <= 0 {
213+
return []ReadDirEntry{}, nil
214+
}
215+
216+
dirEntries, err := os.ReadDir(path)
217+
if err != nil {
218+
return nil, err
219+
}
220+
221+
entries := utils.Map(dirEntries, mapDirEntry(path))
222+
if depth == 1 {
223+
return entries, nil
224+
}
225+
226+
out := []ReadDirEntry{}
227+
for _, entry := range entries {
228+
if !entry.IsDir() {
229+
if !strictDepth {
230+
out = append(out, entry)
231+
}
232+
continue
233+
}
234+
235+
subEntries, err := f.ReadDirRecursive(entry.Path(), depth-1, strictDepth)
236+
if err != nil {
237+
return nil, err
238+
}
239+
if !strictDepth && len(subEntries) == 0 {
240+
out = append(out, entry)
241+
continue
242+
}
243+
out = append(out, subEntries...)
244+
}
245+
246+
return out, nil
247+
}

internal/testhelpers/mocks.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,11 @@ func (m *MockFileSystem) ReadFileLines(filename string) ([]string, error) {
196196
return fnArgs.Get(0).([]string), fnArgs.Error(1)
197197
}
198198

199+
func (m *MockFileSystem) ReadDirRecursive(path string, depth int, strictDepth bool) ([]common.ReadDirEntry, error) {
200+
fnArgs := m.Called(path, depth, strictDepth)
201+
return fnArgs.Get(0).([]common.ReadDirEntry), fnArgs.Error(1)
202+
}
203+
199204
type MockGitHelper struct {
200205
mock.Mock
201206
}

0 commit comments

Comments
 (0)