diff --git a/Makefile b/Makefile index f42c488..dc7394e 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ default: fmt test run: ./mfer.cmd ./$< - ./$< gen --ignore-dotfiles + ./$< gen ci: test diff --git a/README.md b/README.md index badd95d..962be97 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ Reading file contents and computing cryptographic hashes for manifest generation ### scanner.go - **Types** - `Options struct` - Options for scanner behavior - - `IgnoreDotfiles bool` + - `IncludeDotfiles bool` - Include dot (hidden) files (excluded by default) - `FollowSymLinks bool` - `EnumerateStatus struct` - Progress information for enumeration phase - `FilesFound int64` @@ -171,7 +171,7 @@ Reading file contents and computing cryptographic hashes for manifest generation ### manifest.go - **Types** - `ManifestScanOptions struct` - Options for scanning directories - - `IgnoreDotfiles bool` + - `IncludeDotfiles bool` - Include dot (hidden) files (excluded by default) - `FollowSymLinks bool` - **Functions** - `New() *manifest` - Creates a new empty manifest diff --git a/contrib/usage.sh b/contrib/usage.sh index 38661f9..fdda16a 100755 --- a/contrib/usage.sh +++ b/contrib/usage.sh @@ -15,5 +15,5 @@ trap cleanup EXIT echo "Building mfer..." go build -o "$TMPDIR/mfer" ./cmd/mfer -"$TMPDIR/mfer" generate --ignore-dotfiles -o "$MANIFEST" . +"$TMPDIR/mfer" generate -o "$MANIFEST" . "$TMPDIR/mfer" check --base . "$MANIFEST" diff --git a/internal/cli/entry_test.go b/internal/cli/entry_test.go index dce560b..98d19df 100644 --- a/internal/cli/entry_test.go +++ b/internal/cli/entry_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" urfcli "github.com/urfave/cli/v2" + "sneak.berlin/go/mfer/mfer" ) func init() { @@ -186,7 +187,7 @@ func TestUnknownCommand(t *testing.T) { assert.Equal(t, 1, exitCode) } -func TestGenerateWithIgnoreDotfiles(t *testing.T) { +func TestGenerateExcludesDotfilesByDefault(t *testing.T) { fs := afero.NewMemMapFs() // Create test files including dotfiles @@ -194,14 +195,39 @@ func TestGenerateWithIgnoreDotfiles(t *testing.T) { require.NoError(t, afero.WriteFile(fs, "/testdir/file1.txt", []byte("hello"), 0644)) require.NoError(t, afero.WriteFile(fs, "/testdir/.hidden", []byte("secret"), 0644)) - // Generate manifest with --ignore-dotfiles - opts := testOpts([]string{"mfer", "-q", "generate", "--ignore-dotfiles", "-o", "/testdir/test.mf", "/testdir"}, fs) + // Generate manifest without --include-dotfiles (default excludes dotfiles) + opts := testOpts([]string{"mfer", "-q", "generate", "-o", "/testdir/test.mf", "/testdir"}, fs) exitCode := RunWithOptions(opts) require.Equal(t, 0, exitCode) - // Check that manifest exists and we can verify (hidden file won't cause failure even if missing) + // Check that manifest exists exists, _ := afero.Exists(fs, "/testdir/test.mf") assert.True(t, exists) + + // Verify manifest only has 1 file (the non-dotfile) + manifest, err := mfer.NewManifestFromFile(fs, "/testdir/test.mf") + require.NoError(t, err) + assert.Len(t, manifest.Files(), 1) + assert.Equal(t, "file1.txt", manifest.Files()[0].Path) +} + +func TestGenerateWithIncludeDotfiles(t *testing.T) { + fs := afero.NewMemMapFs() + + // Create test files including dotfiles + require.NoError(t, fs.MkdirAll("/testdir", 0755)) + require.NoError(t, afero.WriteFile(fs, "/testdir/file1.txt", []byte("hello"), 0644)) + require.NoError(t, afero.WriteFile(fs, "/testdir/.hidden", []byte("secret"), 0644)) + + // Generate manifest with --include-dotfiles + opts := testOpts([]string{"mfer", "-q", "generate", "--include-dotfiles", "-o", "/testdir/test.mf", "/testdir"}, fs) + exitCode := RunWithOptions(opts) + require.Equal(t, 0, exitCode) + + // Verify manifest has 2 files (including dotfile) + manifest, err := mfer.NewManifestFromFile(fs, "/testdir/test.mf") + require.NoError(t, err) + assert.Len(t, manifest.Files(), 2) } func TestMultipleInputPaths(t *testing.T) { diff --git a/internal/cli/freshen.go b/internal/cli/freshen.go index 4710992..164f857 100644 --- a/internal/cli/freshen.go +++ b/internal/cli/freshen.go @@ -40,7 +40,7 @@ func (mfa *CLIApp) freshenManifestOperation(ctx *cli.Context) error { basePath := ctx.String("base") showProgress := ctx.Bool("progress") - ignoreDotfiles := ctx.Bool("IgnoreDotfiles") + includeDotfiles := ctx.Bool("IncludeDotfiles") followSymlinks := ctx.Bool("FollowSymLinks") // Find manifest file @@ -112,7 +112,7 @@ func (mfa *CLIApp) freshenManifestOperation(ctx *cli.Context) error { } // Handle dotfiles - if ignoreDotfiles && pathIsHidden(relPath) { + if !includeDotfiles && pathIsHidden(relPath) { if info.IsDir() { return filepath.SkipDir } diff --git a/internal/cli/gen.go b/internal/cli/gen.go index feda2f5..2a6d394 100644 --- a/internal/cli/gen.go +++ b/internal/cli/gen.go @@ -16,9 +16,9 @@ func (mfa *CLIApp) generateManifestOperation(ctx *cli.Context) error { log.Debug("generateManifestOperation()") opts := &scanner.Options{ - IgnoreDotfiles: ctx.Bool("IgnoreDotfiles"), - FollowSymLinks: ctx.Bool("FollowSymLinks"), - Fs: mfa.Fs, + IncludeDotfiles: ctx.Bool("IncludeDotfiles"), + FollowSymLinks: ctx.Bool("FollowSymLinks"), + Fs: mfa.Fs, } s := scanner.NewWithOptions(opts) diff --git a/internal/cli/mfer.go b/internal/cli/mfer.go index 06ceb0b..921d6b3 100644 --- a/internal/cli/mfer.go +++ b/internal/cli/mfer.go @@ -111,9 +111,9 @@ func (mfa *CLIApp) run(args []string) { Usage: "Resolve encountered symlinks", }, &cli.BoolFlag{ - Name: "IgnoreDotfiles", - Aliases: []string{"ignore-dotfiles"}, - Usage: "Ignore any dot (hidden) files encountered", + Name: "IncludeDotfiles", + Aliases: []string{"include-dotfiles"}, + Usage: "Include dot (hidden) files (excluded by default)", }, &cli.StringFlag{ Name: "output", @@ -186,9 +186,9 @@ func (mfa *CLIApp) run(args []string) { Usage: "Resolve encountered symlinks", }, &cli.BoolFlag{ - Name: "IgnoreDotfiles", - Aliases: []string{"ignore-dotfiles"}, - Usage: "Ignore any dot (hidden) files encountered", + Name: "IncludeDotfiles", + Aliases: []string{"include-dotfiles"}, + Usage: "Include dot (hidden) files (excluded by default)", }, &cli.BoolFlag{ Name: "progress", diff --git a/internal/scanner/scanner.go b/internal/scanner/scanner.go index 8a44cef..2c62575 100644 --- a/internal/scanner/scanner.go +++ b/internal/scanner/scanner.go @@ -42,9 +42,9 @@ type ScanStatus struct { // Options configures scanner behavior. type Options struct { - IgnoreDotfiles bool // Skip files and directories starting with a dot - FollowSymLinks bool // Resolve symlinks instead of skipping them - Fs afero.Fs // Filesystem to use, defaults to OsFs if nil + IncludeDotfiles bool // Include files and directories starting with a dot (default: exclude) + FollowSymLinks bool // Resolve symlinks instead of skipping them + Fs afero.Fs // Filesystem to use, defaults to OsFs if nil } // FileEntry represents a file that has been enumerated. @@ -152,7 +152,7 @@ func (s *Scanner) enumerateFS(afs afero.Fs, basePath string, progress chan<- Enu if err != nil { return err } - if s.options.IgnoreDotfiles && pathIsHidden(p) { + if !s.options.IncludeDotfiles && pathIsHidden(p) { if info.IsDir() { return filepath.SkipDir } diff --git a/mfer/manifest.go b/mfer/manifest.go index fb6315c..e1eda63 100644 --- a/mfer/manifest.go +++ b/mfer/manifest.go @@ -41,8 +41,8 @@ func (m *manifest) String() string { // ManifestScanOptions configures behavior when scanning directories for manifest generation. type ManifestScanOptions struct { - IgnoreDotfiles bool // Skip files and directories starting with a dot - FollowSymLinks bool // Resolve symlinks instead of skipping them + 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 { @@ -153,7 +153,7 @@ func pathIsHidden(p string) bool { } func (m *manifest) addFile(p string, fi fs.FileInfo, sfsIndex int) error { - if m.scanOptions.IgnoreDotfiles && pathIsHidden(p) { + if !m.scanOptions.IncludeDotfiles && pathIsHidden(p) { return nil } if fi != nil && fi.IsDir() {