class PhusionPassenger::Standalone::AppFinder

Security note: can run arbitrary ruby code by evaluating passenger.conf

def self.looks_like_app_directory?(dir)

def self.looks_like_app_directory?(dir)
	return File.exist?("#{dir}/config.ru") ||
		File.exist?("#{dir}/config/environment.rb") ||
		File.exist?("#{dir}/passenger_wsgi.py")
end

def filename_to_server_names(filename)

def filename_to_server_names(filename)
	basename = File.basename(filename)
	names = [basename]
	if basename !~ /^www\.$/i
		names << "www.#{basename}"
	end
	return names
end

def find_app_root

def find_app_root
	if @dirs.empty?
		return File.expand_path(".")
	else
		return File.expand_path(@dirs[0])
	end
end

def initialize(dirs, options = {})

def initialize(dirs, options = {})
	@dirs = dirs
	@options = options
end

def load_config_file(context, filename)

def load_config_file(context, filename)
	require 'phusion_passenger/standalone/config_file' unless defined?(ConfigFile)
	return ConfigFile.new(context, filename).options
end

def looks_like_app_directory?(dir)

def looks_like_app_directory?(dir)
	return AppFinder.looks_like_app_directory?(dir)
end

def monitor(termination_pipe)

def monitor(termination_pipe)
	raise "You must call #scan first" if !@apps
	
	watcher = PhusionPassenger::Utils::FileSystemWatcher.new(@watchlist, termination_pipe)
	if wait_on_io(termination_pipe, 3)
		return
	end
	
	while true
		changed = watcher.wait_for_change
		watcher.close
		if changed
			old_apps = @apps
			# The change could be caused by a write to some passenger.conf file.
			# Wait for a short period so that the write has a chance to finish.
			if wait_on_io(termination_pipe, 0.25)
				return
			end
			
			new_apps = scan
			watcher = PhusionPassenger::Utils::FileSystemWatcher.new(@watchlist, termination_pipe)
			if old_apps != new_apps
				yield(new_apps)
			end
			
			# Don't process change events again for a short while,
			# but do detect changes while waiting.
			if wait_on_io(termination_pipe, 3)
				return
			end
		else
			return
		end
	end
ensure
	watcher.close if watcher
end

def scan

def scan
	apps = []
	watchlist = []
	
	app_root = find_app_root
	apps << {
		:server_names => ["_"],
		:root => app_root
	}
	watchlist << app_root
	watchlist << "#{app_root}/config" if File.exist?("#{app_root}/config")
	watchlist << "#{app_root}/passenger.conf" if File.exist?("#{app_root}/passenger.conf")
	
	apps.sort! do |a, b|
		a[:root] <=> b[:root]
	end
	apps.map! do |app|
		config_filename = File.join(app[:root], "passenger.conf")
		if File.exist?(config_filename)
			local_options = load_config_file(:local_config, config_filename)
			merged_options = @options.merge(app)
			merged_options.merge!(local_options)
			merged_options
		else
			@options.merge(app)
		end
	end
	
	@apps = apps
	@watchlist = watchlist
	return apps
end

def wait_on_io(io, timeout)

timeout has been reached.
been reached. Returns true if the IO became readable, false if the
Wait until the given IO becomes readable, or until the timeout has
def wait_on_io(io, timeout)
	return !!select([io], nil, nil, timeout)
end