mass_renamer 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/bin/mass-renamer +3 -0
- data/lib/mass_renamer.rb +4 -0
- data/lib/mass_renamer/command_line.rb +71 -0
- data/lib/mass_renamer/driver.rb +177 -0
- data/lib/mass_renamer/free.rb +75 -0
- data/lib/mass_renamer/version.rb +3 -0
- metadata +11 -13
- data/bin/mass_renamer +0 -3
- data/bin/renamer +0 -16
- data/lib/renamer.rb +0 -4
- data/lib/renamer/command_line.rb +0 -71
- data/lib/renamer/driver.rb +0 -177
- data/lib/renamer/free.rb +0 -75
- data/lib/renamer/version.rb +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0bb62c98bf86b0179ff0bbb977095e5ca508d83b36381ddb3d2e0df0e6d44de0
|
4
|
+
data.tar.gz: '0798754ad301d478b23da28eed974c295b3f23818571352f208c0558afe60694'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f5f17e53aecab501f25984baca26c89f4afee3d7dcfc6c88ac5a34e3d72d34797cb405f947f1513fbb935aafd876096728c20e0af7b64adb84827dacbc66585b
|
7
|
+
data.tar.gz: ce973c05053608d44d833be3c7ef57e277c66cc8d39cfd5f8695f5750fde07fa008c4aea49f8c045a36ffaeeeb0226056251c44c9c4cd41a3648148093438531
|
data/bin/mass-renamer
ADDED
data/lib/mass_renamer.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module MassRenamer
|
4
|
+
|
5
|
+
class Command_Line
|
6
|
+
def initialize argv = ARGV
|
7
|
+
opts = parse argv
|
8
|
+
@driver = Driver.new opts
|
9
|
+
end
|
10
|
+
|
11
|
+
def rename!
|
12
|
+
@driver.rename!
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse argv
|
16
|
+
opts = {}
|
17
|
+
OptionParser.new do |opt|
|
18
|
+
opt.banner = 'Usage: renamer [DIRECTORY] [OPTIONS]'
|
19
|
+
opt.separator ''
|
20
|
+
opt.separator 'DIRECTORY in which you want to rename. If not'
|
21
|
+
opt.separator 'provided, `pwd` is used.'
|
22
|
+
opt.separator ''
|
23
|
+
opt.separator 'Editor to use is determined by this priority:'
|
24
|
+
opt.separator ' --editor'
|
25
|
+
opt.separator ' $EDITOR'
|
26
|
+
opt.separator ' vim'
|
27
|
+
opt.separator ''
|
28
|
+
opt.separator 'Options:'
|
29
|
+
|
30
|
+
opt.on('-h', '--help', 'Print usage') do
|
31
|
+
puts opt
|
32
|
+
exit
|
33
|
+
end
|
34
|
+
opt.on('-d', '--dry', 'Dry run') do
|
35
|
+
opts[:dry] = true
|
36
|
+
end
|
37
|
+
opt.on('-r', '--recursive', 'Recurse into subdirectories') do
|
38
|
+
opts[:recursive] = true
|
39
|
+
end
|
40
|
+
opt.on('-F', '--force', 'Don\'t ask if target exists') do
|
41
|
+
opts[:force] = true
|
42
|
+
end
|
43
|
+
opt.on('-D', '--no-delete', 'Completely disables delete function') do
|
44
|
+
opts[:no_delete] = true
|
45
|
+
end
|
46
|
+
opt.on('-v', '--verify', 'Ask for consent before doing each action') do
|
47
|
+
opts[:verify] = true
|
48
|
+
end
|
49
|
+
opt.on('-k', '--keep-going', 'Keep going after failure') do
|
50
|
+
opts[:keep_going] = true
|
51
|
+
end
|
52
|
+
opt.on('-V', '--verbose', 'Be verbose') do
|
53
|
+
opts[:verbose] = true
|
54
|
+
end
|
55
|
+
opt.on('--version', 'Print version') do
|
56
|
+
opts[:version] = true
|
57
|
+
end
|
58
|
+
opt.on('-e', '--editor EDITOR', 'Editor to use') do |editor|
|
59
|
+
opts[:editor] = editor
|
60
|
+
end
|
61
|
+
opt.on('-f', '--filter REGEX', Regexp, 'Regex used to filter files') do |filter|
|
62
|
+
opts[:filter] = filter
|
63
|
+
end
|
64
|
+
end.parse!(argv)
|
65
|
+
opts[:dir] = argv[0] || Dir::pwd
|
66
|
+
opts[:editor] ||= ENV['EDITOR'] || 'vim'
|
67
|
+
opts
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
module MassRenamer
|
5
|
+
|
6
|
+
class Filesystem_Driver
|
7
|
+
|
8
|
+
def initialize ask: , dry:, verbose:, no_delete:, force:
|
9
|
+
@ask = ask
|
10
|
+
@dry = dry
|
11
|
+
@verbose = verbose
|
12
|
+
@no_delete = no_delete
|
13
|
+
@force = force
|
14
|
+
end
|
15
|
+
|
16
|
+
def ask msg, from, to = nil
|
17
|
+
print "#{msg} '#{from}'#{to ? " -> '#{to}'" : '' }? [YN]: "
|
18
|
+
gets.chomp.downcase == ?y
|
19
|
+
end
|
20
|
+
|
21
|
+
def overwrite to
|
22
|
+
loop do
|
23
|
+
print "Overwrite #{to}? [Y(es)/N(o)/A(bort)]: "
|
24
|
+
case gets.chomp.downcase
|
25
|
+
when ?a
|
26
|
+
puts "Aborting."
|
27
|
+
return :abort
|
28
|
+
when ?y
|
29
|
+
return :yes
|
30
|
+
when ?n
|
31
|
+
puts "Not overwriting, skipping."
|
32
|
+
return :no
|
33
|
+
else
|
34
|
+
puts "Unexpected answer, try again."
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
def remove! from
|
41
|
+
raise "Deletes were disables." if @no_delete
|
42
|
+
begin
|
43
|
+
puts "rm -r '#{from}'" if @dry or @verbose
|
44
|
+
if @ask
|
45
|
+
return unless ask("Remove file", from)
|
46
|
+
end
|
47
|
+
return if @dry
|
48
|
+
FileUtils.remove_entry from
|
49
|
+
rescue StandardError => e
|
50
|
+
STDERR.puts "remove of '#{from}' failed: #{e.message}"
|
51
|
+
raise
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def copy! from, to
|
56
|
+
begin
|
57
|
+
puts "cp -r '#{from}' '#{to}'" if @dry or @verbose
|
58
|
+
if @ask
|
59
|
+
return unless ask("Copy", from, to)
|
60
|
+
end
|
61
|
+
return if @dry
|
62
|
+
if File.exist?(to) and not @force
|
63
|
+
case overwrite(to)
|
64
|
+
when :abort
|
65
|
+
exit 1
|
66
|
+
when :no
|
67
|
+
return
|
68
|
+
when :yes
|
69
|
+
end
|
70
|
+
end
|
71
|
+
FileUtils.mkdir_p File.dirname(to)
|
72
|
+
FileUtils.copy_entry from, to, preserve: true, remove_destination: true
|
73
|
+
rescue StandardError => e
|
74
|
+
STDERR.puts "copy '#{from}' -> '#{to}' failed: #{e.message}"
|
75
|
+
raise
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def move! from, to
|
80
|
+
begin
|
81
|
+
puts "mv '#{from}' '#{to}'" if @dry or @verbose
|
82
|
+
if @ask
|
83
|
+
return unless ask("Move", from, to)
|
84
|
+
end
|
85
|
+
return if @dry
|
86
|
+
if File.exist?(to) and not @force
|
87
|
+
case overwrite(to)
|
88
|
+
when :abort
|
89
|
+
exit 1
|
90
|
+
when :no
|
91
|
+
return
|
92
|
+
when :yes
|
93
|
+
end
|
94
|
+
end
|
95
|
+
FileUtils.mkdir_p File.dirname(to)
|
96
|
+
File.rename from, to
|
97
|
+
rescue StandardError => e
|
98
|
+
STDERR.puts "move '#{from}' -> '#{to}' failed: #{e.message}"
|
99
|
+
raise
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
class Driver
|
106
|
+
include Free
|
107
|
+
|
108
|
+
def initialize opts
|
109
|
+
@opts = opts
|
110
|
+
validate_environment!
|
111
|
+
end
|
112
|
+
|
113
|
+
def rename!
|
114
|
+
files = gather_files(
|
115
|
+
@opts[:dir],
|
116
|
+
recursive: @opts[:recursive],
|
117
|
+
filter: @opts[:filter]
|
118
|
+
)
|
119
|
+
renames = invoke_editor files
|
120
|
+
do_renames! renames
|
121
|
+
end
|
122
|
+
|
123
|
+
def do_renames! renames
|
124
|
+
fd = Filesystem_Driver.new(
|
125
|
+
ask: @opts[:ask],
|
126
|
+
dry: @opts[:dry],
|
127
|
+
verbose: @opts[:verbose],
|
128
|
+
no_delete: @opts[:no_delete],
|
129
|
+
force: @opts[:force]
|
130
|
+
)
|
131
|
+
|
132
|
+
renames.each do |from, to|
|
133
|
+
from = File.expand_path from
|
134
|
+
to.map!(&File.method(:expand_path))
|
135
|
+
|
136
|
+
begin
|
137
|
+
case to.length
|
138
|
+
when 0
|
139
|
+
fd.remove! from
|
140
|
+
when 1
|
141
|
+
to = to.first
|
142
|
+
next if from == to
|
143
|
+
fd.move! from, to
|
144
|
+
else
|
145
|
+
to.each { |dst| fd.copy! from, dst unless from == dst }
|
146
|
+
fd.remove! from unless to.include? from
|
147
|
+
end
|
148
|
+
rescue
|
149
|
+
next if @opts[:keep_going]
|
150
|
+
STDERR.puts "Something failed, stopping."
|
151
|
+
exit 1
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def invoke_editor files
|
157
|
+
tmpfile = Tempfile.new
|
158
|
+
begin
|
159
|
+
tmpfile.write generate_file_to_edit(files)
|
160
|
+
tmpfile.close
|
161
|
+
unless system(@opts[:editor], tmpfile.path)
|
162
|
+
raise "Cannot open editor (not in path?). Fix it."
|
163
|
+
end
|
164
|
+
tmpfile.open
|
165
|
+
parse_renames(tmpfile.read)
|
166
|
+
ensure
|
167
|
+
tmpfile.close
|
168
|
+
tmpfile.unlink
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def validate_environment!
|
173
|
+
raise IOError, "Directory does not exist." unless File.exist? @opts[:dir]
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
module MassRenamer
|
5
|
+
module Free
|
6
|
+
|
7
|
+
def gather_files_impl dir, recursive
|
8
|
+
children = dir.children false
|
9
|
+
sort_files! children
|
10
|
+
if recursive
|
11
|
+
children.collect! do |c|
|
12
|
+
filepath = dir + c
|
13
|
+
if filepath.directory?
|
14
|
+
[filepath, gather_files_impl(filepath, recursive)]
|
15
|
+
else
|
16
|
+
filepath
|
17
|
+
end
|
18
|
+
end.flatten!
|
19
|
+
end
|
20
|
+
children
|
21
|
+
end
|
22
|
+
|
23
|
+
def gather_files(dir, recursive: false, filter: nil)
|
24
|
+
files = gather_files_impl Pathname.new(dir), recursive
|
25
|
+
filter_files! files, filter if filter
|
26
|
+
exclude_weird_filenames! files
|
27
|
+
files
|
28
|
+
end
|
29
|
+
|
30
|
+
def filter_files! files, filter
|
31
|
+
files.select! { |i| i.to_s[filter] } if filter
|
32
|
+
end
|
33
|
+
|
34
|
+
def exclude_weird_filenames! files
|
35
|
+
files.reject! { |f| f = f.to_s; f.include?("\n") or f.start_with?(" ") }
|
36
|
+
end
|
37
|
+
|
38
|
+
def sort_files! files
|
39
|
+
files.sort! do |a,b|
|
40
|
+
if a.directory? and b.directory?
|
41
|
+
a <=> b
|
42
|
+
elsif a.directory?
|
43
|
+
-1
|
44
|
+
elsif b.directory?
|
45
|
+
1
|
46
|
+
else
|
47
|
+
a <=> b
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def generate_file_to_edit files
|
53
|
+
res = ""
|
54
|
+
files.each do |f|
|
55
|
+
res << f.to_s << "\n\t" << f.to_s << "\n"
|
56
|
+
end
|
57
|
+
res
|
58
|
+
end
|
59
|
+
|
60
|
+
def parse_renames str
|
61
|
+
lines = str.lines.map(&:chomp).reject { |l| l[/^\s*$/] }
|
62
|
+
renames = []
|
63
|
+
until lines.empty?
|
64
|
+
filename = lines.shift
|
65
|
+
targets = []
|
66
|
+
while lines[0] and lines[0] =~ /^\s/
|
67
|
+
targets << lines.shift.strip
|
68
|
+
end
|
69
|
+
renames << [filename, targets]
|
70
|
+
end
|
71
|
+
renames
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mass_renamer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gray Wolf
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-10-27 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |
|
14
14
|
Tool for renaming multiple files at once with easy. By
|
@@ -16,19 +16,17 @@ description: |
|
|
16
16
|
all the power you editor offers.
|
17
17
|
email: wolf@wolfsden.cz
|
18
18
|
executables:
|
19
|
-
- renamer
|
20
|
-
- mass_renamer
|
19
|
+
- mass-renamer
|
21
20
|
extensions: []
|
22
21
|
extra_rdoc_files: []
|
23
22
|
files:
|
24
|
-
- bin/
|
25
|
-
-
|
26
|
-
- lib/
|
27
|
-
- lib/
|
28
|
-
- lib/
|
29
|
-
- lib/
|
30
|
-
|
31
|
-
homepage: https://github.com/graywolf/renamer
|
23
|
+
- bin/mass-renamer
|
24
|
+
- lib/mass_renamer.rb
|
25
|
+
- lib/mass_renamer/command_line.rb
|
26
|
+
- lib/mass_renamer/driver.rb
|
27
|
+
- lib/mass_renamer/free.rb
|
28
|
+
- lib/mass_renamer/version.rb
|
29
|
+
homepage: https://github.com/graywolf/mass-renamer
|
32
30
|
licenses:
|
33
31
|
- MIT
|
34
32
|
metadata: {}
|
@@ -48,7 +46,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
48
46
|
version: '0'
|
49
47
|
requirements: []
|
50
48
|
rubyforge_project:
|
51
|
-
rubygems_version: 2.6
|
49
|
+
rubygems_version: 2.7.6
|
52
50
|
signing_key:
|
53
51
|
specification_version: 4
|
54
52
|
summary: Rename multiple files with ease!
|
data/bin/mass_renamer
DELETED
data/bin/renamer
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
4
|
-
|
5
|
-
require 'renamer'
|
6
|
-
|
7
|
-
begin
|
8
|
-
cli = Renamer::Command_Line.new ARGV
|
9
|
-
cli.rename!
|
10
|
-
rescue => e
|
11
|
-
STDERR.puts e.message
|
12
|
-
STDERR.puts
|
13
|
-
STDERR.puts "Backtrace:"
|
14
|
-
STDERR.puts e.backtrace
|
15
|
-
exit 1
|
16
|
-
end
|
data/lib/renamer.rb
DELETED
data/lib/renamer/command_line.rb
DELETED
@@ -1,71 +0,0 @@
|
|
1
|
-
require 'optparse'
|
2
|
-
|
3
|
-
module Renamer
|
4
|
-
|
5
|
-
class Command_Line
|
6
|
-
def initialize argv = ARGV
|
7
|
-
opts = parse argv
|
8
|
-
@driver = Driver.new opts
|
9
|
-
end
|
10
|
-
|
11
|
-
def rename!
|
12
|
-
@driver.rename!
|
13
|
-
end
|
14
|
-
|
15
|
-
def parse argv
|
16
|
-
opts = {}
|
17
|
-
OptionParser.new do |opt|
|
18
|
-
opt.banner = 'Usage: renamer [DIRECTORY] [OPTIONS]'
|
19
|
-
opt.separator ''
|
20
|
-
opt.separator 'DIRECTORY in which you want to rename. If not'
|
21
|
-
opt.separator 'provided, `pwd` is used.'
|
22
|
-
opt.separator ''
|
23
|
-
opt.separator 'Editor to use is determined by this priority:'
|
24
|
-
opt.separator ' --editor'
|
25
|
-
opt.separator ' $EDITOR'
|
26
|
-
opt.separator ' vim'
|
27
|
-
opt.separator ''
|
28
|
-
opt.separator 'Options:'
|
29
|
-
|
30
|
-
opt.on('-h', '--help', 'Print usage') do
|
31
|
-
puts opt
|
32
|
-
exit
|
33
|
-
end
|
34
|
-
opt.on('-d', '--dry', 'Dry run') do
|
35
|
-
opts[:dry] = true
|
36
|
-
end
|
37
|
-
opt.on('-r', '--recursive', 'Recurse into subdirectories') do
|
38
|
-
opts[:recursive] = true
|
39
|
-
end
|
40
|
-
opt.on('-F', '--force', 'Don\'t ask if target exists') do
|
41
|
-
opts[:force] = true
|
42
|
-
end
|
43
|
-
opt.on('-D', '--no-delete', 'Completely disables delete function') do
|
44
|
-
opts[:no_delete] = true
|
45
|
-
end
|
46
|
-
opt.on('-v', '--verify', 'Ask for consent before doing each action') do
|
47
|
-
opts[:verify] = true
|
48
|
-
end
|
49
|
-
opt.on('-k', '--keep-going', 'Keep going after failure') do
|
50
|
-
opts[:keep_going] = true
|
51
|
-
end
|
52
|
-
opt.on('-V', '--verbose', 'Be verbose') do
|
53
|
-
opts[:verbose] = true
|
54
|
-
end
|
55
|
-
opt.on('--version', 'Print version') do
|
56
|
-
opts[:version] = true
|
57
|
-
end
|
58
|
-
opt.on('-e', '--editor EDITOR', 'Editor to use') do |editor|
|
59
|
-
opts[:editor] = editor
|
60
|
-
end
|
61
|
-
opt.on('-f', '--filter REGEX', Regexp, 'Regex used to filter files') do |filter|
|
62
|
-
opts[:filter] = filter
|
63
|
-
end
|
64
|
-
end.parse!(argv)
|
65
|
-
opts[:dir] = argv[0] || Dir::pwd
|
66
|
-
opts[:editor] ||= ENV['EDITOR'] || 'vim'
|
67
|
-
opts
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
end
|
data/lib/renamer/driver.rb
DELETED
@@ -1,177 +0,0 @@
|
|
1
|
-
require 'pathname'
|
2
|
-
require 'tempfile'
|
3
|
-
|
4
|
-
module Renamer
|
5
|
-
|
6
|
-
class Filesystem_Driver
|
7
|
-
|
8
|
-
def initialize ask: , dry:, verbose:, no_delete:, force:
|
9
|
-
@ask = ask
|
10
|
-
@dry = dry
|
11
|
-
@verbose = verbose
|
12
|
-
@no_delete = no_delete
|
13
|
-
@force = force
|
14
|
-
end
|
15
|
-
|
16
|
-
def ask msg, from, to = nil
|
17
|
-
print "#{msg} '#{from}'#{to ? " -> '#{to}'" : '' }? [YN]: "
|
18
|
-
gets.chomp.downcase == ?y
|
19
|
-
end
|
20
|
-
|
21
|
-
def overwrite to
|
22
|
-
loop do
|
23
|
-
print "Overwrite #{to}? [Y(es)/N(o)/A(bort)]: "
|
24
|
-
case gets.chomp.downcase
|
25
|
-
when ?a
|
26
|
-
puts "Aborting."
|
27
|
-
return :abort
|
28
|
-
when ?y
|
29
|
-
return :yes
|
30
|
-
when ?n
|
31
|
-
puts "Not overwriting, skipping."
|
32
|
-
return :no
|
33
|
-
else
|
34
|
-
puts "Unexpected answer, try again."
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|
39
|
-
|
40
|
-
def remove! from
|
41
|
-
raise "Deletes were disables." if @no_delete
|
42
|
-
begin
|
43
|
-
puts "rm -r '#{from}'" if @dry or @verbose
|
44
|
-
if @ask
|
45
|
-
return unless ask("Remove file", from)
|
46
|
-
end
|
47
|
-
return if @dry
|
48
|
-
FileUtils.remove_entry from
|
49
|
-
rescue StandardError => e
|
50
|
-
STDERR.puts "remove of '#{from}' failed: #{e.message}"
|
51
|
-
raise
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def copy! from, to
|
56
|
-
begin
|
57
|
-
puts "cp -r '#{from}' '#{to}'" if @dry or @verbose
|
58
|
-
if @ask
|
59
|
-
return unless ask("Copy", from, to)
|
60
|
-
end
|
61
|
-
return if @dry
|
62
|
-
if File.exist?(to) and not @force
|
63
|
-
case overwrite(to)
|
64
|
-
when :abort
|
65
|
-
exit 1
|
66
|
-
when :no
|
67
|
-
return
|
68
|
-
when :yes
|
69
|
-
end
|
70
|
-
end
|
71
|
-
FileUtils.mkdir_p File.dirname(to)
|
72
|
-
FileUtils.copy_entry from, to, preserve: true, remove_destination: true
|
73
|
-
rescue StandardError => e
|
74
|
-
STDERR.puts "copy '#{from}' -> '#{to}' failed: #{e.message}"
|
75
|
-
raise
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def move! from, to
|
80
|
-
begin
|
81
|
-
puts "mv '#{from}' '#{to}'" if @dry or @verbose
|
82
|
-
if @ask
|
83
|
-
return unless ask("Move", from, to)
|
84
|
-
end
|
85
|
-
return if @dry
|
86
|
-
if File.exist?(to) and not @force
|
87
|
-
case overwrite(to)
|
88
|
-
when :abort
|
89
|
-
exit 1
|
90
|
-
when :no
|
91
|
-
return
|
92
|
-
when :yes
|
93
|
-
end
|
94
|
-
end
|
95
|
-
FileUtils.mkdir_p File.dirname(to)
|
96
|
-
File.rename from, to
|
97
|
-
rescue StandardError => e
|
98
|
-
STDERR.puts "move '#{from}' -> '#{to}' failed: #{e.message}"
|
99
|
-
raise
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
end
|
104
|
-
|
105
|
-
class Driver
|
106
|
-
include Free
|
107
|
-
|
108
|
-
def initialize opts
|
109
|
-
@opts = opts
|
110
|
-
validate_environment!
|
111
|
-
end
|
112
|
-
|
113
|
-
def rename!
|
114
|
-
files = gather_files(
|
115
|
-
@opts[:dir],
|
116
|
-
recursive: @opts[:recursive],
|
117
|
-
filter: @opts[:filter]
|
118
|
-
)
|
119
|
-
renames = invoke_editor files
|
120
|
-
do_renames! renames
|
121
|
-
end
|
122
|
-
|
123
|
-
def do_renames! renames
|
124
|
-
fd = Filesystem_Driver.new(
|
125
|
-
ask: @opts[:ask],
|
126
|
-
dry: @opts[:dry],
|
127
|
-
verbose: @opts[:verbose],
|
128
|
-
no_delete: @opts[:no_delete],
|
129
|
-
force: @opts[:force]
|
130
|
-
)
|
131
|
-
|
132
|
-
renames.each do |from, to|
|
133
|
-
from = File.expand_path from
|
134
|
-
to.map!(&File.method(:expand_path))
|
135
|
-
|
136
|
-
begin
|
137
|
-
case to.length
|
138
|
-
when 0
|
139
|
-
fd.remove! from
|
140
|
-
when 1
|
141
|
-
to = to.first
|
142
|
-
next if from == to
|
143
|
-
fd.move! from, to
|
144
|
-
else
|
145
|
-
to.each { |to| fd.copy! from, to unless from == to }
|
146
|
-
fd.remove! from unless to.include? from
|
147
|
-
end
|
148
|
-
rescue
|
149
|
-
next if @opts[:keep_going]
|
150
|
-
STDERR.puts "Something failed, stopping."
|
151
|
-
exit 1
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
def invoke_editor files
|
157
|
-
tmpfile = Tempfile.new
|
158
|
-
begin
|
159
|
-
tmpfile.write generate_file_to_edit(files)
|
160
|
-
tmpfile.close
|
161
|
-
unless system(@opts[:editor], tmpfile.path)
|
162
|
-
raise "Cannot open editor (not in path?). Fix it."
|
163
|
-
end
|
164
|
-
tmpfile.open
|
165
|
-
parse_renames(tmpfile.read)
|
166
|
-
ensure
|
167
|
-
tmpfile.close
|
168
|
-
tmpfile.unlink
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
def validate_environment!
|
173
|
-
raise IOError, "Directory does not exist." unless File.exist? @opts[:dir]
|
174
|
-
end
|
175
|
-
|
176
|
-
end
|
177
|
-
end
|
data/lib/renamer/free.rb
DELETED
@@ -1,75 +0,0 @@
|
|
1
|
-
require 'pathname'
|
2
|
-
require 'tempfile'
|
3
|
-
|
4
|
-
module Renamer
|
5
|
-
module Free
|
6
|
-
|
7
|
-
def gather_files_impl dir, recursive
|
8
|
-
children = dir.children false
|
9
|
-
sort_files! children
|
10
|
-
if recursive
|
11
|
-
children.collect! do |c|
|
12
|
-
filepath = dir + c
|
13
|
-
if filepath.directory?
|
14
|
-
[filepath, gather_files_impl(filepath, recursive)]
|
15
|
-
else
|
16
|
-
filepath
|
17
|
-
end
|
18
|
-
end.flatten!
|
19
|
-
end
|
20
|
-
children
|
21
|
-
end
|
22
|
-
|
23
|
-
def gather_files(dir, recursive: false, filter: nil)
|
24
|
-
files = gather_files_impl Pathname.new(dir), recursive
|
25
|
-
filter_files! files, filter if filter
|
26
|
-
exclude_weird_filenames! files
|
27
|
-
files
|
28
|
-
end
|
29
|
-
|
30
|
-
def filter_files! files, filter
|
31
|
-
files.select! { |i| i.to_s[filter] } if filter
|
32
|
-
end
|
33
|
-
|
34
|
-
def exclude_weird_filenames! files
|
35
|
-
files.reject! { |f| f = f.to_s; f.include?("\n") or f.start_with?(" ") }
|
36
|
-
end
|
37
|
-
|
38
|
-
def sort_files! files
|
39
|
-
files.sort! do |a,b|
|
40
|
-
if a.directory? and b.directory?
|
41
|
-
a <=> b
|
42
|
-
elsif a.directory?
|
43
|
-
-1
|
44
|
-
elsif b.directory?
|
45
|
-
1
|
46
|
-
else
|
47
|
-
a <=> b
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def generate_file_to_edit files
|
53
|
-
res = ""
|
54
|
-
files.each do |f|
|
55
|
-
res << f.to_s << "\n\t" << f.to_s << "\n"
|
56
|
-
end
|
57
|
-
res
|
58
|
-
end
|
59
|
-
|
60
|
-
def parse_renames str
|
61
|
-
lines = str.lines.map(&:chomp).reject { |l| l[/^\s*$/] }
|
62
|
-
renames = []
|
63
|
-
until lines.empty?
|
64
|
-
filename = lines.shift
|
65
|
-
targets = []
|
66
|
-
while lines[0] and lines[0] =~ /^\s/
|
67
|
-
targets << lines.shift.strip
|
68
|
-
end
|
69
|
-
renames << [filename, targets]
|
70
|
-
end
|
71
|
-
renames
|
72
|
-
end
|
73
|
-
|
74
|
-
end
|
75
|
-
end
|
data/lib/renamer/version.rb
DELETED