package mfer import ( "fmt" "io/fs" "path" "path/filepath" "strings" "github.com/spf13/afero" ) //go:generate protoc --go_out=. --go_opt=paths=source_relative mf.proto type ManifestFile struct { Path string FileInfo fs.FileInfo } func (m *ManifestFile) String() string { return fmt.Sprintf("", m.Path) } type Manifest struct { SourceFS afero.Fs SourceFSRoot string Files []*ManifestFile ScanOptions *ManifestScanOptions TotalFileSize int64 } func (m *Manifest) String() string { return fmt.Sprintf("", len(m.Files), m.TotalFileSize) } type ManifestScanOptions struct { IgnoreDotfiles bool FollowSymLinks bool } func NewFromPath(inputPath string, options *ManifestScanOptions) (*Manifest, error) { abs, err := filepath.Abs(inputPath) if err != nil { return nil, err } afs := afero.NewBasePathFs(afero.NewOsFs(), abs) m, err := NewFromFS(afs, options) if err != nil { return nil, err } m.SourceFSRoot = abs return m, nil } func NewFromFS(fs afero.Fs, options *ManifestScanOptions) (*Manifest, error) { m := &Manifest{ SourceFS: fs, ScanOptions: options, } err := m.Scan() if err != nil { return nil, err } return m, nil } func (m *Manifest) GetFileCount() int64 { return int64(len(m.Files)) } func (m *Manifest) GetTotalFileSize() int64 { return m.TotalFileSize } func pathIsHidden(p string) bool { tp := path.Clean(p) if strings.HasPrefix(tp, ".") { return true } for { d, f := path.Split(tp) if strings.HasPrefix(f, ".") { return true } if d == "" { return false } tp = d[0 : len(d)-1] // trim trailing slash from dir } } func (m *Manifest) Scan() error { // FIXME scan and whatever function does the hashing should take ctx oe := afero.Walk(m.SourceFS, "/", func(p string, info fs.FileInfo, err error) error { if m.ScanOptions.IgnoreDotfiles && pathIsHidden(p) { return nil } if info != nil && info.IsDir() { // manifests contain only files, directories are implied. return nil } fileinfo, staterr := m.SourceFS.Stat(p) if staterr != nil { panic(staterr) } nf := &ManifestFile{ Path: p, FileInfo: fileinfo, } m.Files = append(m.Files, nf) m.TotalFileSize = m.TotalFileSize + info.Size() return nil }) if oe != nil { return oe } return nil }