web_server_config_generator 0.0.8 → 0.0.9
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.
data/bin/web_server_setup
CHANGED
@@ -11,6 +11,8 @@ require 'optparse'
|
|
11
11
|
require 'yaml'
|
12
12
|
$:.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
|
13
13
|
require 'web_server_config_generator'
|
14
|
+
require 'web_server_config_generator/pathname'
|
15
|
+
require 'web_server_config_generator/generator'
|
14
16
|
require 'web_server_config_generator/project_directory'
|
15
17
|
require 'web_server_config_generator/sub_uri_project'
|
16
18
|
|
@@ -41,18 +43,18 @@ opts = OptionParser.new do |opts|
|
|
41
43
|
$ENVS << env
|
42
44
|
end
|
43
45
|
|
44
|
-
opts.on("-n", "--list-hosts",
|
45
|
-
"list generated hostnames, useful for setting up the hosts file on your own") do
|
46
|
+
opts.on("-n", "--list-hosts", "list generated hostnames, useful for setting up the hosts file on your own") do
|
46
47
|
$PRINT_HOSTS = true
|
47
48
|
end
|
48
49
|
|
49
50
|
opts.on("-c", "--create-web-server-files-dir",
|
50
|
-
"create web_server_files directory (useful the first time you run this script)
|
51
|
+
"create web_server_files directory (useful the first time you run this script)",
|
52
|
+
" in this case the supplied (or assumed) directory will be set as the",
|
53
|
+
" 'projects' directory") do
|
51
54
|
$CREATE_WEB_SERVER_FILES_DIR = true
|
52
55
|
end
|
53
56
|
|
54
|
-
opts.on("-p", "--projects-dir DIR",
|
55
|
-
"specify the directory containing all your projects") do |dir|
|
57
|
+
opts.on("-p", "--projects-dir DIR", "specify the directory containing all your projects") do |dir|
|
56
58
|
$PROJECTS_DIRECTORY = dir
|
57
59
|
end
|
58
60
|
|
@@ -61,45 +63,29 @@ opts = OptionParser.new do |opts|
|
|
61
63
|
$WEB_SERVER_FILES_DIR = File.expand_path(path)
|
62
64
|
end
|
63
65
|
|
64
|
-
opts.on("-a", "--[no-]add-hosts",
|
65
|
-
"add ghost entries for generated hostnames, requires ghost gem") do |b|
|
66
|
+
opts.on("-a", "--[no-]add-hosts", "add ghost entries for generated hostnames, requires ghost gem") do |b|
|
66
67
|
$ADD_HOSTS = b
|
67
68
|
end
|
68
69
|
|
69
|
-
opts.on("-
|
70
|
-
|
71
|
-
$RESTART_NGINX = b
|
70
|
+
opts.on("-d", "--delete-hosts", "delete ghost entries added by this script, requires ghost gem") do |b|
|
71
|
+
$DELETE_HOSTS = b
|
72
72
|
end
|
73
73
|
|
74
|
-
opts.on("-
|
75
|
-
|
76
|
-
$VERBOSE = true
|
74
|
+
opts.on("-r", "--[no-]restart-nginx", "restart nginx at the end") do |b|
|
75
|
+
$RESTART_NGINX = b
|
77
76
|
end
|
78
77
|
|
79
|
-
opts.on("-
|
80
|
-
|
81
|
-
$TEST_MODE = true
|
78
|
+
opts.on("-v", "--verbose", "verbose") do
|
79
|
+
$VERBOSE = true
|
82
80
|
end
|
83
81
|
|
84
|
-
#
|
85
|
-
#
|
86
|
-
# "Edit ARGV files in place",
|
87
|
-
# " (make backup if EXTENSION supplied)") do |ext|
|
88
|
-
# options.inplace = true
|
89
|
-
# options.extension = ext || ''
|
90
|
-
# options.extension.sub!(/\A\.?(?=.)/, ".") # Ensure extension begins with dot.
|
91
|
-
# end
|
92
|
-
|
93
|
-
# # Boolean switch.
|
94
|
-
# opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
|
95
|
-
# options.verbose = v
|
82
|
+
# opts.on("-t", "--test-mode", "test mode; do not modify the FS, just print messsages") do
|
83
|
+
# $TEST_MODE = true
|
96
84
|
# end
|
97
85
|
|
98
86
|
opts.separator ""
|
99
87
|
opts.separator "Common options:"
|
100
88
|
|
101
|
-
# No argument, shows at tail. This will print an options summary.
|
102
|
-
# Try it and see!
|
103
89
|
opts.on_tail("-h", "--help", "Show this message") do
|
104
90
|
puts opts
|
105
91
|
exit
|
@@ -108,382 +94,13 @@ end
|
|
108
94
|
|
109
95
|
opts.parse!(ARGV)
|
110
96
|
|
111
|
-
def agree( yes_or_no_question, character = nil )
|
112
|
-
ask(yes_or_no_question, lambda { |yn| yn.downcase[0] == ?y}) do |q|
|
113
|
-
q.validate = /\Ay(?:es)?|no?\Z/i
|
114
|
-
q.responses[:not_valid] = 'Please enter "yes" or "no".'
|
115
|
-
q.responses[:ask_on_error] = :question
|
116
|
-
q.character = character
|
117
|
-
yield q if block_given?
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
module WebServerSetup
|
122
|
-
WEB_SERVER_FILES_DIR_NAME = ".webconfig"
|
123
|
-
|
124
|
-
class Directory < Pathname
|
125
|
-
def +(other)
|
126
|
-
other = self.class.new(other) unless self.class === other
|
127
|
-
self.class.new(plus(@path, other.to_s))
|
128
|
-
end
|
129
|
-
|
130
|
-
def mkpath
|
131
|
-
if $TEST_MODE
|
132
|
-
puts "test mode: mkpath #{self}"
|
133
|
-
else
|
134
|
-
super
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
def write(arg)
|
139
|
-
if $TEST_MODE
|
140
|
-
puts "test mode: write #{self}, #{arg.to_s[0, 100]}..."
|
141
|
-
else
|
142
|
-
FileUtils.mkdir_p File.dirname(self)
|
143
|
-
self.open("w") { |f| f.write arg }
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
def read
|
148
|
-
if self.exist?
|
149
|
-
self.open("r") { |f| f.read }
|
150
|
-
else
|
151
|
-
""
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
class Generator
|
157
|
-
def initialize(options)
|
158
|
-
options.each do |opt, val|
|
159
|
-
instance_variable_set("@#{opt}", val)
|
160
|
-
end
|
161
|
-
|
162
|
-
@starting_port = options[:starting_port] || 40000
|
163
|
-
@port_pool_size = options[:port_pool_size] || 10000
|
164
|
-
|
165
|
-
@environment_map = Hash.new(options[:environments]) if options[:environments]
|
166
|
-
|
167
|
-
setup_config_dir
|
168
|
-
|
169
|
-
@project_or_projects_dir ||= projects_dir
|
170
|
-
end
|
171
|
-
|
172
|
-
def write_conf_files
|
173
|
-
FileUtils.cd projects_dir do
|
174
|
-
# generate files for each proj/env
|
175
|
-
list_of_conf_files = []
|
176
|
-
app_projects.each do |p|
|
177
|
-
environment_map[p].each do |env|
|
178
|
-
list_of_conf_files << write_conf_file(p, env)
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
sub_uri_projects.each do |p|
|
183
|
-
create_sub_uri_links_dir p
|
184
|
-
list_of_conf_files << write_conf_file(p, p.env)
|
185
|
-
end
|
186
|
-
|
187
|
-
current_lines = []
|
188
|
-
web_server_vhost_nginx_conf.read.each_line { |l| current_lines << l }
|
189
|
-
new_lines = current_lines + list_of_conf_files.map { |p| "include #{p};\n" }
|
190
|
-
new_lines.uniq!
|
191
|
-
new_lines.sort!
|
192
|
-
web_server_vhost_nginx_conf.write(new_lines.join)
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
def create_sub_uri_links_dir(sub_uri_project)
|
197
|
-
env = sub_uri_project.env
|
198
|
-
|
199
|
-
web_server_sub_uri_apps_dir.mkdir unless web_server_sub_uri_apps_dir.exist?
|
200
|
-
links_dir = web_server_sub_uri_apps_dir + sub_uri_project.server_name
|
201
|
-
links_dir.mkdir unless links_dir.exist?
|
202
|
-
sub_uri_project.projects.each do |p|
|
203
|
-
symlink p.expand_path + "public", File.join(links_dir, p.relative_root_url_for_env(env))
|
204
|
-
if p.relative_root_url_root_for_env(env)
|
205
|
-
symlink p.expand_path + "public", File.join(links_dir, "root")
|
206
|
-
end
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
def server_names
|
211
|
-
projects.map { |p| p.server_names }.flatten.uniq
|
212
|
-
end
|
213
|
-
|
214
|
-
def add_ghost_entries
|
215
|
-
current_hosts = Host.list
|
216
|
-
already_correct = []
|
217
|
-
added = []
|
218
|
-
present_but_incorrect = []
|
219
|
-
server_names.each do |server_name|
|
220
|
-
if host = current_hosts.detect { |h| h.name == server_name }
|
221
|
-
if host.ip == "127.0.0.1"
|
222
|
-
already_correct << host
|
223
|
-
else
|
224
|
-
present_but_incorrect << host
|
225
|
-
end
|
226
|
-
else
|
227
|
-
if $TEST_MODE
|
228
|
-
puts "would have added #{server_name} -> 127.0.0.1"
|
229
|
-
else
|
230
|
-
added << Host.add(server_name)
|
231
|
-
end
|
232
|
-
end
|
233
|
-
end
|
234
|
-
|
235
|
-
if already_correct.size > 0
|
236
|
-
puts "\n#{already_correct.size} hosts were already setup correctly"
|
237
|
-
puts
|
238
|
-
end
|
239
|
-
|
240
|
-
if added.size > 0
|
241
|
-
puts "The following hostnames were added for 127.0.0.1:"
|
242
|
-
puts added.map { |h| " #{h.name}\n" }
|
243
|
-
puts
|
244
|
-
end
|
245
|
-
|
246
|
-
if present_but_incorrect.size > 0
|
247
|
-
puts "The following hostnames were present, but didn't map to 127.0.0.1:"
|
248
|
-
pad = present_but_incorrect.max{|a,b| a.to_s.length <=> b.to_s.length }.to_s.length
|
249
|
-
puts present_but_incorrect.map { |h| "#{h.name.rjust(pad+2)} -> #{h.ip}\n" }
|
250
|
-
puts
|
251
|
-
end
|
252
|
-
end
|
253
|
-
|
254
|
-
def setup_config_dir
|
255
|
-
unless File.exist?(config_dir)
|
256
|
-
unless dir = $PROJECTS_DIRECTORY
|
257
|
-
puts "It looks like this is the first time you've run me."
|
258
|
-
puts
|
259
|
-
dir = @project_or_projects_dir || FileUtils.pwd
|
260
|
-
unless agree("setup #{dir} as your projects dir? [Y/n]") { |q| q.default = "Y"}
|
261
|
-
puts "for your first run you'll need to supply your projects directory"
|
262
|
-
exit
|
263
|
-
end
|
264
|
-
puts "setting up config dir"
|
265
|
-
end
|
266
|
-
|
267
|
-
FileUtils.mkdir_p config_dir
|
268
|
-
initial_config = { :projects_dirs => [File.expand_path(dir)]}
|
269
|
-
save_global_config(initial_config)
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
def symlink(link_target, link_name)
|
274
|
-
if File.exist?(link_name)
|
275
|
-
if FileTest.symlink?(link_name)
|
276
|
-
unless Pathname.new(link_name).realpath == Pathname.new(link_target).realpath
|
277
|
-
puts "symlink '#{link_name}' exists, but doesn't appear to link to the correct place"
|
278
|
-
end
|
279
|
-
else
|
280
|
-
puts "couldn't make symlink '#{link_name}', something's already there"
|
281
|
-
end
|
282
|
-
else
|
283
|
-
File.symlink link_target, link_name
|
284
|
-
end
|
285
|
-
end
|
286
|
-
|
287
|
-
def setup_webserver_links_dir
|
288
|
-
web_server_links_dir.mkpath
|
289
|
-
environments.each do |e|
|
290
|
-
link_name = web_server_links_dir + e
|
291
|
-
symlink(projects_dir, link_name)
|
292
|
-
end
|
293
|
-
end
|
294
|
-
|
295
|
-
def app_projects
|
296
|
-
@app_projects ||=
|
297
|
-
begin
|
298
|
-
find_project_and_symlink_dirs
|
299
|
-
@app_projects
|
300
|
-
end
|
301
|
-
end
|
302
|
-
|
303
|
-
def sub_uri_projects
|
304
|
-
return @sub_uri_projects if @sub_uri_projects
|
305
|
-
server_name_env_project_map = {}
|
306
|
-
app_projects.each do |p|
|
307
|
-
p.server_name_env_pairs.each do |server_name, env|
|
308
|
-
server_name_env_project_map[server_name] ||= {}
|
309
|
-
server_name_env_project_map[server_name][:env] ||= env
|
310
|
-
raise "can't have one hostname map to multiple envs" if server_name_env_project_map[server_name][:env] != env
|
311
|
-
server_name_env_project_map[server_name][:projects] ||= []
|
312
|
-
server_name_env_project_map[server_name][:projects] << p
|
313
|
-
end
|
314
|
-
end
|
315
|
-
server_name_env_project_map = server_name_env_project_map.select do |server_name, env_and_projects|
|
316
|
-
# more than one project with the same server_name
|
317
|
-
# don't count projects that evaluate to the same path
|
318
|
-
env_and_projects[:projects].map { |p| p.realpath }.uniq.size > 1
|
319
|
-
end
|
320
|
-
@sub_uri_projects = server_name_env_project_map.map do |server_name, env_and_projects|
|
321
|
-
WebServerConfigGenerator::SubUriProject.new(server_name, env_and_projects, self)
|
322
|
-
end
|
323
|
-
end
|
324
|
-
|
325
|
-
def projects
|
326
|
-
app_projects + sub_uri_projects
|
327
|
-
end
|
328
|
-
|
329
|
-
def environments
|
330
|
-
@environments ||= environment_map.values.flatten.uniq
|
331
|
-
end
|
332
97
|
|
333
|
-
|
334
|
-
web_server_vhost_nginx_dir + "projects.conf"
|
335
|
-
end
|
336
|
-
|
337
|
-
def check_nginx_conf
|
338
|
-
unless nginx_conf =~ /include.*#{web_server_vhost_nginx_conf}/
|
339
|
-
puts "\nWarning: You'll need to make sure this line is in your nginx config, in the http block:"
|
340
|
-
puts " include #{web_server_vhost_nginx_conf};"
|
341
|
-
end
|
342
|
-
|
343
|
-
unless nginx_conf =~ /server_names_hash_bucket_size.*128/
|
344
|
-
puts "\nWarning: Couldn't find the following line in your nginx conf. It should be in the http block."
|
345
|
-
puts " server_names_hash_bucket_size 128;"
|
346
|
-
end
|
347
|
-
end
|
348
|
-
|
349
|
-
def prompt_to_restart_nginx
|
350
|
-
puts
|
351
|
-
if $RESTART_NGINX || ($RESTART_NGINX.nil? && agree("Restart nginx? [Y/n]") { |q| q.default = "Y"})
|
352
|
-
puts "Restarting nginx..."
|
353
|
-
cmd = "sudo killall nginx; sleep 1 && sudo #{nginx}"
|
354
|
-
puts "running: #{cmd}"
|
355
|
-
system cmd
|
356
|
-
end
|
357
|
-
end
|
358
|
-
|
359
|
-
def web_server_links_dir
|
360
|
-
config_dir + "links"
|
361
|
-
end
|
362
|
-
|
363
|
-
def projects_dir
|
364
|
-
WebServerSetup::Directory.new(global_config[:projects_dirs].first).expand_path
|
365
|
-
end
|
366
|
-
|
367
|
-
def web_server_sub_uri_apps_dir
|
368
|
-
config_dir + "sub_uri_apps"
|
369
|
-
end
|
370
|
-
|
371
|
-
private
|
372
|
-
|
373
|
-
def config_dir
|
374
|
-
@config_dir ||=
|
375
|
-
begin
|
376
|
-
Directory.new $WEB_SERVER_FILES_DIR || begin
|
377
|
-
raise "Couldn't fine $HOME" unless home_dir = ENV["HOME"]
|
378
|
-
File.join(home_dir, ".webconfig")
|
379
|
-
end
|
380
|
-
end
|
381
|
-
end
|
382
|
-
|
383
|
-
def global_config(reload = false)
|
384
|
-
@global_config = nil if reload
|
385
|
-
@global_config ||= YAML.load_file(global_config_path)
|
386
|
-
end
|
387
|
-
|
388
|
-
def save_global_config(config)
|
389
|
-
@global_config = config
|
390
|
-
File.open(global_config_path, "w") { |f| f.write config.to_yaml }
|
391
|
-
end
|
392
|
-
|
393
|
-
def global_config_path
|
394
|
-
File.join(config_dir, "global_config.yml")
|
395
|
-
end
|
396
|
-
|
397
|
-
def web_server_vhost_dir
|
398
|
-
config_dir + "vhost"
|
399
|
-
end
|
400
|
-
|
401
|
-
def web_server_vhost_nginx_dir
|
402
|
-
web_server_vhost_dir + "nginx"
|
403
|
-
end
|
404
|
-
|
405
|
-
def find_project_and_symlink_dirs
|
406
|
-
@app_projects ||= []
|
407
|
-
|
408
|
-
if @project_or_projects_dir.expand_path != projects_dir.expand_path
|
409
|
-
@app_projects = [WebServerConfigGenerator::ProjectDirectory.new(@project_or_projects_dir, self)]
|
410
|
-
return
|
411
|
-
end
|
412
|
-
|
413
|
-
[
|
414
|
-
Dir[File.join(projects_dir, "*", ".webconfig.yml")],
|
415
|
-
Dir[File.join(projects_dir, "*", "*", ".webconfig.yml")],
|
416
|
-
Dir[File.join(projects_dir, "*", "*", "*", ".webconfig.yml")],
|
417
|
-
].flatten.map { |p| Pathname.new(p).realpath.dirname }.uniq.each do |path|
|
418
|
-
@app_projects << WebServerConfigGenerator::ProjectDirectory.new(path, self)
|
419
|
-
end
|
420
|
-
end
|
421
|
-
|
422
|
-
def projects_environment_map
|
423
|
-
app_projects.inject({}) { |map, p| map[p] = p.environments; map }
|
424
|
-
end
|
425
|
-
|
426
|
-
def symlinks_environment_map
|
427
|
-
sub_uri_projects.inject({}) { |map, p| map[p] = p.env.to_s; map }
|
428
|
-
end
|
429
|
-
|
430
|
-
def environment_map
|
431
|
-
@environment_map ||= projects_environment_map.merge(symlinks_environment_map)
|
432
|
-
end
|
433
|
-
|
434
|
-
def projects_relative_project_path(dir)
|
435
|
-
File.expand_path(dir).sub(File.expand_path(projects_dir), '').sub(/^\//, '')
|
436
|
-
end
|
437
|
-
|
438
|
-
def write_conf_file(p, env)
|
439
|
-
project_vhost_dir = web_server_vhost_nginx_dir + projects_relative_project_path(p)
|
440
|
-
project_vhost_dir.mkpath
|
441
|
-
project_env_vhost_filename = project_vhost_dir + "#{env}.conf"
|
442
|
-
new_contents = p.generate_conf_file_contents(:env => env)
|
443
|
-
# if project_env_vhost_filename.exist?
|
444
|
-
# old_contents = project_env_vhost_filename.read
|
445
|
-
# if old_contents != new_contents
|
446
|
-
# puts "#{project_env_vhost_filename} exists, but doesn't match"
|
447
|
-
# end
|
448
|
-
# else
|
449
|
-
project_env_vhost_filename.write new_contents
|
450
|
-
# end
|
451
|
-
project_env_vhost_filename.expand_path
|
452
|
-
end
|
453
|
-
|
454
|
-
def nginx_conf_path
|
455
|
-
m = `#{nginx} -t 2>&1`.match /the configuration file (.*) syntax is ok/
|
456
|
-
m[1]
|
457
|
-
end
|
458
|
-
|
459
|
-
def nginx_conf
|
460
|
-
@nginx_conf ||= begin
|
461
|
-
File.read(nginx_conf_path)
|
462
|
-
rescue Exception => e
|
463
|
-
puts "Warning: Couldn't find/read nginx conf"
|
464
|
-
""
|
465
|
-
end
|
466
|
-
end
|
467
|
-
|
468
|
-
def nginx
|
469
|
-
nginx_path_options = [
|
470
|
-
"nginx",
|
471
|
-
"/opt/nginx/sbin/nginx"
|
472
|
-
]
|
473
|
-
nginx_path_options.detect { |p| system "which #{p} &> /dev/null" }
|
474
|
-
end
|
475
|
-
|
476
|
-
end
|
477
|
-
|
478
|
-
end
|
479
|
-
|
480
|
-
|
481
|
-
project_or_projects_dir = ARGV.first && WebServerSetup::Directory.new(File.expand_path(ARGV.first))
|
98
|
+
project_or_projects_dir = ARGV.first && WebServerConfigGenerator::Pathname.new(File.expand_path(ARGV.first))
|
482
99
|
|
483
100
|
options = {}
|
484
101
|
options[:environments] = $ENVS if $ENVS.any?
|
485
102
|
options[:project_or_projects_dir] = project_or_projects_dir
|
486
|
-
web_server_setup =
|
103
|
+
web_server_setup = WebServerConfigGenerator::Generator.new(options)
|
487
104
|
|
488
105
|
web_server_setup.setup_webserver_links_dir
|
489
106
|
|
@@ -492,12 +109,14 @@ if $PRINT_HOSTS
|
|
492
109
|
exit 0
|
493
110
|
end
|
494
111
|
|
495
|
-
|
496
|
-
web_server_setup.write_conf_files
|
497
|
-
|
498
112
|
begin
|
499
113
|
require 'ghost'
|
500
114
|
puts
|
115
|
+
if $DELETE_HOSTS
|
116
|
+
puts "Deleting ghost entries..."
|
117
|
+
web_server_setup.delete_ghost_entries
|
118
|
+
exit 0
|
119
|
+
end
|
501
120
|
if $ADD_HOSTS || ($ADD_HOSTS.nil? && agree("Setup ghost entries for projects? [Y/n]") { |q| q.default = "Y"})
|
502
121
|
puts "Setting up ghost entries..."
|
503
122
|
web_server_setup.add_ghost_entries
|
@@ -506,11 +125,12 @@ rescue LoadError
|
|
506
125
|
puts "Couldn't load ghost so I won't add hostname entries for you. Install the 'ghost' gem, or run me with a -n to get a list of hostnames to setup youself."
|
507
126
|
end
|
508
127
|
|
128
|
+
web_server_setup.write_conf_files
|
129
|
+
|
509
130
|
pp web_server_setup.app_projects if $VERBOSE
|
510
|
-
|
131
|
+
pp web_server_setup.sub_uri_projects if $VERBOSE
|
511
132
|
pp web_server_setup.environments if $VERBOSE
|
512
133
|
|
513
134
|
web_server_setup.check_nginx_conf
|
514
135
|
|
515
136
|
web_server_setup.prompt_to_restart_nginx
|
516
|
-
|
@@ -3,6 +3,17 @@ $:.unshift(File.dirname(__FILE__)) unless
|
|
3
3
|
|
4
4
|
module WebServerConfigGenerator
|
5
5
|
VERSION = '0.0.1'
|
6
|
+
WEB_SERVER_FILES_DIR_NAME = ".webconfig"
|
6
7
|
STARTING_PORT = 40_000
|
7
8
|
PORT_POOL_SIZE = 10_000
|
8
9
|
end
|
10
|
+
|
11
|
+
def agree( yes_or_no_question, character = nil )
|
12
|
+
ask(yes_or_no_question, lambda { |yn| yn.downcase[0] == ?y}) do |q|
|
13
|
+
q.validate = /\Ay(?:es)?|no?\Z/i
|
14
|
+
q.responses[:not_valid] = 'Please enter "yes" or "no".'
|
15
|
+
q.responses[:ask_on_error] = :question
|
16
|
+
q.character = character
|
17
|
+
yield q if block_given?
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,335 @@
|
|
1
|
+
module WebServerConfigGenerator
|
2
|
+
class Generator
|
3
|
+
def initialize(options)
|
4
|
+
options.each do |opt, val|
|
5
|
+
instance_variable_set("@#{opt}", val)
|
6
|
+
end
|
7
|
+
|
8
|
+
@starting_port = options[:starting_port] || 40000
|
9
|
+
@port_pool_size = options[:port_pool_size] || 10000
|
10
|
+
|
11
|
+
@environment_map = Hash.new(options[:environments]) if options[:environments]
|
12
|
+
|
13
|
+
setup_config_dir
|
14
|
+
|
15
|
+
@project_or_projects_dir ||= projects_dir
|
16
|
+
end
|
17
|
+
|
18
|
+
def write_conf_files
|
19
|
+
FileUtils.cd projects_dir do
|
20
|
+
# generate files for each proj/env
|
21
|
+
list_of_conf_files = []
|
22
|
+
app_projects.each do |p|
|
23
|
+
environment_map[p].each do |env|
|
24
|
+
list_of_conf_files << write_conf_file(p, env)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
sub_uri_projects.each do |p|
|
29
|
+
create_sub_uri_links_dir p
|
30
|
+
list_of_conf_files << write_conf_file(p, p.env)
|
31
|
+
end
|
32
|
+
|
33
|
+
current_lines = []
|
34
|
+
web_server_vhost_nginx_conf.read.each_line { |l| current_lines << l }
|
35
|
+
new_lines = current_lines + list_of_conf_files.map { |p| "include #{p};\n" }
|
36
|
+
new_lines.uniq!
|
37
|
+
new_lines.sort!
|
38
|
+
web_server_vhost_nginx_conf.write(new_lines.join)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def create_sub_uri_links_dir(sub_uri_project)
|
43
|
+
env = sub_uri_project.env
|
44
|
+
|
45
|
+
web_server_sub_uri_apps_dir.mkdir unless web_server_sub_uri_apps_dir.exist?
|
46
|
+
links_dir = web_server_sub_uri_apps_dir + sub_uri_project.server_name
|
47
|
+
links_dir.mkdir unless links_dir.exist?
|
48
|
+
sub_uri_project.projects.each do |p|
|
49
|
+
symlink p.expand_path + "public", File.join(links_dir, p.relative_root_url_for_env(env))
|
50
|
+
if p.relative_root_url_root_for_env(env)
|
51
|
+
symlink p.expand_path + "public", File.join(links_dir, "root")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def server_names
|
57
|
+
projects.map { |p| p.server_names }.flatten.uniq
|
58
|
+
end
|
59
|
+
|
60
|
+
def delete_ghost_entries
|
61
|
+
global_config[:hosts].each do |host|
|
62
|
+
Host.delete host
|
63
|
+
end
|
64
|
+
global_config[:hosts] = []
|
65
|
+
save_global_config(global_config)
|
66
|
+
end
|
67
|
+
|
68
|
+
def add_ghost_entries
|
69
|
+
current_hosts = Host.list
|
70
|
+
already_correct = []
|
71
|
+
added = []
|
72
|
+
present_but_incorrect = []
|
73
|
+
server_names.each do |server_name|
|
74
|
+
if host = current_hosts.detect { |h| h.name == server_name }
|
75
|
+
if host.ip == "127.0.0.1"
|
76
|
+
already_correct << host
|
77
|
+
else
|
78
|
+
present_but_incorrect << host
|
79
|
+
end
|
80
|
+
else
|
81
|
+
if $TEST_MODE
|
82
|
+
puts "would have added #{server_name} -> 127.0.0.1"
|
83
|
+
else
|
84
|
+
added << Host.add(server_name)
|
85
|
+
global_config[:hosts] ||= []
|
86
|
+
global_config[:hosts] << server_name
|
87
|
+
save_global_config(global_config)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
if already_correct.size > 0
|
93
|
+
puts "\n#{already_correct.size} hosts were already setup correctly"
|
94
|
+
puts
|
95
|
+
end
|
96
|
+
|
97
|
+
if added.size > 0
|
98
|
+
puts "The following hostnames were added for 127.0.0.1:"
|
99
|
+
puts added.map { |h| " #{h.name}\n" }
|
100
|
+
puts
|
101
|
+
end
|
102
|
+
|
103
|
+
if present_but_incorrect.size > 0
|
104
|
+
puts "The following hostnames were present, but didn't map to 127.0.0.1:"
|
105
|
+
pad = present_but_incorrect.max{|a,b| a.to_s.length <=> b.to_s.length }.to_s.length
|
106
|
+
puts present_but_incorrect.map { |h| "#{h.name.rjust(pad+2)} -> #{h.ip}\n" }
|
107
|
+
puts
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def setup_config_dir
|
112
|
+
unless File.exist?(config_dir)
|
113
|
+
unless dir = $PROJECTS_DIRECTORY
|
114
|
+
puts "It looks like this is the first time you've run me."
|
115
|
+
puts
|
116
|
+
dir = @project_or_projects_dir || FileUtils.pwd
|
117
|
+
unless agree("setup #{dir} as your projects dir? [Y/n]") { |q| q.default = "Y"}
|
118
|
+
puts "for your first run you'll need to supply your projects directory"
|
119
|
+
exit
|
120
|
+
end
|
121
|
+
puts "setting up config dir"
|
122
|
+
end
|
123
|
+
|
124
|
+
FileUtils.mkdir_p config_dir
|
125
|
+
initial_config = { :projects_dirs => [File.expand_path(dir)]}
|
126
|
+
save_global_config(initial_config)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def symlink(link_target, link_name)
|
131
|
+
if File.exist?(link_name)
|
132
|
+
if FileTest.symlink?(link_name)
|
133
|
+
unless Pathname.new(link_name).realpath == Pathname.new(link_target).realpath
|
134
|
+
puts "symlink '#{link_name}' exists, but doesn't appear to link to the correct place"
|
135
|
+
end
|
136
|
+
else
|
137
|
+
puts "couldn't make symlink '#{link_name}', something's already there"
|
138
|
+
end
|
139
|
+
else
|
140
|
+
File.symlink link_target, link_name
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def setup_webserver_links_dir
|
145
|
+
web_server_links_dir.mkpath
|
146
|
+
environments.each do |e|
|
147
|
+
link_name = web_server_links_dir + e
|
148
|
+
symlink(projects_dir, link_name)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def app_projects
|
153
|
+
@app_projects ||=
|
154
|
+
begin
|
155
|
+
find_project_and_symlink_dirs
|
156
|
+
@app_projects
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def sub_uri_projects
|
161
|
+
return @sub_uri_projects if @sub_uri_projects
|
162
|
+
server_name_env_project_map = {}
|
163
|
+
app_projects.each do |p|
|
164
|
+
p.server_name_env_pairs.each do |server_name, env|
|
165
|
+
server_name_env_project_map[server_name] ||= {}
|
166
|
+
server_name_env_project_map[server_name][:env] ||= env
|
167
|
+
raise "can't have one hostname map to multiple envs" if server_name_env_project_map[server_name][:env] != env
|
168
|
+
server_name_env_project_map[server_name][:projects] ||= []
|
169
|
+
server_name_env_project_map[server_name][:projects] << p
|
170
|
+
end
|
171
|
+
end
|
172
|
+
server_name_env_project_map = server_name_env_project_map.select do |server_name, env_and_projects|
|
173
|
+
# more than one project with the same server_name
|
174
|
+
# don't count projects that evaluate to the same path
|
175
|
+
env_and_projects[:projects].map { |p| p.realpath }.uniq.size > 1
|
176
|
+
end
|
177
|
+
@sub_uri_projects = server_name_env_project_map.map do |server_name, env_and_projects|
|
178
|
+
WebServerConfigGenerator::SubUriProject.new(server_name, env_and_projects, self)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def projects
|
183
|
+
app_projects + sub_uri_projects
|
184
|
+
end
|
185
|
+
|
186
|
+
def environments
|
187
|
+
@environments ||= environment_map.values.flatten.uniq
|
188
|
+
end
|
189
|
+
|
190
|
+
def web_server_vhost_nginx_conf
|
191
|
+
web_server_vhost_nginx_dir + "projects.conf"
|
192
|
+
end
|
193
|
+
|
194
|
+
def check_nginx_conf
|
195
|
+
unless nginx_conf =~ /include.*#{web_server_vhost_nginx_conf}/
|
196
|
+
puts "\nWarning: You'll need to make sure this line is in your nginx config, in the http block:"
|
197
|
+
puts " include #{web_server_vhost_nginx_conf};"
|
198
|
+
end
|
199
|
+
|
200
|
+
unless nginx_conf =~ /server_names_hash_bucket_size.*128/
|
201
|
+
puts "\nWarning: Couldn't find the following line in your nginx conf. It should be in the http block."
|
202
|
+
puts " server_names_hash_bucket_size 128;"
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def prompt_to_restart_nginx
|
207
|
+
puts
|
208
|
+
if $RESTART_NGINX || ($RESTART_NGINX.nil? && agree("Restart nginx? [Y/n]") { |q| q.default = "Y"})
|
209
|
+
puts "Restarting nginx..."
|
210
|
+
cmd = "sudo killall nginx; sleep 1 && sudo #{nginx}"
|
211
|
+
puts "running: #{cmd}"
|
212
|
+
system cmd
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def web_server_links_dir
|
217
|
+
config_dir + "links"
|
218
|
+
end
|
219
|
+
|
220
|
+
def projects_dir
|
221
|
+
WebServerConfigGenerator::Pathname.new(global_config[:projects_dirs].first).expand_path
|
222
|
+
end
|
223
|
+
|
224
|
+
def web_server_sub_uri_apps_dir
|
225
|
+
config_dir + "sub_uri_apps"
|
226
|
+
end
|
227
|
+
|
228
|
+
private
|
229
|
+
|
230
|
+
def config_dir
|
231
|
+
@config_dir ||=
|
232
|
+
begin
|
233
|
+
WebServerConfigGenerator::Pathname.new $WEB_SERVER_FILES_DIR || begin
|
234
|
+
raise "Couldn't fine $HOME" unless home_dir = ENV["HOME"]
|
235
|
+
File.join(home_dir, ".webconfig")
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def global_config(reload = false)
|
241
|
+
@global_config = nil if reload
|
242
|
+
@global_config ||= YAML.load_file(global_config_path)
|
243
|
+
end
|
244
|
+
|
245
|
+
def save_global_config(config)
|
246
|
+
@global_config = config
|
247
|
+
File.open(global_config_path, "w") { |f| f.write config.to_yaml }
|
248
|
+
end
|
249
|
+
|
250
|
+
def global_config_path
|
251
|
+
File.join(config_dir, "global_config.yml")
|
252
|
+
end
|
253
|
+
|
254
|
+
def web_server_vhost_dir
|
255
|
+
config_dir + "vhost"
|
256
|
+
end
|
257
|
+
|
258
|
+
def web_server_vhost_nginx_dir
|
259
|
+
web_server_vhost_dir + "nginx"
|
260
|
+
end
|
261
|
+
|
262
|
+
def find_project_and_symlink_dirs
|
263
|
+
@app_projects ||= []
|
264
|
+
|
265
|
+
if @project_or_projects_dir.expand_path != projects_dir.expand_path
|
266
|
+
@app_projects = [WebServerConfigGenerator::ProjectDirectory.new(@project_or_projects_dir, self)]
|
267
|
+
return
|
268
|
+
end
|
269
|
+
|
270
|
+
[
|
271
|
+
Dir[File.join(projects_dir, "*", ".webconfig.yml")],
|
272
|
+
Dir[File.join(projects_dir, "*", "*", ".webconfig.yml")],
|
273
|
+
Dir[File.join(projects_dir, "*", "*", "*", ".webconfig.yml")],
|
274
|
+
].flatten.map { |p| Pathname.new(p).realpath.dirname }.uniq.each do |path|
|
275
|
+
@app_projects << WebServerConfigGenerator::ProjectDirectory.new(path, self)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
def projects_environment_map
|
280
|
+
app_projects.inject({}) { |map, p| map[p] = p.environments; map }
|
281
|
+
end
|
282
|
+
|
283
|
+
def symlinks_environment_map
|
284
|
+
sub_uri_projects.inject({}) { |map, p| map[p] = p.env.to_s; map }
|
285
|
+
end
|
286
|
+
|
287
|
+
def environment_map
|
288
|
+
@environment_map ||= projects_environment_map.merge(symlinks_environment_map)
|
289
|
+
end
|
290
|
+
|
291
|
+
def projects_relative_project_path(dir)
|
292
|
+
File.expand_path(dir).sub(File.expand_path(projects_dir), '').sub(/^\//, '')
|
293
|
+
end
|
294
|
+
|
295
|
+
def write_conf_file(p, env)
|
296
|
+
project_vhost_dir = web_server_vhost_nginx_dir + projects_relative_project_path(p)
|
297
|
+
project_vhost_dir.mkpath
|
298
|
+
project_env_vhost_filename = project_vhost_dir + "#{env}.conf"
|
299
|
+
new_contents = p.generate_conf_file_contents(:env => env)
|
300
|
+
# if project_env_vhost_filename.exist?
|
301
|
+
# old_contents = project_env_vhost_filename.read
|
302
|
+
# if old_contents != new_contents
|
303
|
+
# puts "#{project_env_vhost_filename} exists, but doesn't match"
|
304
|
+
# end
|
305
|
+
# else
|
306
|
+
project_env_vhost_filename.write new_contents
|
307
|
+
# end
|
308
|
+
project_env_vhost_filename.expand_path
|
309
|
+
end
|
310
|
+
|
311
|
+
def nginx_conf_path
|
312
|
+
m = `#{nginx} -t 2>&1`.match /the configuration file (.*) syntax is ok/
|
313
|
+
m[1]
|
314
|
+
end
|
315
|
+
|
316
|
+
def nginx_conf
|
317
|
+
@nginx_conf ||= begin
|
318
|
+
File.read(nginx_conf_path)
|
319
|
+
rescue Exception => e
|
320
|
+
puts "Warning: Couldn't find/read nginx conf"
|
321
|
+
""
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
def nginx
|
326
|
+
nginx_path_options = [
|
327
|
+
"nginx",
|
328
|
+
"/opt/nginx/sbin/nginx"
|
329
|
+
]
|
330
|
+
nginx_path_options.detect { |p| system "which #{p} &> /dev/null" }
|
331
|
+
end
|
332
|
+
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
Binary file
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 9
|
9
|
+
version: 0.0.9
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Expected Behavior
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-03-
|
17
|
+
date: 2010-03-18 00:00:00 -04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|
@@ -28,6 +28,8 @@ extra_rdoc_files:
|
|
28
28
|
- README
|
29
29
|
files:
|
30
30
|
- lib/web_server_config_generator.rb
|
31
|
+
- lib/web_server_config_generator/generator.rb
|
32
|
+
- lib/web_server_config_generator/pathname.rb
|
31
33
|
- lib/web_server_config_generator/project_directory.rb
|
32
34
|
- lib/web_server_config_generator/sub_uri_project.rb
|
33
35
|
has_rdoc: true
|