-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathforkman.rb
142 lines (111 loc) · 3.54 KB
/
forkman.rb
1
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
require 'mixlib/cli'
require 'yaml'
require 'fileutils'
require 'filemagic'
STDOUT.sync = true
class ForkMan
include Mixlib::CLI
banner "#{__FILE__} (options)"
option :config,
long: '--config YAML',
required: true,
proc: ->(x) { File.expand_path(x) },
description: 'YAML-based configuration file'
option :repo,
long: '--repo DIR',
required: true,
proc: ->(x) { File.expand_path(x) },
description: 'Directory with GIT project'
option :steps,
long: '--steps NUM',
default: 1_000_000,
proc: ->(x) { Integer(x) },
description: 'How many patterns to apply. Default: 1_000_000'
option :preserve_tokens,
long: '--[no-]preserve-tokens',
boolean: true,
default: false,
description: 'Stop translating and leave tokens'
def run
parse_options
yaml = YAML.load_file(File.expand_path(config[:config]))
config[:patterns] = (yaml['patterns'] || {}).to_a
config[:excludes] = yaml['excludes'] || []
config[:deletes] = yaml['deletes'] || []
Dir.chdir(config[:repo]) do
FileUtils.rm_rf(config[:deletes]) unless config[:deletes].empty?
translate_filenames
translate_contents
end
word, translate = config[:patterns][config[:steps] - 1]
puts "Last applied: #{word} -> #{translate}."
end
def translate_filenames
each_repo_file do |file|
new_file = file.dup
# We must tokenize all patterns BEFORE replace them with a new text
each_dict_pattern do |word, translate, token|
new_file.gsub!(word, token)
rescue => e
puts "[#{file}] Error tokinization: #{word}"
raise e
end
# After all tokens have been generated it is time to translate
each_dict_pattern do |word, translate, token|
new_file.gsub!(token, translate)
rescue => e
puts "[#{file}] Error translating: #{translate}"
raise e
end
next if new_file == file
puts "Binary file renamed: #{file} -> #{new_file}" unless FileMagic.fm.file(file) =~ /text/
FileUtils.mkdir_p(File.dirname(new_file))
`git mv "#{file}" "#{new_file}"`
end
end
def translate_contents
each_repo_file do |file|
next if File.symlink?(file)
file_content = File.read(file)
hash = file_content.hash
# We must tokenize all pattern BEFORE replace it with new text
each_dict_pattern do |word, translate, token|
file_content.gsub!(word, token)
rescue => e
puts "[#{file}] Error tokinization: #{word}"
raise e
end
# After all tokens have been generated it is time to translate
each_dict_pattern do |word, translate, token|
file_content.gsub!(token, translate)
rescue => e
puts "[#{file}] Error translating: #{translate}"
raise e
end
next if hash == file_content.hash
puts "Binary content replaced: #{file}" unless FileMagic.fm.file(file) =~ /text/
File.write(file, file_content)
end
end
def each_repo_file
Dir.glob('**/*', File::FNM_DOTMATCH) do |file|
next if file =~ %r|^.git/|
next if File.directory?(file)
next if config[:excludes].include?(file)
yield file
end
end
def each_dict_pattern
config[:patterns].each_with_index do |pattern, index|
return if index >= config[:steps]
token = "TOKEN_%07d" % index
# For debug preserve tokens otherwise - replace
if config[:preserve_tokens]
yield(pattern[0], token, token)
else
yield(pattern[0], pattern[1], token)
end
end
end
end
ForkMan.new.run