wolftrans 0.0.1
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 +7 -0
- data/LICENSE +363 -0
- data/README.md +42 -0
- data/bin/wolftrans +11 -0
- data/lib/wolfrpg.rb +65 -0
- data/lib/wolfrpg/command.rb +218 -0
- data/lib/wolfrpg/common_events.rb +160 -0
- data/lib/wolfrpg/database.rb +315 -0
- data/lib/wolfrpg/game_dat.rb +76 -0
- data/lib/wolfrpg/io.rb +63 -0
- data/lib/wolfrpg/map.rb +250 -0
- data/lib/wolfrpg/route.rb +36 -0
- data/lib/wolftrans.rb +169 -0
- data/lib/wolftrans/context.rb +193 -0
- data/lib/wolftrans/patch_data.rb +341 -0
- data/lib/wolftrans/patch_text.rb +319 -0
- data/wolftrans.gemspec +14 -0
- metadata +60 -0
@@ -0,0 +1,193 @@
|
|
1
|
+
module WolfTrans
|
2
|
+
# Represents the context of a translatable string
|
3
|
+
class Context
|
4
|
+
def eql?(other)
|
5
|
+
self.class == other.class
|
6
|
+
end
|
7
|
+
|
8
|
+
# Parse a string to determine context
|
9
|
+
def self.from_string(string)
|
10
|
+
pair = string.split(':', 2)
|
11
|
+
if pair.size != 2
|
12
|
+
raise "malformed context line"
|
13
|
+
end
|
14
|
+
type, path = pair
|
15
|
+
path = path.split('/')
|
16
|
+
|
17
|
+
case type
|
18
|
+
when 'MPS'
|
19
|
+
return MapEvent.from_string(path)
|
20
|
+
when 'GAMEDAT'
|
21
|
+
return GameDat.from_string(path)
|
22
|
+
when 'DB'
|
23
|
+
return Database.from_string(path)
|
24
|
+
when 'COMMONEVENT'
|
25
|
+
return CommonEvent.from_string(path)
|
26
|
+
end
|
27
|
+
raise "unrecognized context type '#{type}'"
|
28
|
+
end
|
29
|
+
|
30
|
+
class MapEvent < Context
|
31
|
+
attr_reader :map_name
|
32
|
+
attr_reader :event_num
|
33
|
+
attr_reader :page_num
|
34
|
+
attr_reader :line_num
|
35
|
+
attr_reader :command_name
|
36
|
+
|
37
|
+
def initialize(map_name, event_num, page_num, line_num, command_name)
|
38
|
+
@map_name = map_name
|
39
|
+
@event_num = event_num
|
40
|
+
@page_num = page_num
|
41
|
+
@line_num = line_num
|
42
|
+
@command_name = command_name
|
43
|
+
end
|
44
|
+
|
45
|
+
def eql?(other)
|
46
|
+
super &&
|
47
|
+
@map_name == other.map_name &&
|
48
|
+
@event_num == other.event_num &&
|
49
|
+
@page_num == other.page_num
|
50
|
+
end
|
51
|
+
|
52
|
+
def hash
|
53
|
+
[@map_name, @event_num, @page_num].hash
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_s
|
57
|
+
"MPS:#{@map_name}/events/#{@event_num}/pages/#{@page_num}/#{@line_num}/#{@command_name}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.from_data(map_name, event, page, cmd_index, command)
|
61
|
+
MapEvent.new(map_name, event.id, page.id + 1, cmd_index + 1, command.class.name.split('::').last)
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.from_string(path)
|
65
|
+
map_name, events_str, event_num, pages_str, page_num, line_num, command_name = path
|
66
|
+
if events_str != 'events' || pages_str != 'pages'
|
67
|
+
raise "unexpected path element in MPS context line"
|
68
|
+
end
|
69
|
+
MapEvent.new(map_name, event_num.to_i, page_num.to_i, line_num.to_i, command_name)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class CommonEvent < Context
|
74
|
+
attr_reader :event_num
|
75
|
+
attr_reader :line_num
|
76
|
+
attr_reader :command_name
|
77
|
+
|
78
|
+
def initialize(event_num, line_num, command_name)
|
79
|
+
@event_num = event_num
|
80
|
+
@line_num = line_num
|
81
|
+
@command_name = command_name
|
82
|
+
end
|
83
|
+
|
84
|
+
def eql?(other)
|
85
|
+
super && @event_num == other.event_num
|
86
|
+
end
|
87
|
+
|
88
|
+
def hash
|
89
|
+
@event_num.hash
|
90
|
+
end
|
91
|
+
|
92
|
+
def to_s
|
93
|
+
"COMMONEVENT:#{@event_num}/#{@line_num}/#{@command_name}"
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.from_data(event, cmd_index, command)
|
97
|
+
CommonEvent.new(event.id, cmd_index + 1, command.class.name.split('::').last)
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.from_string(path)
|
101
|
+
event_num, line_num, command_name = path
|
102
|
+
CommonEvent.new(event_num.to_i, line_num.to_i, command_name)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
class GameDat < Context
|
107
|
+
attr_reader :name
|
108
|
+
|
109
|
+
def initialize(name)
|
110
|
+
@name = name
|
111
|
+
end
|
112
|
+
|
113
|
+
def eql?(other)
|
114
|
+
super && @name == other.name
|
115
|
+
end
|
116
|
+
|
117
|
+
def hash
|
118
|
+
@name.hash
|
119
|
+
end
|
120
|
+
|
121
|
+
def to_s
|
122
|
+
"GAMEDAT:#{@name}"
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.from_data(name)
|
126
|
+
GameDat.new(name)
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.from_string(path)
|
130
|
+
if path.size != 1
|
131
|
+
raise "invalid path specified for GAMEDAT context line"
|
132
|
+
end
|
133
|
+
GameDat.new(path.first)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
class Database < Context
|
138
|
+
attr_reader :db_name
|
139
|
+
attr_reader :type_index
|
140
|
+
attr_reader :type_name
|
141
|
+
attr_reader :datum_index
|
142
|
+
attr_reader :datum_name
|
143
|
+
attr_reader :field_index
|
144
|
+
attr_reader :field_name
|
145
|
+
|
146
|
+
def initialize(db_name, type_index, type_name, datum_index, datum_name, field_index, field_name)
|
147
|
+
@db_name = db_name
|
148
|
+
@type_index = type_index
|
149
|
+
@type_name = WolfTrans.full_strip(type_name)
|
150
|
+
@datum_index = datum_index
|
151
|
+
@datum_name = WolfTrans.full_strip(datum_name)
|
152
|
+
@field_index = field_index
|
153
|
+
@field_name = WolfTrans.full_strip(field_name)
|
154
|
+
end
|
155
|
+
|
156
|
+
def eql?(other)
|
157
|
+
super &&
|
158
|
+
@db_name == db_name &&
|
159
|
+
@type_index == other.type_index &&
|
160
|
+
@datum_index == other.datum_index &&
|
161
|
+
@field_index == other.field_index
|
162
|
+
end
|
163
|
+
|
164
|
+
def hash
|
165
|
+
[@db_name, @type_index, @datum_index, @field_index].hash
|
166
|
+
end
|
167
|
+
|
168
|
+
def to_s
|
169
|
+
"DB:#{@db_name}/[#{@type_index}]#{@type_name}/[#{@datum_index}]#{@datum_name}/[#{@field_index}]#{@field_name}"
|
170
|
+
end
|
171
|
+
|
172
|
+
def self.from_data(db_name, type_index, type, datum_index, datum, field)
|
173
|
+
Database.new(db_name, type_index, type.name, datum_index, datum.name, field.index, field.name)
|
174
|
+
end
|
175
|
+
|
176
|
+
def self.from_string(path)
|
177
|
+
if path.size != 4
|
178
|
+
raise "invalid path specified for DB context line"
|
179
|
+
end
|
180
|
+
indices = Array.new(3)
|
181
|
+
path.each_with_index do |str, i|
|
182
|
+
next if i == 0
|
183
|
+
str.match(/^\[\d+\]/) do |m|
|
184
|
+
indices[i-1] = m.to_s[1..-2].to_i
|
185
|
+
end
|
186
|
+
str.sub!(/^\[\d+\]/, '')
|
187
|
+
end
|
188
|
+
|
189
|
+
Database.new(path[0], indices[0], path[1], indices[1], path[2], indices[2], path[3])
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
@@ -0,0 +1,341 @@
|
|
1
|
+
require 'wolftrans/context'
|
2
|
+
require 'wolfrpg'
|
3
|
+
|
4
|
+
require 'fileutils'
|
5
|
+
require 'find'
|
6
|
+
|
7
|
+
#####################
|
8
|
+
# Loading Game data #
|
9
|
+
module WolfTrans
|
10
|
+
class Patch
|
11
|
+
def load_data(game_dir)
|
12
|
+
@game_dir = WolfTrans.sanitize_path(game_dir)
|
13
|
+
unless Dir.exist? @game_dir
|
14
|
+
raise "could not find game folder '#{@game_dir}'"
|
15
|
+
end
|
16
|
+
@game_data_dir = WolfTrans.join_path_nocase(@game_dir, 'data')
|
17
|
+
if @game_data_dir == nil
|
18
|
+
raise "could not find data folder in '#{@game_dir}'"
|
19
|
+
end
|
20
|
+
|
21
|
+
@maps = {}
|
22
|
+
@databases = {}
|
23
|
+
|
24
|
+
# Find and read all necessary data
|
25
|
+
Dir.entries(@game_data_dir).each do |parent_name|
|
26
|
+
parent_name_downcase = parent_name.downcase
|
27
|
+
next unless ['basicdata', 'mapdata'].include? parent_name_downcase
|
28
|
+
parent_path = "#{@game_data_dir}/#{parent_name}"
|
29
|
+
Dir.entries(parent_path).each do |basename|
|
30
|
+
basename_downcase = basename.downcase
|
31
|
+
extension = File.extname(basename_downcase)
|
32
|
+
basename_noext = File.basename(basename_downcase, '.*')
|
33
|
+
filename = "#{parent_path}/#{basename}"
|
34
|
+
case parent_name_downcase
|
35
|
+
when 'mapdata'
|
36
|
+
load_map(filename) if extension == '.mps'
|
37
|
+
when 'basicdata'
|
38
|
+
if basename_downcase == 'game.dat'
|
39
|
+
load_game_dat(filename)
|
40
|
+
elsif extension == '.project'
|
41
|
+
next if basename_downcase == 'sysdatabasebasic.project'
|
42
|
+
dat_filename = WolfTrans.join_path_nocase(parent_path, "#{basename_noext}.dat")
|
43
|
+
next if dat_filename == nil
|
44
|
+
load_game_database(filename, dat_filename)
|
45
|
+
elsif basename_downcase == 'commonevent.dat'
|
46
|
+
load_common_events(filename)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Apply the patch to the files in the game path and write them to the
|
54
|
+
# output directory
|
55
|
+
def apply(out_dir)
|
56
|
+
out_dir = WolfTrans.sanitize_path(out_dir)
|
57
|
+
out_data_dir = "#{out_dir}/Data"
|
58
|
+
|
59
|
+
# Clear out directory
|
60
|
+
FileUtils.rm_rf(out_dir)
|
61
|
+
|
62
|
+
# Patch all the maps and dump them
|
63
|
+
FileUtils.mkdir_p("#{out_data_dir}/MapData")
|
64
|
+
@maps.each do |map_name, map|
|
65
|
+
map.events.each do |event|
|
66
|
+
event.pages.each do |page|
|
67
|
+
page.commands.each_with_index do |command, cmd_index|
|
68
|
+
context = Context::MapEvent.from_data(map_name, event, page, cmd_index, command)
|
69
|
+
patch_command(command, context)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
map.dump("#{out_data_dir}/MapData/#{map_name}.mps")
|
74
|
+
end
|
75
|
+
|
76
|
+
# Patch the databases
|
77
|
+
FileUtils.mkdir_p("#{out_data_dir}/BasicData")
|
78
|
+
@databases.each do |db_name, db|
|
79
|
+
db.types.each_with_index do |type, type_index|
|
80
|
+
next if type.name.empty?
|
81
|
+
type.data.each_with_index do |datum, datum_index|
|
82
|
+
datum.each_translatable do |str, field|
|
83
|
+
context = Context::Database.from_data(db_name, type_index, type, datum_index, datum, field)
|
84
|
+
yield_translation(str, context) do |newstr|
|
85
|
+
datum[field] = newstr
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
name_noext = "#{out_data_dir}/BasicData/#{db_name}"
|
91
|
+
db.dump("#{name_noext}.project", "#{name_noext}.dat")
|
92
|
+
end
|
93
|
+
|
94
|
+
# Patch the common events
|
95
|
+
@common_events.events.each do |event|
|
96
|
+
event.commands.each_with_index do |command, cmd_index|
|
97
|
+
context = Context::CommonEvent.from_data(event, cmd_index, command)
|
98
|
+
patch_command(command, context)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
@common_events.dump("#{out_data_dir}/BasicData/CommonEvent.dat")
|
102
|
+
|
103
|
+
# Patch Game.dat
|
104
|
+
FileUtils.mkdir_p("#{out_data_dir}/BasicData")
|
105
|
+
patch_game_dat
|
106
|
+
@game_dat.dump("#{out_data_dir}/BasicData/Game.dat")
|
107
|
+
|
108
|
+
# Copy image files
|
109
|
+
[
|
110
|
+
'BattleEffect',
|
111
|
+
'CharaChip',
|
112
|
+
'EnemyGraphic',
|
113
|
+
'Fog_BackGround',
|
114
|
+
'MapChip',
|
115
|
+
'Picture',
|
116
|
+
'SystemFile',
|
117
|
+
].each do |dirname|
|
118
|
+
copy_data_files(out_data_dir, dirname, ['png','jpg','jpeg','bmp'])
|
119
|
+
end
|
120
|
+
|
121
|
+
# Copy sound/music files
|
122
|
+
[
|
123
|
+
'BGM',
|
124
|
+
'SE',
|
125
|
+
'SystemFile',
|
126
|
+
].each do |dirname|
|
127
|
+
copy_data_files(out_data_dir, dirname, ['ogg','mp3','wav','mid','midi'])
|
128
|
+
end
|
129
|
+
|
130
|
+
# Copy BasicData
|
131
|
+
copy_data_files(out_data_dir, 'BasicData', ['dat','project','xxxxx','png'])
|
132
|
+
|
133
|
+
# Copy fonts
|
134
|
+
copy_data_files(out_data_dir, '', ['ttf','ttc'])
|
135
|
+
|
136
|
+
# Copy remainder of files in the base patch/game dirs
|
137
|
+
copy_files(@patch_assets_dir, @patch_data_dir, out_dir)
|
138
|
+
copy_files(@game_dir, @game_data_dir, out_dir)
|
139
|
+
end
|
140
|
+
|
141
|
+
private
|
142
|
+
def load_map(filename)
|
143
|
+
map_name = File.basename(filename, '.*')
|
144
|
+
patch_filename = "dump/mps/#{map_name}.txt"
|
145
|
+
|
146
|
+
map = WolfRpg::Map.new(filename)
|
147
|
+
map.events.each do |event|
|
148
|
+
event.pages.each do |page|
|
149
|
+
page.commands.each_with_index do |command, cmd_index|
|
150
|
+
strings_of_command(command) do |string|
|
151
|
+
@strings[string][Context::MapEvent.from_data(map_name, event, page, cmd_index, command)] ||=
|
152
|
+
Translation.new(patch_filename)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
@maps[map_name] = map
|
158
|
+
end
|
159
|
+
|
160
|
+
def load_game_dat(filename)
|
161
|
+
patch_filename = 'dump/GameDat.txt'
|
162
|
+
@game_dat = WolfRpg::GameDat.new(filename)
|
163
|
+
unless @game_dat.title.empty?
|
164
|
+
@strings[@game_dat.title][Context::GameDat.from_data('Title')] = Translation.new(patch_filename)
|
165
|
+
end
|
166
|
+
unless @game_dat.version.empty?
|
167
|
+
@strings[@game_dat.version][Context::GameDat.from_data('Version')] = Translation.new(patch_filename)
|
168
|
+
end
|
169
|
+
unless @game_dat.font.empty?
|
170
|
+
@strings[@game_dat.font][Context::GameDat.from_data('Font')] = Translation.new(patch_filename)
|
171
|
+
end
|
172
|
+
@game_dat.subfonts.each_with_index do |sf, i|
|
173
|
+
unless sf.empty?
|
174
|
+
name = 'SubFont' + (i + 1).to_s
|
175
|
+
@strings[sf][Context::GameDat.from_data(name)] ||=
|
176
|
+
Translation.new(patch_filename)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def load_game_database(project_filename, dat_filename)
|
182
|
+
db = WolfRpg::Database.new(project_filename, dat_filename)
|
183
|
+
db.types.each_with_index do |type, type_index|
|
184
|
+
next if type.name.empty?
|
185
|
+
patch_filename = "dump/db/#{db.name}/#{WolfTrans.escape_path(type.name)}.txt"
|
186
|
+
type.data.each_with_index do |datum, datum_index|
|
187
|
+
datum.each_translatable do |str, field|
|
188
|
+
context = Context::Database.from_data(db.name, type_index, type, datum_index, datum, field)
|
189
|
+
@strings[str][context] ||= Translation.new(patch_filename)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
@databases[db.name] = db
|
194
|
+
end
|
195
|
+
|
196
|
+
def load_common_events(filename)
|
197
|
+
@common_events = WolfRpg::CommonEvents.new(filename)
|
198
|
+
@common_events.events.each do |event|
|
199
|
+
patch_filename = "dump/common/#{'%03d' % event.id}_#{WolfTrans.escape_path(event.name)}.txt"
|
200
|
+
event.commands.each_with_index do |command, cmd_index|
|
201
|
+
strings_of_command(command) do |string|
|
202
|
+
@strings[string][Context::CommonEvent.from_data(event, cmd_index, command)] ||=
|
203
|
+
Translation.new(patch_filename)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def strings_of_command(command)
|
210
|
+
case command
|
211
|
+
when WolfRpg::Command::Message
|
212
|
+
yield command.text unless command.text.empty?
|
213
|
+
when WolfRpg::Command::Choices
|
214
|
+
command.text.each do |s|
|
215
|
+
yield s
|
216
|
+
end
|
217
|
+
when WolfRpg::Command::StringCondition
|
218
|
+
command.string_args.each do |s|
|
219
|
+
yield s unless s.empty?
|
220
|
+
end
|
221
|
+
when WolfRpg::Command::SetString
|
222
|
+
yield command.text unless command.text.empty?
|
223
|
+
when WolfRpg::Command::Picture
|
224
|
+
if command.type == :text
|
225
|
+
yield command.text unless command.text.empty?
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def patch_command(command, context)
|
231
|
+
case command
|
232
|
+
when WolfRpg::Command::Message
|
233
|
+
yield_translation(command.text, context) do |str|
|
234
|
+
command.text = str
|
235
|
+
end
|
236
|
+
when WolfRpg::Command::Choices
|
237
|
+
command.text.each_with_index do |text, i|
|
238
|
+
yield_translation(text, context) do |str|
|
239
|
+
command.text[i] = str
|
240
|
+
end
|
241
|
+
end
|
242
|
+
when WolfRpg::Command::StringCondition
|
243
|
+
command.string_args.each_with_index do |arg, i|
|
244
|
+
next if arg.empty?
|
245
|
+
yield_translation(arg, context) do |str|
|
246
|
+
command.string_args[i] = str
|
247
|
+
end
|
248
|
+
end
|
249
|
+
when WolfRpg::Command::SetString
|
250
|
+
yield_translation(command.text, context) do |str|
|
251
|
+
command.text = str
|
252
|
+
end
|
253
|
+
when WolfRpg::Command::Picture
|
254
|
+
if command.type == :text
|
255
|
+
yield_translation(command.text, context) do |str|
|
256
|
+
command.text = str
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
def patch_game_dat
|
263
|
+
yield_translation(@game_dat.title, Context::GameDat.from_data('Title')) do |str|
|
264
|
+
@game_dat.title = str
|
265
|
+
end
|
266
|
+
yield_translation(@game_dat.version, Context::GameDat.from_data('Version')) do |str|
|
267
|
+
@game_dat.version = str
|
268
|
+
end
|
269
|
+
yield_translation(@game_dat.font, Context::GameDat.from_data('Font')) do |str|
|
270
|
+
@game_dat.font = str
|
271
|
+
end
|
272
|
+
@game_dat.subfonts.each_with_index do |sf, i|
|
273
|
+
name = 'SubFont' + (i + 1).to_s
|
274
|
+
yield_translation(sf, Context::GameDat.from_data(name)) do |str|
|
275
|
+
@game_dat.subfonts[i] = str
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
# Yield a translation for the given string and context if it exists
|
281
|
+
def yield_translation(string, context)
|
282
|
+
return if string.empty?
|
283
|
+
if @strings.include? string
|
284
|
+
unless @strings[string][context].string.empty?
|
285
|
+
yield @strings[string][context].string
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
# Copy normal, non-data files
|
291
|
+
def copy_files(src_dir, src_data_dir, out_dir)
|
292
|
+
Find.find(src_dir) do |path|
|
293
|
+
next if path == src_dir
|
294
|
+
Find.prune if path == src_data_dir
|
295
|
+
short_path = path[src_dir.length+1..-1]
|
296
|
+
Find.prune if @file_blacklist.include? short_path.downcase
|
297
|
+
out_path = "#{out_dir}/#{short_path}"
|
298
|
+
if FileTest.directory? path
|
299
|
+
FileUtils.mkdir_p(out_path)
|
300
|
+
else
|
301
|
+
next if ['thumbs.db', 'desktop.ini', '.ds_store'].include? File.basename(path).downcase
|
302
|
+
FileUtils.cp(path, out_path) unless File.exist? out_path
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
# Copy data files
|
308
|
+
def copy_data_files(out_data_dir, dirname, extensions)
|
309
|
+
copy_data_files_from(@game_data_dir, out_data_dir, dirname, extensions)
|
310
|
+
if @patch_data_dir
|
311
|
+
copy_data_files_from(@patch_data_dir, out_data_dir, dirname, extensions)
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
def copy_data_files_from(src_data_dir, out_data_dir, dirname, extensions)
|
316
|
+
out_dir = File.join(out_data_dir, dirname)
|
317
|
+
FileUtils.mkdir_p(out_dir)
|
318
|
+
|
319
|
+
Find.find(src_data_dir) do |path|
|
320
|
+
if dirname.empty?
|
321
|
+
if FileTest.directory? path
|
322
|
+
Find.prune if path != src_data_dir
|
323
|
+
next
|
324
|
+
end
|
325
|
+
else
|
326
|
+
next if path == src_data_dir
|
327
|
+
if FileTest.directory?(path)
|
328
|
+
Find.prune unless File.basename(path).casecmp(dirname) == 0
|
329
|
+
next
|
330
|
+
end
|
331
|
+
next if File.dirname(path) == src_data_dir
|
332
|
+
end
|
333
|
+
basename = File.basename(path)
|
334
|
+
next unless extensions.include? File.extname(basename)[1..-1]
|
335
|
+
next if @file_blacklist.include? "data/#{dirname.downcase}/#{basename.downcase}"
|
336
|
+
out_name = "#{out_dir}/#{basename}"
|
337
|
+
FileUtils.cp(path, out_name) unless File.exist? out_name
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|