2023-01-27 15:04:58 +00:00
|
|
|
package fileset
|
|
|
|
|
|
|
|
import (
|
2023-01-31 17:34:36 +00:00
|
|
|
"fmt"
|
2023-01-27 15:04:58 +00:00
|
|
|
"io/fs"
|
2023-02-15 16:02:54 +00:00
|
|
|
"os"
|
2024-05-30 07:41:50 +00:00
|
|
|
|
|
|
|
"github.com/databricks/cli/libs/vfs"
|
2023-01-27 15:04:58 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// FileSet facilitates fast recursive file listing of a path.
|
|
|
|
// It optionally takes into account ignore rules through the [Ignorer] interface.
|
|
|
|
type FileSet struct {
|
2024-05-30 07:41:50 +00:00
|
|
|
// Root path of the fileset.
|
|
|
|
root vfs.Path
|
|
|
|
|
|
|
|
// Ignorer interface to check if a file or directory should be ignored.
|
2023-01-27 15:04:58 +00:00
|
|
|
ignore Ignorer
|
|
|
|
}
|
|
|
|
|
|
|
|
// New returns a [FileSet] for the given root path.
|
2024-05-30 07:41:50 +00:00
|
|
|
func New(root vfs.Path) *FileSet {
|
2023-01-27 15:04:58 +00:00
|
|
|
return &FileSet{
|
2024-05-30 07:41:50 +00:00
|
|
|
root: root,
|
2023-01-27 15:04:58 +00:00
|
|
|
ignore: nopIgnorer{},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ignorer returns the [FileSet]'s current ignorer.
|
|
|
|
func (w *FileSet) Ignorer() Ignorer {
|
|
|
|
return w.ignore
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetIgnorer sets the [Ignorer] interface for this [FileSet].
|
|
|
|
func (w *FileSet) SetIgnorer(ignore Ignorer) {
|
|
|
|
w.ignore = ignore
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return all tracked files for Repo
|
|
|
|
func (w *FileSet) All() ([]File, error) {
|
2023-08-21 07:35:02 +00:00
|
|
|
return w.recursiveListFiles()
|
2023-01-27 15:04:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Recursively traverses dir in a depth first manner and returns a list of all files
|
|
|
|
// that are being tracked in the FileSet (ie not being ignored for matching one of the
|
|
|
|
// patterns in w.ignore)
|
2023-08-21 07:35:02 +00:00
|
|
|
func (w *FileSet) recursiveListFiles() (fileList []File, err error) {
|
2024-05-30 07:41:50 +00:00
|
|
|
err = fs.WalkDir(w.root, ".", func(name string, d fs.DirEntry, err error) error {
|
2023-01-27 15:04:58 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-02-15 16:02:54 +00:00
|
|
|
// skip symlinks
|
|
|
|
info, err := d.Info()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if info.Mode()&os.ModeSymlink != 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-01-27 15:04:58 +00:00
|
|
|
if d.IsDir() {
|
2024-05-30 07:41:50 +00:00
|
|
|
ign, err := w.ignore.IgnoreDirectory(name)
|
2023-01-31 17:34:36 +00:00
|
|
|
if err != nil {
|
2024-05-30 07:41:50 +00:00
|
|
|
return fmt.Errorf("cannot check if %s should be ignored: %w", name, err)
|
2023-01-31 17:34:36 +00:00
|
|
|
}
|
|
|
|
if ign {
|
2024-05-30 07:41:50 +00:00
|
|
|
return fs.SkipDir
|
2023-01-27 15:04:58 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-05-30 07:41:50 +00:00
|
|
|
ign, err := w.ignore.IgnoreFile(name)
|
2023-01-31 17:34:36 +00:00
|
|
|
if err != nil {
|
2024-05-30 07:41:50 +00:00
|
|
|
return fmt.Errorf("cannot check if %s should be ignored: %w", name, err)
|
2023-01-31 17:34:36 +00:00
|
|
|
}
|
|
|
|
if ign {
|
2023-01-27 15:04:58 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-05-30 07:41:50 +00:00
|
|
|
fileList = append(fileList, NewFile(w.root, d, name))
|
2023-01-27 15:04:58 +00:00
|
|
|
return nil
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|