github.com/rsc/tmp@v0.0.0-20240517235954-6deaab19748b/dredge/dredge.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "flag" 9 "fmt" 10 "io/ioutil" 11 "log" 12 "os" 13 "os/exec" 14 "regexp" 15 "strings" 16 ) 17 18 var chop = flag.Bool("chop", false, "show pieces on stdout and exit") 19 var cmdstr = flag.String("cmd", "", "command to run") 20 var cmd []string 21 22 func usage() { 23 fmt.Fprintf(os.Stderr, "usage: dredge -cmd 'command args' files...\n") 24 os.Exit(2) 25 } 26 27 func main() { 28 log.SetFlags(0) 29 log.SetPrefix("dredge: ") 30 31 flag.Usage = usage 32 flag.Parse() 33 34 if !*chop { 35 cmd = strings.Fields(*cmdstr) 36 if len(cmd) == 0 || flag.NArg() == 0 { 37 usage() 38 } 39 40 out, err := runCmd() 41 if err != nil { 42 log.Fatalf("command failed before any changes: %s\n%s", err, out) 43 } 44 } 45 46 for { 47 progress := false 48 for _, file := range flag.Args() { 49 progress = dredgeFile(file) || progress 50 } 51 if !progress { 52 break 53 } 54 } 55 } 56 57 var cblockRE = regexp.MustCompile(`(?m)^([^/{ \t\n][^/{\n]*\n)*([^/{ \t\n][^/{\n]*)?{[ \t]*\n(([^}\n].*)?\n)*};?[ \t]*\n`) 58 59 func dredgeFile(file string) bool { 60 fmt.Printf("%s\n", file) 61 data, err := ioutil.ReadFile(file) 62 if err != nil { 63 log.Fatal(err) 64 } 65 66 matches := cblockRE.FindAllIndex(data, -1) 67 if *chop { 68 for _, m := range matches { 69 fmt.Printf("«\n%s»\n", data[m[0]:m[1]]) 70 } 71 return false 72 } 73 74 progress := false 75 for { 76 loopProgress := false 77 for i := len(matches) - 1; i >= 0; i-- { 78 m := matches[i] 79 new := append(data[:m[0]:m[0]], data[m[1]:]...) 80 if err := ioutil.WriteFile(file, new, 0666); err != nil { 81 log.Fatal(err) 82 } 83 if _, err := runCmd(); err == nil { 84 fmt.Printf("+") 85 loopProgress = true 86 progress = true 87 data = new 88 } 89 } 90 if !loopProgress { 91 break 92 } 93 matches = cblockRE.FindAllIndex(data, -1) 94 } 95 ioutil.WriteFile(file, data, 0666) // always; must at least restore original 96 return progress 97 } 98 99 func runCmd() (out []byte, err error) { 100 fmt.Printf(".") 101 return exec.Command(cmd[0], cmd[1:]...).CombinedOutput() 102 }