PageRenderTime 47ms CodeModel.GetById 14ms app.highlight 28ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/passenger_pane/application.rb

http://github.com/tgunr/passengerpane
Ruby | 219 lines | 174 code | 40 blank | 5 comment | 13 complexity | 4db2564c41c8e596af18d605cff0b5e0 MD5 | raw file
  1require 'fileutils'
  2
  3module PassengerPane
  4  class Application
  5    RAILS_APP_REGEXP = /::Initializer\.run|Application\.initialize!/
  6    ATTRIBUTES = [:config_filename, :host, :aliases, :path, :framework, :environment, :vhost_address, :user_defined_data]
  7    
  8    def self.glob(configuration)
  9      File.join(
 10        configuration.apache_directory,
 11        configuration.passenger_vhosts,
 12        "*.#{configuration.passenger_vhosts_ext}"
 13      )
 14    end
 15    
 16    def self.all(configuration)
 17      Dir.glob(glob(configuration)).map do |config_filename|
 18        new(configuration, :config_filename => config_filename)
 19      end
 20    end
 21    
 22    def self.find(configuration, conditions={})
 23      if conditions[:host]
 24        all(configuration).detect do |app|
 25          app.host == conditions[:host]
 26        end
 27      end
 28    end
 29    
 30    attr_accessor(*ATTRIBUTES)
 31    
 32    def initialize(configuration, options={})
 33      @configuration = configuration
 34      set(options)
 35      if options[:config_filename]
 36        @new = false
 37        _parse
 38      elsif options[:path]
 39        @new = true
 40        _derive
 41      else
 42        raise ArgumentError, "Please specify either a :config_filename or :path"
 43      end
 44      @before_changes = to_hash
 45    end
 46    
 47    def set(options)
 48      options.each do |key, value|
 49        setter = trust("#{key}=")
 50        send(setter, trust(value)) if respond_to?(setter)
 51      end
 52    end
 53    
 54    def new?
 55      @new
 56    end
 57    
 58    # -- Virtual Host reading and writing
 59    
 60    def contents
 61      @contents ||= File.read(trust(@config_filename))
 62    end
 63    
 64    attr_writer :contents
 65    
 66    def _parse
 67      data = contents.dup
 68      
 69      data.gsub!(/\n\s*ServerName\s+(.+)/, '')
 70      @host = $1
 71      
 72      data.gsub!(/\n\s*ServerAlias\s+(.+)/, '')
 73      @aliases = $1 || ''
 74      
 75      data.gsub!(/\n\s*DocumentRoot\s+"(.+)"/, '')
 76      path = $1
 77      if path.end_with?('public')
 78        @path = File.dirname(path)
 79      else
 80        @path = path
 81      end
 82      
 83      data.gsub!(/\n\s*(Rails|Rack)Env\s+(\w+)/, '')
 84      @framework   = $1 ? $1.downcase : nil
 85      @environment = $2
 86      
 87      data.gsub!(/<VirtualHost\s(.+?)>/, '')
 88      @vhost_address = $1
 89      
 90      data.gsub!(/\s*<\/VirtualHost>\n*/, '').gsub!(/^\n*/, '')
 91      @user_defined_data = data.strip
 92    end
 93    
 94    def _document_root
 95      File.join(@path, 'public')
 96    end
 97    
 98    def _directory_defaults
 99      %{
100  <Directory "#{_document_root}">
101    Order allow,deny
102    Allow from all
103  </Directory>
104      }.strip
105    end
106    
107    def _config_filename
108      File.join(
109        @configuration.apache_directory,
110        @configuration.passenger_vhosts,
111        "#{@host}.#{@configuration.passenger_vhosts_ext}"
112      )
113    end
114    
115    def _framework
116      environment_file = File.join(@path, 'config', 'environment.rb')
117      if File.exist?(environment_file) and File.read(environment_file) =~ RAILS_APP_REGEXP
118        'rails'
119      else
120        'rack'
121      end
122    end
123    
124    def _derive
125      @host ||= "#{File.basename(path).downcase.gsub('_','-')}.local"
126      @aliases ||= ''
127      @environment ||= 'development'
128      @vhost_address ||= '*:80'
129      @user_defined_data ||= _directory_defaults
130      @config_filename ||= _config_filename
131      @framework ||= _framework
132    end
133    
134    def rails?; @framework == 'rails' end
135    def rack?;  @framework == 'rack'  end
136    
137    def vhost_snippet
138      lines = []
139      lines << "<VirtualHost #{vhost_address}>"
140      lines << "  ServerName #{host}"
141      lines << "  ServerAlias #{aliases}" unless aliases == ''
142      lines << "  DocumentRoot \"#{_document_root}\""
143      if @framework
144        lines << "  #{rails? ? 'RailsEnv' : 'RackEnv'} #{environment}"
145      end
146      lines << "  #{user_defined_data}" unless user_defined_data.strip == ''
147      lines << "</VirtualHost>"
148      lines.join("\n")
149    end
150    
151    def write
152      FileUtils.mkdir_p(File.dirname(@config_filename))
153      File.open(@config_filename, 'w') do |file|
154        file.write(vhost_snippet)
155      end; true
156    end
157    
158    # -- Dirty checking
159    
160    def to_hash
161      hash = { 'hosts' => [host, *aliases.split] }
162      ATTRIBUTES.each do |key|
163        hash[key.to_s] = instance_variable_get("@#{key}")
164      end; hash
165    end
166    
167    def changed?
168      @before_changes != to_hash
169    end
170    
171    def added_hosts
172      to_hash['hosts'] - @before_changes['hosts']
173    end
174    
175    def removed_hosts
176      @before_changes['hosts'] - to_hash['hosts']
177    end
178    
179    # -- Directory services
180    
181    def register
182      PassengerPane::DirectoryServices.register(to_hash['hosts'])
183    end
184    
185    def unregister
186      PassengerPane::DirectoryServices.unregister(to_hash['hosts'])
187    end
188    
189    def sync_host_registration
190      if new?
191        register
192      else
193        PassengerPane::DirectoryServices.register(added_hosts) and
194        PassengerPane::DirectoryServices.unregister(removed_hosts)
195      end
196    end
197    
198    # -- Persisting
199    
200    def save
201      write and sync_host_registration
202    end
203    
204    def delete
205      FileUtils.rm_rf(config_filename)
206      unregister
207      true
208    end
209    
210    # -- Operational
211    
212    def restart
213      if File.exist?(@path)
214        FileUtils.mkdir_p(File.join(File.join(@path, 'tmp')))
215        FileUtils.touch(File.join(@path, 'tmp', 'restart.txt'))
216      end
217    end
218  end
219end