Absolutely butcher globbing to support absolute paths in globs

This commit is contained in:
2025-04-01 11:57:48 +02:00
parent 4ff2ee80ee
commit 0fc5300786

View File

@@ -4,6 +4,7 @@ import (
"fmt"
"modify/logger"
"os"
"path/filepath"
"strings"
"github.com/bmatcuk/doublestar/v4"
@@ -110,7 +111,7 @@ func AggregateGlobs(commands []ModifyCommand) map[string]struct{} {
globs := make(map[string]struct{})
for _, command := range commands {
for _, glob := range command.Files {
glob = strings.Replace(glob, "~", os.Getenv("HOME"), 1)
glob = strings.ReplaceAll(glob, "~", os.Getenv("USERPROFILE"))
glob = strings.ReplaceAll(glob, "\\", "/")
globs[glob] = struct{}{}
}
@@ -130,10 +131,51 @@ func ExpandGLobs(patterns map[string]struct{}) ([]string, error) {
logger.Debug("Expanding patterns from directory: %s", cwd)
for pattern := range patterns {
root := pattern
if !filepath.IsAbs(pattern) {
root = filepath.Join(cwd, pattern)
}
root = filepath.Clean(root)
// In either case (whatever our root may be), we have to figure out
// Where to start, what our FS will be
// The best place would be the last sure entry
// That is to say the final directory that is not a wildcard
finalroot := ""
// TODO: This will probably explode on linux because oooooooooo we have to be clever oooooooooo / on linux \\ on windows ooooooooooo
parts := strings.Split(root, "\\")
lastIndex := len(parts) - 1
// In the case our pattern ends with a file (and many of them do)
// Look for only the folders, we cannot mount a file as a FS
// In any case we have to match files so they have to be the last part
for i := 0; i < len(parts)-1; i++ {
part := parts[i]
if part == "*" || part == "?" || part == "[" {
lastIndex = i
break
}
// We can't use join here because it joins C: and Users as C:Users
// Instead of C:/Users/
// God damn it
if finalroot != "" {
finalroot = finalroot + "/" + part
} else {
finalroot = finalroot + part
}
}
finalroot = filepath.Clean(finalroot)
// After all this juggling our pattern is whatever is left after the finalroot
// Which is, in "worst" case, only a file
pattern = strings.Join(parts[lastIndex:], "/")
logger.Trace("Processing pattern: %s", pattern)
matches, _ := doublestar.Glob(os.DirFS(cwd), pattern)
matches, err := doublestar.Glob(os.DirFS(finalroot), pattern)
if err != nil {
return nil, fmt.Errorf("failed to glob pattern %s: %w", pattern, err)
}
logger.Debug("Found %d matches for pattern %s", len(matches), pattern)
for _, m := range matches {
m = filepath.Join(finalroot, m)
info, err := os.Stat(m)
if err != nil {
logger.Warning("Error getting file info for %s: %v", m, err)