Remove unused legacy manifest APIs
Removed: - New(), NewFromPaths(), NewFromFS() - unused constructors - Scan(), addFile(), addInputPath(), addInputFS() - unused scanning code - WriteToFile(), Write() - unused output methods (Builder.Build() is used) - GetFileCount(), GetTotalFileSize() - unused accessors - pathIsHidden() - duplicated in internal/scanner - ManifestScanOptions - unused options struct - HasError(), AddError(), WithContext() - unused error/context handling - NewFromProto() - deprecated alias - manifestFile struct - unused internal type Kept: - manifest struct (simplified to just pbInner, pbOuter, output) - NewManifestFromReader(), NewManifestFromFile() - for loading manifests - Files() - returns files from loaded manifest - Builder and its methods - for creating manifests
This commit is contained in:
parent
09e8da0855
commit
1588e1bb9f
@ -61,7 +61,7 @@ func validateMagic(dat []byte) bool {
|
|||||||
|
|
||||||
// NewManifestFromReader reads a manifest from an io.Reader.
|
// NewManifestFromReader reads a manifest from an io.Reader.
|
||||||
func NewManifestFromReader(input io.Reader) (*manifest, error) {
|
func NewManifestFromReader(input io.Reader) (*manifest, error) {
|
||||||
m := New()
|
m := &manifest{}
|
||||||
dat, err := io.ReadAll(input)
|
dat, err := io.ReadAll(input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -102,8 +102,3 @@ func NewManifestFromFile(fs afero.Fs, path string) (*manifest, error) {
|
|||||||
defer func() { _ = f.Close() }()
|
defer func() { _ = f.Close() }()
|
||||||
return NewManifestFromReader(f)
|
return NewManifestFromReader(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFromProto is deprecated, use NewManifestFromReader instead.
|
|
||||||
func NewFromProto(input io.Reader) (*manifest, error) {
|
|
||||||
return NewManifestFromReader(input)
|
|
||||||
}
|
|
||||||
|
|||||||
202
mfer/manifest.go
202
mfer/manifest.go
@ -2,139 +2,24 @@ package mfer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/spf13/afero"
|
|
||||||
"sneak.berlin/go/mfer/internal/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type manifestFile struct {
|
// manifest holds the internal representation of a manifest file.
|
||||||
path string
|
// Use NewManifestFromFile or NewManifestFromReader to load an existing manifest,
|
||||||
info fs.FileInfo
|
// or use Builder to create a new one.
|
||||||
}
|
|
||||||
|
|
||||||
func (m *manifestFile) String() string {
|
|
||||||
return fmt.Sprintf("<File \"%s\">", m.path)
|
|
||||||
}
|
|
||||||
|
|
||||||
type manifest struct {
|
type manifest struct {
|
||||||
sourceFS []afero.Fs
|
pbInner *MFFile
|
||||||
files []*manifestFile
|
pbOuter *MFFileOuter
|
||||||
scanOptions *ManifestScanOptions
|
output *bytes.Buffer
|
||||||
totalFileSize int64
|
|
||||||
pbInner *MFFile
|
|
||||||
pbOuter *MFFileOuter
|
|
||||||
output *bytes.Buffer
|
|
||||||
ctx context.Context
|
|
||||||
errors []*error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *manifest) String() string {
|
func (m *manifest) String() string {
|
||||||
return fmt.Sprintf("<Manifest count=%d totalSize=%d>", len(m.files), m.totalFileSize)
|
count := 0
|
||||||
}
|
|
||||||
|
|
||||||
// ManifestScanOptions configures behavior when scanning directories for manifest generation.
|
|
||||||
type ManifestScanOptions struct {
|
|
||||||
IncludeDotfiles bool // Include files and directories starting with a dot (default: exclude)
|
|
||||||
FollowSymLinks bool // Resolve symlinks instead of skipping them
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *manifest) HasError() bool {
|
|
||||||
return len(m.errors) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *manifest) AddError(e error) *manifest {
|
|
||||||
m.errors = append(m.errors, &e)
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *manifest) WithContext(c context.Context) *manifest {
|
|
||||||
m.ctx = c
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *manifest) addInputPath(inputPath string) error {
|
|
||||||
abs, err := filepath.Abs(inputPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Validate path exists
|
|
||||||
if _, err := os.Stat(abs); err != nil {
|
|
||||||
return fmt.Errorf("path does not exist: %s", inputPath)
|
|
||||||
}
|
|
||||||
afs := afero.NewReadOnlyFs(afero.NewBasePathFs(afero.NewOsFs(), abs))
|
|
||||||
return m.addInputFS(afs)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *manifest) addInputFS(f afero.Fs) error {
|
|
||||||
if f == nil {
|
|
||||||
return errors.New("filesystem cannot be nil")
|
|
||||||
}
|
|
||||||
// Validate filesystem is accessible by statting root
|
|
||||||
if _, err := f.Stat("/"); err != nil {
|
|
||||||
return fmt.Errorf("filesystem not accessible: %w", err)
|
|
||||||
}
|
|
||||||
if m.sourceFS == nil {
|
|
||||||
m.sourceFS = make([]afero.Fs, 0)
|
|
||||||
}
|
|
||||||
m.sourceFS = append(m.sourceFS, f)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates an empty manifest.
|
|
||||||
func New() *manifest {
|
|
||||||
m := &manifest{}
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFromPaths creates a manifest configured to scan the given filesystem paths.
|
|
||||||
func NewFromPaths(options *ManifestScanOptions, inputPaths ...string) (*manifest, error) {
|
|
||||||
log.Dump(inputPaths)
|
|
||||||
m := New()
|
|
||||||
m.scanOptions = options
|
|
||||||
for _, p := range inputPaths {
|
|
||||||
err := m.addInputPath(p)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFromFS creates a manifest configured to scan the given afero filesystem.
|
|
||||||
func NewFromFS(options *ManifestScanOptions, fs afero.Fs) (*manifest, error) {
|
|
||||||
m := New()
|
|
||||||
m.scanOptions = options
|
|
||||||
err := m.addInputFS(fs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *manifest) GetFileCount() int64 {
|
|
||||||
if m.pbInner != nil {
|
if m.pbInner != nil {
|
||||||
return int64(len(m.pbInner.Files))
|
count = len(m.pbInner.Files)
|
||||||
}
|
}
|
||||||
return int64(len(m.files))
|
return fmt.Sprintf("<Manifest count=%d>", count)
|
||||||
}
|
|
||||||
|
|
||||||
func (m *manifest) GetTotalFileSize() int64 {
|
|
||||||
if m.pbInner != nil {
|
|
||||||
var total int64
|
|
||||||
for _, f := range m.pbInner.Files {
|
|
||||||
total += f.Size
|
|
||||||
}
|
|
||||||
return total
|
|
||||||
}
|
|
||||||
return m.totalFileSize
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Files returns all file entries from a loaded manifest.
|
// Files returns all file entries from a loaded manifest.
|
||||||
@ -144,72 +29,3 @@ func (m *manifest) Files() []*MFFilePath {
|
|||||||
}
|
}
|
||||||
return m.pbInner.Files
|
return m.pbInner.Files
|
||||||
}
|
}
|
||||||
|
|
||||||
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) addFile(p string, fi fs.FileInfo, sfsIndex int) error {
|
|
||||||
if !m.scanOptions.IncludeDotfiles && pathIsHidden(p) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if fi == nil {
|
|
||||||
// fi should come from Walk; if nil, stat to get info
|
|
||||||
var err error
|
|
||||||
fi, err = m.sourceFS[sfsIndex].Stat(p)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if fi.IsDir() {
|
|
||||||
// manifests contain only files, directories are implied.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
cleanPath := p
|
|
||||||
if cleanPath[0:1] == "/" {
|
|
||||||
cleanPath = cleanPath[1:]
|
|
||||||
}
|
|
||||||
nf := &manifestFile{
|
|
||||||
path: cleanPath,
|
|
||||||
info: fi,
|
|
||||||
}
|
|
||||||
m.files = append(m.files, nf)
|
|
||||||
m.totalFileSize = m.totalFileSize + fi.Size()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *manifest) Scan() error {
|
|
||||||
for idx, sfs := range m.sourceFS {
|
|
||||||
if sfs == nil {
|
|
||||||
return errors.New("invalid source fs")
|
|
||||||
}
|
|
||||||
e := afero.Walk(sfs, "/", func(p string, info fs.FileInfo, err error) error {
|
|
||||||
// Check for context cancellation
|
|
||||||
if m.ctx != nil {
|
|
||||||
select {
|
|
||||||
case <-m.ctx.Done():
|
|
||||||
return m.ctx.Err()
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return m.addFile(p, info, idx)
|
|
||||||
})
|
|
||||||
if e != nil {
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,15 +0,0 @@
|
|||||||
package mfer
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPathHiddenFunc(t *testing.T) {
|
|
||||||
assert.False(t, pathIsHidden("/a/b/c/hello.txt"))
|
|
||||||
assert.True(t, pathIsHidden("/a/b/c/.hello.txt"))
|
|
||||||
assert.True(t, pathIsHidden("/a/.b/c/hello.txt"))
|
|
||||||
assert.True(t, pathIsHidden("/.a/b/c/hello.txt"))
|
|
||||||
assert.False(t, pathIsHidden("./a/b/c/hello.txt"))
|
|
||||||
}
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
package mfer
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
// WriteToFile writes the manifest to the given path.
|
|
||||||
// It will overwrite any existing file. Callers should check for existing files
|
|
||||||
// before calling if overwrite confirmation is needed.
|
|
||||||
func (m *manifest) WriteToFile(path string) error {
|
|
||||||
f, err := os.Create(path)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer func() { _ = f.Close() }()
|
|
||||||
|
|
||||||
return m.Write(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *manifest) Write(output io.Writer) error {
|
|
||||||
if m.pbOuter == nil {
|
|
||||||
err := m.generate()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := output.Write(m.output.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user