Hallucinate some logs

Hallucinate more logs

fix(utils/db.go): handle auto migration errors gracefully

fix(utils/modifycommand.go): improve file matching accuracy

fix(processor/regex.go): improve capture group deduplication logic

fix(utils/db.go): add logging for database wrapper initialization

feat(processor/regex.go): preserve input order when deduplicating capture groups

fix(utils/modifycommand.go): add logging for file matching skips

feat(processor/regex.go): add logging for capture group processing

feat(main.go): add trace logging for arguments and parallel workers

fix(main.go): add trace logging for file content

fix(utils/db.go): add logging for database opening

fix(main.go): add trace logging for file processing

fix(utils/modifycommand.go): improve file matching by using absolute paths

feat(modifycommand.go): add trace logging for file matching in AssociateFilesWithCommands

feat(main.go): add per-file association summary for better visibility when debugging
This commit is contained in:
2025-08-07 23:33:19 +02:00
parent 8ffd8af13c
commit 4b58e00c26
8 changed files with 702 additions and 328 deletions

View File

@@ -6,151 +6,106 @@ import (
"net/http"
"strings"
"cook/utils"
logger "git.site.quack-lab.dev/dave/cylogger"
lua "github.com/yuin/gopher-lua"
)
// processorLogger is a scoped logger for the processor package.
var processorLogger = logger.Default.WithPrefix("processor")
// Maybe we make this an interface again for the shits and giggles
// We will see, it could easily be...
func NewLuaState() (*lua.LState, error) {
newLStateLogger := processorLogger.WithPrefix("NewLuaState")
newLStateLogger.Debug("Creating new Lua state")
L := lua.NewState()
// defer L.Close()
// Load math library
logger.Debug("Loading Lua math library")
newLStateLogger.Debug("Loading Lua math library")
L.Push(L.GetGlobal("require"))
L.Push(lua.LString("math"))
if err := L.PCall(1, 1, nil); err != nil {
logger.Error("Failed to load Lua math library: %v", err)
newLStateLogger.Error("Failed to load Lua math library: %v", err)
return nil, fmt.Errorf("error loading Lua math library: %v", err)
}
newLStateLogger.Debug("Lua math library loaded")
// Initialize helper functions
logger.Debug("Initializing Lua helper functions")
newLStateLogger.Debug("Initializing Lua helper functions")
if err := InitLuaHelpers(L); err != nil {
logger.Error("Failed to initialize Lua helper functions: %v", err)
newLStateLogger.Error("Failed to initialize Lua helper functions: %v", err)
return nil, err
}
newLStateLogger.Debug("Lua helper functions initialized")
newLStateLogger.Debug("New Lua state created successfully")
return L, nil
}
// func Process(filename string, pattern string, luaExpr string) (int, int, error) {
// logger.Debug("Processing file %q with pattern %q", filename, pattern)
//
// // Read file content
// cwd, err := os.Getwd()
// if err != nil {
// logger.Error("Failed to get current working directory: %v", err)
// return 0, 0, fmt.Errorf("error getting current working directory: %v", err)
// }
//
// fullPath := filepath.Join(cwd, filename)
// logger.Trace("Reading file from: %s", fullPath)
//
// stat, err := os.Stat(fullPath)
// if err != nil {
// logger.Error("Failed to stat file %s: %v", fullPath, err)
// return 0, 0, fmt.Errorf("error getting file info: %v", err)
// }
// logger.Debug("File size: %d bytes, modified: %s", stat.Size(), stat.ModTime().Format(time.RFC3339))
//
// content, err := os.ReadFile(fullPath)
// if err != nil {
// logger.Error("Failed to read file %s: %v", fullPath, err)
// return 0, 0, fmt.Errorf("error reading file: %v", err)
// }
//
// fileContent := string(content)
// logger.Trace("File read successfully: %d bytes, hash: %x", len(content), md5sum(content))
//
// // Detect and log file type
// fileType := detectFileType(filename, fileContent)
// if fileType != "" {
// logger.Debug("Detected file type: %s", fileType)
// }
//
// // Process the content
// logger.Debug("Starting content processing")
// modifiedContent, modCount, matchCount, err := ProcessContent(fileContent, pattern, luaExpr)
// if err != nil {
// logger.Error("Processing error: %v", err)
// return 0, 0, err
// }
//
// logger.Debug("Processing results: %d matches, %d modifications", matchCount, modCount)
//
// // If we made modifications, save the file
// if modCount > 0 {
// // Calculate changes summary
// changePercent := float64(len(modifiedContent)) / float64(len(fileContent)) * 100
// logger.Info("File size change: %d → %d bytes (%.1f%%)",
// len(fileContent), len(modifiedContent), changePercent)
//
// logger.Debug("Writing modified content to %s", fullPath)
// err = os.WriteFile(fullPath, []byte(modifiedContent), 0644)
// if err != nil {
// logger.Error("Failed to write to file %s: %v", fullPath, err)
// return 0, 0, fmt.Errorf("error writing file: %v", err)
// }
// logger.Debug("File written successfully, new hash: %x", md5sum([]byte(modifiedContent)))
// } else if matchCount > 0 {
// logger.Debug("No content modifications needed for %d matches", matchCount)
// } else {
// logger.Debug("No matches found in file")
// }
//
// return modCount, matchCount, nil
// }
// FromLua converts a Lua table to a struct or map recursively
func FromLua(L *lua.LState, luaValue lua.LValue) (interface{}, error) {
fromLuaLogger := processorLogger.WithPrefix("FromLua").WithField("luaType", luaValue.Type().String())
fromLuaLogger.Debug("Converting Lua value to Go interface")
switch v := luaValue.(type) {
// Well shit...
// Tables in lua are both maps and arrays
// As arrays they are ordered and as maps, obviously, not
// So when we parse them to a go map we fuck up the order for arrays
// We have to find a better way....
case *lua.LTable:
fromLuaLogger.Debug("Processing Lua table")
isArray, err := IsLuaTableArray(L, v)
if err != nil {
fromLuaLogger.Error("Failed to determine if Lua table is array: %v", err)
return nil, err
}
fromLuaLogger.Debug("Lua table is array: %t", isArray)
if isArray {
fromLuaLogger.Debug("Converting Lua table to Go array")
result := make([]interface{}, 0)
v.ForEach(func(key lua.LValue, value lua.LValue) {
converted, _ := FromLua(L, value)
result = append(result, converted)
})
fromLuaLogger.Trace("Converted Go array: %v", result)
return result, nil
} else {
fromLuaLogger.Debug("Converting Lua table to Go map")
result := make(map[string]interface{})
v.ForEach(func(key lua.LValue, value lua.LValue) {
converted, _ := FromLua(L, value)
result[key.String()] = converted
})
fromLuaLogger.Trace("Converted Go map: %v", result)
return result, nil
}
case lua.LString:
fromLuaLogger.Debug("Converting Lua string to Go string")
fromLuaLogger.Trace("Lua string: %q", string(v))
return string(v), nil
case lua.LBool:
fromLuaLogger.Debug("Converting Lua boolean to Go boolean")
fromLuaLogger.Trace("Lua boolean: %t", bool(v))
return bool(v), nil
case lua.LNumber:
fromLuaLogger.Debug("Converting Lua number to Go float64")
fromLuaLogger.Trace("Lua number: %f", float64(v))
return float64(v), nil
default:
fromLuaLogger.Debug("Unsupported Lua type, returning nil")
return nil, nil
}
}
func IsLuaTableArray(L *lua.LState, v *lua.LTable) (bool, error) {
logger.Trace("Checking if Lua table is an array")
isLuaTableArrayLogger := processorLogger.WithPrefix("IsLuaTableArray")
isLuaTableArrayLogger.Debug("Checking if Lua table is an array")
isLuaTableArrayLogger.Trace("Lua table input: %v", v)
L.SetGlobal("table_to_check", v)
// Use our predefined helper function from InitLuaHelpers
err := L.DoString(`is_array = isArray(table_to_check)`)
if err != nil {
logger.Error("Error determining if table is an array: %v", err)
isLuaTableArrayLogger.Error("Error determining if table is an array: %v", err)
return false, fmt.Errorf("error determining if table is array: %w", err)
}
@@ -158,13 +113,15 @@ func IsLuaTableArray(L *lua.LState, v *lua.LTable) (bool, error) {
isArray := L.GetGlobal("is_array")
// LVIsFalse returns true if a given LValue is a nil or false otherwise false.
result := !lua.LVIsFalse(isArray)
logger.Trace("Lua table is array: %v", result)
isLuaTableArrayLogger.Debug("Lua table is array: %t", result)
isLuaTableArrayLogger.Trace("isArray result Lua value: %v", isArray)
return result, nil
}
// InitLuaHelpers initializes common Lua helper functions
func InitLuaHelpers(L *lua.LState) error {
logger.Debug("Loading Lua helper functions")
initLuaHelpersLogger := processorLogger.WithPrefix("InitLuaHelpers")
initLuaHelpersLogger.Debug("Loading Lua helper functions")
helperScript := `
-- Custom Lua helpers for math operations
@@ -245,26 +202,21 @@ end
modified = false
`
if err := L.DoString(helperScript); err != nil {
logger.Error("Failed to load Lua helper functions: %v", err)
initLuaHelpersLogger.Error("Failed to load Lua helper functions: %v", err)
return fmt.Errorf("error loading helper functions: %v", err)
}
initLuaHelpersLogger.Debug("Lua helper functions loaded")
logger.Debug("Setting up Lua print function to Go")
initLuaHelpersLogger.Debug("Setting up Lua print function to Go")
L.SetGlobal("print", L.NewFunction(printToGo))
L.SetGlobal("fetch", L.NewFunction(fetch))
initLuaHelpersLogger.Debug("Lua print and fetch functions bound to Go")
return nil
}
// LimitString truncates a string to maxLen and adds "..." if truncated
func LimitString(s string, maxLen int) string {
s = strings.ReplaceAll(s, "\n", "\\n")
if len(s) <= maxLen {
return s
}
return s[:maxLen-3] + "..."
}
func PrependLuaAssignment(luaExpr string) string {
prependLuaAssignmentLogger := processorLogger.WithPrefix("PrependLuaAssignment").WithField("originalLuaExpr", luaExpr)
prependLuaAssignmentLogger.Debug("Prepending Lua assignment if necessary")
// Auto-prepend v1 for expressions starting with operators
if strings.HasPrefix(luaExpr, "*") ||
strings.HasPrefix(luaExpr, "/") ||
@@ -273,30 +225,29 @@ func PrependLuaAssignment(luaExpr string) string {
strings.HasPrefix(luaExpr, "^") ||
strings.HasPrefix(luaExpr, "%") {
luaExpr = "v1 = v1" + luaExpr
prependLuaAssignmentLogger.Debug("Prepended 'v1 = v1' due to operator prefix")
} else if strings.HasPrefix(luaExpr, "=") {
// Handle direct assignment with = operator
luaExpr = "v1 " + luaExpr
prependLuaAssignmentLogger.Debug("Prepended 'v1' due to direct assignment operator")
}
// Add assignment if needed
if !strings.Contains(luaExpr, "=") {
luaExpr = "v1 = " + luaExpr
prependLuaAssignmentLogger.Debug("Prepended 'v1 =' as no assignment was found")
}
prependLuaAssignmentLogger.Trace("Final Lua expression after prepending: %q", luaExpr)
return luaExpr
}
// BuildLuaScript prepares a Lua expression from shorthand notation
func BuildLuaScript(luaExpr string) string {
logger.Debug("Building Lua script from expression: %s", luaExpr)
buildLuaScriptLogger := processorLogger.WithPrefix("BuildLuaScript").WithField("inputLuaExpr", luaExpr)
buildLuaScriptLogger.Debug("Building full Lua script from expression")
luaExpr = PrependLuaAssignment(luaExpr)
// This allows the user to specify whether or not they modified a value
// If they do nothing we assume they did modify (no return at all)
// If they return before our return then they themselves specify what they did
// If nothing is returned lua assumes nil
// So we can say our value was modified if the return value is either nil or true
// If the return value is false then the user wants to keep the original
fullScript := fmt.Sprintf(`
function run()
%s
@@ -304,11 +255,14 @@ func BuildLuaScript(luaExpr string) string {
local res = run()
modified = res == nil or res
`, luaExpr)
buildLuaScriptLogger.Trace("Generated full Lua script: %q", utils.LimitString(fullScript, 200))
return fullScript
}
func printToGo(L *lua.LState) int {
printToGoLogger := processorLogger.WithPrefix("printToGo")
printToGoLogger.Debug("Lua print function called, redirecting to Go logger")
top := L.GetTop()
args := make([]interface{}, top)
@@ -322,20 +276,26 @@ func printToGo(L *lua.LState) int {
parts = append(parts, fmt.Sprintf("%v", arg))
}
message := strings.Join(parts, " ")
printToGoLogger.Trace("Lua print message: %q", message)
// Use the LUA log level with a script tag
logger.Lua("%s", message)
printToGoLogger.Debug("Message logged from Lua")
return 0
}
func fetch(L *lua.LState) int {
fetchLogger := processorLogger.WithPrefix("fetch")
fetchLogger.Debug("Lua fetch function called")
// Get URL from first argument
url := L.ToString(1)
if url == "" {
fetchLogger.Error("Fetch failed: URL is required")
L.Push(lua.LNil)
L.Push(lua.LString("URL is required"))
return 2
}
fetchLogger.Debug("Fetching URL: %q", url)
// Get options from second argument if provided
var method string = "GET"
@@ -345,30 +305,38 @@ func fetch(L *lua.LState) int {
if L.GetTop() > 1 {
options := L.ToTable(2)
if options != nil {
fetchLogger.Debug("Processing fetch options")
// Get method
if methodVal := options.RawGetString("method"); methodVal != lua.LNil {
method = methodVal.String()
fetchLogger.Trace("Method from options: %q", method)
}
// Get headers
if headersVal := options.RawGetString("headers"); headersVal != lua.LNil {
if headersTable, ok := headersVal.(*lua.LTable); ok {
fetchLogger.Trace("Processing headers table")
headersTable.ForEach(func(key lua.LValue, value lua.LValue) {
headers[key.String()] = value.String()
fetchLogger.Trace("Header: %q = %q", key.String(), value.String())
})
}
fetchLogger.Trace("All headers: %v", headers)
}
// Get body
if bodyVal := options.RawGetString("body"); bodyVal != lua.LNil {
body = bodyVal.String()
fetchLogger.Trace("Body from options: %q", utils.LimitString(body, 100))
}
}
}
fetchLogger.Debug("Fetch request details: Method=%q, URL=%q, BodyLength=%d, Headers=%v", method, url, len(body), headers)
// Create HTTP request
req, err := http.NewRequest(method, url, strings.NewReader(body))
if err != nil {
fetchLogger.Error("Error creating HTTP request: %v", err)
L.Push(lua.LNil)
L.Push(lua.LString(fmt.Sprintf("Error creating request: %v", err)))
return 2
@@ -378,24 +346,33 @@ func fetch(L *lua.LState) int {
for key, value := range headers {
req.Header.Set(key, value)
}
fetchLogger.Debug("HTTP request created and headers set")
fetchLogger.Trace("HTTP Request: %+v", req)
// Make request
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fetchLogger.Error("Error making HTTP request: %v", err)
L.Push(lua.LNil)
L.Push(lua.LString(fmt.Sprintf("Error making request: %v", err)))
return 2
}
defer resp.Body.Close()
defer func() {
fetchLogger.Debug("Closing HTTP response body")
resp.Body.Close()
}()
fetchLogger.Debug("HTTP request executed. Status Code: %d", resp.StatusCode)
// Read response body
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
fetchLogger.Error("Error reading response body: %v", err)
L.Push(lua.LNil)
L.Push(lua.LString(fmt.Sprintf("Error reading response: %v", err)))
return 2
}
fetchLogger.Trace("Response body length: %d", len(bodyBytes))
// Create response table
responseTable := L.NewTable()
@@ -403,14 +380,18 @@ func fetch(L *lua.LState) int {
responseTable.RawSetString("statusText", lua.LString(resp.Status))
responseTable.RawSetString("ok", lua.LBool(resp.StatusCode >= 200 && resp.StatusCode < 300))
responseTable.RawSetString("body", lua.LString(string(bodyBytes)))
fetchLogger.Debug("Created Lua response table")
// Set headers in response
headersTable := L.NewTable()
for key, values := range resp.Header {
headersTable.RawSetString(key, lua.LString(values[0]))
fetchLogger.Trace("Response header: %q = %q", key, values[0])
}
responseTable.RawSetString("headers", headersTable)
fetchLogger.Trace("Full response table: %v", responseTable)
L.Push(responseTable)
fetchLogger.Debug("Pushed response table to Lua stack")
return 1
}