167 lines
3.0 KiB
Go
167 lines
3.0 KiB
Go
package rule
|
|
|
|
import (
|
|
"io"
|
|
"path/filepath"
|
|
"sync"
|
|
|
|
"git.foosoft.net/alex/goldsmith"
|
|
"git.foosoft.net/alex/goldsmith/filters/operator"
|
|
"git.foosoft.net/alex/goldsmith/filters/wildcard"
|
|
"github.com/BurntSushi/toml"
|
|
)
|
|
|
|
type rule struct {
|
|
Accept []string
|
|
Reject []string
|
|
baseDir string
|
|
}
|
|
|
|
type ruleApply struct {
|
|
rule
|
|
Props map[string]goldsmith.FileProp
|
|
}
|
|
|
|
type ruleDrop struct {
|
|
rule
|
|
}
|
|
|
|
func (self *rule) accept(inputFile goldsmith.File) bool {
|
|
if !wildcard.New(filepath.Join(self.baseDir, "**")).Accept(inputFile) {
|
|
return false
|
|
}
|
|
|
|
var acceptPaths []string
|
|
for _, path := range self.Accept {
|
|
acceptPaths = append(acceptPaths, filepath.Join(self.baseDir, path))
|
|
}
|
|
|
|
if wildcard.New(acceptPaths...).Accept(inputFile) {
|
|
return true
|
|
}
|
|
|
|
var rejectPaths []string
|
|
for _, path := range self.Reject {
|
|
rejectPaths = append(rejectPaths, filepath.Join(self.baseDir, path))
|
|
}
|
|
|
|
if len(rejectPaths) == 0 {
|
|
return false
|
|
}
|
|
|
|
return operator.Not(wildcard.New(rejectPaths...)).Accept(inputFile)
|
|
}
|
|
|
|
func (self *ruleApply) apply(inputFile goldsmith.File) {
|
|
if self.accept(inputFile) {
|
|
for name, value := range self.Props {
|
|
inputFile.SetProp(name, value)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (self *ruleDrop) drop(inputFile goldsmith.File) bool {
|
|
return self.accept(inputFile)
|
|
}
|
|
|
|
type ruleSet struct {
|
|
Apply []*ruleApply
|
|
Drop []*ruleDrop
|
|
}
|
|
|
|
func newRuleSet(inputFile goldsmith.File) (*ruleSet, error) {
|
|
data, err := io.ReadAll(inputFile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var ruleSet ruleSet
|
|
if err := toml.Unmarshal(data, &ruleSet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, rule := range ruleSet.Apply {
|
|
rule.baseDir = inputFile.Dir()
|
|
}
|
|
|
|
for _, rule := range ruleSet.Drop {
|
|
rule.baseDir = inputFile.Dir()
|
|
}
|
|
|
|
return &ruleSet, nil
|
|
}
|
|
|
|
func (self *ruleSet) process(inputFile goldsmith.File) bool {
|
|
for _, rule := range self.Apply {
|
|
rule.apply(inputFile)
|
|
}
|
|
|
|
for _, rule := range self.Drop {
|
|
if rule.drop(inputFile) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// Rule chainable context.
|
|
type Rule struct {
|
|
filename string
|
|
|
|
ruleSets []*ruleSet
|
|
inputFiles []goldsmith.File
|
|
mutex sync.Mutex
|
|
}
|
|
|
|
// New creates a new instance of the Rule plugin.
|
|
func New() *Rule {
|
|
return &Rule{filename: "rules.toml"}
|
|
}
|
|
|
|
func (self *Rule) Filename(filename string) *Rule {
|
|
self.filename = filename
|
|
return self
|
|
}
|
|
|
|
func (*Rule) Name() string {
|
|
return "rule"
|
|
}
|
|
|
|
func (self *Rule) Process(context *goldsmith.Context, inputFile goldsmith.File) error {
|
|
if inputFile.Name() == self.filename {
|
|
ruleSet, err := newRuleSet(inputFile)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
self.mutex.Lock()
|
|
self.ruleSets = append(self.ruleSets, ruleSet)
|
|
self.mutex.Unlock()
|
|
} else {
|
|
self.mutex.Lock()
|
|
self.inputFiles = append(self.inputFiles, inputFile)
|
|
self.mutex.Unlock()
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (self *Rule) Finalize(context *goldsmith.Context) error {
|
|
for _, inputFile := range self.inputFiles {
|
|
var block bool
|
|
for _, ruleSet := range self.ruleSets {
|
|
if !ruleSet.process(inputFile) {
|
|
block = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !block {
|
|
context.DispatchFile(inputFile)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|