From 66bad8b4d67259abba23478ea0b4d01e34d1e6d8 Mon Sep 17 00:00:00 2001 From: Taco de Wolff Date: Thu, 29 Jan 2026 14:44:23 +0100 Subject: [PATCH 1/3] cmd: fix --match for Windows, fixes #901 --- cmd/minify/main.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cmd/minify/main.go b/cmd/minify/main.go index f25fee7a2..003a6dbe4 100644 --- a/cmd/minify/main.go +++ b/cmd/minify/main.go @@ -624,13 +624,18 @@ func minifyWorker(chanTasks <-chan Task, chanFails chan<- int) { // compilePattern returns *regexp.Regexp or glob.Glob func compilePattern(pattern string) (*regexp.Regexp, error) { if len(pattern) == 0 || pattern[0] != '~' { + sep := string(filepath.Separator) + if sep == `\` { + sep = `\\` + } + if strings.HasPrefix(pattern, `\~`) { pattern = pattern[1:] } pattern = regexp.QuoteMeta(pattern) pattern = strings.ReplaceAll(pattern, `\*\*`, `.*`) - pattern = strings.ReplaceAll(pattern, `\*`, fmt.Sprintf(`[^%c]*`, filepath.Separator)) - pattern = strings.ReplaceAll(pattern, `\?`, fmt.Sprintf(`[^%c]?`, filepath.Separator)) + pattern = strings.ReplaceAll(pattern, `\*`, fmt.Sprintf(`[^%s]*`, sep)) + pattern = strings.ReplaceAll(pattern, `\?`, fmt.Sprintf(`[^%s]?`, sep)) pattern = "^" + pattern + "$" } return regexp.Compile(pattern) From 58d4d9097b0595cee985c706d6f25ca3f1f9a009 Mon Sep 17 00:00:00 2001 From: Taco de Wolff Date: Thu, 29 Jan 2026 15:15:09 +0100 Subject: [PATCH 2/3] cmd: fix --match for Windows, see #901 --- cmd/minify/main.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cmd/minify/main.go b/cmd/minify/main.go index 003a6dbe4..d3b8fdc64 100644 --- a/cmd/minify/main.go +++ b/cmd/minify/main.go @@ -624,11 +624,7 @@ func minifyWorker(chanTasks <-chan Task, chanFails chan<- int) { // compilePattern returns *regexp.Regexp or glob.Glob func compilePattern(pattern string) (*regexp.Regexp, error) { if len(pattern) == 0 || pattern[0] != '~' { - sep := string(filepath.Separator) - if sep == `\` { - sep = `\\` - } - + sep := regexp.QuoteMeta(string(filepath.Separator)) if strings.HasPrefix(pattern, `\~`) { pattern = pattern[1:] } From 429f46535a7ef0f3a56be4283284372bc70c1113 Mon Sep 17 00:00:00 2001 From: Taco de Wolff Date: Thu, 29 Jan 2026 18:18:55 +0100 Subject: [PATCH 3/3] cmd: ignore bad softlinks, remove verbosity level for warning (now 1 is info, 2 is debug); fix bugs for --match/--include/--exclude, see #901 --- cmd/minify/README.md | 7 +++++++ cmd/minify/main.go | 18 +++++++++++------- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/cmd/minify/README.md b/cmd/minify/README.md index b10815204..7c447c1ee 100644 --- a/cmd/minify/README.md +++ b/cmd/minify/README.md @@ -219,6 +219,13 @@ Match will filters all files by the given pattern, eg. `--match '*.css'` will on You may define multiple patterns within one option, such as: `--exclude '**/folder1/**' '**/folder2/**' '**/folder3/**'` Doing this might result in unexpected behaviour when it is followed immediately by the input files, as this would be interpreted as another pattern, and not as inputs. `--exclude dir_to_exclude folder_input` Instead format accordingly: `--exclude dir_to_exclude -- folder_input`. +To match `*` or `?` literally, precede by a backslash. To specify a regular expression directly instead of a glob, use the tilde as a prefix (to use a tilde literally at the beginning, precede by a backslash). Examples of regular expressions: + +``` +./minify --match ~^path[0-9]/[^/]*.(js|html)$ +./minify --match ~^(?i)pathCaseInsensitive[0-9]/[^/]*.(js|html)$ +``` + ### Concatenate When multiple inputs are given and the output is either standard output or a single file, it will concatenate the files together if you use the bundle option. diff --git a/cmd/minify/main.go b/cmd/minify/main.go index d3b8fdc64..def765d95 100644 --- a/cmd/minify/main.go +++ b/cmd/minify/main.go @@ -292,13 +292,11 @@ func run() int { Debug = log.New(io.Discard, "", 0) if !quiet { Error = log.New(os.Stderr, "ERROR: ", 0) + Warning = log.New(os.Stderr, "WARNING: ", 0) if 0 < verbose { - Warning = log.New(os.Stderr, "WARNING: ", 0) - } - if 1 < verbose { Info = log.New(os.Stderr, "INFO: ", 0) } - if 2 < verbose { + if 1 < verbose { Debug = log.New(os.Stderr, "DEBUG: ", 0) } } @@ -629,10 +627,14 @@ func compilePattern(pattern string) (*regexp.Regexp, error) { pattern = pattern[1:] } pattern = regexp.QuoteMeta(pattern) + pattern = strings.ReplaceAll(pattern, `\\\*`, `\*`) + pattern = strings.ReplaceAll(pattern, `\\\?`, `\?`) pattern = strings.ReplaceAll(pattern, `\*\*`, `.*`) pattern = strings.ReplaceAll(pattern, `\*`, fmt.Sprintf(`[^%s]*`, sep)) - pattern = strings.ReplaceAll(pattern, `\?`, fmt.Sprintf(`[^%s]?`, sep)) + pattern = strings.ReplaceAll(pattern, `\?`, fmt.Sprintf(`[^%s]`, sep)) pattern = "^" + pattern + "$" + } else { + pattern = pattern[1:] } return regexp.Compile(pattern) } @@ -693,7 +695,8 @@ func createTasks(fsys fs.FS, inputs []string, output string) ([]Task, []string, info, err = os.Lstat(input) } if err != nil { - return nil, nil, err + Error.Println(err) + continue } if preserveLinks && info.Mode()&os.ModeSymlink != 0 { @@ -747,7 +750,8 @@ func createTasks(fsys fs.FS, inputs []string, output string) ([]Task, []string, // follow and dereference symlinks info, err := fs.Stat(fsys, input) if err != nil { - return err + Error.Println(err) + return nil } if info.IsDir() { return fs.WalkDir(fsys, input, walkFn)