Skip to content

Commit 4385930

Browse files
committed
better flag&option handling, slightly optimized patternMatcher
1 parent 7de2d40 commit 4385930

4 files changed

Lines changed: 140 additions & 13 deletions

File tree

c2mConfig/c2mConfig.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,16 @@ func InitializeConfigFromFlags() (*Config, error) {
2929
inputFolder := flag.String("input", "", "Input folder to scan")
3030
outputMarkdown := flag.String("output", "", "Output Markdown file")
3131
languages := flag.String("languages", "", "Comma-separated list of allowed languages (empty = use defaults)")
32-
ignorePatterns := flag.String("ignore", "", "Comma-separated list of files and/or search patterns to ignore")
32+
var ignorePatterns string
33+
flag.StringVar(&ignorePatterns, "ignore", defaultIgnoredPatterns, "Comma-separated list of files and/or search patterns to ignore")
3334
maxFileSize := flag.Int64("max-file-size", defaultMaxFileSize, "Maximum file size in bytes to process")
3435
help := flag.Bool("help", false, "Show help")
3536
v := flag.Bool("version", false, "Show version information")
3637

3738
flag.StringVar(inputFolder, "i", "", "Input folder to scan (shorthand)")
3839
flag.StringVar(outputMarkdown, "o", "", "Output Markdown file (shorthand)")
3940
flag.StringVar(languages, "l", "", "languages (shorthand)")
40-
flag.StringVar(ignorePatterns, "I", defaultIgnoredPatterns, "ignore patterns (shorthand)")
41+
flag.StringVar(&ignorePatterns, "I", defaultIgnoredPatterns, "ignore patterns (shorthand)")
4142
flag.Int64Var(maxFileSize, "m", defaultMaxFileSize, "max file size (shorthand)")
4243
flag.BoolVar(help, "h", false, "help (shorthand)")
4344
flag.BoolVar(v, "v", false, "version (shorthand)")
@@ -47,10 +48,14 @@ func InitializeConfigFromFlags() (*Config, error) {
4748
allowedLanguages := language.ParseLanguages(*languages)
4849

4950
var ignorePatternsList []string
50-
if *ignorePatterns == "" {
51-
ignorePatternsList = []string{*outputMarkdown}
52-
} else {
53-
ignorePatternsList = append(strings.Split(*ignorePatterns, ","), *outputMarkdown)
51+
for _, p := range strings.Split(ignorePatterns, ",") {
52+
trimmed := strings.TrimSpace(p)
53+
if trimmed != "" {
54+
ignorePatternsList = append(ignorePatternsList, trimmed)
55+
}
56+
}
57+
if *outputMarkdown != "" {
58+
ignorePatternsList = append(ignorePatternsList, *outputMarkdown)
5459
}
5560

5661
if allowedLanguages[".css"] || allowedLanguages[".scss"] {

c2mConfig/c2mConfig_test.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,113 @@
11
package c2mConfig
22

33
import (
4+
"flag"
45
"os"
56
"path/filepath"
67
"reflect"
8+
"strings"
79
"testing"
810
)
911

12+
func TestInitializeConfigFromFlags(t *testing.T) {
13+
t.Run("default ignore patterns present when no flags passed", func(t *testing.T) {
14+
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
15+
origArgs := os.Args
16+
defer func() { os.Args = origArgs }()
17+
18+
tempDir := t.TempDir()
19+
origDir, _ := os.Getwd()
20+
os.Chdir(tempDir)
21+
defer os.Chdir(origDir)
22+
23+
os.Args = []string{"cmd", "-i", tempDir}
24+
config, err := InitializeConfigFromFlags()
25+
if err != nil {
26+
t.Fatalf("InitializeConfigFromFlags() error: %v", err)
27+
}
28+
29+
defaults := strings.Split(defaultIgnoredPatterns, ",")
30+
for _, d := range defaults {
31+
found := false
32+
for _, p := range config.IgnorePatterns {
33+
if p == d {
34+
found = true
35+
break
36+
}
37+
}
38+
if !found {
39+
t.Errorf("expected default ignore pattern %q in %v", d, config.IgnorePatterns)
40+
}
41+
}
42+
})
43+
44+
t.Run("explicit ignore overrides defaults", func(t *testing.T) {
45+
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
46+
origArgs := os.Args
47+
defer func() { os.Args = origArgs }()
48+
49+
tempDir := t.TempDir()
50+
origDir, _ := os.Getwd()
51+
os.Chdir(tempDir)
52+
defer os.Chdir(origDir)
53+
54+
os.Args = []string{"cmd", "-i", tempDir, "--ignore", "custom.txt,other.log"}
55+
config, err := InitializeConfigFromFlags()
56+
if err != nil {
57+
t.Fatalf("InitializeConfigFromFlags() error: %v", err)
58+
}
59+
60+
for _, expected := range []string{"custom.txt", "other.log"} {
61+
found := false
62+
for _, p := range config.IgnorePatterns {
63+
if p == expected {
64+
found = true
65+
break
66+
}
67+
}
68+
if !found {
69+
t.Errorf("expected ignore pattern %q in %v", expected, config.IgnorePatterns)
70+
}
71+
}
72+
73+
for _, d := range strings.Split(defaultIgnoredPatterns, ",") {
74+
for _, p := range config.IgnorePatterns {
75+
if p == d {
76+
t.Errorf("default pattern %q should not be present when --ignore is explicit, got %v", d, config.IgnorePatterns)
77+
}
78+
}
79+
}
80+
})
81+
82+
t.Run("output file added to ignore patterns", func(t *testing.T) {
83+
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
84+
origArgs := os.Args
85+
defer func() { os.Args = origArgs }()
86+
87+
tempDir := t.TempDir()
88+
origDir, _ := os.Getwd()
89+
os.Chdir(tempDir)
90+
defer os.Chdir(origDir)
91+
92+
os.Args = []string{"cmd", "-i", tempDir, "-o", "output.md"}
93+
config, err := InitializeConfigFromFlags()
94+
if err != nil {
95+
t.Fatalf("InitializeConfigFromFlags() error: %v", err)
96+
}
97+
98+
found := false
99+
for _, p := range config.IgnorePatterns {
100+
if p == "output.md" {
101+
found = true
102+
break
103+
}
104+
}
105+
if !found {
106+
t.Errorf("expected output file 'output.md' in ignore patterns %v", config.IgnorePatterns)
107+
}
108+
})
109+
}
110+
10111
func TestIsConfigValid(t *testing.T) {
11112
tests := []struct {
12113
name string

patternMatcher/patternMatcher.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func CompilePatterns(patterns []string) []CompiledPattern {
2525

2626
cp := CompiledPattern{original: pattern}
2727

28-
if strings.HasPrefix(pattern, "/") && strings.HasSuffix(pattern, "/") {
28+
if strings.HasPrefix(pattern, "/") && !strings.Contains(pattern, "*") {
2929
cp.isSlashPrefix = true
3030
cp.prefix = strings.TrimPrefix(pattern, "/")
3131
} else if strings.HasSuffix(pattern, "/") {
@@ -51,8 +51,15 @@ func IsPathIgnored(path string, patterns []CompiledPattern) bool {
5151
return true
5252
}
5353

54-
if pattern.isSlashPrefix && strings.HasPrefix(path, pattern.prefix) {
55-
return true
54+
if pattern.isSlashPrefix {
55+
withSlash := pattern.prefix
56+
if !strings.HasSuffix(withSlash, "/") {
57+
withSlash += "/"
58+
}
59+
if strings.HasPrefix(path, withSlash) ||
60+
path == strings.TrimSuffix(withSlash, "/") {
61+
return true
62+
}
5663
}
5764

5865
if pattern.isDirPrefix && strings.HasPrefix(path, pattern.prefix) {

patternMatcher/patternMatcher_test.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ func TestPathPatternMatching(t *testing.T) {
3535
{"slash prefix nested match", "example/nested/file.txt", "/example/", true},
3636
{"slash prefix mismatch", "example.txt", "/example/", false},
3737
{"slash prefix other dir", "other/file.txt", "/example/", false},
38+
{"slash prefix no trailing slash file", "vendor/file.go", "/vendor", true},
39+
{"slash prefix no trailing slash nested", "vendor/pkg/lib.go", "/vendor", true},
40+
{"slash prefix no trailing slash exact", "vendor", "/vendor", true},
41+
{"slash prefix no trailing slash mismatch", "src/vendor/file.go", "/vendor", false},
3842
}
3943

4044
for _, tt := range tests {
@@ -74,7 +78,7 @@ func TestPathIgnoring(t *testing.T) {
7478
}
7579

7680
func TestSlashPrefixPatterns(t *testing.T) {
77-
patterns := CompilePatterns([]string{"/vendor/", "/node_modules/"})
81+
patterns := CompilePatterns([]string{"/vendor/", "/node_modules/", "/build"})
7882
tests := []struct {
7983
name string
8084
path string
@@ -84,6 +88,9 @@ func TestSlashPrefixPatterns(t *testing.T) {
8488
{"node_modules root", "node_modules/lib/index.js", true},
8589
{"nested vendor allowed", "src/vendor/file.go", false},
8690
{"other directory", "src/main.go", false},
91+
{"build no trailing slash", "build/output.js", true},
92+
{"build exact", "build", true},
93+
{"nested build allowed", "src/build/output.js", false},
8794
}
8895

8996
for _, tt := range tests {
@@ -96,10 +103,10 @@ func TestSlashPrefixPatterns(t *testing.T) {
96103
}
97104

98105
func TestCompiledPatterns(t *testing.T) {
99-
patterns := CompilePatterns([]string{"*.txt", "ignore/", "temp/*.log", "**.min.css", "/vendor/"})
106+
patterns := CompilePatterns([]string{"*.txt", "ignore/", "temp/*.log", "**.min.css", "/vendor/", "/build"})
100107

101-
if len(patterns) != 5 {
102-
t.Errorf("Expected 5 compiled patterns, got %d", len(patterns))
108+
if len(patterns) != 6 {
109+
t.Errorf("Expected 6 compiled patterns, got %d", len(patterns))
103110
}
104111

105112
for _, p := range patterns {
@@ -127,6 +134,13 @@ func TestCompiledPatterns(t *testing.T) {
127134
if p.prefix != "vendor/" {
128135
t.Errorf("/vendor/ prefix should be 'vendor/', got %q", p.prefix)
129136
}
137+
case "/build":
138+
if !p.isSlashPrefix {
139+
t.Error("/build should be marked as slash prefix")
140+
}
141+
if p.prefix != "build" {
142+
t.Errorf("/build prefix should be 'build', got %q", p.prefix)
143+
}
130144
}
131145
}
132146
}

0 commit comments

Comments
 (0)