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:
Jeffrey Paul 2025-12-17 17:16:35 -08:00
parent 09e8da0855
commit 1588e1bb9f
4 changed files with 10 additions and 248 deletions

View File

@ -61,7 +61,7 @@ func validateMagic(dat []byte) bool {
// NewManifestFromReader reads a manifest from an io.Reader.
func NewManifestFromReader(input io.Reader) (*manifest, error) {
m := New()
m := &manifest{}
dat, err := io.ReadAll(input)
if err != nil {
return nil, err
@ -102,8 +102,3 @@ func NewManifestFromFile(fs afero.Fs, path string) (*manifest, error) {
defer func() { _ = f.Close() }()
return NewManifestFromReader(f)
}
// NewFromProto is deprecated, use NewManifestFromReader instead.
func NewFromProto(input io.Reader) (*manifest, error) {
return NewManifestFromReader(input)
}

View File

@ -2,139 +2,24 @@ package mfer
import (
"bytes"
"context"
"errors"
"fmt"
"io/fs"
"os"
"path"
"path/filepath"
"strings"
"github.com/spf13/afero"
"sneak.berlin/go/mfer/internal/log"
)
type manifestFile struct {
path string
info fs.FileInfo
}
func (m *manifestFile) String() string {
return fmt.Sprintf("<File \"%s\">", m.path)
}
// manifest holds the internal representation of a manifest file.
// Use NewManifestFromFile or NewManifestFromReader to load an existing manifest,
// or use Builder to create a new one.
type manifest struct {
sourceFS []afero.Fs
files []*manifestFile
scanOptions *ManifestScanOptions
totalFileSize int64
pbInner *MFFile
pbOuter *MFFileOuter
output *bytes.Buffer
ctx context.Context
errors []*error
}
func (m *manifest) String() string {
return fmt.Sprintf("<Manifest count=%d totalSize=%d>", len(m.files), m.totalFileSize)
}
// 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 {
count := 0
if m.pbInner != nil {
return int64(len(m.pbInner.Files))
count = len(m.pbInner.Files)
}
return int64(len(m.files))
}
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
return fmt.Sprintf("<Manifest count=%d>", count)
}
// Files returns all file entries from a loaded manifest.
@ -144,72 +29,3 @@ func (m *manifest) Files() []*MFFilePath {
}
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
}

View File

@ -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"))
}

View File

@ -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
}