122 lines
2.3 KiB
Go
122 lines
2.3 KiB
Go
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("<File \"%s\">", m.Path)
|
|
}
|
|
|
|
type Manifest struct {
|
|
SourceFS afero.Fs
|
|
SourceFSRoot string
|
|
Files []*ManifestFile
|
|
ScanOptions *ManifestScanOptions
|
|
TotalFileSize int64
|
|
}
|
|
|
|
func (m *Manifest) String() string {
|
|
return fmt.Sprintf("<Manifest count=%d totalSize=%d>", 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
|
|
}
|