web_server_config_generator 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
data/README
ADDED
Binary file
|
@@ -0,0 +1,513 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'pp'
|
5
|
+
require 'find'
|
6
|
+
require 'digest/sha1'
|
7
|
+
require 'pathname'
|
8
|
+
require 'rubygems'
|
9
|
+
require 'highline/import'
|
10
|
+
require 'optparse'
|
11
|
+
require 'yaml'
|
12
|
+
$:.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
|
13
|
+
require 'web_server_config_generator'
|
14
|
+
require 'web_server_config_generator/project_directory'
|
15
|
+
require 'web_server_config_generator/sub_uri_project'
|
16
|
+
|
17
|
+
|
18
|
+
$ENVS = []
|
19
|
+
$TEST_MODE = false
|
20
|
+
$CREATE_WEB_SERVER_FILES_DIR = false
|
21
|
+
$PRINT_HOSTS = false
|
22
|
+
$WEB_SERVER_FILES_DIR = nil
|
23
|
+
$ADD_HOSTS = nil
|
24
|
+
$RESTART_NGINX = nil
|
25
|
+
|
26
|
+
opts = OptionParser.new do |opts|
|
27
|
+
opts.banner = "Usage: #{File.basename(__FILE__)} [project(s) dir] [options]"
|
28
|
+
|
29
|
+
opts.separator ""
|
30
|
+
opts.separator "This will generate web server configuration files for your projects."
|
31
|
+
opts.separator ""
|
32
|
+
opts.separator "If you supply a project directory we assume you have run this before and will just generate the files for that project. If you specify your projects directory we will generate the files for all projects found. Not supplying a directory is the same as supplying your current directory."
|
33
|
+
opts.separator ""
|
34
|
+
opts.separator "No flags = try to generate files for all envs"
|
35
|
+
opts.separator ""
|
36
|
+
opts.separator "Specific options:"
|
37
|
+
|
38
|
+
# Mandatory argument.
|
39
|
+
opts.on("-e", "--environment ENV",
|
40
|
+
"specify a specific environment to generate (defaults to all in database.yml)") do |env|
|
41
|
+
$ENVS << env
|
42
|
+
end
|
43
|
+
|
44
|
+
opts.on("-n", "--list-hosts",
|
45
|
+
"list generated hostnames, useful for setting up the hosts file on your own") do
|
46
|
+
$PRINT_HOSTS = true
|
47
|
+
end
|
48
|
+
|
49
|
+
opts.on("-c", "--create-web-server-files-dir",
|
50
|
+
"create web_server_files directory (useful the first time you run this script) in this case the supplied (or assumed) directory will be set as the 'projects' directory") do
|
51
|
+
$CREATE_WEB_SERVER_FILES_DIR = true
|
52
|
+
end
|
53
|
+
|
54
|
+
opts.on("-p", "--projects-dir DIR",
|
55
|
+
"specify the directory containing all your projects") do |dir|
|
56
|
+
$PROJECTS_DIRECTORY = dir
|
57
|
+
end
|
58
|
+
|
59
|
+
opts.on("-l", "--web-server-files-dir-location DIR",
|
60
|
+
"put all the web server configuration files in DIR instead of the default location") do |path|
|
61
|
+
$WEB_SERVER_FILES_DIR = File.expand_path(path)
|
62
|
+
end
|
63
|
+
|
64
|
+
opts.on("-a", "--[no-]add-hosts",
|
65
|
+
"add ghost entries for generated hostnames, requires ghost gem") do |b|
|
66
|
+
$ADD_HOSTS = b
|
67
|
+
end
|
68
|
+
|
69
|
+
opts.on("-r", "--[no-]restart-nginx",
|
70
|
+
"restart nginx at the end") do |b|
|
71
|
+
$RESTART_NGINX = b
|
72
|
+
end
|
73
|
+
|
74
|
+
opts.on("-v", "--verbose",
|
75
|
+
"verbose") do
|
76
|
+
$VERBOSE = true
|
77
|
+
end
|
78
|
+
|
79
|
+
opts.on("-t", "--test-mode",
|
80
|
+
"test mode; do not modify the FS, just print messsages") do
|
81
|
+
$TEST_MODE = true
|
82
|
+
end
|
83
|
+
|
84
|
+
# # Optional argument; multi-line description.
|
85
|
+
# opts.on("-i", "--inplace [EXTENSION]",
|
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
|
96
|
+
# end
|
97
|
+
|
98
|
+
opts.separator ""
|
99
|
+
opts.separator "Common options:"
|
100
|
+
|
101
|
+
# No argument, shows at tail. This will print an options summary.
|
102
|
+
# Try it and see!
|
103
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
104
|
+
puts opts
|
105
|
+
exit
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
opts.parse!(ARGV)
|
110
|
+
|
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
|
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
|
+
if agree("setup #{@project_or_projects_dir} as your projects dir? [Y/n]") { |q| q.default = "Y"}
|
260
|
+
dir = @project_or_projects_dir
|
261
|
+
else
|
262
|
+
puts "for your first run you'll need to supply your projects directory"
|
263
|
+
exit
|
264
|
+
end
|
265
|
+
puts "setting up config dir"
|
266
|
+
end
|
267
|
+
|
268
|
+
FileUtils.mkdir_p config_dir
|
269
|
+
initial_config = { :projects_dirs => [File.expand_path(dir)]}
|
270
|
+
save_global_config(initial_config)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
def symlink(link_target, link_name)
|
275
|
+
if File.exist?(link_name)
|
276
|
+
if FileTest.symlink?(link_name)
|
277
|
+
unless File.readlink(link_name) == link_target
|
278
|
+
puts "symlink '#{link_name}' exists, but doesn't appear to link to the correct place"
|
279
|
+
end
|
280
|
+
else
|
281
|
+
puts "couldn't make symlink '#{link_name}', something's already there"
|
282
|
+
end
|
283
|
+
else
|
284
|
+
File.symlink link_target, link_name
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
def setup_webserver_links_dir
|
289
|
+
FileUtils.cd projects_dir do
|
290
|
+
link_target = File.join "..", ".."
|
291
|
+
web_server_links_dir.mkpath
|
292
|
+
environments.each do |e|
|
293
|
+
link_name = web_server_links_dir + e
|
294
|
+
symlink(link_target, link_name)
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
def app_projects
|
300
|
+
@app_projects ||=
|
301
|
+
begin
|
302
|
+
find_project_and_symlink_dirs
|
303
|
+
@app_projects
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
def sub_uri_projects
|
308
|
+
return @sub_uri_projects if @sub_uri_projects
|
309
|
+
server_name_env_project_map = {}
|
310
|
+
app_projects.each do |p|
|
311
|
+
p.server_name_env_pairs.each do |server_name, env|
|
312
|
+
server_name_env_project_map[server_name] ||= {}
|
313
|
+
server_name_env_project_map[server_name][:env] ||= env
|
314
|
+
raise "can't have one hostname map to multiple envs" if server_name_env_project_map[server_name][:env] != env
|
315
|
+
server_name_env_project_map[server_name][:projects] ||= []
|
316
|
+
server_name_env_project_map[server_name][:projects] << p
|
317
|
+
end
|
318
|
+
end
|
319
|
+
server_name_env_project_map = server_name_env_project_map.select { |server_name, env_and_projects| env_and_projects[:projects].size > 1 }
|
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
|
+
|
333
|
+
def web_server_vhost_nginx_conf
|
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
|
+
web_server_files_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
|
+
web_server_files_dir + "sub_uri_apps"
|
369
|
+
end
|
370
|
+
|
371
|
+
private
|
372
|
+
|
373
|
+
def config_dir
|
374
|
+
$WEB_SERVER_FILES_DIR || begin
|
375
|
+
raise "Couldn't fine $HOME" unless home_dir = ENV["HOME"]
|
376
|
+
File.join(home_dir, ".webconfig")
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
def global_config(reload = false)
|
381
|
+
@global_config = nil if reload
|
382
|
+
@global_config ||= YAML.load_file(global_config_path)
|
383
|
+
end
|
384
|
+
|
385
|
+
def save_global_config(config)
|
386
|
+
@global_config = config
|
387
|
+
File.open(global_config_path, "w") { |f| f.write config.to_yaml }
|
388
|
+
end
|
389
|
+
|
390
|
+
def global_config_path
|
391
|
+
File.join(config_dir, "global_config.yml")
|
392
|
+
end
|
393
|
+
|
394
|
+
def web_server_files_dir
|
395
|
+
$WEB_SERVER_FILES_DIR ? Directory.new($WEB_SERVER_FILES_DIR) : config_dir
|
396
|
+
end
|
397
|
+
|
398
|
+
def web_server_vhost_dir
|
399
|
+
web_server_files_dir + "vhost"
|
400
|
+
end
|
401
|
+
|
402
|
+
def web_server_vhost_nginx_dir
|
403
|
+
web_server_vhost_dir + "nginx"
|
404
|
+
end
|
405
|
+
|
406
|
+
def find_project_and_symlink_dirs
|
407
|
+
@app_projects ||= []
|
408
|
+
|
409
|
+
if @project_or_projects_dir.expand_path != projects_dir.expand_path
|
410
|
+
@app_projects = [WebServerConfigGenerator::ProjectDirectory.new(@project_or_projects_dir, self)]
|
411
|
+
return
|
412
|
+
end
|
413
|
+
|
414
|
+
Dir[File.join(projects_dir, "**", ".webconfig.yml")].each do |webconfig_path|
|
415
|
+
@app_projects << WebServerConfigGenerator::ProjectDirectory.new(File.dirname(webconfig_path), self)
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
def projects_environment_map
|
420
|
+
app_projects.inject({}) { |map, p| map[p] = p.environments; map }
|
421
|
+
end
|
422
|
+
|
423
|
+
def symlinks_environment_map
|
424
|
+
sub_uri_projects.inject({}) { |map, p| map[p] = p.env.to_s; map }
|
425
|
+
end
|
426
|
+
|
427
|
+
def environment_map
|
428
|
+
@environment_map ||= projects_environment_map.merge(symlinks_environment_map)
|
429
|
+
end
|
430
|
+
|
431
|
+
def projects_relative_project_path(dir)
|
432
|
+
File.expand_path(dir).sub(File.expand_path(projects_dir), '').sub(/^\//, '')
|
433
|
+
end
|
434
|
+
|
435
|
+
def write_conf_file(p, env)
|
436
|
+
project_vhost_dir = web_server_vhost_nginx_dir + projects_relative_project_path(p)
|
437
|
+
project_vhost_dir.mkpath
|
438
|
+
project_env_vhost_filename = project_vhost_dir + "#{env}.conf"
|
439
|
+
new_contents = p.generate_conf_file_contents(:env => env)
|
440
|
+
if project_env_vhost_filename.exist?
|
441
|
+
old_contents = project_env_vhost_filename.read
|
442
|
+
if old_contents != new_contents
|
443
|
+
puts "#{project_env_vhost_filename} exists, but doesn't match"
|
444
|
+
end
|
445
|
+
else
|
446
|
+
project_env_vhost_filename.write new_contents
|
447
|
+
end
|
448
|
+
project_env_vhost_filename.expand_path
|
449
|
+
end
|
450
|
+
|
451
|
+
def nginx_conf_path
|
452
|
+
m = `#{nginx} -t 2>&1`.match /the configuration file (.*) syntax is ok/
|
453
|
+
m[1]
|
454
|
+
end
|
455
|
+
|
456
|
+
def nginx_conf
|
457
|
+
@nginx_conf ||= begin
|
458
|
+
File.read(nginx_conf_path)
|
459
|
+
rescue Exception => e
|
460
|
+
puts "Warning: Couldn't find/read nginx conf"
|
461
|
+
""
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
465
|
+
def nginx
|
466
|
+
nginx_path_options = [
|
467
|
+
"nginx",
|
468
|
+
"/opt/nginx/sbin/nginx"
|
469
|
+
]
|
470
|
+
nginx_path_options.detect { |p| system "which #{p} &> /dev/null" }
|
471
|
+
end
|
472
|
+
|
473
|
+
end
|
474
|
+
|
475
|
+
end
|
476
|
+
|
477
|
+
|
478
|
+
project_or_projects_dir = ARGV.first && WebServerSetup::Directory.new(File.expand_path(ARGV.first))
|
479
|
+
|
480
|
+
options = {}
|
481
|
+
options[:environments] = $ENVS if $ENVS.any?
|
482
|
+
options[:project_or_projects_dir] = project_or_projects_dir
|
483
|
+
web_server_setup = WebServerSetup::Generator.new(options)
|
484
|
+
|
485
|
+
web_server_setup.setup_webserver_links_dir
|
486
|
+
|
487
|
+
if $PRINT_HOSTS
|
488
|
+
puts web_server_setup.server_names.join("\n")
|
489
|
+
exit 0
|
490
|
+
end
|
491
|
+
|
492
|
+
|
493
|
+
web_server_setup.write_conf_files
|
494
|
+
|
495
|
+
begin
|
496
|
+
require 'ghost'
|
497
|
+
puts
|
498
|
+
if $ADD_HOSTS || ($ADD_HOSTS.nil? && agree("Setup ghost entries for projects? [Y/n]") { |q| q.default = "Y"})
|
499
|
+
puts "Setting up ghost entries..."
|
500
|
+
web_server_setup.add_ghost_entries
|
501
|
+
end
|
502
|
+
rescue LoadError
|
503
|
+
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."
|
504
|
+
end
|
505
|
+
|
506
|
+
pp web_server_setup.app_projects if $VERBOSE
|
507
|
+
# pp web_server_setup.symlink_dirs if $VERBOSE
|
508
|
+
pp web_server_setup.environments if $VERBOSE
|
509
|
+
|
510
|
+
web_server_setup.check_nginx_conf
|
511
|
+
|
512
|
+
web_server_setup.prompt_to_restart_nginx
|
513
|
+
|
Binary file
|
Binary file
|
metadata
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: web_server_config_generator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Expected Behavior
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-03-17 00:00:00 -04:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: automatically generate web server config files for you projects directory
|
22
|
+
email:
|
23
|
+
executables:
|
24
|
+
- web_server_setup
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files:
|
28
|
+
- README
|
29
|
+
files:
|
30
|
+
- lib/web_server_config_generator.rb
|
31
|
+
- lib/web_server_config_generator/project_directory.rb
|
32
|
+
- lib/web_server_config_generator/sub_uri_project.rb
|
33
|
+
has_rdoc: true
|
34
|
+
homepage: http://github.com/expectedbehavior/web_server_config_generator
|
35
|
+
licenses: []
|
36
|
+
|
37
|
+
post_install_message:
|
38
|
+
rdoc_options: []
|
39
|
+
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
segments:
|
47
|
+
- 0
|
48
|
+
version: "0"
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
segments:
|
54
|
+
- 0
|
55
|
+
version: "0"
|
56
|
+
requirements: []
|
57
|
+
|
58
|
+
rubyforge_project:
|
59
|
+
rubygems_version: 1.3.6
|
60
|
+
signing_key:
|
61
|
+
specification_version: 3
|
62
|
+
summary: automatically generate web server config files for you projects directory
|
63
|
+
test_files: []
|
64
|
+
|