regren 0.0.3 → 0.0.4
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 +4 -4
- data/bin/regren +99 -94
- data/lib/filename_history.rb +68 -75
- data/lib/folder_contents_history.rb +106 -100
- data/test/filename_history_test.rb +0 -0
- data/test/folder_contents_history_test.rb +0 -0
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b37b7b976a4778f6d1bd4c6a4e400f596c7ddb0b
|
4
|
+
data.tar.gz: d3574cf7d20b64e468f0db47acf5033f228ec1cf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f6553b71b3311525b6699cc5b31f94cd231a43939346b386489962d6036fcc77f47deba2b4c118514f4cc76222454182af289b9186bfd8eadb566a0c7a18d82b
|
7
|
+
data.tar.gz: f723d1200a3be1e993aef3c7c8e75f8d0ade430352a987a1e72bd615d95c7d653221c905963abe9fc4abb275af9afbef86459b62decd1bf9967587612fbfecf4
|
data/bin/regren
CHANGED
@@ -1,94 +1,99 @@
|
|
1
|
-
#!/bin/env ruby
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
require 'optparse'
|
6
|
-
require 'folder_contents_history'
|
7
|
-
require 'filename_history'
|
8
|
-
|
9
|
-
def string_prompt(prompt = '>')
|
10
|
-
begin
|
11
|
-
|
12
|
-
|
13
|
-
rescue Interrupt
|
14
|
-
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def prompt?(text, options = {})
|
19
|
-
begin
|
20
|
-
default = options[:yes]
|
21
|
-
return default if options[:quiet]
|
22
|
-
opts = default ?
|
23
|
-
|
24
|
-
print "#{text} #{opts} "
|
25
|
-
c = STDIN.gets.chomp!
|
26
|
-
if c.downcase == 'y'
|
27
|
-
return true
|
28
|
-
elsif c.downcase == 'n'
|
29
|
-
return false
|
30
|
-
end
|
31
|
-
end
|
32
|
-
rescue Interrupt
|
33
|
-
exit 130
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
options = { mode: :rename }
|
38
|
-
optparse = OptionParser.new do |opts|
|
39
|
-
opts.on('-b','--backup','Make backup') { options[:backup] = true }
|
40
|
-
opts.on('-B','--new-backup','Start backups anew, implies --backup') do
|
41
|
-
options[:new_backup] = true
|
42
|
-
options[:backup] = true
|
43
|
-
end
|
44
|
-
opts.on('-n','--dry-run','Simulate') { options[:dry_run] = true }
|
45
|
-
opts.on('-y','--yes','Assume yes as default') { options[:yes] = true }
|
46
|
-
opts.on('-q','--quiet','Do not print anything') { options[:quiet] = true }
|
47
|
-
opts.on('-r','--restore','Restore backup') { options[:mode] = :restore }
|
48
|
-
opts.on('-R','--reapply','Reapply history')
|
49
|
-
|
50
|
-
|
51
|
-
opts.on('-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
end
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
1
|
+
#!/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
|
4
|
+
|
5
|
+
require 'optparse'
|
6
|
+
require 'folder_contents_history'
|
7
|
+
require 'filename_history'
|
8
|
+
|
9
|
+
def string_prompt(prompt = '>')
|
10
|
+
begin
|
11
|
+
print("#{prompt} ")
|
12
|
+
gets.chomp
|
13
|
+
rescue Interrupt
|
14
|
+
exit 130
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def prompt?(text, options = {})
|
19
|
+
begin
|
20
|
+
default = options[:yes]
|
21
|
+
return default if options[:quiet]
|
22
|
+
opts = default ? '[Y/n]' : '[y/N]'
|
23
|
+
loop do
|
24
|
+
print "#{text} #{opts} "
|
25
|
+
c = STDIN.gets.chomp!
|
26
|
+
if c.downcase == 'y' || (default && c == '')
|
27
|
+
return true
|
28
|
+
elsif c.downcase == 'n' || (!default && c == '')
|
29
|
+
return false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
rescue Interrupt
|
33
|
+
exit 130
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
options = { mode: :rename }
|
38
|
+
optparse = OptionParser.new do |opts|
|
39
|
+
opts.on('-b', '--backup', 'Make backup') { options[:backup] = true }
|
40
|
+
opts.on('-B', '--new-backup', 'Start backups anew, implies --backup') do
|
41
|
+
options[:new_backup] = true
|
42
|
+
options[:backup] = true
|
43
|
+
end
|
44
|
+
opts.on('-n', '--dry-run', 'Simulate') { options[:dry_run] = true }
|
45
|
+
opts.on('-y', '--yes', 'Assume yes as default') { options[:yes] = true }
|
46
|
+
opts.on('-q', '--quiet', 'Do not print anything') { options[:quiet] = true }
|
47
|
+
opts.on('-r', '--restore', 'Restore backup') { options[:mode] = :restore }
|
48
|
+
opts.on('-R', '--reapply', 'Reapply history') do
|
49
|
+
options[:mode] = :reapply
|
50
|
+
end
|
51
|
+
opts.on('-f', '--file FILE', 'File for backup/restore') do |file|
|
52
|
+
options[:history_file] = file
|
53
|
+
end
|
54
|
+
opts.on('-H', '--history', 'Show history for file') do
|
55
|
+
options[:mode] = :history
|
56
|
+
end
|
57
|
+
opts.on('-h', '--help', 'Print help') do
|
58
|
+
puts opts
|
59
|
+
exit
|
60
|
+
end
|
61
|
+
end
|
62
|
+
optparse.parse!
|
63
|
+
options[:history_file] ||= '.backup'
|
64
|
+
|
65
|
+
if options[:mode] == :rename
|
66
|
+
if ARGV.length != 2
|
67
|
+
options[:regexp] = Regexp.compile(string_prompt)
|
68
|
+
options[:replacement] = string_prompt
|
69
|
+
else
|
70
|
+
options[:regexp] = Regexp.compile(ARGV[0])
|
71
|
+
options[:replacement] = ARGV[1]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
if File.exist?(options[:history_file]) && !options[:new_backup]
|
76
|
+
history = FolderContentsHistory.new_from_history(options[:history_file])
|
77
|
+
else
|
78
|
+
history = FolderContentsHistory.new
|
79
|
+
end
|
80
|
+
|
81
|
+
history.load_entries
|
82
|
+
|
83
|
+
case options[:mode]
|
84
|
+
when :history
|
85
|
+
history.show_history(ARGV.empty? ? Dir['*'] : ARGV)
|
86
|
+
when :restore
|
87
|
+
history.plan_rollbacks
|
88
|
+
when :rename
|
89
|
+
history.plan_renames(options[:regexp], options[:replacement])
|
90
|
+
when :reapply
|
91
|
+
history.plan_reapplication('.')
|
92
|
+
end
|
93
|
+
history.log unless options[:quiet]
|
94
|
+
unless options[:dry_run] || options[:mode] == :history
|
95
|
+
if !history.changed.empty? && prompt?('Execute the rename?', options)
|
96
|
+
history.log_backup(options[:history_file]) if options[:backup]
|
97
|
+
history.execute
|
98
|
+
end
|
99
|
+
end
|
data/lib/filename_history.rb
CHANGED
@@ -1,75 +1,68 @@
|
|
1
|
-
class FileNameHistory
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
end
|
70
|
-
|
71
|
-
def current
|
72
|
-
@current
|
73
|
-
end
|
74
|
-
|
75
|
-
end
|
1
|
+
class FileNameHistory
|
2
|
+
attr_reader :history, :current
|
3
|
+
|
4
|
+
def initialize(name, history = [])
|
5
|
+
@history = history.empty? ? [name] : history
|
6
|
+
@current = name
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_hash
|
10
|
+
{
|
11
|
+
@history.last => @history
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.new_from_history(history)
|
16
|
+
FileNameHistory.new(history.last,
|
17
|
+
history)
|
18
|
+
end
|
19
|
+
|
20
|
+
def present?
|
21
|
+
File.exist?(@current)
|
22
|
+
end
|
23
|
+
|
24
|
+
def original
|
25
|
+
@history.first
|
26
|
+
end
|
27
|
+
|
28
|
+
def last_name
|
29
|
+
@history.last
|
30
|
+
end
|
31
|
+
|
32
|
+
def plan_rename(regexp, replacement)
|
33
|
+
new_name = @current.gsub(regexp, replacement)
|
34
|
+
@history << new_name if new_name != current
|
35
|
+
end
|
36
|
+
|
37
|
+
def plan_rollback
|
38
|
+
@history << original
|
39
|
+
end
|
40
|
+
|
41
|
+
def was_named?(name)
|
42
|
+
@history.include? name
|
43
|
+
end
|
44
|
+
|
45
|
+
def plan_reapplication(name)
|
46
|
+
@current = name
|
47
|
+
end
|
48
|
+
|
49
|
+
def changed?
|
50
|
+
@history.last != @current
|
51
|
+
end
|
52
|
+
|
53
|
+
def rename
|
54
|
+
File.rename("#{@current}", "#{@history.last}")
|
55
|
+
@current = @history.last
|
56
|
+
end
|
57
|
+
|
58
|
+
def print_history(where = $stdout)
|
59
|
+
where.puts(@current)
|
60
|
+
where.print "-> #{@history.join("\n-> ")}\n\n"
|
61
|
+
end
|
62
|
+
|
63
|
+
def log(where = $stdout)
|
64
|
+
return unless changed?
|
65
|
+
where.puts(@current)
|
66
|
+
where.puts("-> #{@history.last}")
|
67
|
+
end
|
68
|
+
end
|
@@ -1,100 +1,106 @@
|
|
1
|
-
class FolderContentsHistory
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
pathless
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
@entries
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
end
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
end
|
81
|
-
|
82
|
-
def
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
entries
|
96
|
-
|
97
|
-
end
|
98
|
-
|
99
|
-
|
100
|
-
|
1
|
+
class FolderContentsHistory
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
def initialize(entries = {})
|
5
|
+
@entries = entries
|
6
|
+
end
|
7
|
+
|
8
|
+
def load_entries(path = '.')
|
9
|
+
entries = Dir["#{path}/*"].reduce({}) do |hash, item|
|
10
|
+
pathless = item.gsub(/#{path}\//, '')
|
11
|
+
hash.update(pathless => FileNameHistory.new(pathless))
|
12
|
+
end
|
13
|
+
@entries.merge!(entries) do |_key, old_hash, new_hash|
|
14
|
+
old_hash.history.length > new_hash.history.length ? old_hash : new_hash
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def plan_renames(regexp, replacement)
|
19
|
+
@entries.select { |key, _value| key[regexp] }.each_pair do |_key, value|
|
20
|
+
value.plan_rename(regexp, replacement)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def plan_rollbacks
|
25
|
+
@entries.each_value do |file_history|
|
26
|
+
file_history.plan_rollback
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def plan_reapplication(path)
|
31
|
+
entries = Dir["#{path}/*"].map { |file| file.gsub(/#{path}\//, '') }
|
32
|
+
histories = @entries.values
|
33
|
+
@entries = merge_histories(histories, entries)
|
34
|
+
@entries.select! { |_name, history| history }
|
35
|
+
@entries.each { |name, history| history.plan_reapplication(name) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def merge_histories(old, new)
|
39
|
+
new.reduce({}) do |hash, item|
|
40
|
+
hash.tap do |obj|
|
41
|
+
new_history = old.select { |history| history.was_named? item }.first
|
42
|
+
obj.update(item => new_history.clone) unless new_history.nil?
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def execute
|
48
|
+
changed.each_pair do |key, value|
|
49
|
+
value.rename
|
50
|
+
@entries[value.current] = @entries.delete(key)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def log
|
55
|
+
if conflicts?
|
56
|
+
puts <<-NOTE.gsub(/^.*\|/, '')
|
57
|
+
|==================================================
|
58
|
+
|!!! Some files would be lost by this operation !!!
|
59
|
+
|==================================================
|
60
|
+
NOTE
|
61
|
+
end
|
62
|
+
changed.each_value do |file_history|
|
63
|
+
file_history.log
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def log_backup(where)
|
68
|
+
with_history = @entries
|
69
|
+
.select { |_name, history| history.history.length > 1 }
|
70
|
+
backup = with_history.reduce({}) do |hash, item|
|
71
|
+
hash.update(item.last.to_hash)
|
72
|
+
end
|
73
|
+
File.write(where, JSON.pretty_generate(backup))
|
74
|
+
end
|
75
|
+
|
76
|
+
def to_hash(input_hash = @entries)
|
77
|
+
input_hash.reduce({}) do |hash, entry|
|
78
|
+
hash.update(entry[0] => entry[1].to_hash)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def changed
|
83
|
+
@entries.select { |_key, value| value.changed? && value.present? }
|
84
|
+
end
|
85
|
+
|
86
|
+
def show_history(files)
|
87
|
+
files.each do |file|
|
88
|
+
@entries[file] = FileNameHistory.new(file) unless @entries[file]
|
89
|
+
@entries[file].print_history
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def conflicts?
|
94
|
+
# changed.map { |entry| entry.last }.compact.uniq.length < changed.length
|
95
|
+
@entries.map do |entry|
|
96
|
+
entry.last.last_name
|
97
|
+
end.compact.uniq.length < @entries.length
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.new_from_history(history_file)
|
101
|
+
entries = JSON.parse(File.read(history_file)).reduce({}) do |hash, item|
|
102
|
+
hash.update(item.first => FileNameHistory.new_from_history(item.last))
|
103
|
+
end
|
104
|
+
FolderContentsHistory.new(entries)
|
105
|
+
end
|
106
|
+
end
|
File without changes
|
File without changes
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: regren
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam Ruzicka
|
@@ -31,7 +31,7 @@ dependencies:
|
|
31
31
|
- - ~>
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '1.3'
|
34
|
-
- -
|
34
|
+
- - '>='
|
35
35
|
- !ruby/object:Gem::Version
|
36
36
|
version: 4.7.3
|
37
37
|
type: :development
|
@@ -41,7 +41,7 @@ dependencies:
|
|
41
41
|
- - ~>
|
42
42
|
- !ruby/object:Gem::Version
|
43
43
|
version: '1.3'
|
44
|
-
- -
|
44
|
+
- - '>='
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: 4.7.3
|
47
47
|
description: A simple gem for batch renaming files
|
@@ -52,8 +52,8 @@ extensions: []
|
|
52
52
|
extra_rdoc_files: []
|
53
53
|
files:
|
54
54
|
- bin/regren
|
55
|
-
- lib/filename_history.rb
|
56
55
|
- lib/folder_contents_history.rb
|
56
|
+
- lib/filename_history.rb
|
57
57
|
- test/filename_history_test.rb
|
58
58
|
- test/folder_contents_history_test.rb
|
59
59
|
homepage: https://github.com/adamruzicka/regren
|
@@ -66,17 +66,17 @@ require_paths:
|
|
66
66
|
- lib
|
67
67
|
required_ruby_version: !ruby/object:Gem::Requirement
|
68
68
|
requirements:
|
69
|
-
- -
|
69
|
+
- - '>='
|
70
70
|
- !ruby/object:Gem::Version
|
71
71
|
version: 1.9.2
|
72
72
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
73
|
requirements:
|
74
|
-
- -
|
74
|
+
- - '>='
|
75
75
|
- !ruby/object:Gem::Version
|
76
76
|
version: '0'
|
77
77
|
requirements: []
|
78
78
|
rubyforge_project:
|
79
|
-
rubygems_version: 2.
|
79
|
+
rubygems_version: 2.1.11
|
80
80
|
signing_key:
|
81
81
|
specification_version: 4
|
82
82
|
summary: regren
|