15 Commits

5 changed files with 85 additions and 149 deletions

9
.vscode/launch.json vendored
View File

@@ -9,13 +9,8 @@
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}",
"args": [
"-mode=json",
"$..name",
"v='pero'",
"test.json"
]
"program": "${fileDirname}",
"args": []
}
]
}

22
main.go
View File

@@ -32,6 +32,7 @@ var logger *log.Logger
var (
fileModeFlag = flag.String("mode", "regex", "Processing mode: regex, xml, json")
verboseFlag = flag.Bool("verbose", false, "Enable verbose output")
)
func init() {
@@ -47,6 +48,12 @@ func main() {
fmt.Fprintf(os.Stderr, "\nOptions:\n")
fmt.Fprintf(os.Stderr, " -mode string\n")
fmt.Fprintf(os.Stderr, " Processing mode: regex, xml, json (default \"regex\")\n")
fmt.Fprintf(os.Stderr, " -xpath string\n")
fmt.Fprintf(os.Stderr, " XPath expression (for XML mode)\n")
fmt.Fprintf(os.Stderr, " -jsonpath string\n")
fmt.Fprintf(os.Stderr, " JSONPath expression (for JSON mode)\n")
fmt.Fprintf(os.Stderr, " -verbose\n")
fmt.Fprintf(os.Stderr, " Enable verbose output\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])
@@ -76,9 +83,15 @@ func main() {
var pattern, luaExpr string
var filePatterns []string
if *fileModeFlag == "regex" {
pattern = args[0]
luaExpr = args[1]
filePatterns = args[2:]
} else {
// For XML/JSON modes, pattern comes from flags
luaExpr = args[0]
filePatterns = args[1:]
}
// Prepare the Lua expression
originalLuaExpr := luaExpr
@@ -111,10 +124,11 @@ func main() {
// pattern = *xpathFlag
// logger.Printf("Starting XML modifier with XPath %q, expression %q on %d files",
// pattern, luaExpr, len(files))
case "json":
proc = &processor.JSONProcessor{}
logger.Printf("Starting JSON modifier with JSONPath %q, expression %q on %d files",
pattern, luaExpr, len(files))
// case "json":
// proc = &processor.JSONProcessor{}
// pattern = *jsonpathFlag
// logger.Printf("Starting JSON modifier with JSONPath %q, expression %q on %d files",
// pattern, luaExpr, len(files))
}
var wg sync.WaitGroup

View File

@@ -3,7 +3,6 @@ package processor
import (
"encoding/json"
"fmt"
"log"
"modify/processor/jsonpath"
"os"
"path/filepath"
@@ -68,44 +67,34 @@ func (p *JSONProcessor) ProcessContent(content string, pattern string, luaExpr s
return content, 0, 0, nil
}
for _, node := range nodes {
log.Printf("Processing node at path: %s with value: %v", node.Path, node.Value)
// Initialize Lua
L, err := NewLuaState()
if err != nil {
return content, len(nodes), 0, fmt.Errorf("error creating Lua state: %v", err)
}
defer L.Close()
log.Println("Lua state initialized successfully.")
err = p.ToLua(L, node.Value)
err = p.ToLua(L, nodes)
if err != nil {
return content, len(nodes), 0, fmt.Errorf("error converting to Lua: %v", err)
}
log.Printf("Converted node value to Lua: %v", node.Value)
// Execute Lua script
log.Printf("Executing Lua script: %s", luaExpr)
if err := L.DoString(luaExpr); err != nil {
return content, len(nodes), 0, fmt.Errorf("error executing Lua %s: %v", luaExpr, err)
}
log.Println("Lua script executed successfully.")
// Get modified value
result, err := p.FromLua(L)
if err != nil {
return content, len(nodes), 0, fmt.Errorf("error getting result from Lua: %v", err)
}
log.Printf("Retrieved modified value from Lua: %v", result)
// Apply the modification to the JSON data
err = p.updateJSONValue(jsonData, node.Path, result)
err = p.updateJSONValue(jsonData, pattern, result)
if err != nil {
return content, len(nodes), 0, fmt.Errorf("error updating JSON: %v", err)
}
log.Printf("Updated JSON at path: %s with new value: %v", node.Path, result)
}
// Convert the modified JSON back to a string with same formatting
var jsonBytes []byte
@@ -165,16 +154,12 @@ func detectJsonIndentation(content string) (string, error) {
// updateJSONValue updates a value in the JSON structure based on its JSONPath
func (p *JSONProcessor) updateJSONValue(jsonData interface{}, path string, newValue interface{}) error {
err := jsonpath.Set(jsonData, path, newValue)
if err != nil {
return fmt.Errorf("failed to update JSON value at path '%s': %w", path, err)
}
return nil
}
// ToLua converts JSON values to Lua variables
func (p *JSONProcessor) ToLua(L *lua.LState, data interface{}) error {
table, err := ToLua(L, data)
table, err := ToLuaTable(L, data)
if err != nil {
return err
}
@@ -185,5 +170,5 @@ func (p *JSONProcessor) ToLua(L *lua.LState, data interface{}) error {
// FromLua retrieves values from Lua
func (p *JSONProcessor) FromLua(L *lua.LState) (interface{}, error) {
luaValue := L.GetGlobal("v")
return FromLua(L, luaValue)
return FromLuaTable(L, luaValue.(*lua.LTable))
}

View File

@@ -2,7 +2,7 @@ package processor
import (
"fmt"
"strconv"
"reflect"
"strings"
lua "github.com/yuin/gopher-lua"
@@ -52,75 +52,65 @@ func NewLuaState() (*lua.LState, error) {
return L, nil
}
// ToLua converts a struct or map to a Lua table recursively
func ToLua(L *lua.LState, data interface{}) (lua.LValue, error) {
// ToLuaTable converts a struct or map to a Lua table recursively
func ToLuaTable(L *lua.LState, data interface{}) (*lua.LTable, error) {
luaTable := L.NewTable()
switch v := data.(type) {
case map[string]interface{}:
luaTable := L.NewTable()
for key, value := range v {
luaValue, err := ToLua(L, value)
luaValue, err := ToLuaTable(L, value)
if err != nil {
return nil, err
}
luaTable.RawSetString(key, luaValue)
}
return luaTable, nil
case []interface{}:
luaTable := L.NewTable()
for i, value := range v {
luaValue, err := ToLua(L, value)
case struct{}:
val := reflect.ValueOf(v)
for i := 0; i < val.NumField(); i++ {
field := val.Type().Field(i)
luaValue, err := ToLuaTable(L, val.Field(i).Interface())
if err != nil {
return nil, err
}
luaTable.RawSetInt(i+1, luaValue) // Lua arrays are 1-indexed
luaTable.RawSetString(field.Name, luaValue)
}
return luaTable, nil
case string:
return lua.LString(v), nil
luaTable.RawSetString("v", lua.LString(v))
case bool:
return lua.LBool(v), nil
luaTable.RawSetString("v", lua.LBool(v))
case float64:
return lua.LNumber(v), nil
luaTable.RawSetString("v", lua.LNumber(v))
default:
return nil, fmt.Errorf("unsupported data type: %T", data)
}
return luaTable, nil
}
// FromLua converts a Lua table to a struct or map recursively
func FromLua(L *lua.LState, luaValue lua.LValue) (interface{}, error) {
switch v := luaValue.(type) {
case *lua.LTable:
// FromLuaTable converts a Lua table to a struct or map recursively
func FromLuaTable(L *lua.LState, luaTable *lua.LTable) (map[string]interface{}, error) {
result := make(map[string]interface{})
v.ForEach(func(key lua.LValue, value lua.LValue) {
result[key.String()], _ = FromLua(L, value)
})
// This may be a bit wasteful...
// Hopefully it won't run often enough to matter
isArray := true
for key := range result {
_, err := strconv.Atoi(key)
luaTable.ForEach(func(key lua.LValue, value lua.LValue) {
switch v := value.(type) {
case *lua.LTable:
nestedMap, err := FromLuaTable(L, v)
if err != nil {
isArray = false
break
return
}
}
if isArray {
list := make([]interface{}, 0, len(result))
for _, value := range result {
list = append(list, value)
}
return list, nil
}
return result, nil
result[key.String()] = nestedMap
case lua.LString:
return string(v), nil
result[key.String()] = string(v)
case lua.LBool:
return bool(v), nil
result[key.String()] = bool(v)
case lua.LNumber:
return float64(v), nil
result[key.String()] = float64(v)
default:
return nil, nil
result[key.String()] = nil
}
})
return result, nil
}
// InitLuaHelpers initializes common Lua helper functions

View File

@@ -1,48 +0,0 @@
#!/bin/bash
echo "Figuring out the tag..."
TAG=$(git describe --tags --exact-match 2>/dev/null || echo "")
if [ -z "$TAG" ]; then
# Get the latest tag
LATEST_TAG=$(git describe --tags $(git rev-list --tags --max-count=1))
# Increment the patch version
IFS='.' read -r -a VERSION_PARTS <<< "$LATEST_TAG"
VERSION_PARTS[2]=$((VERSION_PARTS[2]+1))
TAG="${VERSION_PARTS[0]}.${VERSION_PARTS[1]}.${VERSION_PARTS[2]}"
# Create a new tag
git tag $TAG
git push origin $TAG
fi
echo "Tag: $TAG"
echo "Building the thing..."
go build -o BigChef.exe .
echo "Creating a release..."
TOKEN="$GITEA_API_KEY"
GITEA="https://git.site.quack-lab.dev"
REPO="dave/BigChef"
# Create a release
RELEASE_RESPONSE=$(curl -s -X POST \
-H "Authorization: token $TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"tag_name": "'"$TAG"'",
"name": "'"$TAG"'",
"draft": false,
"prerelease": false
}' \
$GITEA/api/v1/repos/$REPO/releases)
# Extract the release ID
echo $RELEASE_RESPONSE
RELEASE_ID=$(echo $RELEASE_RESPONSE | awk -F'"id":' '{print $2+0; exit}')
echo "Release ID: $RELEASE_ID"
echo "Uploading the things..."
curl -X POST \
-H "Authorization: token $TOKEN" \
-F "attachment=@BigChef.exe" \
"$GITEA/api/v1/repos/$REPO/releases/${RELEASE_ID}/assets?name=BigChef.exe"
rm BigChef.exe