diff options
Diffstat (limited to 'vendor/github.com/tdewolff/minify/cmd/minify/main.go')
-rw-r--r-- | vendor/github.com/tdewolff/minify/cmd/minify/main.go | 200 |
1 files changed, 101 insertions, 99 deletions
diff --git a/vendor/github.com/tdewolff/minify/cmd/minify/main.go b/vendor/github.com/tdewolff/minify/cmd/minify/main.go index 62263ba..2ed981c 100644 --- a/vendor/github.com/tdewolff/minify/cmd/minify/main.go +++ b/vendor/github.com/tdewolff/minify/cmd/minify/main.go @@ -15,7 +15,6 @@ import ( "runtime" "sort" "strings" - "sync/atomic" "time" humanize "github.com/dustin/go-humanize" @@ -45,6 +44,7 @@ var filetypeMime = map[string]string{ } var ( + help bool hidden bool list bool m *min.M @@ -55,7 +55,7 @@ var ( watch bool ) -type task struct { +type Task struct { srcs []string srcDir string dst string @@ -80,15 +80,18 @@ func main() { svgMinifier := &svg.Minifier{} xmlMinifier := &xml.Minifier{} + flag := flag.NewFlagSet("minify", flag.ContinueOnError) flag.Usage = func() { fmt.Fprintf(os.Stderr, "Usage: %s [options] [input]\n\nOptions:\n", os.Args[0]) flag.PrintDefaults() fmt.Fprintf(os.Stderr, "\nInput:\n Files or directories, leave blank to use stdin\n") } + + flag.BoolVarP(&help, "help", "h", false, "Show usage") flag.StringVarP(&output, "output", "o", "", "Output file or directory (must have trailing slash), leave blank to use stdout") - flag.StringVar(&mimetype, "mime", "", "Mimetype (text/css, application/javascript, ...), optional for input filenames, has precedence over -type") - flag.StringVar(&filetype, "type", "", "Filetype (css, html, js, ...), optional for input filenames") - flag.StringVar(&match, "match", "", "Filename pattern matching using regular expressions, see https://github.com/google/re2/wiki/Syntax") + flag.StringVar(&mimetype, "mime", "", "Mimetype (eg. text/css), optional for input filenames, has precedence over -type") + flag.StringVar(&filetype, "type", "", "Filetype (eg. css), optional for input filenames") + flag.StringVar(&match, "match", "", "Filename pattern matching using regular expressions") flag.BoolVarP(&recursive, "recursive", "r", false, "Recursively minify directories") flag.BoolVarP(&hidden, "all", "a", false, "Minify all files, including hidden files and files in hidden directories") flag.BoolVarP(&list, "list", "l", false, "List all accepted filetypes") @@ -105,7 +108,11 @@ func main() { flag.BoolVar(&htmlMinifier.KeepWhitespace, "html-keep-whitespace", false, "Preserve whitespace characters but still collapse multiple into one") flag.IntVar(&svgMinifier.Decimals, "svg-decimals", -1, "Number of decimals to preserve in numbers, -1 is all") flag.BoolVar(&xmlMinifier.KeepWhitespace, "xml-keep-whitespace", false, "Preserve whitespace characters but still collapse multiple into one") - flag.Parse() + if err := flag.Parse(os.Args[1:]); err != nil { + fmt.Printf("Error: %v\n\n", err) + flag.Usage() + os.Exit(2) + } rawInputs := flag.Args() Error = log.New(os.Stderr, "ERROR: ", 0) @@ -115,13 +122,18 @@ func main() { Info = log.New(ioutil.Discard, "INFO: ", 0) } + if help { + flag.Usage() + os.Exit(0) + } + if version { if Version == "devel" { fmt.Printf("minify version devel+%.7s %s\n", Commit, Date) } else { fmt.Printf("minify version %s\n", Version) } - return + os.Exit(0) } if list { @@ -133,7 +145,7 @@ func main() { for _, k := range keys { fmt.Println(k + "\t" + filetypeMime[k]) } - return + os.Exit(0) } useStdin := len(rawInputs) == 0 @@ -148,7 +160,11 @@ func main() { } if watch && (useStdin || output == "") { - Error.Fatalln("watch doesn't work with stdin or stdout") + Error.Fatalln("watch doesn't work on stdin and stdout, specify input and output") + } + + if recursive && (useStdin || output == "") { + Error.Fatalln("recursive minification doesn't work on stdin and stdout, specify input and output") } //////////////// @@ -174,7 +190,7 @@ func main() { } if len(tasks) == 0 { - tasks = append(tasks, task{[]string{""}, "", output}) // stdin + tasks = append(tasks, Task{[]string{""}, "", output}) // stdin } m = min.New() @@ -191,47 +207,33 @@ func main() { start := time.Now() - var fails int32 - if verbose || len(tasks) == 1 { - for _, t := range tasks { - if ok := minify(mimetype, t); !ok { - fails++ - } - } - } else { - numWorkers := 4 + chanTasks := make(chan Task, 100) + chanFails := make(chan int, 100) + + numWorkers := 1 + if !verbose && len(tasks) > 1 { + numWorkers = 4 if n := runtime.NumCPU(); n > numWorkers { numWorkers = n } + } - sem := make(chan struct{}, numWorkers) - for _, t := range tasks { - sem <- struct{}{} - go func(t task) { - defer func() { - <-sem - }() - if ok := minify(mimetype, t); !ok { - atomic.AddInt32(&fails, 1) - } - }(t) - } + for n := 0; n < numWorkers; n++ { + go minifyWorker(mimetype, chanTasks, chanFails) + } - // wait for all jobs to be done - for i := 0; i < cap(sem); i++ { - sem <- struct{}{} - } + for _, task := range tasks { + chanTasks <- task } if watch { - var watcher *RecursiveWatcher - watcher, err = NewRecursiveWatcher(recursive) + watcher, err := NewRecursiveWatcher(recursive) if err != nil { Error.Fatalln(err) } defer watcher.Close() - var watcherTasks = make(map[string]task, len(rawInputs)) + watcherTasks := make(map[string]Task, len(rawInputs)) for _, task := range tasks { for _, src := range task.srcs { watcherTasks[src] = task @@ -248,6 +250,7 @@ func main() { select { case <-c: watcher.Close() + fmt.Printf("\n") case file, ok := <-changes: if !ok { changes = nil @@ -260,10 +263,10 @@ func main() { continue } - var t task + var t Task if t, ok = watcherTasks[file]; ok { if !verbose { - fmt.Fprintln(os.Stderr, file, "changed") + Info.Println(file, "changed") } for _, src := range t.srcs { if src == t.dst { @@ -271,21 +274,35 @@ func main() { break } } - if ok := minify(mimetype, t); !ok { - fails++ - } + chanTasks <- t } } } } + fails := 0 + close(chanTasks) + for n := 0; n < numWorkers; n++ { + fails += <-chanFails + } + if verbose { Info.Println(time.Since(start), "total") } - if fails > 0 { os.Exit(1) } + os.Exit(0) +} + +func minifyWorker(mimetype string, chanTasks <-chan Task, chanFails chan<- int) { + fails := 0 + for task := range chanTasks { + if ok := minify(mimetype, task); !ok { + fails++ + } + } + chanFails <- fails } func getMimetype(mimetype, filetype string, useStdin bool) string { @@ -344,9 +361,9 @@ func validDir(info os.FileInfo) bool { return info.Mode().IsDir() && len(info.Name()) > 0 && (hidden || info.Name()[0] != '.') } -func expandInputs(inputs []string, dirDst bool) ([]task, bool) { +func expandInputs(inputs []string, dirDst bool) ([]Task, bool) { ok := true - tasks := []task{} + tasks := []Task{} for _, input := range inputs { input = sanitizePath(input) info, err := os.Stat(input) @@ -357,7 +374,7 @@ func expandInputs(inputs []string, dirDst bool) ([]task, bool) { } if info.Mode().IsRegular() { - tasks = append(tasks, task{[]string{filepath.ToSlash(input)}, "", ""}) + tasks = append(tasks, Task{[]string{filepath.ToSlash(input)}, "", ""}) } else if info.Mode().IsDir() { expandDir(input, &tasks, &ok) } else { @@ -391,7 +408,7 @@ func expandInputs(inputs []string, dirDst bool) ([]task, bool) { return tasks, ok } -func expandDir(input string, tasks *[]task, ok *bool) { +func expandDir(input string, tasks *[]Task, ok *bool) { if !recursive { if verbose { Info.Println("expanding directory", input) @@ -404,7 +421,7 @@ func expandDir(input string, tasks *[]task, ok *bool) { } for _, info := range infos { if validFile(info) { - *tasks = append(*tasks, task{[]string{path.Join(input, info.Name())}, input, ""}) + *tasks = append(*tasks, Task{[]string{path.Join(input, info.Name())}, input, ""}) } } } else { @@ -417,7 +434,7 @@ func expandDir(input string, tasks *[]task, ok *bool) { return err } if validFile(info) { - *tasks = append(*tasks, task{[]string{filepath.ToSlash(path)}, input, ""}) + *tasks = append(*tasks, Task{[]string{filepath.ToSlash(path)}, input, ""}) } else if info.Mode().IsDir() && !validDir(info) && info.Name() != "." && info.Name() != ".." { // check for IsDir, so we don't skip the rest of the directory when we have an invalid file return filepath.SkipDir } @@ -430,7 +447,7 @@ func expandDir(input string, tasks *[]task, ok *bool) { } } -func expandOutputs(output string, tasks *[]task) bool { +func expandOutputs(output string, tasks *[]Task) bool { if verbose { if output == "" { Info.Println("minify to stdout") @@ -459,7 +476,7 @@ func expandOutputs(output string, tasks *[]task) bool { return ok } -func getOutputFilename(output string, t task) (string, error) { +func getOutputFilename(output string, t Task) (string, error) { if len(output) > 0 && output[len(output)-1] == '/' { rel, err := filepath.Rel(t.srcDir, t.srcs[0]) if err != nil { @@ -470,47 +487,44 @@ func getOutputFilename(output string, t task) (string, error) { return output, nil } -func openInputFile(input string) (*os.File, bool) { +func openInputFile(input string) (io.ReadCloser, error) { var r *os.File if input == "" { r = os.Stdin } else { err := try.Do(func(attempt int) (bool, error) { - var err error - r, err = os.Open(input) - return attempt < 5, err + var ferr error + r, ferr = os.Open(input) + return attempt < 5, ferr }) if err != nil { - Error.Println(err) - return nil, false + return nil, err } } - return r, true + return r, nil } -func openOutputFile(output string) (*os.File, bool) { +func openOutputFile(output string) (*os.File, error) { var w *os.File if output == "" { w = os.Stdout } else { if err := os.MkdirAll(path.Dir(output), 0777); err != nil { - Error.Println(err) - return nil, false + return nil, err } err := try.Do(func(attempt int) (bool, error) { - var err error - w, err = os.OpenFile(output, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666) - return attempt < 5, err + var ferr error + w, ferr = os.OpenFile(output, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666) + return attempt < 5, ferr }) if err != nil { - Error.Println(err) - return nil, false + return nil, err } } - return w, true + return w, nil } -func minify(mimetype string, t task) bool { +func minify(mimetype string, t Task) bool { if mimetype == "" { for _, src := range t.srcs { if len(path.Ext(src)) > 0 { @@ -545,8 +559,8 @@ func minify(mimetype string, t task) bool { if t.srcs[i] == t.dst { t.srcs[i] += ".bak" err := try.Do(func(attempt int) (bool, error) { - err := os.Rename(t.dst, t.srcs[i]) - return attempt < 5, err + ferr := os.Rename(t.dst, t.srcs[i]) + return attempt < 5, ferr }) if err != nil { Error.Println(err) @@ -557,42 +571,32 @@ func minify(mimetype string, t task) bool { } } - frs := make([]io.Reader, len(t.srcs)) - for i, src := range t.srcs { - fr, ok := openInputFile(src) - if !ok { - for _, fr := range frs { - fr.(io.ReadCloser).Close() - } - return false - } - if i > 0 && mimetype == filetypeMime["js"] { - // prepend newline when concatenating JS files - frs[i] = NewPrependReader(fr, []byte("\n")) - } else { - frs[i] = fr - } + fr, err := NewConcatFileReader(t.srcs, openInputFile) + if err != nil { + Error.Println(err) + return false } - r := &countingReader{io.MultiReader(frs...), 0} + if mimetype == filetypeMime["js"] { + fr.SetSeparator([]byte("\n")) + } + r := NewCountingReader(fr) - fw, ok := openOutputFile(t.dst) - if !ok { - for _, fr := range frs { - fr.(io.ReadCloser).Close() - } + fw, err := openOutputFile(t.dst) + if err != nil { + Error.Println(err) + fr.Close() return false } var w *countingWriter if fw == os.Stdout { - w = &countingWriter{fw, 0} + w = NewCountingWriter(fw) } else { - w = &countingWriter{bufio.NewWriter(fw), 0} + w = NewCountingWriter(bufio.NewWriter(fw)) } success := true startTime := time.Now() - err := m.Minify(mimetype, w, r) - if err != nil { + if err = m.Minify(mimetype, w, r); err != nil { Error.Println("cannot minify "+srcName+":", err) success = false } @@ -615,9 +619,7 @@ func minify(mimetype string, t task) bool { } } - for _, fr := range frs { - fr.(io.ReadCloser).Close() - } + fr.Close() if bw, ok := w.Writer.(*bufio.Writer); ok { bw.Flush() } |