Skip to content

Commit

Permalink
WIP: Add ListRecursiveFS
Browse files Browse the repository at this point in the history
Blocked by: golang/go#49580
  • Loading branch information
DavidGamba committed Jan 20, 2022
1 parent 2eca04d commit 1904a46
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 4 deletions.
26 changes: 26 additions & 0 deletions buildutils/buildutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ package buildutils
import (
"os"
"strings"
"time"

"github.com/DavidGamba/dgtools/run"
)
Expand All @@ -36,3 +37,28 @@ func CDGitRepoRoot() error {
}
return nil
}

// TODO: ALlow for fs override for testing

func SymlinkF(target, name string) error {
_ = os.Remove(name)
return os.Symlink(target, name)
}

func Touch(filename string) error {
_, err := os.Stat(filename)
if os.IsNotExist(err) {
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
} else {
currentTime := time.Now().Local()
err = os.Chtimes(filename, currentTime, currentTime)
if err != nil {
return err
}
}
return nil
}
102 changes: 98 additions & 4 deletions ffind/lib/ffind/ffind.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ For example: '.rb' and '.erb' for ruby files.
package ffind

import (
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"
)
Expand Down Expand Up @@ -103,10 +106,7 @@ func ListOneLevel(path string, follow bool, sortFn SortFn) <-chan FileError {
// If `file` is a symlink and we are not following symlinks, will return a FileError channel with itself.
// If `file` is a symlink and we are following symlinks, will return a FileError channel with the readlink file.
// If `file` is a dir, will return a FileError channel with one level list under the dir.
func listOneLevel(
fe *FileError,
follow bool,
sortFn SortFn) <-chan FileError {
func listOneLevel(fe *FileError, follow bool, sortFn SortFn) <-chan FileError {
fInfo := fe.FileInfo
file := fe.Path
Logger.Printf("file: %s\n", file)
Expand Down Expand Up @@ -257,3 +257,97 @@ func listRecursive(fe *FileError, follow bool, s FileMatcher, sortFn SortFn) <-c
}()
return c
}

type EntryError struct {
FileInfo fs.FileInfo
Path string
Error error
fsys fs.FS
Depth int
}

func NewEntryError(fsys fs.FS, path string) *EntryError {
fi, err := fs.Stat(fsys, path)

// Logger.Printf("NewFileError: %s", path)
// fInfo, err := os.Lstat(path)
// if err != nil {
// Logger.Printf("NewFileError ERROR: %s", err)
// if os.IsNotExist(err) {
// // Clean up error context
// err = os.ErrNotExist
// }
// }
// return &FileError{fInfo, filepath.Clean(path), err}, err

return &EntryError{
FileInfo: fi,
Path: filepath.Clean(path),
Error: err,
fsys: fsys,
Depth: 0,
}
}

func listRecursiveFS(ee *EntryError, maxDepth int, follow bool, sortFn SortFn) <-chan EntryError {
c := make(chan EntryError)

go func(ee EntryError) {

if ee.Error != nil {
c <- ee
close(c)
return
}

checkSymlink := func() {
if ee.FileInfo.Mode()&fs.ModeSymlink != 0 && follow {
// https://github.com/golang/go/issues/49580
// Waiting for readlink implementation on FS
eval, err := filepath.EvalSymlinks(ee.Path)
fmt.Printf("eval: %v - %s\n", eval, ee.Path)
if err != nil {
// If the link is broken then just return the original file
if errors.Is(err, fs.ErrNotExist) {
return
}
ee.Error = err
return
}
ne := NewEntryError(ee.fsys, eval)
if ne.Error != nil {
ee.Error = err
return
}
ee = *ne
c <- ee
}
}

checkSymlink()

if ee.FileInfo.IsDir() {
c <- ee

dde, err := fs.ReadDir(ee.fsys, ee.Path)
if err != nil {
ee.Error = fmt.Errorf("reading dir: %w", err)
c <- ee
close(c)
return
}
for _, de := range dde {
fi, err := de.Info()
cr := listRecursiveFS(&EntryError{fi, filepath.Join(ee.Path, fi.Name()), err, ee.fsys, ee.Depth + 1}, maxDepth, follow, sortFn)
for e := range cr {
c <- e
}
}
} else {
c <- EntryError{ee.FileInfo, ee.Path, nil, ee.fsys, ee.Depth}
}

close(c)
}(*ee)
return c
}
48 changes: 48 additions & 0 deletions ffind/lib/ffind/ffind_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,63 @@ package ffind

import (
"fmt"
"io/fs"
"io/ioutil"
"log"
"os"
"path/filepath"
"reflect"
"strings"
"testing"
"testing/fstest"
)

func makeFS() fstest.MapFS {
m := make(fstest.MapFS)

m["test_tree"] = &fstest.MapFile{Mode: 0777 | fs.ModeDir}

m["test_tree/.A"] = &fstest.MapFile{Mode: 0777 | fs.ModeDir}
m["test_tree/.a"] = &fstest.MapFile{Mode: 0777 | fs.ModeDir}
m["test_tree/.hg"] = &fstest.MapFile{Mode: 0777 | fs.ModeDir}
m["test_tree/.svn"] = &fstest.MapFile{Mode: 0777 | fs.ModeDir}
m["test_tree/.git"] = &fstest.MapFile{Mode: 0777 | fs.ModeDir}
m["test_tree/A"] = &fstest.MapFile{Mode: 0777 | fs.ModeDir}
m["test_tree/a"] = &fstest.MapFile{Mode: 0777 | fs.ModeDir}

m["test_tree/slnA"] = &fstest.MapFile{Mode: 0777 | fs.ModeSymlink, Data: []byte("A")}
m["test_tree/slnB"] = &fstest.MapFile{Mode: 0777 | fs.ModeSymlink, Data: []byte("slnA")}
m["test_tree/slnC"] = &fstest.MapFile{Mode: 0777 | fs.ModeSymlink, Data: []byte("A/b/C/d/E")}
m["test_tree/slnD"] = &fstest.MapFile{Mode: 0777 | fs.ModeSymlink, Data: []byte("a/B/c/D/e")}
m["test_tree/slnE"] = &fstest.MapFile{Mode: 0777 | fs.ModeSymlink, Data: []byte("snlF")}
m["test_tree/slnF"] = &fstest.MapFile{Mode: 0777 | fs.ModeSymlink, Data: []byte("snlG")}
m["test_tree/slnG"] = &fstest.MapFile{Mode: 0777 | fs.ModeSymlink, Data: []byte("broken")}

m["test_tree/.A/b/C/d/E"] = &fstest.MapFile{Mode: 0666}
m["test_tree/.a/B/c/D/e"] = &fstest.MapFile{Mode: 0666}
m["test_tree/.hg/E"] = &fstest.MapFile{Mode: 0666}
m["test_tree/.hg/e"] = &fstest.MapFile{Mode: 0666}
m["test_tree/.svn/E"] = &fstest.MapFile{Mode: 0666}
m["test_tree/.svn/e"] = &fstest.MapFile{Mode: 0666}
m["test_tree/A/b/C/d/E"] = &fstest.MapFile{Mode: 0666}
m["test_tree/a/B/c/D/e"] = &fstest.MapFile{Mode: 0666}

return m
}

func TestListRecursiveFS(t *testing.T) {
// m := makeFS()
m := os.DirFS("../../test_files")
ee := NewEntryError(m, "test_tree")
ch := listRecursiveFS(ee, 0, true, nil)
for e := range ch {
if e.Error != nil {
t.Errorf("Error: %v\n", e.Error)
}
t.Errorf("%v\n", e.Path)
}
}

func goToRootDir() {
log.SetOutput(os.Stderr)
cwd, _ := os.Getwd()
Expand Down

0 comments on commit 1904a46

Please sign in to comment.