4 Commits

Author SHA1 Message Date
a2201053c5 Remove some random ass fmt printf 2025-03-28 13:24:12 +01:00
04cedf5ece Fix the concurrent map writes 2025-03-28 11:35:38 +01:00
ebb07854cc Memoize the match table 2025-03-28 11:31:27 +01:00
8a86ae2f40 Add filter flag 2025-03-28 11:20:44 +01:00
3 changed files with 52 additions and 55 deletions

73
main.go
View File

@@ -21,14 +21,14 @@ type GlobalStats struct {
TotalModifications int
ProcessedFiles int
FailedFiles int
ModificationsPerCommand map[string]int
ModificationsPerCommand sync.Map
}
var (
repo *git.Repository
worktree *git.Worktree
stats GlobalStats = GlobalStats{
ModificationsPerCommand: make(map[string]int),
ModificationsPerCommand: sync.Map{},
}
)
@@ -53,48 +53,7 @@ func main() {
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")
}
// TODO: Implement -f flag for filtering recipes by name
// TODO: Fix bed shitting when doing *.yml in barotrauma directory
// TODO: Fix disaster:
// fatal error: concurrent map writes
//
// goroutine 243 [running]:
// internal/runtime/maps.fatal({0x8b9c77?, 0xc003399ce8?})
// C:/Users/Administrator/scoop/apps/go/current/src/runtime/panic.go:1058 +0x18
// main.main.func2({0x0?, 0x0?, 0x0?})
// C:/Users/Administrator/Seafile/Projects-Go/GoProjects/modifier/main.go:137 +0x31d
// modify/logger.SafeGoWithArgs.func1()
// C:/Users/Administrator/Seafile/Projects-Go/GoProjects/modifier/logger/panic_handler.go:31 +0x43
// created by modify/logger.SafeGoWithArgs in goroutine 1
// C:/Users/Administrator/Seafile/Projects-Go/GoProjects/modifier/logger/panic_handler.go:29 +0x86
//
// goroutine 1 [chan send]:
// main.main()
// C:/Users/Administrator/Seafile/Projects-Go/GoProjects/modifier/main.go:107 +0x5aa
//
// goroutine 547 [sync.Mutex.Lock]:
// internal/sync.runtime_SemacquireMutex(0x0?, 0x5b?, 0x0?)
// C:/Users/Administrator/scoop/apps/go/current/src/runtime/sema.go:95 +0x25
// internal/sync.(*Mutex).lockSlow(0xc0000a2240)
// C:/Users/Administrator/scoop/apps/go/current/src/internal/sync/mutex.go:149 +0x15d
// internal/sync.(*Mutex).Lock(...)
// C:/Users/Administrator/scoop/apps/go/current/src/internal/sync/mutex.go:70
// sync.(*Mutex).Lock(...)
// C:/Users/Administrator/scoop/apps/go/current/src/sync/mutex.go:46
// modify/logger.(*Logger).log(0xc0000a2240, 0x1, {0x8bf8ab, 0x1e}, {0xc007049d08, 0x1, 0x1})
// C:/Users/Administrator/Seafile/Projects-Go/GoProjects/modifier/logger/logger.go:321 +0x9d
// modify/logger.(*Logger).Warning(...)
// C:/Users/Administrator/Seafile/Projects-Go/GoProjects/modifier/logger/logger.go:335
// modify/logger.Warning({0x8bf8ab?, 0x5c?}, {0xc004d87d08?, 0xc006b85ae0?, 0x53f3b9?})
// C:/Users/Administrator/Seafile/Projects-Go/GoProjects/modifier/logger/logger.go:373 +0x87
// modify/processor.ProcessRegex({0xc004025000, 0x1f0}, {{0xc00026c450, 0xa}, {0xc000015bd0, 0x4b}, {0xc000261c00, 0xf4}, {0xc000282110, 0x1, ...}, ...})
// C:/Users/Administrator/Seafile/Projects-Go/GoProjects/modifier/processor/regex.go:64 +0x5c5
// main.main.func2({0x0?, 0x0?, 0x0?})
// C:/Users/Administrator/Seafile/Projects-Go/GoProjects/modifier/main.go:128 +0x471
// modify/logger.SafeGoWithArgs.func1()
// C:/Users/Administrator/Seafile/Projects-Go/GoProjects/modifier/logger/panic_handler.go:31 +0x43
// created by modify/logger.SafeGoWithArgs in goroutine 1
// C:/Users/Administrator/Seafile/Projects-Go/GoProjects/modifier/logger/panic_handler.go:29 +0x86
flag.Parse()
args := flag.Args()
@@ -111,6 +70,12 @@ func main() {
return
}
if *utils.Filter != "" {
logger.Info("Filtering commands by name: %s", *utils.Filter)
commands = utils.FilterCommands(commands, *utils.Filter)
logger.Info("Filtered %d commands", len(commands))
}
// Then aggregate all the globs and deduplicate them
globs := utils.AggregateGlobs(commands)
logger.Debug("Aggregated %d globs before deduplication", utils.CountGlobsBeforeDedup(commands))
@@ -173,7 +138,11 @@ func main() {
// 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...
stats.ModificationsPerCommand[command.Name] += len(commands)
count, ok := stats.ModificationsPerCommand.Load(command.Name)
if !ok {
count = 0
}
stats.ModificationsPerCommand.Store(command.Name, count.(int)+len(commands))
}
if len(modifications) == 0 {
@@ -250,21 +219,19 @@ func main() {
// Print summary
if stats.TotalModifications == 0 {
logger.Warning("No modifications were made in any files")
fmt.Fprintf(os.Stderr, "No modifications were made in any files\n")
} else {
logger.Info("Operation complete! Modified %d values in %d/%d files",
stats.TotalModifications, stats.ProcessedFiles, stats.ProcessedFiles+stats.FailedFiles)
fmt.Printf("Operation complete! Modified %d values in %d/%d files\n",
stats.TotalModifications, stats.ProcessedFiles, stats.ProcessedFiles+stats.FailedFiles)
sortedCommands := make([]string, 0, len(stats.ModificationsPerCommand))
for command := range stats.ModificationsPerCommand {
sortedCommands = append(sortedCommands, command)
}
sortedCommands := []string{}
stats.ModificationsPerCommand.Range(func(key, value interface{}) bool {
sortedCommands = append(sortedCommands, key.(string))
return true
})
sort.Strings(sortedCommands)
for _, command := range sortedCommands {
count := stats.ModificationsPerCommand[command]
if count > 0 {
count, _ := stats.ModificationsPerCommand.Load(command)
if count.(int) > 0 {
logger.Info("\tCommand %q made %d modifications", command, count)
} else {
logger.Warning("\tCommand %q made no modifications", command)

View File

@@ -12,4 +12,5 @@ var (
LogLevel = flag.String("loglevel", "INFO", "Set log level: ERROR, WARNING, INFO, DEBUG, TRACE")
Cookfile = flag.String("cook", "**/cook.yml", "Path to cook config files, can be globbed")
ParallelFiles = flag.Int("P", 100, "Number of files to process in parallel")
Filter = flag.String("filter", "", "Filter commands before running them")
)

View File

@@ -4,6 +4,7 @@ import (
"fmt"
"modify/logger"
"os"
"strings"
"github.com/bmatcuk/doublestar/v4"
"gopkg.in/yaml.v3"
@@ -36,14 +37,29 @@ func (c *ModifyCommand) Validate() error {
return nil
}
// Ehh.. Not much better... Guess this wasn't the big deal
var matchesMemoTable map[string]bool = make(map[string]bool)
func Matches(path string, glob string) (bool, error) {
key := fmt.Sprintf("%s:%s", path, glob)
if matches, ok := matchesMemoTable[key]; ok {
logger.Debug("Found match for file %q and glob %q in memo table", path, glob)
return matches, nil
}
matches, err := doublestar.Match(glob, path)
if err != nil {
return false, fmt.Errorf("failed to match glob %s with file %s: %w", glob, path, err)
}
matchesMemoTable[key] = matches
return matches, nil
}
func AssociateFilesWithCommands(files []string, commands []ModifyCommand) (map[string][]ModifyCommand, error) {
associationCount := 0
fileCommands := make(map[string][]ModifyCommand)
for _, file := range files {
for _, command := range commands {
for _, glob := range command.Files {
// TODO: Maybe memoize this function call
matches, err := doublestar.Match(glob, file)
matches, err := Matches(file, glob)
if err != nil {
logger.Trace("Failed to match glob %s with file %s: %v", glob, file, err)
continue
@@ -206,3 +222,16 @@ func CountGlobsBeforeDedup(commands []ModifyCommand) int {
}
return count
}
func FilterCommands(commands []ModifyCommand, filter string) []ModifyCommand {
filteredCommands := []ModifyCommand{}
filters := strings.Split(filter, ",")
for _, cmd := range commands {
for _, filter := range filters {
if strings.Contains(cmd.Name, filter) {
filteredCommands = append(filteredCommands, cmd)
}
}
}
return filteredCommands
}