-
Notifications
You must be signed in to change notification settings - Fork 219
Expand file tree
/
Copy pathRakefile
More file actions
262 lines (214 loc) · 6.87 KB
/
Rakefile
File metadata and controls
262 lines (214 loc) · 6.87 KB
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# frozen_string_literal: true
unless ENV['RACK_ENV'] == 'production'
require 'parallel_tests'
require 'rspec/core/rake_task'
require 'rubocop/rake_task'
require_relative 'lib/assets'
# Specs
RSpec::Core::RakeTask.new(:spec)
RuboCop::RakeTask.new do |task|
task.requires << 'rubocop-performance'
end
desc 'Build the main JavaScript files'
task :compile do
Assets.new.combine
end
desc 'Build the main JavaScript files and all game-specific files'
task :compile_all do
Assets.new.combine(:all)
end
desc 'Run spec in parallel'
task :spec_parallel do
ParallelTests::CLI.new.run(['--type', 'rspec'])
end
task default: %i[compile spec_parallel rubocop]
end
# Migrate
migrate = lambda do |env, version, truncate = false|
ENV['RACK_ENV'] = env
require_relative 'db'
require 'logger'
Sequel.extension :migration
DB.loggers << Logger.new($stdout) if DB.loggers.empty?
DB[:actions].truncate if truncate && DB.tables.include?(:actions)
Sequel::Migrator.apply(DB, 'migrate', version)
end
desc 'Migrate development database to latest version'
task :dev_up do
migrate.call('development', nil)
end
desc 'Migrate development database to version x (0 if no arg given)'
task :dev_down, [:version] do |_t, args|
migrate.call('development', args[:version].to_i, true)
end
desc 'Migrate development database down to version x (0 if no arg given) and then back up'
task :dev_bounce, [:version] do |_t, args|
migrate.call('development', args[:version].to_i, true)
Sequel::Migrator.apply(DB, 'migrate')
end
desc 'Migrate production database to latest version'
task :prod_up do
migrate.call('production', nil)
end
desc 'irb with -I lib/ -I assets/app/'
task :irb do
sh 'irb -I lib/ -I assets/app/'
end
# Shell
irb = proc do |env|
ENV['RACK_ENV'] = env
trap('INT', 'IGNORE')
dir, base = File.split(FileUtils::RUBY)
cmd = if base.sub!(/\Aruby/, 'irb')
File.join(dir, base)
else
"#{FileUtils::RUBY} -S irb"
end
sh "#{cmd} -r ./models"
end
desc 'Open irb shell in test mode'
task :test_irb do
irb.call('test')
end
desc 'Open irb shell in development mode'
task :dev_irb do
irb.call('development')
end
desc 'Open irb shell in production mode'
task :prod_irb do
irb.call('production')
end
# Other
desc 'Annotate Sequel models'
task 'annotate' do
ENV['RACK_ENV'] = 'development'
require_relative 'models'
DB.loggers.clear
require 'sequel/annotate'
Sequel::Annotate.annotate(Dir['models/*.rb'])
end
desc 'Precompile assets for production'
task :precompile do
require_relative 'lib/assets'
assets = Assets.new(cache: false, compress: true, gzip: true)
assets.combine(:all)
# Copy to the pin directory
git_rev = `git rev-parse --short HEAD`.strip
version_epochtime = Time.now.strftime('%s')
pin_dir = Assets::OUTPUT_BASE + Assets::PIN_DIR
File.write(Assets::OUTPUT_BASE + '/assets/version.json', JSON.dump(
hash: git_rev,
url: "https://github.com/tobymao/18xx/commit/#{git_rev}",
version_epochtime: version_epochtime,
))
FileUtils.mkdir_p(pin_dir)
assets.pin("#{pin_dir}#{git_rev}.js.gz")
assets.clean_intermediate_output_files
end
desc 'Profile loading data'
task 'stackprof', [:json] do |_task, args|
require 'stackprof'
require_relative 'lib/engine'
starttime = Time.new
StackProf.run(mode: :cpu, out: 'stackprof.dump', raw: true, interval: 10) do
10.times do
Engine::Game.load(args[:json])
end
end
endtime = Time.new
puts "#{endtime - starttime} seconds"
end
desc 'Migrate JSON'
task 'migrate_json', [:json] do |_task, args|
require_relative 'models'
require_relative 'lib/engine'
require_relative 'migrate_game'
migrate_json(args[:json])
end
desc 'Format and compress fixtures matching public/fixtures/*/<id>.json'
task 'fixture_format', [:id, :pretty] do |_task, args|
Dir.glob("public/fixtures/*/#{args[:id]}.json").each do |filename|
format_fixture_json(filename, pretty: args[:pretty])
end
end
def format_fixture_json(filename, pretty: nil)
orig_text = File.read(filename)
data = JSON.parse(orig_text)
settings = data['fixture_format'] || {}
# remove player names
data['players'].each.with_index do |player, index|
player['name'] = "Player #{index + 1}" unless /^(Player )?(\d+|[A-Z])$/.match?(player['name'])
end
data['user'] = { 'id' => 0, 'name' => 'You' } unless settings['keep_user']
data['description'] = '' unless settings['keep_description']
# remove or chats, unless chat arg was "keep"
if settings['chat'] == 'scrub'
data['actions'].each do |action|
action['message'] = 'chat' if action['type'] == 'message'
end
elsif settings['chat'] != 'keep'
data['actions'].filter! do |action|
action['type'] != 'message'
end
end
data['result'].transform_values!(&:to_i)
if data['game_end_reason'].nil?
game = Engine::Game.load(data).maybe_raise!
data['game_end_reason'] = game.game_end_reason
end
# TODO: get rid of undone actions
# if 'pretty' arg is given, any value other than "0" will produce
# readable/diffable JSON; if arg is not given or is "0", the JSON will be
# compressed to a single line with minimal whitespace
if !pretty.nil? && pretty != '0'
out_text = JSON.pretty_generate(data)
return if out_text == orig_text
File.write(filename, out_text)
puts "Wrote #{filename} in \"pretty\" format"
puts 'Use `make fixture_format` to compress it and all other fixtures before submitting a PR'
else
out_text = data.to_json
return if out_text == orig_text
File.write(filename, out_text)
puts "Wrote #{filename}"
end
end
desc 'Add game from DB to fixtures/, downloading it if necessary'
task 'fixture_import', [:id] do |_task, args|
require_relative 'db'
require_relative 'scripts/import_game'
# get game from DB
retried = false
begin
game_id = args[:id].to_i
db_game = ::Game[game_id]
raise "Cannot find game in local DB: #{game_id}" if db_game.nil?
puts 'Found game in local DB'
rescue RuntimeError => e
raise e if retried
# if game wasn't in DB, import to DB from 18xx.games API, then try once
# more
puts 'Downloading game from 18xx.games...'
import_game(game_id)
retried = true
retry
end
game = Engine::Game.load(db_game)
# get the game data needed to dump game to JSON
game_data = db_game.to_h
game_data[:actions] = game.raw_actions.map(&:to_h)
# this is required for opening fixtures in the browser at /fixture/<title>/<id>
game_data[:loaded] = true
user = 1000
group = 1000
# ensure proper fixtures dir exists
dir = File.join('public', 'fixtures', game.meta.fixture_dir_name)
FileUtils.mkdir_p(dir)
FileUtils.chown(user, group, dir)
# dump game to JSON file
filename = File.join(dir, "#{game_id}.json")
File.write(filename, JSON.pretty_generate(game_data))
FileUtils.chown(user, group, filename)
format_fixture_json(filename, pretty: true)
sh "git add '#{filename}'"
end