Implement regexes, an entry option allow for same modification to apply to multiple regexes and variables that can be referenced in lua
This commit is contained in:
58
main.go
58
main.go
@@ -96,6 +96,23 @@ func main() {
|
|||||||
flag.Usage()
|
flag.Usage()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// Collect global modifiers from special entries and filter them out
|
||||||
|
vars := map[string]interface{}{}
|
||||||
|
filtered := make([]utils.ModifyCommand, 0, len(commands))
|
||||||
|
for _, c := range commands {
|
||||||
|
if len(c.Modifiers) > 0 && c.Name == "" && c.Regex == "" && len(c.Regexes) == 0 && c.Lua == "" && len(c.Files) == 0 {
|
||||||
|
for k, v := range c.Modifiers {
|
||||||
|
vars[k] = v
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
filtered = append(filtered, c)
|
||||||
|
}
|
||||||
|
if len(vars) > 0 {
|
||||||
|
mainLogger.Info("Loaded %d global modifiers", len(vars))
|
||||||
|
processor.SetVariables(vars)
|
||||||
|
}
|
||||||
|
commands = filtered
|
||||||
mainLogger.Info("Loaded %d commands", len(commands))
|
mainLogger.Info("Loaded %d commands", len(commands))
|
||||||
|
|
||||||
if *utils.Filter != "" {
|
if *utils.Filter != "" {
|
||||||
@@ -111,7 +128,11 @@ func main() {
|
|||||||
|
|
||||||
for _, command := range commands {
|
for _, command := range commands {
|
||||||
mainLogger.Trace("Command: %s", command.Name)
|
mainLogger.Trace("Command: %s", command.Name)
|
||||||
|
if len(command.Regexes) > 0 {
|
||||||
|
mainLogger.Trace("Regexes: %v", command.Regexes)
|
||||||
|
} else {
|
||||||
mainLogger.Trace("Regex: %s", command.Regex)
|
mainLogger.Trace("Regex: %s", command.Regex)
|
||||||
|
}
|
||||||
mainLogger.Trace("Files: %v", command.Files)
|
mainLogger.Trace("Files: %v", command.Files)
|
||||||
mainLogger.Trace("Lua: %s", command.Lua)
|
mainLogger.Trace("Lua: %s", command.Lua)
|
||||||
mainLogger.Trace("Reset: %t", command.Reset)
|
mainLogger.Trace("Reset: %t", command.Reset)
|
||||||
@@ -428,31 +449,36 @@ func RunOtherCommands(file string, fileDataStr string, association utils.FileCom
|
|||||||
cmdLogger = cmdLog
|
cmdLogger = cmdLog
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdLogger.Debug("Begin processing file with command %q", command.Regex)
|
patterns := command.Regexes
|
||||||
|
if len(patterns) == 0 {
|
||||||
|
patterns = []string{command.Regex}
|
||||||
|
}
|
||||||
|
for idx, pattern := range patterns {
|
||||||
|
tmpCmd := command
|
||||||
|
tmpCmd.Regex = pattern
|
||||||
|
cmdLogger.Debug("Begin processing file with command %q (pattern %d/%d)", command.Name, idx+1, len(patterns))
|
||||||
numCommandsConsidered++
|
numCommandsConsidered++
|
||||||
newModifications, err := processor.ProcessRegex(fileDataStr, command, file)
|
newModifications, err := processor.ProcessRegex(fileDataStr, tmpCmd, file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
runOtherCommandsLogger.Error("Failed to process file with command %q: %v", command.Regex, err)
|
runOtherCommandsLogger.Error("Failed to process file with command %q: %v", command.Name, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
modifications = append(modifications, newModifications...)
|
modifications = append(modifications, newModifications...)
|
||||||
// It is not guranteed that all the commands will be executed...
|
|
||||||
// TODO: Make this better
|
|
||||||
// We'd have to pass the map to executemodifications or something...
|
|
||||||
count, ok := stats.ModificationsPerCommand.Load(command.Name)
|
count, ok := stats.ModificationsPerCommand.Load(command.Name)
|
||||||
if !ok {
|
if !ok {
|
||||||
count = 0
|
count = 0
|
||||||
}
|
}
|
||||||
stats.ModificationsPerCommand.Store(command.Name, count.(int)+len(newModifications))
|
stats.ModificationsPerCommand.Store(command.Name, count.(int)+len(newModifications))
|
||||||
|
|
||||||
cmdLogger.Debug("Command %q generated %d modifications", command.Name, len(newModifications))
|
cmdLogger.Debug("Command %q generated %d modifications (pattern %d/%d)", command.Name, len(newModifications), idx+1, len(patterns))
|
||||||
cmdLogger.Trace("Modifications generated by command %q: %v", command.Name, newModifications)
|
cmdLogger.Trace("Modifications generated by command %q: %v", command.Name, newModifications)
|
||||||
if len(newModifications) == 0 {
|
if len(newModifications) == 0 {
|
||||||
cmdLogger.Debug("No modifications yielded by command %q", command.Name)
|
cmdLogger.Debug("No modifications yielded by command %q (pattern %d/%d)", command.Name, idx+1, len(patterns))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
runOtherCommandsLogger.Debug("Aggregated %d modifications from %d commands", len(modifications), numCommandsConsidered)
|
runOtherCommandsLogger.Debug("Aggregated %d modifications from %d command-pattern runs", len(modifications), numCommandsConsidered)
|
||||||
runOtherCommandsLogger.Trace("All aggregated modifications: %v", modifications)
|
runOtherCommandsLogger.Trace("All aggregated modifications: %v", modifications)
|
||||||
|
|
||||||
if len(modifications) == 0 {
|
if len(modifications) == 0 {
|
||||||
@@ -480,14 +506,21 @@ func RunIsolateCommands(association utils.FileCommandAssociation, file string, f
|
|||||||
anythingDone := false
|
anythingDone := false
|
||||||
for _, isolateCommand := range association.IsolateCommands {
|
for _, isolateCommand := range association.IsolateCommands {
|
||||||
runIsolateCommandsLogger.Debug("Begin processing file with isolate command %q", isolateCommand.Regex)
|
runIsolateCommandsLogger.Debug("Begin processing file with isolate command %q", isolateCommand.Regex)
|
||||||
modifications, err := processor.ProcessRegex(fileDataStr, isolateCommand, file)
|
patterns := isolateCommand.Regexes
|
||||||
|
if len(patterns) == 0 {
|
||||||
|
patterns = []string{isolateCommand.Regex}
|
||||||
|
}
|
||||||
|
for idx, pattern := range patterns {
|
||||||
|
tmpCmd := isolateCommand
|
||||||
|
tmpCmd.Regex = pattern
|
||||||
|
modifications, err := processor.ProcessRegex(fileDataStr, tmpCmd, file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
runIsolateCommandsLogger.Error("Failed to process file with isolate command %q: %v", isolateCommand.Regex, err)
|
runIsolateCommandsLogger.Error("Failed to process file with isolate command %q (pattern %d/%d): %v", isolateCommand.Name, idx+1, len(patterns), err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(modifications) == 0 {
|
if len(modifications) == 0 {
|
||||||
runIsolateCommandsLogger.Debug("Isolate command %q produced no modifications", isolateCommand.Name)
|
runIsolateCommandsLogger.Debug("Isolate command %q produced no modifications (pattern %d/%d)", isolateCommand.Name, idx+1, len(patterns))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
anythingDone = true
|
anythingDone = true
|
||||||
@@ -502,6 +535,7 @@ func RunIsolateCommands(association utils.FileCommandAssociation, file string, f
|
|||||||
|
|
||||||
runIsolateCommandsLogger.Info("Executed %d isolate modifications for file", count)
|
runIsolateCommandsLogger.Info("Executed %d isolate modifications for file", count)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if !anythingDone {
|
if !anythingDone {
|
||||||
runIsolateCommandsLogger.Debug("No isolate modifications were made for file")
|
runIsolateCommandsLogger.Debug("No isolate modifications were made for file")
|
||||||
return fileDataStr, NothingToDo
|
return fileDataStr, NothingToDo
|
||||||
|
@@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"cook/utils"
|
"cook/utils"
|
||||||
@@ -18,6 +19,14 @@ var processorLogger = logger.Default.WithPrefix("processor")
|
|||||||
// Maybe we make this an interface again for the shits and giggles
|
// Maybe we make this an interface again for the shits and giggles
|
||||||
// We will see, it could easily be...
|
// We will see, it could easily be...
|
||||||
|
|
||||||
|
var globalVariables = map[string]interface{}{}
|
||||||
|
|
||||||
|
func SetVariables(vars map[string]interface{}) {
|
||||||
|
for k, v := range vars {
|
||||||
|
globalVariables[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func NewLuaState() (*lua.LState, error) {
|
func NewLuaState() (*lua.LState, error) {
|
||||||
newLStateLogger := processorLogger.WithPrefix("NewLuaState")
|
newLStateLogger := processorLogger.WithPrefix("NewLuaState")
|
||||||
newLStateLogger.Debug("Creating new Lua state")
|
newLStateLogger.Debug("Creating new Lua state")
|
||||||
@@ -42,6 +51,34 @@ func NewLuaState() (*lua.LState, error) {
|
|||||||
}
|
}
|
||||||
newLStateLogger.Debug("Lua helper functions initialized")
|
newLStateLogger.Debug("Lua helper functions initialized")
|
||||||
|
|
||||||
|
// Inject global variables
|
||||||
|
if len(globalVariables) > 0 {
|
||||||
|
newLStateLogger.Debug("Injecting %d global variables into Lua state", len(globalVariables))
|
||||||
|
for k, v := range globalVariables {
|
||||||
|
switch val := v.(type) {
|
||||||
|
case int:
|
||||||
|
L.SetGlobal(k, lua.LNumber(float64(val)))
|
||||||
|
case int64:
|
||||||
|
L.SetGlobal(k, lua.LNumber(float64(val)))
|
||||||
|
case float32:
|
||||||
|
L.SetGlobal(k, lua.LNumber(float64(val)))
|
||||||
|
case float64:
|
||||||
|
L.SetGlobal(k, lua.LNumber(val))
|
||||||
|
case string:
|
||||||
|
L.SetGlobal(k, lua.LString(val))
|
||||||
|
case bool:
|
||||||
|
if val {
|
||||||
|
L.SetGlobal(k, lua.LTrue)
|
||||||
|
} else {
|
||||||
|
L.SetGlobal(k, lua.LFalse)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// Fallback to string representation
|
||||||
|
L.SetGlobal(k, lua.LString(fmt.Sprintf("%v", val)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
newLStateLogger.Debug("New Lua state created successfully")
|
newLStateLogger.Debug("New Lua state created successfully")
|
||||||
return L, nil
|
return L, nil
|
||||||
}
|
}
|
||||||
@@ -246,6 +283,9 @@ func BuildLuaScript(luaExpr string) string {
|
|||||||
buildLuaScriptLogger := processorLogger.WithPrefix("BuildLuaScript").WithField("inputLuaExpr", luaExpr)
|
buildLuaScriptLogger := processorLogger.WithPrefix("BuildLuaScript").WithField("inputLuaExpr", luaExpr)
|
||||||
buildLuaScriptLogger.Debug("Building full Lua script from expression")
|
buildLuaScriptLogger.Debug("Building full Lua script from expression")
|
||||||
|
|
||||||
|
// Perform $var substitutions from globalVariables
|
||||||
|
luaExpr = replaceVariables(luaExpr)
|
||||||
|
|
||||||
luaExpr = PrependLuaAssignment(luaExpr)
|
luaExpr = PrependLuaAssignment(luaExpr)
|
||||||
|
|
||||||
fullScript := fmt.Sprintf(`
|
fullScript := fmt.Sprintf(`
|
||||||
@@ -260,6 +300,32 @@ func BuildLuaScript(luaExpr string) string {
|
|||||||
return fullScript
|
return fullScript
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func replaceVariables(expr string) string {
|
||||||
|
// $varName -> literal value
|
||||||
|
varNameRe := regexp.MustCompile(`\$(\w+)`)
|
||||||
|
return varNameRe.ReplaceAllStringFunc(expr, func(m string) string {
|
||||||
|
name := varNameRe.FindStringSubmatch(m)[1]
|
||||||
|
if v, ok := globalVariables[name]; ok {
|
||||||
|
switch val := v.(type) {
|
||||||
|
case int, int64, float32, float64:
|
||||||
|
return fmt.Sprintf("%v", val)
|
||||||
|
case bool:
|
||||||
|
if val {
|
||||||
|
return "true"
|
||||||
|
} else {
|
||||||
|
return "false"
|
||||||
|
}
|
||||||
|
case string:
|
||||||
|
// Quote strings for Lua literal
|
||||||
|
return fmt.Sprintf("%q", val)
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("%q", fmt.Sprintf("%v", val))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func printToGo(L *lua.LState) int {
|
func printToGo(L *lua.LState) int {
|
||||||
printToGoLogger := processorLogger.WithPrefix("printToGo")
|
printToGoLogger := processorLogger.WithPrefix("printToGo")
|
||||||
printToGoLogger.Debug("Lua print function called, redirecting to Go logger")
|
printToGoLogger.Debug("Lua print function called, redirecting to Go logger")
|
||||||
|
@@ -17,6 +17,7 @@ var modifyCommandLogger = logger.Default.WithPrefix("utils/modifycommand")
|
|||||||
type ModifyCommand struct {
|
type ModifyCommand struct {
|
||||||
Name string `yaml:"name"`
|
Name string `yaml:"name"`
|
||||||
Regex string `yaml:"regex"`
|
Regex string `yaml:"regex"`
|
||||||
|
Regexes []string `yaml:"regexes"`
|
||||||
Lua string `yaml:"lua"`
|
Lua string `yaml:"lua"`
|
||||||
Files []string `yaml:"files"`
|
Files []string `yaml:"files"`
|
||||||
Reset bool `yaml:"reset"`
|
Reset bool `yaml:"reset"`
|
||||||
@@ -24,6 +25,7 @@ type ModifyCommand struct {
|
|||||||
Isolate bool `yaml:"isolate"`
|
Isolate bool `yaml:"isolate"`
|
||||||
NoDedup bool `yaml:"nodedup"`
|
NoDedup bool `yaml:"nodedup"`
|
||||||
Disabled bool `yaml:"disable"`
|
Disabled bool `yaml:"disable"`
|
||||||
|
Modifiers map[string]interface{} `yaml:"modifiers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CookFile []ModifyCommand
|
type CookFile []ModifyCommand
|
||||||
@@ -31,7 +33,7 @@ type CookFile []ModifyCommand
|
|||||||
func (c *ModifyCommand) Validate() error {
|
func (c *ModifyCommand) Validate() error {
|
||||||
validateLogger := modifyCommandLogger.WithPrefix("Validate").WithField("commandName", c.Name)
|
validateLogger := modifyCommandLogger.WithPrefix("Validate").WithField("commandName", c.Name)
|
||||||
validateLogger.Debug("Validating command")
|
validateLogger.Debug("Validating command")
|
||||||
if c.Regex == "" {
|
if c.Regex == "" && len(c.Regexes) == 0 {
|
||||||
validateLogger.Error("Validation failed: Regex pattern is required")
|
validateLogger.Error("Validation failed: Regex pattern is required")
|
||||||
return fmt.Errorf("pattern is required")
|
return fmt.Errorf("pattern is required")
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user