gt/internal/files/disk.go
Lilian Jónsdóttir 6af87e4d9d add keybind to sort table
lots of refactoring to do so
files on disk, and files in trash interface'd so table is agnostic
model keeps track of the files now, to facilitate sorting, and updates its own rows accordingly
2024-07-03 15:09:05 -07:00

176 lines
3.6 KiB
Go

package files
import (
"io/fs"
"os"
"path/filepath"
"strings"
"time"
"git.burning.moe/celediel/gt/internal/filter"
"github.com/charmbracelet/log"
"github.com/dustin/go-humanize"
)
type DiskFile struct {
name, path string
filesize int64
modified time.Time
isdir bool
}
func (f DiskFile) Name() string { return f.name }
func (f DiskFile) Path() string { return filepath.Join(f.path, f.name) }
func (f DiskFile) Date() time.Time { return f.modified }
func (f DiskFile) Filesize() int64 { return f.filesize }
func (f DiskFile) IsDir() bool { return f.isdir }
func NewDisk(path string) (DiskFile, error) {
info, err := os.Stat(path)
if err != nil {
return DiskFile{}, err
}
abs, err := filepath.Abs(path)
if err != nil {
log.Errorf("couldn't get absolute path for %s", path)
abs = path
}
name := filepath.Base(abs)
base_path := filepath.Dir(abs)
log.Debugf("%s (base:%s) (size:%s) (modified:%s) exists",
name, base_path, humanize.Bytes(uint64(info.Size())), info.ModTime())
return DiskFile{
name: name,
path: base_path,
filesize: info.Size(),
modified: info.ModTime(),
isdir: info.IsDir(),
}, nil
}
func FindDisk(dir string, recursive bool, f *filter.Filter) (files Files, err error) {
if dir == "." || dir == "" {
var d string
if d, err = os.Getwd(); err != nil {
return
} else {
dir = d
}
}
var recursively string
if recursive {
recursively = " recursively"
}
log.Debugf("gonna find files%s in %s matching %s", recursively, dir, f)
if recursive {
files = append(files, walk_dir(dir, f)...)
} else {
files = append(files, read_dir(dir, f)...)
}
return
}
// is_in_recursive_dir checks `path` and parent directories
// of `path` up to `base` for a hidden parent
func is_in_recursive_dir(base, path string) bool {
me := path
for {
me = filepath.Clean(me)
if me == base {
break
}
if strings.HasPrefix(filepath.Base(me), ".") {
return true
}
me += string(os.PathSeparator) + ".."
}
return false
}
func walk_dir(dir string, f *filter.Filter) (files Files) {
err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
if dir == path {
return nil
}
if is_in_recursive_dir(dir, path) && !f.IgnoreHidden() {
return nil
}
p, e := filepath.Abs(path)
if e != nil {
return err
}
name := d.Name()
info, _ := d.Info()
if f.Match(name, info.ModTime(), info.Size(), info.IsDir()) {
log.Debugf("found matching file: %s %s", name, info.ModTime())
i, err := os.Stat(p)
if err != nil {
log.Debugf("error in file stat: %s", err)
return nil
}
files = append(files, DiskFile{
path: filepath.Dir(p),
name: name,
filesize: i.Size(),
modified: i.ModTime(),
isdir: i.IsDir(),
})
} else {
log.Debugf("ignoring file %s (%s)", name, info.ModTime())
}
return nil
})
if err != nil {
log.Errorf("error walking directory %s: %s", dir, err)
return Files{}
}
return
}
func read_dir(dir string, f *filter.Filter) (files Files) {
fs, err := os.ReadDir(dir)
if err != nil {
return Files{}
}
for _, file := range fs {
name := file.Name()
if name == dir {
continue
}
info, err := file.Info()
if err != nil {
return Files{}
}
path := filepath.Dir(filepath.Join(dir, name))
if f.Match(name, info.ModTime(), info.Size(), info.IsDir()) {
log.Debugf("found matching file: %s %s", name, info.ModTime())
files = append(files, DiskFile{
name: name,
path: path,
modified: info.ModTime(),
filesize: info.Size(),
isdir: info.IsDir(),
})
} else {
log.Debugf("ignoring file %s (%s)", name, info.ModTime())
}
}
return
}