Skip to content

Commit 03c4744

Browse files
committed
Implement path search function
Instead of passing files (eg. using find and using xargs) go-replace can search files itself: --path= use files in this path --path-pattern= file pattern (* for wildcard, only basename of file) --path-regex= file pattern (regex, full path) Fixes #3
1 parent 110daa0 commit 03c4744

File tree

2 files changed

+88
-9
lines changed

2 files changed

+88
-9
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# goreplace
2+
23
[![GitHub release](https://img.shields.io/github/release/webdevops/goreplace.svg)](https://github.com/webdevops/goreplace/releases)
34
[![license](https://img.shields.io/github/license/webdevops/goreplace.svg)](https://github.com/webdevops/goreplace/blob/master/LICENSE)
45

@@ -7,6 +8,7 @@ Cli utility for replacing text in files, written in golang and compiled for usag
78
Inspired by https://github.com/piranha/goreplace
89

910
## Usage
11+
1012
```
1113
Usage:
1214
goreplace
@@ -18,6 +20,10 @@ Application Options:
1820
--replace-line replace whole line instead of only match
1921
--regex treat pattern as regex
2022
--regex-backrefs enable backreferences in replace term
23+
--regex-posix parse regex term as POSIX regex
24+
--path= use files in this path
25+
--path-pattern= file pattern (* for wildcard, only basename of file)
26+
--path-regex= file pattern (regex, full path)
2127
-v, --verbose verbose mode
2228
--dry-run dry run mode
2329
-V, --version show version and exit
@@ -41,3 +47,4 @@ GOREPLACE_VERSION=0.2.1 \
4147
&& wget -O /usr/local/bin/go-replace https://github.com/webdevops/goreplace/releases/download/$GOREPLACE_VERSION/gr-64-linux \
4248
&& chmod +x /usr/local/bin/go-replace
4349
```
50+

goreplace.go

Lines changed: 81 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
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
3642
func 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

199259
func 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

Comments
 (0)