2 Commits

Author SHA1 Message Date
73d93367a0 Refactor some things around a little 2025-03-25 23:16:03 +01:00
64f690f6b4 Fix usage to reflect recent flag changes 2025-03-25 23:02:32 +01:00
5 changed files with 57 additions and 99 deletions

24
main.go
View File

@@ -35,22 +35,39 @@ func init() {
}
func main() {
// TODO: Implement some sort of git integration
// Maybe use go-git
// Specify a -git flag
// If we are operating with git then:
// Inmitialize a repo if one doesn't exist (try to open right?)
// For each file matched by glob first figure out if it's already tracked
// If not tracked then track it and commit (either it alone or maybe multiple together somehow)
// Then reset the file (to undo previous modifications)
// THEN change the file
// In addition add a -undo flag that will ONLY reset the files without changing them
// Only for the ones matched by glob
// ^ important because binary files would fuck us up
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage: %s [options] <pattern> <lua_expression> <...files_or_globs>\n", os.Args[0])
fmt.Fprintf(os.Stderr, "\nOptions:\n")
fmt.Fprintf(os.Stderr, " -json\n")
fmt.Fprintf(os.Stderr, " Process JSON files\n")
fmt.Fprintf(os.Stderr, " -xml\n")
fmt.Fprintf(os.Stderr, " Process XML files\n")
fmt.Fprintf(os.Stderr, " -mode string\n")
fmt.Fprintf(os.Stderr, " Processing mode: regex, xml, json (default \"regex\")\n")
fmt.Fprintf(os.Stderr, "\nExamples:\n")
fmt.Fprintf(os.Stderr, " Regex mode (default):\n")
fmt.Fprintf(os.Stderr, " %s \"<value>(\\d+)</value>\" \"*1.5\" data.xml\n", os.Args[0])
fmt.Fprintf(os.Stderr, " XML mode:\n")
fmt.Fprintf(os.Stderr, " %s -mode=xml -xpath=\"//value\" \"*1.5\" data.xml\n", os.Args[0])
fmt.Fprintf(os.Stderr, " %s -xml \"//value\" \"*1.5\" data.xml\n", os.Args[0])
fmt.Fprintf(os.Stderr, " JSON mode:\n")
fmt.Fprintf(os.Stderr, " %s -mode=json -jsonpath=\"$.items[*].value\" \"*1.5\" data.json\n", os.Args[0])
fmt.Fprintf(os.Stderr, " %s -json \"$.items[*].value\" \"*1.5\" data.json\n", os.Args[0])
fmt.Fprintf(os.Stderr, "\nNote: v1, v2, etc. are used to refer to capture groups as numbers.\n")
fmt.Fprintf(os.Stderr, " s1, s2, etc. are used to refer to capture groups as strings.\n")
fmt.Fprintf(os.Stderr, " Helper functions: num(str) converts string to number, str(num) converts number to string\n")
fmt.Fprintf(os.Stderr, " is_number(str) checks if a string is numeric\n")
fmt.Fprintf(os.Stderr, " For XML and JSON, the captured values are exposed as 'v', which can be of any type we capture (string, number, table).\n")
fmt.Fprintf(os.Stderr, " If expression starts with an operator like *, /, +, -, =, etc., v1 is automatically prepended\n")
fmt.Fprintf(os.Stderr, " You can use any valid Lua code, including if statements, loops, etc.\n")
fmt.Fprintf(os.Stderr, " Glob patterns are supported for file selection (*.xml, data/**.xml, etc.)\n")
@@ -117,7 +134,8 @@ func main() {
defer wg.Done()
logger.Printf("Processing file: %s", file)
modCount, matchCount, err := proc.Process(file, pattern, luaExpr)
// It's a bit fucked, maybe I could do better to call it from proc... But it'll do for now
modCount, matchCount, err := processor.Process(proc, file, pattern, luaExpr)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to process file %s: %v\n", file, err)
stats.FailedFiles++

View File

@@ -5,8 +5,6 @@ import (
"fmt"
"log"
"modify/processor/jsonpath"
"os"
"path/filepath"
lua "github.com/yuin/gopher-lua"
)
@@ -14,39 +12,6 @@ import (
// JSONProcessor implements the Processor interface for JSON documents
type JSONProcessor struct{}
// Process implements the Processor interface for JSONProcessor
func (p *JSONProcessor) Process(filename string, pattern string, luaExpr string) (int, int, error) {
// Read file content
cwd, err := os.Getwd()
if err != nil {
return 0, 0, fmt.Errorf("error getting current working directory: %v", err)
}
fullPath := filepath.Join(cwd, filename)
content, err := os.ReadFile(fullPath)
if err != nil {
return 0, 0, fmt.Errorf("error reading file: %v", err)
}
fileContent := string(content)
// Process the content
modifiedContent, modCount, matchCount, err := p.ProcessContent(fileContent, pattern, luaExpr)
if err != nil {
return 0, 0, err
}
// If we made modifications, save the file
if modCount > 0 {
err = os.WriteFile(fullPath, []byte(modifiedContent), 0644)
if err != nil {
return 0, 0, fmt.Errorf("error writing file: %v", err)
}
}
return modCount, matchCount, nil
}
// ProcessContent implements the Processor interface for JSONProcessor
func (p *JSONProcessor) ProcessContent(content string, pattern string, luaExpr string) (string, int, int, error) {
// Parse JSON document

View File

@@ -2,6 +2,8 @@ package processor
import (
"fmt"
"os"
"path/filepath"
"strings"
lua "github.com/yuin/gopher-lua"
@@ -10,7 +12,8 @@ import (
// Processor defines the interface for all file processors
type Processor interface {
// Process handles processing a file with the given pattern and Lua expression
Process(filename string, pattern string, luaExpr string) (int, int, error)
// Now implemented as a base function in processor.go
// Process(filename string, pattern string, luaExpr string) (int, int, error)
// ProcessContent handles processing a string content directly with the given pattern and Lua expression
// Returns the modified content, modification count, match count, and any error
@@ -51,6 +54,38 @@ func NewLuaState() (*lua.LState, error) {
return L, nil
}
func Process(p Processor, filename string, pattern string, luaExpr string) (int, int, error) {
// Read file content
cwd, err := os.Getwd()
if err != nil {
return 0, 0, fmt.Errorf("error getting current working directory: %v", err)
}
fullPath := filepath.Join(cwd, filename)
content, err := os.ReadFile(fullPath)
if err != nil {
return 0, 0, fmt.Errorf("error reading file: %v", err)
}
fileContent := string(content)
// Process the content
modifiedContent, modCount, matchCount, err := p.ProcessContent(fileContent, pattern, luaExpr)
if err != nil {
return 0, 0, err
}
// If we made modifications, save the file
if modCount > 0 {
err = os.WriteFile(fullPath, []byte(modifiedContent), 0644)
if err != nil {
return 0, 0, fmt.Errorf("error writing file: %v", err)
}
}
return modCount, matchCount, nil
}
// ToLua converts a struct or map to a Lua table recursively
func ToLua(L *lua.LState, data interface{}) (lua.LValue, error) {
switch v := data.(type) {

View File

@@ -2,8 +2,6 @@ package processor
import (
"fmt"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
@@ -14,34 +12,6 @@ import (
// RegexProcessor implements the Processor interface using regex patterns
type RegexProcessor struct{}
// Process implements the Processor interface for RegexProcessor
func (p *RegexProcessor) Process(filename string, pattern string, luaExpr string) (int, int, error) {
// Read file content
fullPath := filepath.Join(".", filename)
content, err := os.ReadFile(fullPath)
if err != nil {
return 0, 0, fmt.Errorf("error reading file: %v", err)
}
fileContent := string(content)
// Process the content
modifiedContent, modCount, matchCount, err := p.ProcessContent(fileContent, pattern, luaExpr)
if err != nil {
return 0, 0, err
}
// If we made modifications, save the file
if modCount > 0 {
err = os.WriteFile(fullPath, []byte(modifiedContent), 0644)
if err != nil {
return 0, 0, fmt.Errorf("error writing file: %v", err)
}
}
return modCount, matchCount, nil
}
// ToLua sets capture groups as Lua variables (v1, v2, etc. for numeric values and s1, s2, etc. for strings)
func (p *RegexProcessor) ToLua(L *lua.LState, data interface{}) error {
captures, ok := data.([]string)

View File

@@ -2,8 +2,6 @@ package processor
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/antchfx/xmlquery"
@@ -13,34 +11,6 @@ import (
// XMLProcessor implements the Processor interface for XML documents
type XMLProcessor struct{}
// Process implements the Processor interface for XMLProcessor
func (p *XMLProcessor) Process(filename string, pattern string, luaExpr string) (int, int, error) {
// Read file content
fullPath := filepath.Join(".", filename)
content, err := os.ReadFile(fullPath)
if err != nil {
return 0, 0, fmt.Errorf("error reading file: %v", err)
}
fileContent := string(content)
// Process the content
modifiedContent, modCount, matchCount, err := p.ProcessContent(fileContent, pattern, luaExpr)
if err != nil {
return 0, 0, err
}
// If we made modifications, save the file
if modCount > 0 {
err = os.WriteFile(fullPath, []byte(modifiedContent), 0644)
if err != nil {
return 0, 0, fmt.Errorf("error writing file: %v", err)
}
}
return modCount, matchCount, nil
}
// ProcessContent implements the Processor interface for XMLProcessor
func (p *XMLProcessor) ProcessContent(content string, pattern string, luaExpr string) (string, int, int, error) {
// Parse XML document