Skip to content

Commit

Permalink
v2.6.0: users can choose how to handle overwriting
Browse files Browse the repository at this point in the history
  • Loading branch information
shenwei356 committed Apr 10, 2018
1 parent 9cc1d83 commit c89571b
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 25 deletions.
74 changes: 62 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

- **Cross-platform**. Supporting Windows, Mac OS X and Linux.
- **Safe**. By ***checking potential conflicts and errors***.
- **Overwrite can be detected and users can choose whether overwrite or leave it**.
- **File filtering**. Supporting including and excluding files via regular expression.
No need to run commands like `find ./ -name "*.html" -exec CMD`.
- **Renaming submatch with corresponding value via key-value file**.
Expand All @@ -48,19 +49,19 @@

#### Method 1: Download binaries

[brename v2.5.2](https://github.com/shenwei356/brename/releases/tag/v2.5.2)
[![Github Releases (by Release)](https://img.shields.io/github/downloads/shenwei356/brename/v2.5.2/total.svg)](https://github.com/shenwei356/brename/releases/tag/v2.5.2)
[brename v2.6.0](https://github.com/shenwei356/brename/releases/tag/v2.6.0)
[![Github Releases (by Release)](https://img.shields.io/github/downloads/shenwei356/brename/v2.6.0/total.svg)](https://github.com/shenwei356/brename/releases/tag/v2.6.0)

***Tip: run `brename -V` to check update !!!***

OS |Arch |File, 中国镜像 |Download Count
:------|:---------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Linux |32-bit |[brename_linux_386.tar.gz](https://github.com/shenwei356/brename/releases/download/v2.5.2/brename_linux_386.tar.gz),<br/> [中国镜像](http://app.shenwei.me/data/brename/brename_linux_386.tar.gz) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/brename/latest/brename_linux_386.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/brename/releases/download/v2.5.2/brename_linux_386.tar.gz)
Linux |**64-bit**|[**brename_linux_amd64.tar.gz**](https://github.com/shenwei356/brename/releases/download/v2.5.2/brename_linux_amd64.tar.gz),<br/> [中国镜像](http://app.shenwei.me/data/brename/brename_linux_amd64.tar.gz) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/brename/latest/brename_linux_amd64.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/brename/releases/download/v2.5.2/brename_linux_amd64.tar.gz)
OS X |32-bit |[brename_darwin_386.tar.gz](https://github.com/shenwei356/brename/releases/download/v2.5.2/brename_darwin_386.tar.gz),<br/> [中国镜像](http://app.shenwei.me/data/brename/brename_darwin_386.tar.gz) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/brename/latest/brename_darwin_386.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/brename/releases/download/v2.5.2/brename_darwin_386.tar.gz)
OS X |**64-bit**|[**brename_darwin_amd64.tar.gz**](https://github.com/shenwei356/brename/releases/download/v2.5.2/brename_darwin_amd64.tar.gz),<br/> [中国镜像](http://app.shenwei.me/data/brename/brename_darwin_amd64.tar.gz) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/brename/latest/brename_darwin_amd64.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/brename/releases/download/v2.5.2/brename_darwin_amd64.tar.gz)
Windows|32-bit |[brename_windows_386.exe.tar.gz](https://github.com/shenwei356/brename/releases/download/v2.5.2/brename_windows_386.exe.tar.gz),<br/> [中国镜像](http://app.shenwei.me/data/brename/brename_windows_386.exe.tar.gz) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/brename/latest/brename_windows_386.exe.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/brename/releases/download/v2.5.2/brename_windows_386.exe.tar.gz)
Windows|**64-bit**|[**brename_windows_amd64.exe.tar.gz**](https://github.com/shenwei356/brename/releases/download/v2.5.2/brename_windows_amd64.exe.tar.gz),<br/> [中国镜像](http://app.shenwei.me/data/brename/brename_windows_amd64.exe.tar.gz)|[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/brename/latest/brename_windows_amd64.exe.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/brename/releases/download/v2.5.2/brename_windows_amd64.exe.tar.gz)
Linux |32-bit |[brename_linux_386.tar.gz](https://github.com/shenwei356/brename/releases/download/v2.6.0/brename_linux_386.tar.gz),<br/> [中国镜像](http://app.shenwei.me/data/brename/brename_linux_386.tar.gz) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/brename/latest/brename_linux_386.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/brename/releases/download/v2.6.0/brename_linux_386.tar.gz)
Linux |**64-bit**|[**brename_linux_amd64.tar.gz**](https://github.com/shenwei356/brename/releases/download/v2.6.0/brename_linux_amd64.tar.gz),<br/> [中国镜像](http://app.shenwei.me/data/brename/brename_linux_amd64.tar.gz) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/brename/latest/brename_linux_amd64.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/brename/releases/download/v2.6.0/brename_linux_amd64.tar.gz)
OS X |32-bit |[brename_darwin_386.tar.gz](https://github.com/shenwei356/brename/releases/download/v2.6.0/brename_darwin_386.tar.gz),<br/> [中国镜像](http://app.shenwei.me/data/brename/brename_darwin_386.tar.gz) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/brename/latest/brename_darwin_386.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/brename/releases/download/v2.6.0/brename_darwin_386.tar.gz)
OS X |**64-bit**|[**brename_darwin_amd64.tar.gz**](https://github.com/shenwei356/brename/releases/download/v2.6.0/brename_darwin_amd64.tar.gz),<br/> [中国镜像](http://app.shenwei.me/data/brename/brename_darwin_amd64.tar.gz) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/brename/latest/brename_darwin_amd64.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/brename/releases/download/v2.6.0/brename_darwin_amd64.tar.gz)
Windows|32-bit |[brename_windows_386.exe.tar.gz](https://github.com/shenwei356/brename/releases/download/v2.6.0/brename_windows_386.exe.tar.gz),<br/> [中国镜像](http://app.shenwei.me/data/brename/brename_windows_386.exe.tar.gz) |[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/brename/latest/brename_windows_386.exe.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/brename/releases/download/v2.6.0/brename_windows_386.exe.tar.gz)
Windows|**64-bit**|[**brename_windows_amd64.exe.tar.gz**](https://github.com/shenwei356/brename/releases/download/v2.6.0/brename_windows_amd64.exe.tar.gz),<br/> [中国镜像](http://app.shenwei.me/data/brename/brename_windows_amd64.exe.tar.gz)|[![Github Releases (by Asset)](https://img.shields.io/github/downloads/shenwei356/brename/latest/brename_windows_amd64.exe.tar.gz.svg?maxAge=3600)](https://github.com/shenwei356/brename/releases/download/v2.6.0/brename_windows_amd64.exe.tar.gz)


Just [download](https://github.com/shenwei356/brename/releases) compressed
Expand Down Expand Up @@ -93,18 +94,18 @@ And then:
## Usage

```
brename -- a practical cross-platform command-line tool for safely batch renaming files/directories via regular expression
Version: 2.5.2
Version: 2.6.0
Author: Wei Shen <[email protected]>
Homepage: https://github.com/shenwei356/brename
Attention:
1. Paths starting with "." is ignored.
2. Overwriting existed files is not allowed.
3. Flag -f/--include-filters and -F/--exclude-filters support multiple values,
2. Flag -f/--include-filters and -F/--exclude-filters support multiple values,
e.g., -f ".html" -f ".htm".
But ATTENTION: comma in filter is treated as separater of multiple filters.
Expand Down Expand Up @@ -155,11 +156,12 @@ Flags:
-l, --list only list paths that match pattern
-a, --list-abs list absolute path, using along with -l/--list
--nr-width int minimum width for {nr} in flag -r/--replacement. e.g., formating "1" to "001" by --nr-width 3 (default 1)
-o, --overwrite-mode int overwrite mode (0 for reporting error, 1 for overwrite, 2 for not renaming) (default 0)
-p, --pattern string search pattern (regular expression)
-R, --recursive rename recursively
-r, --replacement string replacement. capture variables supported. e.g. $1 represents the first submatch. ATTENTION: for *nix OS, use SINGLE quote NOT double quotes or use the \ escape character. Ascending integer is also supported by "{nr}"
-n, --start-num int starting number when using {nr} in replacement (default 1)
-v, --verbose int verbose level (0 for all, 1 for warning and error, 2 for only error)
-v, --verbose int verbose level (0 for all, 1 for warning and error, 2 for only error) (default 0)
-V, --version print version information and check for update
```

Expand Down Expand Up @@ -375,6 +377,54 @@ Take a directory for example:
/home/shenwei/project/src/github.com/shenwei356/brename/binaries/brename_windows_386.exe.tar.gz
/home/shenwei/project/src/github.com/shenwei356/brename/binaries/brename_windows_amd64.exe.tar.gz

1. Overwrite mode (`-o/--overwrite-mode`)

$ ls *.tar.gz
brename_darwin_386.tar.gz brename_linux_386.tar.gz brename_windows_386.exe.tar.gz
brename_darwin_amd64.tar.gz brename_linux_amd64.tar.gz brename_windows_amd64.exe.tar.gz

1. default mode: reporting error

$ brename -p 386 -r amd64 -d
[ERRO] checking: [ new path existed ] 'brename_darwin_386.tar.gz' -> 'brename_darwin_amd64.tar.gz'
[ERRO] checking: [ new path existed ] 'brename_linux_386.tar.gz' -> 'brename_linux_amd64.tar.gz'
[ERRO] checking: [ new path existed ] 'brename_windows_386.exe.tar.gz' -> 'brename_windows_amd64.exe.tar.gz'
[ERRO] 3 potential error(s) detected, please check

1. allowing overwrite

$ brename -p 386 -r amd64 -d -o 1
[WARN] checking: [ new path existed ] 'brename_darwin_386.tar.gz' -> 'brename_darwin_amd64.tar.gz' (will be overwrited)
[WARN] checking: [ new path existed ] 'brename_linux_386.tar.gz' -> 'brename_linux_amd64.tar.gz' (will be overwrited)
[WARN] checking: [ new path existed ] 'brename_windows_386.exe.tar.gz' -> 'brename_windows_amd64.exe.tar.gz' (will be overwrited)
[INFO] 3 path(s) to be renamed

1. leave it

$ brename -p 386 -r amd64 -d -o 2
[WARN] checking: [ new path existed ] 'brename_darwin_386.tar.gz' -> 'brename_darwin_amd64.tar.gz' (will NOT be overwrited)
[WARN] checking: [ new path existed ] 'brename_linux_386.tar.gz' -> 'brename_linux_amd64.tar.gz' (will NOT be overwrited)
[WARN] checking: [ new path existed ] 'brename_windows_386.exe.tar.gz' -> 'brename_windows_amd64.exe.tar.gz' (will NOT be overwrited)
[INFO] 0 path(s) to be renamed

1. this flag also works for another case, where two or more files are renamed to same new path

$ brename -f 386 -p 'darwin|linux' -r unix-like -d
[INFO] checking: [ ok ] 'brename_darwin_386.tar.gz' -> 'brename_unix-like_386.tar.gz'
[ERRO] checking: [ overwriting newly renamed path ] 'brename_linux_386.tar.gz' -> 'brename_unix-like_386.tar.gz'
[ERRO] 1 potential error(s) detected, please check

$ brename -f 386 -p 'darwin|linux' -r unix-like -d -o 1
[INFO] checking: [ ok ] 'brename_darwin_386.tar.gz' -> 'brename_unix-like_386.tar.gz'
[WARN] checking: [ overwriting newly renamed path ] 'brename_linux_386.tar.gz' -> 'brename_unix-like_386.tar.gz' (will be overwrited)
[INFO] 2 path(s) to be renamed

$ brename -f 386 -p 'darwin|linux' -r unix-like -d -o 2
[INFO] checking: [ ok ] 'brename_darwin_386.tar.gz' -> 'brename_unix-like_386.tar.gz'
[WARN] checking: [ overwriting newly renamed path ] 'brename_linux_386.tar.gz' -> 'brename_unix-like_386.tar.gz' (will NOT be overwrited)
[INFO] 1 path(s) to be renamed



## Real-world examples

Expand Down
76 changes: 63 additions & 13 deletions brename.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,12 @@ import (

var log *logging.Logger

var version = "2.5.2"
var version = "2.6.0"
var app = "brename"

// for detecting one case where two or more files are renamed to same new path
var pathTree map[string]struct{}

// Options is the struct containing all global options
type Options struct {
Verbose int
Expand Down Expand Up @@ -76,6 +79,8 @@ type Options struct {
KeepKey bool
KeyCaptIdx int
KeyMissRepl string

OverwriteMode int
}

var reNR = regexp.MustCompile(`\{(NR|nr)\}`)
Expand Down Expand Up @@ -175,8 +180,20 @@ func getOptions(cmd *cobra.Command) *Options {
log.Infof("%d pairs of key-value loaded", len(kvs))
}

verbose := getFlagNonNegativeInt(cmd, "verbose")
if verbose > 2 {
log.Errorf("illegal value of flag --verbose: %d, only 0/1/2 allowed", verbose)
os.Exit(1)
}

overwriteMode := getFlagNonNegativeInt(cmd, "overwrite-mode")
if overwriteMode > 2 {
log.Errorf("illegal value of flag -o/--overwrite-mode: %d, only 0/1/2 allowed", overwriteMode)
os.Exit(1)
}

return &Options{
Verbose: getFlagNonNegativeInt(cmd, "verbose"),
Verbose: verbose,
Version: version,
DryRun: getFlagBool(cmd, "dry-run"),

Expand Down Expand Up @@ -206,6 +223,8 @@ func getOptions(cmd *cobra.Command) *Options {
KeepKey: getFlagBool(cmd, "keep-key"),
KeyCaptIdx: getFlagPositiveInt(cmd, "key-capt-idx"),
KeyMissRepl: getFlagString(cmd, "key-miss-repl"),

OverwriteMode: overwriteMode,
}
}

Expand All @@ -220,7 +239,7 @@ func init() {
logging.SetBackend(backendFormatter)
log = logging.MustGetLogger(app)

RootCmd.Flags().IntP("verbose", "v", 0, "verbose level (0 for all, 1 for warning and error, 2 for only error)")
RootCmd.Flags().IntP("verbose", "v", 0, "verbose level (0 for all, 1 for warning and error, 2 for only error) (default 0)")
RootCmd.Flags().BoolP("version", "V", false, "print version information and check for update")
RootCmd.Flags().BoolP("dry-run", "d", false, "print rename operations but do not run")

Expand All @@ -245,6 +264,8 @@ func init() {
RootCmd.Flags().IntP("start-num", "n", 1, `starting number when using {nr} in replacement`)
RootCmd.Flags().IntP("nr-width", "", 1, `minimum width for {nr} in flag -r/--replacement. e.g., formating "1" to "001" by --nr-width 3`)

RootCmd.Flags().IntP("overwrite-mode", "o", 0, "overwrite mode (0 for reporting error, 1 for overwrite, 2 for not renaming) (default 0)")

RootCmd.Example = ` 1. dry run and showing potential dangerous operations
brename -p "abc" -d
2. dry run and only show operations that will cause error
Expand Down Expand Up @@ -292,6 +313,8 @@ Additional help topics:{{range .Commands}}{{if .IsHelpCommand}}
Use "{{.CommandPath}} --help" for more information about a command.{{end}}
`)

pathTree = make(map[string]struct{}, 1000)
}

func main() {
Expand Down Expand Up @@ -399,8 +422,7 @@ Homepage: https://github.com/shenwei356/brename
Attention:
1. Paths starting with "." is ignored.
2. Overwriting existed files is not allowed.
3. Flag -f/--include-filters and -F/--exclude-filters support multiple values,
2. Flag -f/--include-filters and -F/--exclude-filters support multiple values,
e.g., -f ".html" -f ".htm".
But ATTENTION: comma in filter is treated as separater of multiple filters.
Expand Down Expand Up @@ -447,18 +469,37 @@ Special replacement symbols:
log.Infof("checking: %s\n", op)
case codeUnchanged:
log.Warningf("checking: %s\n", op)
case codeExisted:
log.Errorf("checking: %s\n", op)
case codeExisted, codeOverwriteNewPath:
switch opt.OverwriteMode {
case 0: // report error
log.Errorf("checking: %s\n", op)
case 1: // overwrite
log.Warningf("checking: %s (will be overwrited)\n", op)
case 2: // no renaming
log.Warningf("checking: %s (will NOT be overwrited)\n", op)
}
case codeMissingTarget:
log.Errorf("checking: %s\n", op)
}
}

switch op.code {
case 0:
case codeOK:
ops = append(ops, op)
n++
case 1:
case codeUnchanged:
case codeExisted, codeOverwriteNewPath:
switch opt.OverwriteMode {
case 0: // report error
hasErr = true
nErr++
continue
case 1: // overwrite
ops = append(ops, op)
n++
case 2: // no renaming

}
default:
hasErr = true
nErr++
Expand Down Expand Up @@ -528,6 +569,7 @@ const (
codeOK code = iota
codeUnchanged
codeExisted
codeOverwriteNewPath
codeMissingTarget
)

Expand All @@ -543,6 +585,8 @@ func (c code) String() string {
return yellow("unchanged")
case codeExisted:
return red("new path existed")
case codeOverwriteNewPath:
return red("overwriting newly renamed path")
case codeMissingTarget:
return red("missing target")
}
Expand Down Expand Up @@ -601,20 +645,26 @@ func checkOperation(opt *Options, path string) (bool, operation) {
}

filename2 := opt.PatternRe.ReplaceAllString(filename, r) + ext
target := filepath.Join(dir, filename2)

if filename2 == "" {
return true, operation{path, filepath.Join(dir, filename2), codeMissingTarget}
return true, operation{path, target, codeMissingTarget}
}

if filename2 == filename+ext {
return true, operation{path, filepath.Join(dir, filename2), codeUnchanged}
return true, operation{path, target, codeUnchanged}
}

target := filepath.Join(dir, filename2)
if _, err := os.Stat(target); err == nil {
return true, operation{path, target, codeExisted}
}

return true, operation{path, filepath.Join(dir, filename2), codeOK}
if _, ok := pathTree[target]; ok {
return true, operation{path, target, codeOverwriteNewPath}
}
pathTree[target] = struct{}{}

return true, operation{path, target, codeOK}
}

func ignore(opt *Options, path string) bool {
Expand Down

0 comments on commit c89571b

Please sign in to comment.