JasonKing-pulp 0.0.2

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.
Files changed (4) hide show
  1. data/README.markdown +38 -0
  2. data/bin/pulp +13 -0
  3. data/lib/passenger/config.rb +426 -0
  4. metadata +65 -0
@@ -0,0 +1,38 @@
1
+ pulp
2
+ ====
3
+
4
+ This is a simple helper for [passenger](http://modrails.com/) in development. It does two things:
5
+
6
+ 1. Simplifies the setup of new passenger virtual hosts by adding the necessary
7
+ records to your apache config as well as to your hosts file.
8
+ 2. Checks your apache config to make sure that you have the right settings, and
9
+ right order of settings (like that your passenger vhosts are **after** your
10
+ `NameVirtualHost` directive).
11
+
12
+ It works magically, by querying apache itself to find the location of your conf
13
+ files. It **isn't** magical enough to work on Windows.
14
+
15
+ Installation
16
+ ------------
17
+
18
+ To perform a system wide installation:
19
+
20
+ gem source -a http://gems.github.com
21
+ gem install JasonKing-pulp
22
+
23
+ Usage
24
+ -----
25
+
26
+ Typically you'll setup a new rails app with the `rails` executable, and then
27
+ call `pulp` afterwards, like this:
28
+
29
+ > rails foobar
30
+ > sudo pulp foobar
31
+
32
+ Done. You will now be able to visit http://foobar.dev/ and see your new rails
33
+ site running.
34
+
35
+ Contributors
36
+ ------------
37
+
38
+ * Jason King (JasonKing)
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ require File.join( File.dirname(__FILE__), '..', 'lib', 'passenger', 'config')
3
+
4
+ if %w(--version -v).include? ARGV.first
5
+ puts "#{File.basename(__FILE__)} #{Passenger::Config::VERSION}"
6
+ exit(0)
7
+ end
8
+
9
+ c = Passenger::Config.new( :root => ARGV[0] )
10
+ c.update_hosts
11
+ c.update_apache
12
+
13
+ c.consolidate
@@ -0,0 +1,426 @@
1
+ require 'fileutils'
2
+ require 'etc'
3
+ require 'find'
4
+ require 'grep'
5
+
6
+ module Passenger
7
+ class Config
8
+ VERSION = '0.8.1'
9
+ attr_reader :domain
10
+ attr_reader :ip
11
+ attr_reader :hosts
12
+
13
+ @@marker_string = "#----- #{File.basename($0, '.rb')} marker line -- DO NOT DELETE -----#"
14
+
15
+ @@httpd_cmd = 'httpd'
16
+ @@apachectl = 'apachectl'
17
+
18
+ @@user_re = /^\s*User\s+(\S+)/i
19
+ @@group_re = /^\s*Group\s+(\S+)/i
20
+
21
+ def initialize(p)
22
+ self.root = p[:root]
23
+ @domain = (p[:domain] || '.dev').sub(/^\.*/,'.')
24
+ @hosts = p[:hosts] || '/etc/hosts'
25
+ @ip = p[:ip] || '127.0.0.1'
26
+
27
+ @check_for_user = lambda {|l|
28
+ if m = l.match(@@user_re)
29
+ @user = m[1]
30
+ end
31
+ }
32
+ @check_for_group = lambda {|l|
33
+ if m = l.match(@@user_re)
34
+ @group = m[1]
35
+ end
36
+ }
37
+
38
+ read_conf
39
+ check_root_perms
40
+
41
+ setup_vhost
42
+ end
43
+
44
+ def consolidate
45
+ _hosts = list_hosts
46
+ _vhosts = list_vhosts
47
+
48
+ _hosts.each_index do |i|
49
+ case _hosts[i] <=> _vhosts[i]
50
+ when 0
51
+ next
52
+ when 1
53
+ puts "Missing from #{hosts}: #{_vhosts[i]}"
54
+ _hosts.insert(i, _vhosts[i])
55
+ when -1
56
+ puts "Missing from #{passenger_conf}: #{_hosts[i]}"
57
+ _vhosts.insert(i, _hosts[i])
58
+ end
59
+ end
60
+ end
61
+
62
+ def update_hosts
63
+ _had_domain_line = false
64
+ File.open(hosts, 'r+') do |f|
65
+ f.flock File::LOCK_EX
66
+ _buffer = []
67
+ f.each do |l|
68
+ if l.match(domain_re) # add it to the same line that the other #{domain} entries are on
69
+ _had_domain_line = true
70
+ unless l.match(host_re) # already exists - don't re-add
71
+ l = "#{l.chomp} #{host}\n"
72
+ end
73
+ end
74
+ _buffer << l
75
+ end
76
+
77
+ unless _had_domain_line # if there was no #{domain} line then just add it to the end
78
+ _buffer << "#{ip} #{host}\n"
79
+ end
80
+ f.seek 0
81
+ f.truncate 0
82
+ f << _buffer
83
+ end
84
+ end
85
+
86
+ def update_apache
87
+ File.open(passenger_conf, 'r+') do |f|
88
+ f.flock File::LOCK_EX
89
+ catch(:out) do
90
+ f.each("\n\n") do |ir|
91
+ if ir == @vhost_entry
92
+ f.seek 0, IO::SEEK_END
93
+ throw :out
94
+ end
95
+ end
96
+ f.puts @vhost_entry
97
+ end
98
+ end
99
+ system("#{@@apachectl} restart")
100
+ end
101
+
102
+ private
103
+ def list_hosts
104
+ _hosts = []
105
+ File.open(hosts).each do |l|
106
+ if l.match(domain_re)
107
+ _hosts += l.scan(/\S+#{Regexp.quote(domain)}(?!\S)/)
108
+ end
109
+ end
110
+ _hosts.sort.uniq
111
+ end
112
+
113
+ def list_vhosts
114
+ _h = []
115
+ File.open(passenger_conf).each do |l|
116
+ if m = l.match( %r{^\s*ServerName\s+(\S+#{Regexp.quote(domain)})(?!\S)})
117
+ _h << m[1]
118
+ end
119
+ end
120
+ _h.sort.uniq
121
+ end
122
+
123
+ def setup_vhost
124
+ @vhost_entry =<<-__EOI
125
+ <VirtualHost #{vhost}>
126
+ DocumentRoot #{root}
127
+ ServerName #{host}
128
+ <Location />
129
+ Order allow,deny
130
+ Allow from all
131
+ </Location>
132
+ </VirtualHost>
133
+
134
+ __EOI
135
+ end
136
+
137
+ def root=(_d)
138
+ @root = File.expand_path(_d || '.')
139
+ end
140
+
141
+ def root
142
+ File.join(@root, 'public')
143
+ end
144
+
145
+ def app
146
+ @app ||= File.basename(@root)
147
+ end
148
+
149
+ def host
150
+ @host ||= app + domain
151
+ end
152
+
153
+ def localhost_re
154
+ @localhost_re ||= %r{^\s*#{Regexp.quote(ip)}\s.*}
155
+ end
156
+
157
+ def domain_re
158
+ @domain_re ||= %r{#{localhost_re}\b#{Regexp.quote(domain)}(?!\S)}
159
+ end
160
+
161
+ def host_re
162
+ @host_re ||= %r{#{localhost_re}\s#{Regexp.quote(host)}(?!\S)}
163
+ end
164
+
165
+ def conf
166
+ @conf ||= from_server('SERVER_CONFIG_FILE')
167
+ end
168
+
169
+ def dir
170
+ @dir ||= File.dirname(self.conf)
171
+ end
172
+
173
+ def server_root
174
+ @server_root ||= File.open(conf).grep(/^\s*ServerRoot\s+['"]?([^'"\s]+)['"]?/i).first[:match][1] || from_server('HTTPD_ROOT')
175
+ end
176
+
177
+ def dir_handle
178
+ @dir_handle ||= Dir.open(dir)
179
+ end
180
+
181
+ def user
182
+ @user ||= get_user
183
+ end
184
+
185
+ def group
186
+ @group ||= get_group
187
+ end
188
+
189
+ def get_user
190
+ File.open(conf).each do |line|
191
+ return @user if @check_for_user.call(line)
192
+ end
193
+ end
194
+
195
+ def check_root_perms
196
+ system("sudo -u #{user} ls #{root} 1>/dev/null 2>&1") or raise %Q{Your Apache user "#{user}" can't read your document root "#{root}"}
197
+ end
198
+
199
+ def get_group
200
+ File.open(conf).each do |line|
201
+ return @group if @check_for_group.call(line)
202
+ end
203
+ end
204
+
205
+ def retrieve_passenger_conf
206
+ File.open(conf) do |f|
207
+ f.each do |line|
208
+ @check_for_user.call(line)
209
+ @check_for_group.call(line)
210
+ if line.chomp == @@marker_string
211
+ until line.match(/^\s*[^#]/)
212
+ line = f.gets
213
+ unless m = line.match(/^\s*Include\s+(\S+)/)
214
+ raise "Non-include following marker: #{@@marker_string} in #{conf}"
215
+ end
216
+ return m[1]
217
+ end
218
+ end
219
+ end
220
+ end
221
+ return nil
222
+ end
223
+
224
+ def passenger_conf
225
+ return @passenger_conf if @passenger_conf || @passenger_conf = retrieve_passenger_conf
226
+
227
+ # the logic for where we're going to add our vhosts is a little complex
228
+ #
229
+ # 1. We use the RailsEnv file as long as it comes after the
230
+ # NameVirtualHost entry
231
+ # 2. Otherwise we're going to create our own file, include it from the
232
+ # main conf, and use that
233
+
234
+ if @conf_files[:renv][:order] > @conf_files[:vhost][:order]
235
+ if @conf_files[:renv][:file] != conf
236
+ return @passenger_conf = @conf_files[:renv][:file]
237
+ end
238
+ end
239
+
240
+ @passenger_conf = make_new_file
241
+ end
242
+
243
+ def read_conf
244
+ @conf_files = {}
245
+ # Strings that we're looking for:
246
+ #
247
+ # NameVirtualHost *:80
248
+ # LoadModule passenger_module /opt/local/lib/ruby/gems/1.8/gems/passenger-2.0.6/ext/apache2/mod_passenger.so
249
+ # PassengerRoot /opt/local/lib/ruby/gems/1.8/gems/passenger-2.0.6
250
+ # PassengerRuby /opt/local/bin/ruby
251
+ #
252
+ @_conf_strings = {
253
+ :vhost => /^\s*NameVirtualHost\s+(\S+)/i,
254
+ :load => %r{^\s*LoadModule\s+passenger_module\s+((/\S+)/lib/ruby/gems/\S+/passenger-[\d.]+)/ext/apache2/mod_passenger.so}i,
255
+ :root => %r{^\s*PassengerRoot\s+(['"]?)(/\S+/lib/ruby/gems/\S+/passenger-[\d.]+)\1}i,
256
+ :ruby => %r{^\s*PassengerRuby\s+(['"]?)(/\S+)/bin/ruby\1}i,
257
+ :renv => %r{^\s*RailsEnv\s+(['"]?)(\S+)\1}i
258
+ }
259
+
260
+ # change into the server root so that any relative paths in the conf files work
261
+ Dir.chdir(server_root) do |p|
262
+
263
+ # start at the conf and drill down through all includes looking for our
264
+ # strings and recording where they are - we're just going to barf if we
265
+ # find the strings in more than one location - let the user sort that
266
+ # out
267
+ drill_down(conf)
268
+ end
269
+ ensure_conf
270
+ end
271
+
272
+ def ensure_dir(d)
273
+ _umask = File.umask(022)
274
+ _dir = File.mkdirs(File.join(dir, d))
275
+ File.umask(_umask)
276
+ _dir
277
+ end
278
+
279
+ def make_new_file
280
+ _dir = ensure_dir('extra')
281
+
282
+ # we're going to make sure that we get a filename that doesn't exist
283
+ %w{passenger.conf mod_rails.conf httpd-passenger.conf httpd-mod_rails.conf j20qmcjidhe93knd.conf}.each do |fn|
284
+ _f = File.join(_dir,fn)
285
+ if !File.exist?(_f)
286
+ FileUtils.touch _f
287
+ File.open(conf, 'a') do |f|
288
+ f.puts @@marker_string
289
+ f.puts "Include #{_f}"
290
+ end
291
+ return _f
292
+ end
293
+ end
294
+ raise "Couldn't find a unique filename in #{_dir}."
295
+ end
296
+
297
+ def ensure_conf
298
+ _need_re_read = false
299
+ unless @conf_files[:root]
300
+ add_to_conf( "PassengerRoot #{@conf_files[:load][:match][1]}", :load, :root )
301
+ _need_re_read = true
302
+ end
303
+
304
+ unless @conf_files[:ruby]
305
+ add_to_conf( "PassengerRuby #{@conf_files[:load][:match][2]}/bin/ruby", :root, :ruby )
306
+ _need_re_read = true
307
+ end
308
+
309
+ unless @conf_files[:renv]
310
+ add_to_conf( "RailsEnv #{ENV['RAILS_ENV'] || 'development'}\n", :ruby, :renv )
311
+ _need_re_read = true
312
+ end
313
+
314
+ unless @conf_files[:vhost]
315
+ add_to_conf( "NameVirtualHost *:80\n", :renv, :vhost )
316
+ _need_re_read = true
317
+ end
318
+
319
+ if _need_re_read
320
+ read_conf
321
+ end
322
+ check_conf
323
+ end
324
+
325
+ def add_to_conf( str, from, to)
326
+ p = @conf_files[from]
327
+ File.open( p[:file], 'r+' ) do |f|
328
+ f.flock File::LOCK_EX
329
+ _buffer = []
330
+ f.each do |l|
331
+ _buffer << l
332
+ if $. == p[:lineno]
333
+ @conf_files[to] = { :file => p[:file], :lineno => $. + 1 + str.count("\n") }
334
+ _buffer << str + "\n"
335
+ end
336
+ end
337
+ f.truncate 0
338
+ f.seek 0
339
+ f << _buffer
340
+ end
341
+ end
342
+
343
+ def check_conf
344
+ # we can add everything except the LoadModule line
345
+ unless @conf_files[:load]
346
+ raise "LoadModule line missing, maybe you forgot to run: passenger-install-apache2-module"
347
+ end
348
+
349
+ _load_order = @conf_files[:load][:order]
350
+ [ :root, :ruby, :renv ].each do |s|
351
+ next unless @conf_files[s]
352
+ if _load_order > @conf_files[s][:order]
353
+ raise "Passenger module loaded too late: #{@conf_files[:load][:file]},#{@conf_files[:load][:lineno]} needs to happen before #{@conf_files[s][:file]},#{@conf_files[s][:lineno]}"
354
+ end
355
+ end
356
+
357
+ _load_passenger_location = @conf_files[:load][:match][1]
358
+ if @conf_files[:root]
359
+ unless _load_passenger_location == _root_passenger_location = @conf_files[:root][:match][2]
360
+ raise "Passenger module location #{_load_passenger_location} and PassengerRoot setting #{_root_passenger_location} should be the same."
361
+ end
362
+ end
363
+
364
+ _load_passenger_prefix = @conf_files[:load][:match][2]
365
+ if @conf_files[:ruby]
366
+ unless _load_passenger_prefix == _ruby_passenger_prefix = @conf_files[:ruby][:match][2]
367
+ raise "Passenger module prefix #{_load_passenger_prefix} and PassengerRuby prefix #{_ruby_passenger_prefix} should be the same."
368
+ end
369
+ end
370
+ end
371
+
372
+ def vhost
373
+ @vhost ||= @conf_files[:vhost][:match][1]
374
+ end
375
+
376
+ def drill_down(_c)
377
+ @_order ||= 0
378
+ _c = File.expand_path(_c)
379
+ File.open(_c).each_line do |line|
380
+ @_conf_strings.each do |k,v|
381
+ if m = line.match(v)
382
+ _exists = @conf_files[k]
383
+ raise "#{k} was already found in #{_exists[:file]},#{_exists[:lineno]} for #{_c},#{$.}" if _exists
384
+ @conf_files[k] = { :file => _c, :lineno => $., :match => m, :order => @_order += 1 }
385
+ end
386
+ end
387
+
388
+ if m = line.match(/^\s*Include\s+(['"]?)(\S+)\1/i)
389
+ # apache includes are commonly file globs
390
+ Dir.glob(m[2]).each do |f|
391
+ drill_down(f)
392
+ end
393
+ end
394
+ end
395
+ end
396
+
397
+
398
+ def recursive_tracking(_c)
399
+ _c.each do |c|
400
+ _filename = c[:file]
401
+ _new = dir_handle.grep(/^\s*Include.*#{Regexp.escape(_filename)}/i)
402
+ unless _new.size > 0
403
+ # do some other things
404
+ end
405
+
406
+ if _new.find{|c| c[:file] == conf}
407
+ return true
408
+ end
409
+
410
+ ret = recursive_tracking(_new)
411
+ if ret
412
+ @includes << c
413
+ else
414
+ @includes.pop
415
+ end
416
+ return ret
417
+ end
418
+ return false
419
+ end
420
+
421
+ def from_server(s)
422
+ @httpd_string ||= `#{@@httpd_cmd} -V`
423
+ @httpd_string.match(/#{s}="([^"]+)"/i)[1]
424
+ end
425
+ end
426
+ end
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: JasonKing-pulp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Jason King
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-03-12 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: JasonKing-grep
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.2
24
+ version:
25
+ description:
26
+ email: jk@handle.it
27
+ executables:
28
+ - pulp
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - README.markdown
35
+ - lib/passenger/config.rb
36
+ - bin/pulp
37
+ has_rdoc: true
38
+ homepage: http://github.com/JasonKing/pulp
39
+ post_install_message:
40
+ rdoc_options:
41
+ - --inline-source
42
+ - --charset=UTF-8
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: "0"
50
+ version:
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ version:
57
+ requirements: []
58
+
59
+ rubyforge_project:
60
+ rubygems_version: 1.2.0
61
+ signing_key:
62
+ specification_version: 2
63
+ summary: pulp - Passenger Helper - for simple setup of Ruby Apps using Passenger
64
+ test_files: []
65
+