diff --git a/.run-httpd.py b/.run-httpd.py index 51b222318..514d33f09 100755 --- a/.run-httpd.py +++ b/.run-httpd.py @@ -1,137 +1,19 @@ #!/usr/bin/env python from tempfile import mkdtemp -from os.path import join, exists -from subprocess import Popen, PIPE, check_output from argparse import ArgumentParser -from shutil import rmtree -from time import sleep -from re import compile -from os import mkdir + +from httpd import run_apache_with_jekyll parser = ArgumentParser(description='Serve Jekyll site') parser.add_argument('--watch', dest='watch', action='store_true', help='Watch for changes and rebuild.') -config = ''' -LoadModule rewrite_module {ModulesPath}/mod_rewrite.so -LoadModule alias_module {ModulesPath}/mod_alias.so -LoadModule dir_module {ModulesPath}/mod_dir.so -LoadModule mime_module {ModulesPath}/mod_mime.so - - - LoadModule unixd_module {ModulesPath}/mod_unixd.so - - - - LoadModule mpm_event_module {ModulesPath}/mod_mpm_event.so - - - - LoadModule log_config_module {ModulesPath}/mod_log_config.so - LockFile "{ServerRoot}/accept.lock" - - - - LoadModule authz_core_module {ModulesPath}/mod_authz_core.so - Mutex file:{ServerRoot} - - -Listen 0.0.0.0:{Port} -PidFile "{ServerRoot}/httpd.pid" -DocumentRoot "{DocumentRoot}" -TypesConfig {MimeTypes} - - - Options +FollowSymLinks - AllowOverride Options FileInfo Indexes - -''' - -def build_site(destination, watch): - ''' - ''' - command = 'jekyll', 'build', '-d', destination - - if watch: - command += ('--watch', ) - - Popen(command).wait() - print 'Built to', destination - -def write_config(doc_root, root, port): - ''' Look for Apache modules, write a configuration file. - - Return module directory. - ''' - mod_paths = '/usr/lib/apache2/modules', '/usr/libexec/apache2' - mime_paths = '/etc/apache2/mime.types', '/etc/mime.types' - - mod_path = filter(exists, mod_paths)[0] - mime_path = filter(exists, mime_paths)[0] - - vars = dict(DocumentRoot=doc_root, ModulesPath=mod_path, - Port=port, ServerRoot=root, MimeTypes=mime_path) - - with open(join(root, 'httpd.conf'), 'w') as file: - file.write(config.format(**vars)) - - if not exists(join(root, 'httpd.conf')): - raise RuntimeError('Did not make httpd.conf') - - return mod_path - -def apache_version(httpd_path): - ''' Return major, minor version tuple. - ''' - pattern = compile(r'^Server version: Apache/(\d+)\.(\d+)\.(\d+)\b') - match = pattern.match(check_output((httpd_path, '-v'))) - major, minor, patch = [int(match.group(i)) for i in (1, 2, 3)] - - return major, minor - -def run_apache(root, port, watch): - ''' Look for Apache executable and start it up. - ''' - try: - doc_root = join(root, '_site') - mkdir(doc_root) - mkdir(join(root, 'logs')) - - mod_path = write_config(doc_root, root, port) - httpd_paths = '/usr/sbin/httpd', '/usr/sbin/apache2' - httpd_path = filter(exists, httpd_paths)[0] - - version_param = '-DVersion{}.{}'.format(*apache_version(httpd_path)) - - httpd_cmd = (httpd_path, '-d', root, '-f', 'httpd.conf', - '-DFOREGROUND', '-DNO_DETACH', version_param) - - if exists(join(mod_path, 'mod_unixd.so')): - httpd_cmd += ('-DUnixd', ) - - if exists(join(mod_path, 'mod_mpm_event.so')): - httpd_cmd += ('-DMpmEvent', ) - - stderr = open(join(root, 'stderr'), 'w') - stdout = open(join(root, 'stdout'), 'w') - - try: - httpd = Popen(httpd_cmd, stderr=stderr, stdout=stdout) - print 'Running at http://127.0.0.1:{}'.format(port) - build_site(doc_root, watch) - sleep(7 * 86400) - finally: - httpd.kill() - - except KeyboardInterrupt: - rmtree(root) - def main(): ''' ''' args = parser.parse_args() - run_apache(mkdtemp(prefix='codeforamerica.org-'), 4000, args.watch) + run_apache_with_jekyll(mkdtemp(prefix='codeforamerica.org-'), 4000, args.watch) if __name__ == '__main__': exit(main()) diff --git a/.run-tests.sh b/.run-tests.sh deleted file mode 100755 index 807861b7e..000000000 --- a/.run-tests.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -e -jekyll build -./.test-httpd.py diff --git a/.test-httpd.py b/.test-httpd.py index 4742a3760..23d297b40 100755 --- a/.test-httpd.py +++ b/.test-httpd.py @@ -1,13 +1,14 @@ #!/usr/bin/env python from tempfile import mkdtemp -from os.path import join, abspath, dirname, exists +from os.path import join, abspath, dirname from urlparse import urljoin, urlparse from httplib import HTTPConnection -from subprocess import Popen, PIPE from random import randrange from shutil import rmtree from time import sleep +from httpd import run_apache_forever, build_site + import unittest config = ''' @@ -38,36 +39,9 @@ def setUp(self): ''' self.root = mkdtemp() self.port = randrange(0x1000, 0x10000) + doc_root = join(dirname(abspath(__file__)), '_site') - # - # Look for Apache modules, write a configuration file. - # - for mod_path in ('/usr/lib/apache2/modules', '/usr/libexec/apache2'): - if not exists(join(mod_path, 'mod_dir.so')): - continue - - doc_root = join(dirname(abspath(__file__)), '_site') - log_config_so_path = join(mod_path, 'mod_log_config.so') - log_config_prefix = '' if exists(log_config_so_path) else '#' - vars = dict(DocumentRoot=doc_root, ModulesPath=mod_path, - Port=self.port, MLCP=log_config_prefix) - - with open(join(self.root, 'httpd.conf'), 'w') as file: - file.write(config.format(**vars)) - - if not exists(join(self.root, 'httpd.conf')): - raise RuntimeError('Did not make httpd.conf') - - # - # Look for Apache executable and start it up. - # - for httpd_path in ('/usr/sbin/httpd', '/usr/sbin/apache2'): - if not exists(httpd_path): - continue - - httpd_cmd = (httpd_path, '-d', self.root, '-f', 'httpd.conf', '-X') - - self.httpd = Popen(httpd_cmd, stderr=PIPE, stdout=PIPE) + self.httpd = run_apache_forever(doc_root, self.root, self.port, False) sleep(.5) def tearDown(self): @@ -229,4 +203,5 @@ def test_redirects(self): assert end_path == url_path, '{0} instead of {1} from {2}'.format(url_path, end_path, start_path) if __name__ == '__main__': + build_site(join(dirname(abspath(__file__)), '_site'), False) unittest.main() diff --git a/.travis.yml b/.travis.yml index cd100f3aa..c896e91cb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: ruby before_install: - travis_retry gem install jekyll --no-ri --no-rdoc - sudo apt-get install -y apache2 -script: ./.run-tests.sh +script: ./.test-httpd.py branches: only: - master diff --git a/httpd/__init__.py b/httpd/__init__.py new file mode 100644 index 000000000..2ed2d1b6c --- /dev/null +++ b/httpd/__init__.py @@ -0,0 +1,158 @@ +from os.path import join, exists +from subprocess import Popen, PIPE, check_output +from shutil import rmtree +from time import sleep +from re import compile +from os import mkdir + +config = ''' +LoadModule rewrite_module {ModulesPath}/mod_rewrite.so +LoadModule alias_module {ModulesPath}/mod_alias.so +LoadModule dir_module {ModulesPath}/mod_dir.so +LoadModule mime_module {ModulesPath}/mod_mime.so + + + LoadModule unixd_module {ModulesPath}/mod_unixd.so + + + + LoadModule mpm_event_module {ModulesPath}/mod_mpm_event.so + + + + LoadModule log_config_module {ModulesPath}/mod_log_config.so + LockFile "{ServerRoot}/accept.lock" + + + + LoadModule authz_core_module {ModulesPath}/mod_authz_core.so + Mutex file:{ServerRoot} + + +Listen 0.0.0.0:{Port} +PidFile "{ServerRoot}/httpd.pid" +DocumentRoot "{DocumentRoot}" +TypesConfig {MimeTypes} + + + Options +FollowSymLinks + AllowOverride Options FileInfo Indexes + +''' + +def build_site(destination, watch): + ''' + ''' + command = 'jekyll', 'build', '-d', destination + + if watch: + command += ('--watch', ) + + Popen(command).wait() + print 'Built to', destination + +def write_config(doc_root, root, port): + ''' Look for Apache modules, write a configuration file. + + Return module directory. + ''' + mod_paths = '/usr/lib/apache2/modules', '/usr/libexec/apache2' + mime_paths = '/etc/apache2/mime.types', '/etc/mime.types' + + mod_path = filter(exists, mod_paths)[0] + mime_path = filter(exists, mime_paths)[0] + + vars = dict(DocumentRoot=doc_root, ModulesPath=mod_path, + Port=port, ServerRoot=root, MimeTypes=mime_path) + + with open(join(root, 'httpd.conf'), 'w') as file: + file.write(config.format(**vars)) + + if not exists(join(root, 'httpd.conf')): + raise RuntimeError('Did not make httpd.conf') + + return mod_path + +def apache_version(httpd_path): + ''' Return major, minor version tuple. + ''' + pattern = compile(r'^Server version: Apache/(\d+)\.(\d+)\.(\d+)\b') + match = pattern.match(check_output((httpd_path, '-v'))) + major, minor, patch = [int(match.group(i)) for i in (1, 2, 3)] + + return major, minor + +def run_apache_with_jekyll(root, port, watch): + ''' Look for Apache executable and start it up. + + When the user cancels or kills the process, stop Apache. + ''' + try: + doc_root = join(root, '_site') + mkdir(doc_root) + mkdir(join(root, 'logs')) + + mod_path = write_config(doc_root, root, port) + httpd_paths = '/usr/sbin/httpd', '/usr/sbin/apache2' + httpd_path = filter(exists, httpd_paths)[0] + + version_param = '-DVersion{}.{}'.format(*apache_version(httpd_path)) + + httpd_cmd = (httpd_path, '-d', root, '-f', 'httpd.conf', + '-DFOREGROUND', '-DNO_DETACH', version_param) + + if exists(join(mod_path, 'mod_unixd.so')): + httpd_cmd += ('-DUnixd', ) + + if exists(join(mod_path, 'mod_mpm_event.so')): + httpd_cmd += ('-DMpmEvent', ) + + stderr = open(join(root, 'stderr'), 'w') + stdout = open(join(root, 'stdout'), 'w') + + try: + httpd = Popen(httpd_cmd, stderr=stderr, stdout=stdout) + print 'Running at http://127.0.0.1:{}'.format(port) + build_site(doc_root, watch) + sleep(7 * 86400) + finally: + httpd.kill() + + except KeyboardInterrupt: + rmtree(root) + +def run_apache_forever(doc_root, root, port, watch): + ''' Look for Apache executable and start it up. + + Return an instance of subprocess.Process. + + Assumes that jekyll build has already created root/_site. + ''' + try: + mkdir(join(root, 'logs')) + + mod_path = write_config(doc_root, root, port) + httpd_paths = '/usr/sbin/httpd', '/usr/sbin/apache2' + httpd_path = filter(exists, httpd_paths)[0] + + version_param = '-DVersion{}.{}'.format(*apache_version(httpd_path)) + + httpd_cmd = (httpd_path, '-d', root, '-f', 'httpd.conf', + '-DFOREGROUND', '-DNO_DETACH', version_param) + + if exists(join(mod_path, 'mod_unixd.so')): + httpd_cmd += ('-DUnixd', ) + + if exists(join(mod_path, 'mod_mpm_event.so')): + httpd_cmd += ('-DMpmEvent', ) + + stderr = open(join(root, 'stderr'), 'w') + stdout = open(join(root, 'stdout'), 'w') + + httpd = Popen(httpd_cmd, stderr=stderr, stdout=stdout) + print 'Running at http://127.0.0.1:{} from {}'.format(port, root) + + return httpd + + except KeyboardInterrupt: + rmtree(root)