feat(client): ignore rule in .lodge
This commit is contained in:
1 parent
4207f7e6f8
commit
45c81cfcaf
8 files changed
+146
-18
No files matched your search
@@ -5,6 +5,7 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"lodge/internal/gitrepo"
|
||||
@@ -15,6 +16,7 @@ const (
|
||||
RulesFile = ".lodge"
|
||||
sharedKeyword = "shared"
|
||||
branchKeyword = "branch"
|
||||
ignoreKeyword = "ignore"
|
||||
excludeBegin = "# lodge begin"
|
||||
excludeEnd = "# lodge end"
|
||||
DefaultRules = "shared docs/agents\nshared CLAUDE.local.md\nbranch .agent\n"
|
||||
@@ -23,6 +25,7 @@ const (
|
||||
type Rule struct {
|
||||
Path string `json:"path"`
|
||||
Shared bool `json:"shared"`
|
||||
Ignore bool `json:"ignore,omitempty"`
|
||||
}
|
||||
|
||||
type Rules []Rule
|
||||
@@ -31,12 +34,12 @@ func parseRules(text string) Rules {
|
||||
rules := Rules{{Path: RulesFile, Shared: true}}
|
||||
for _, line := range strings.Split(text, "\n") {
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) != 2 || fields[0] != sharedKeyword && fields[0] != branchKeyword {
|
||||
if len(fields) != 2 || !slices.Contains([]string{sharedKeyword, branchKeyword, ignoreKeyword}, fields[0]) {
|
||||
continue
|
||||
}
|
||||
rulePath := path.Clean(strings.Trim(filepath.ToSlash(fields[1]), "/"))
|
||||
if protocol.SafePath(rulePath) {
|
||||
rules = append(rules, Rule{Path: rulePath, Shared: fields[0] == sharedKeyword})
|
||||
rules = append(rules, Rule{Path: rulePath, Shared: fields[0] == sharedKeyword, Ignore: fields[0] == ignoreKeyword})
|
||||
}
|
||||
}
|
||||
return rules
|
||||
@@ -50,9 +53,14 @@ func LoadRules(root string) Rules {
|
||||
return parseRules(string(data))
|
||||
}
|
||||
|
||||
func (rules Rules) synced() Rules {
|
||||
return slices.DeleteFunc(slices.Clone(rules), func(rule Rule) bool { return rule.Ignore })
|
||||
}
|
||||
|
||||
func (rules Rules) paths() []string {
|
||||
paths := make([]string, len(rules))
|
||||
for i, rule := range rules {
|
||||
synced := rules.synced()
|
||||
paths := make([]string, len(synced))
|
||||
for i, rule := range synced {
|
||||
paths[i] = rule.Path
|
||||
}
|
||||
return paths
|
||||
@@ -60,12 +68,29 @@ func (rules Rules) paths() []string {
|
||||
|
||||
func (rules Rules) covers(file string, shared bool) bool {
|
||||
best := Rule{}
|
||||
for _, rule := range rules {
|
||||
for _, rule := range rules.synced() {
|
||||
if within(file, rule.Path) && len(rule.Path) > len(best.Path) {
|
||||
best = rule
|
||||
}
|
||||
}
|
||||
return best.Path != "" && best.Shared == shared
|
||||
return best.Path != "" && best.Shared == shared && !rules.ignored(file)
|
||||
}
|
||||
|
||||
func (rules Rules) ignored(file string) bool {
|
||||
return file != RulesFile && slices.ContainsFunc(rules, func(rule Rule) bool { return rule.Ignore && rule.matches(file) })
|
||||
}
|
||||
|
||||
func (rule Rule) matches(file string) bool {
|
||||
for name := file; name != "." && name != "/"; name = path.Dir(name) {
|
||||
target := name
|
||||
if !strings.Contains(rule.Path, "/") {
|
||||
target = path.Base(name)
|
||||
}
|
||||
if matched, _ := path.Match(rule.Path, target); matched {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func within(path, dir string) bool {
|
||||
|
||||
Reference in new issue
Block a user