github.com/relnod/pegomock@v2.0.1+incompatible/pegomock/remove/remove.go (about) 1 package remove 2 3 import ( 4 "bufio" 5 "fmt" 6 "io" 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 "sort" 11 "strings" 12 13 "errors" 14 ) 15 16 func Remove( 17 path string, 18 recursive bool, 19 shouldConfirm bool, 20 dryRun bool, 21 silent bool, 22 out io.Writer, 23 in io.Reader, 24 removeFn func(path string) error, 25 ) { 26 filepaths, matchersDirPaths, e := getFilePaths(recursive, path, out) 27 if e != nil { 28 fmt.Fprintln(out, e.Error()) 29 return 30 } 31 if len(filepaths) == 0 { 32 fmt.Fprintln(out, "No files to remove.") 33 return 34 } 35 36 allFilepathsSorted := make([]string, len(filepaths)) 37 copy(allFilepathsSorted, filepaths) 38 for matchersDirPath := range matchersDirPaths { 39 if containsOnlyGeneratedFiles(matchersDirPath, allFilepathsSorted) { 40 allFilepathsSorted = append(allFilepathsSorted, matchersDirPath) 41 } 42 } 43 sort.Strings(allFilepathsSorted) 44 45 if dryRun { 46 fmt.Fprintln(out, "This is a dry-run. Would delete the following files:") 47 fmt.Fprintln(out, strings.Join(allFilepathsSorted, "\n")) 48 return 49 } 50 51 if shouldConfirm { 52 fmt.Fprintln(out, "Will delete the following files:") 53 fmt.Fprintln(out, strings.Join(allFilepathsSorted, "\n")) 54 if !askForConfirmation("Continue?", in, out) { 55 return 56 } 57 } else if !silent { 58 fmt.Fprintln(out, "Deleting the following files:") 59 fmt.Fprintln(out, strings.Join(allFilepathsSorted, "\n")) 60 } 61 62 var errs []error 63 for _, filepath := range filepaths { 64 e := removeFn(filepath) 65 if e != nil { 66 errs = append(errs, e) 67 } 68 } 69 for matcherPath := range matchersDirPaths { 70 if dirEmpty(matcherPath) { 71 e := removeFn(matcherPath) 72 if e != nil { 73 errs = append(errs, e) 74 } 75 } 76 } 77 if len(errs) > 0 { 78 fmt.Fprintf(out, "There were some errors when trying to delete files: %v", errs) 79 } 80 } 81 func containsOnlyGeneratedFiles(matchersDirPath string, generatedFilenames []string) bool { 82 f, e := os.Open(matchersDirPath) 83 if e != nil { 84 return false 85 } 86 defer f.Close() 87 filenamesInMatchersDir, e := f.Readdirnames(-1) 88 if e != nil { 89 return false 90 } 91 if len(difference(matchersDirPath, filenamesInMatchersDir, generatedFilenames)) == 0 { 92 return true 93 } 94 return false 95 } 96 97 func difference(root string, a, b []string) map[string]bool { 98 m := make(map[string]bool, len(b)) 99 for _, s := range a { 100 m[filepath.Join(root, s)] = true 101 } 102 for _, s := range b { 103 delete(m, s) 104 } 105 return m 106 } 107 108 func dirEmpty(path string) bool { 109 f, e := os.Open(path) 110 if e != nil { 111 return false 112 } 113 defer f.Close() 114 115 _, e = f.Readdirnames(1) 116 return e == io.EOF 117 } 118 119 func getFilePaths(recursive bool, path string, out io.Writer) ([]string, map[string]bool, error) { 120 matcherPaths := make(map[string]bool) 121 var walk func(root string, walkFn filepath.WalkFunc) error 122 if recursive { 123 walk = filepath.Walk 124 } else { 125 walk = walkFilesInDir 126 } 127 filepaths := make([]string, 0) 128 e := walk(path, func(path string, info os.FileInfo, err error) error { 129 if !info.IsDir() && filepath.Ext(path) == ".go" && isPegomockGenerated(path, out) { 130 filepaths = append(filepaths, path) 131 if filepath.Base(filepath.Dir(path)) == "matchers" { 132 matcherPaths[filepath.Dir(path)] = true 133 } 134 } 135 return nil 136 }) 137 if e != nil { 138 return nil, nil, errors.New("Could not get files in path " + path) 139 } 140 return filepaths, matcherPaths, nil 141 } 142 143 func walkFilesInDir(path string, walk filepath.WalkFunc) error { 144 fileInfos, e := ioutil.ReadDir(path) 145 if e != nil { 146 errors.New("Could not get files in path " + path) 147 } 148 for _, info := range fileInfos { 149 walk(filepath.Join(path, info.Name()), info, nil) 150 } 151 return nil 152 } 153 154 func isPegomockGenerated(path string, out io.Writer) bool { 155 file, e := os.Open(path) 156 if e != nil { 157 fmt.Fprintf(out, "Could not open file %v. Error: %v\n", path, e) 158 return false 159 } 160 b := make([]byte, 50) 161 _, e = file.Read(b) 162 if e != nil { 163 fmt.Fprintf(out, "Could not read from file %v. Error: %v\n", path, e) 164 return false 165 } 166 if strings.Contains(string(b), "// Code generated by pegomock. DO NOT EDIT.") { 167 return true 168 } 169 return false 170 } 171 172 func askForConfirmation(s string, in io.Reader, out io.Writer) bool { 173 reader := bufio.NewReader(in) 174 175 for { 176 fmt.Fprintf(out, "%s [y/n]: ", s) 177 178 response, err := reader.ReadString('\n') 179 if err != nil { 180 fmt.Fprintln(out, "Could not get confirmation from StdIn", err) 181 return false 182 } 183 184 response = strings.ToLower(strings.TrimSpace(response)) 185 186 if response == "y" || response == "yes" { 187 return true 188 } else if response == "n" || response == "no" { 189 return false 190 } 191 } 192 }