55 "errors"
66 "bytes"
77 "io/ioutil"
8+ "path/filepath"
89 "bufio"
910 "os"
1011 "strings"
@@ -26,12 +27,17 @@ var opts struct {
2627 Regex bool ` long:"regex" description:"treat pattern as regex"`
2728 RegexBackref bool ` long:"regex-backrefs" description:"enable backreferences in replace term"`
2829 RegexPosix bool ` long:"regex-posix" description:"parse regex term as POSIX regex"`
30+ Path string ` long:"path" description:"use files in this path"`
31+ PathPattern string ` long:"path-pattern" description:"file pattern (* for wildcard, only basename of file)"`
32+ PathRegex string ` long:"path-regex" description:"file pattern (regex, full path)"`
2933 Verbose bool `short:"v" long:"verbose" description:"verbose mode"`
3034 DryRun bool ` long:"dry-run" description:"dry run mode"`
3135 ShowVersion bool `short:"V" long:"version" description:"show version and exit"`
3236 ShowHelp bool `short:"h" long:"help" description:"show this help message"`
3337}
3438
39+ var pathFilterDirectories = []string {"autom4te.cache" , "blib" , "_build" , ".bzr" , ".cdv" , "cover_db" , "CVS" , "_darcs" , "~.dep" , "~.dot" , ".git" , ".hg" , "~.nib" , ".pc" , "~.plst" , "RCS" , "SCCS" , "_sgbak" , ".svn" , "_obj" , ".idea" }
40+
3541// Replace line (if match is found) in file
3642func replaceInFile (filepath string ) {
3743 // try open file
@@ -173,7 +179,62 @@ func buildSearchTerm() {
173179 }
174180}
175181
176- func handleSpecialCliOptions (argparser * flags.Parser , args []string ) {
182+ // check if string is contained in an array
183+ func contains (slice []string , item string ) bool {
184+ set := make (map [string ]struct {}, len (slice ))
185+ for _ , s := range slice {
186+ set [s ] = struct {}{}
187+ }
188+
189+ _ , ok := set [item ]
190+ return ok
191+ }
192+
193+ // search files in path
194+ func searchFilesInPath (path string , callback func (os.FileInfo , string )) {
195+ var pathRegex * regexp.Regexp
196+
197+ // --path-regex
198+ if (opts .PathRegex != "" ) {
199+ pathRegex = regexp .MustCompile (opts .PathRegex )
200+ }
201+
202+ // collect all files
203+ filepath .Walk (path , func (path string , f os.FileInfo , err error ) error {
204+ filename := f .Name ()
205+
206+ // skip directories
207+ if f .IsDir () {
208+ if contains (pathFilterDirectories , f .Name ()) {
209+ return filepath .SkipDir
210+ }
211+
212+ return nil
213+ }
214+
215+ if (opts .PathPattern != "" ) {
216+ matched , _ := filepath .Match (opts .PathPattern , filename )
217+ if (! matched ) {
218+ return nil
219+ }
220+ }
221+
222+ if pathRegex != nil {
223+ if (! pathRegex .MatchString (path )) {
224+ return nil
225+ }
226+ }
227+
228+ callback (f , path )
229+ return nil
230+ })
231+ }
232+
233+ // handle special cli options
234+ // eg. --help
235+ // --version
236+ // --path
237+ func handleSpecialCliOptions (argparser * flags.Parser , args []string ) ([]string ) {
177238 // --version
178239 if (opts .ShowVersion ) {
179240 fmt .Printf ("goreplace version %s\n " , Version )
@@ -186,31 +247,42 @@ func handleSpecialCliOptions(argparser *flags.Parser, args []string) {
186247 os .Exit (1 )
187248 }
188249
189- // missing any files
190- if (len (args ) == 0 ) {
191- err := errors .New ("No files specified" )
192- logError (err )
193- fmt .Println ()
194- argparser .WriteHelp (os .Stdout )
195- os .Exit (1 )
250+ // --path
251+ if (opts .Path != "" ) {
252+ searchFilesInPath (opts .Path , func (f os.FileInfo , path string ) {
253+ args = append (args , path )
254+ })
196255 }
256+ return args
197257}
198258
199259func main () {
200260 var argparser = flags .NewParser (& opts , flags .PassDoubleDash )
201261 args , err := argparser .Parse ()
202262
203- handleSpecialCliOptions (argparser , args )
263+ args = handleSpecialCliOptions (argparser , args )
204264
265+ // check if there is an parse error
205266 if err != nil {
206267 logError (err )
207268 fmt .Println ()
208269 argparser .WriteHelp (os .Stdout )
209270 os .Exit (1 )
210271 }
211272
273+ // check if there is at least one file to process
274+ if (len (args ) == 0 ) {
275+ err := errors .New ("No files specified" )
276+ logError (err )
277+ fmt .Println ()
278+ argparser .WriteHelp (os .Stdout )
279+ os .Exit (1 )
280+ }
281+
282+ // build regex search term
212283 buildSearchTerm ()
213284
285+ // process file list
214286 for i := range args {
215287 var file string
216288 file = args [i ]
0 commit comments