257 lines
7.3 KiB
Ruby
257 lines
7.3 KiB
Ruby
require 'fileutils'
|
|
require 'rainbow'
|
|
|
|
module Apache
|
|
# The core class of Apache Config Generator.
|
|
#
|
|
# Configuration is built by calling either build or build_if:
|
|
#
|
|
# Ex: Build a config file regardless of current environment:
|
|
#
|
|
# Apache::Config.build('my-config.conf') do
|
|
# document_root '/my/document/root'
|
|
# ...
|
|
# end
|
|
#
|
|
# Ex: Build a config file only if you're in the development environment:
|
|
#
|
|
# Apache::Config.build_if('my-config.conf', :development) do
|
|
# document_root '/my/document/root'
|
|
# ...
|
|
# end
|
|
#
|
|
# By default, methods called within the block are NerdCapsed to match the Apache config directive format:
|
|
#
|
|
# document_root #=> DocumentRoot
|
|
# options #=> Options
|
|
# allow_override #=> AllowOverride
|
|
#
|
|
# Parameters passed into the methods are quoted if they're Strings or Integers, and not quoted if they're Symbols:
|
|
#
|
|
# document_root '/my/document/root' #=> DocumentRoot "/my/document/root"
|
|
# document_root '/my/document/root'.to_sym #=> DocumentRoot /my/document/root
|
|
# accept_path_info :off #=> AcceptPathInfo off
|
|
#
|
|
# Suffixing the method name with an exclamation point turns off quoting for all parameters:
|
|
#
|
|
# document_root! '/my/document/root' #=> DocumentRoot /my/document/root
|
|
#
|
|
# Block-level directives work the same as the top-level build method:
|
|
#
|
|
# directory '/my/site' do
|
|
# allow_from_all
|
|
# satisfy :any
|
|
# end
|
|
#
|
|
# Directives that require a regular expression take a Regexp:
|
|
#
|
|
# location_match %r{^/my/site} do
|
|
# set_env 'this_is_my_site', 'yes'
|
|
# end
|
|
|
|
class Config
|
|
class << self
|
|
attr_accessor :line_indent, :rotate_logs_path
|
|
|
|
include Apache::Master
|
|
include Apache::Permissions
|
|
include Apache::Directories
|
|
include Apache::Logging
|
|
include Apache::Performance
|
|
include Apache::Rewrites
|
|
include Apache::MPM
|
|
include Apache::SSL
|
|
|
|
# Build the provided configuration only if the current environment matches one of the conditions
|
|
def build_if(target, *conditions, &block)
|
|
build(target, &block) if environment_ok?(*conditions)
|
|
end
|
|
|
|
# Build the provided configuration
|
|
def build_and_return(&block)
|
|
reset!
|
|
|
|
self.instance_eval(&block)
|
|
|
|
@config
|
|
end
|
|
|
|
def build_and_return_if(*conditions, &block)
|
|
build_and_return(&block) if environment_ok?(*conditions)
|
|
end
|
|
|
|
def environment_ok?(*environments)
|
|
return true if APACHE_ENV == true
|
|
environments.include?(APACHE_ENV)
|
|
end
|
|
|
|
def build(target, &block)
|
|
config = build_and_return(&block)
|
|
|
|
if !disabled?
|
|
FileUtils.mkdir_p File.split(target).first
|
|
File.open(target, 'w') { |file| file.puts generate_config_file(config) * "\n" }
|
|
@was_written = true
|
|
end
|
|
|
|
config
|
|
end
|
|
|
|
# If included in a configuration, will not generate the config file in the Rake task
|
|
def disable!
|
|
@is_disabled = true
|
|
end
|
|
|
|
def disabled?
|
|
@is_disabled
|
|
end
|
|
|
|
def written?
|
|
@was_written
|
|
end
|
|
|
|
def generate_config_file(config)
|
|
[ "# Generated by apache-config-generator #{Time.now.to_s}", config ].flatten
|
|
end
|
|
|
|
# Reset the current settings
|
|
def reset!
|
|
@config = []
|
|
@line_indent = 0
|
|
@is_disabled = false
|
|
@was_written = false
|
|
end
|
|
|
|
# Indent the string by the current @line_indent level
|
|
def indent(string_or_array)
|
|
case string_or_array
|
|
when Array
|
|
string_or_array.collect { |line| indent(line) }
|
|
else
|
|
" " * (@line_indent * 2) + string_or_array.to_s
|
|
end
|
|
end
|
|
|
|
# Add the string to the current config
|
|
def <<(string)
|
|
@config << indent(string)
|
|
end
|
|
|
|
# Append the array to the current config
|
|
def +(other)
|
|
@config += other
|
|
end
|
|
|
|
# Get the config
|
|
def to_a
|
|
@config
|
|
end
|
|
|
|
# Handle options that aren't specially handled
|
|
#
|
|
# Method names are NerdCapsed and paramters are quoted, unless the method ends with !
|
|
def method_missing(method, *args)
|
|
method_name = method.to_s
|
|
if method_name[-1..-1] == "!"
|
|
method = method_name[0..-2].to_sym
|
|
else
|
|
args.quoteize!
|
|
end
|
|
|
|
self << [ method.apachify, *args ].compact * ' '
|
|
end
|
|
|
|
# Handle creating block methods
|
|
#
|
|
# Methods created this way are:
|
|
# * virtual_host
|
|
# * location
|
|
# * files
|
|
def block_methods(*methods)
|
|
methods.each do |method|
|
|
self.class.class_eval <<-EOT
|
|
def #{method}(*name, &block)
|
|
blockify("#{method}".apachify, name, &block)
|
|
end
|
|
EOT
|
|
end
|
|
end
|
|
|
|
# If the given module is loaded, process the directives within.
|
|
#
|
|
# The provided module name is converted into Apache module name format:
|
|
# if_module(:php5) do #=> <IfModule mod_php5>
|
|
def if_module(mod, &block)
|
|
blockify('if_module'.apachify, "#{mod}_module".to_sym, &block)
|
|
end
|
|
|
|
# Create a directory block, checking to see if the source directory exists.
|
|
def directory(dir, &block)
|
|
directory? dir
|
|
blockify('directory'.apachify, dir, &block)
|
|
end
|
|
|
|
# Create a LocationMatch block with the provided Regexp:
|
|
# location_match %r{^/my/location/[a-z0-9]+\.html} do #=> <LocationMatch "^/my/location/[a-z0-9]+\.html">
|
|
def location_match(regexp, &block)
|
|
blockify('location_match'.apachify, regexp.source, &block)
|
|
end
|
|
|
|
# Create a FilesMatch block with the provied Regexp:
|
|
# files_match %r{\.html$} do #=> FilesMatch "\.html$">
|
|
def files_match(regexp, &block)
|
|
blockify('files_match'.apachify, regexp.source, &block)
|
|
end
|
|
|
|
# Only execute the provided block if APACHE_ENV matches one of the provided enviroment symbols:
|
|
# if_environment(:production) do
|
|
def if_environment(*env, &block)
|
|
self.instance_eval(&block) if env.include?(APACHE_ENV)
|
|
end
|
|
|
|
# Handle the blockification of a provided block
|
|
def blockify(tag_name, name, &block)
|
|
self + [ '', "<#{[ tag_name, name.blockify ].compact * ' '}>" ]
|
|
@line_indent += 1
|
|
self.instance_eval(&block)
|
|
@line_indent -= 1
|
|
self + [ "</#{tag_name}>", '' ]
|
|
end
|
|
|
|
def blank_line!
|
|
self << ""
|
|
end
|
|
|
|
# Build a string that invokes Apache's rotatelogs command
|
|
def rotatelogs(path, time)
|
|
begin
|
|
time = time.to_i
|
|
rescue
|
|
raise "Time should be an integer: #{path} #{time}"
|
|
end
|
|
|
|
"|#{@rotate_logs_path} #{path} #{time}"
|
|
end
|
|
|
|
def warn_msg(from, color = :red)
|
|
"[warn::#{from}]".foreground(color)
|
|
end
|
|
|
|
private
|
|
def writable?(path)
|
|
puts " #{warn_msg('writable?')} #{path.foreground(:yellow)} may not be writable!" if !File.directory? File.split(path).first
|
|
end
|
|
|
|
def directory?(path)
|
|
puts " #{warn_msg('directory?')} #{path.foreground(:yellow)} does not exist!" if !File.directory? path
|
|
end
|
|
|
|
def exist?(path)
|
|
puts " #{warn_msg('exist?')} #{path.foreground(:yellow)} does not exist!" if !File.exist?(path)
|
|
end
|
|
end
|
|
|
|
block_methods :virtual_host, :location, :files
|
|
end
|
|
end
|