# Experimental top-level setup.py for rpki CA tools. # # This is not yet ready for prime time. # # General idea here is that we can use this with Python-aware platform # packaging systems, and our code here deals with the strange build # environment required when the system copy of OpenSSL isn't usable. # # So yes, you are seeing a setup.py which calls autoconf and make. # Strange, but so long as it works as Python expects, good enough. # $Id$ # # Copyright (C) 2011-2013 Internet Systems Consortium ("ISC") # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH # REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY # AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. import os import stat import subprocess from distutils.core import setup, Extension, Command from distutils.command.build_ext import build_ext as _build_ext from distutils.command.install_data import install_data as _install_data from distutils.command.sdist import sdist as _sdist try: from ac_rpki import ac except ImportError: ac = None class autoconf(Command): description = "run autoconf if hasn't been run already" user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): global ac if ac is None: subprocess.check_call(("./configure",)) import ac_rpki ac = ac_rpki.ac class build_openssl(Command): description = "build private OpenSSL libraries when needed by POW extension" user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): self.run_command("autoconf") if ac.build_openssl: subprocess.check_call(("make",), cwd = "openssl") class build_ext(_build_ext): def run(self): self.run_command("autoconf") self.run_command("build_openssl") # Non-standard extension build specification: we need to force # whatever build options our top-level ./configure selected, and we # have to specify our libraries as extra_link_args because they may be # complete pathnames to .a files elsewhere in the build tree. Most of # this insanity is to kludge around pre-existing OpenSSL libraries # that would screw up our build without these gymnastics. # Not sure yet, but if we use autoconf to update or override # options to build_ext, we might need to reinitialize here, # something like: # #self = self.reinitialize_command(self) #self.ensure_finalized() # Might end up just whacking the one and only Extension object # queued up for this build_ext command. Ugly, non-standard, but # simple. # For now just try whacking self.extensions and see what happens assert self.extensions and len(self.extensions) == 1 ext = self.extensions[0] ext.extra_compile_args = ac.CFLAGS ext.extra_link_args = ac.LDFLAGS + ac.LIBS return _build_ext.run(self) # The following hack uses "svn ls -R" to generate the manifest. # Haven't decided yet whether that's a good idea or not, commented out # of cmdclass for now. class sdist(_sdist): def add_defaults(self): try: self.filelist.extend(subprocess.check_output(("svn", "ls", "-R")).splitlines()) except CalledProcessError: return _sdist.add_default(self) # Be careful constructing data_files, empty file lists here appear to # confuse setup into putting dangerous nonsense into the list of # installed files. # # bdist_rpm seems to get confused by relative names for scripts, so we # have to prefix source names here with the build directory name. # We handle these as data files instead of scripts because # install_scripts isn't clever enough to let us choose the # installation directory. We need to construct these files anyway, so # that's not a big deal. # # At present we build these in rpkid/Makefile, but we need to change that # to build these here in a new (not yet written) distutils command. daemon_scripts = ["rpkid/rpki-sql-backup", "rpkid/rpki-sql-setup", "rpkid/rpki-start-servers", "rpkid/irbe_cli", "rpkid/irdbd", "rpkid/pubd", "rpkid/rootd", "rpkid/rpkic", "rpkid/rpkid"] django_scripts = ["rpkid/portal-gui/scripts/rpkigui-rcynic", "rpkid/portal-gui/scripts/rpkigui-import-routes", "rpkid/portal-gui/scripts/rpkigui-check-expired", #"rpkid/portal-gui/scripts/rpki-manage", ] # rpkid/Makefile.in stuff not handled yet: # portal-gui/settings.py # portal-gui/scripts/rpki-manage # Not sure these really all should be in sbin, the Django stuff looks # more libexec to me. Preserve existing locations for now. sbin_scripts = daemon_scripts + django_scripts libexec_scripts = [] daemon_script_template = '''\ #!%(ac_PYTHON)s # Automatically constructed script header # Set location of global rpki.conf file if __name__ == "__main__": import rpki.config rpki.config.default_dirname = "%(ac_sysconfdir)s" # Original script starts here ''' django_script_template = '''\ #!%(ac_PYTHON)s # Automatically constructed script header import sys, os # sys.path[0] is the cwd of the script being executed, so we add the # path to the settings.py file after it sys.path.insert(1, '%(ac_sysconfdir)s/rpki') os.environ['DJANGO_SETTINGS_MODULE'] = 'settings' # Original script starts here ''' class build_data(Command): description = 'build various constructed "data" files' # Most of these are really scripts, but install_scripts has no # provision for installing in different directories, and we do have # some real data files as well, so it's easiest just to handle all # of that here. user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): self.run_command("autoconf") for fn in daemon_scripts: self.build_script(fn, daemon_script_template, ac_PYTHON = ac.PYTHON, ac_sysconfdir = ac.sysconfdir) for fn in django_scripts: self.build_script(fn, django_script_template, ac_PYTHON = ac.PYTHON, ac_sysconfdir = ac.sysconfdir) def build_script(self, fn, template, **kwargs): pyfn = fn + ".py" mode = stat.S_IMODE(os.stat(pyfn).st_mode) | 0555 f = open(fn, "w") f.write(template % kwargs) f.write(open(pyfn, "r").read()) f.close() os.chmod(fn, mode) class install_data(_install_data): def run(self): self.run_command("build_data") return _install_data.run(self) # Have to be careful with configuration that comes from autoconf. data_files = [] if ac is not None: if ac.sbindir and sbin_scripts: data_files.append((ac.sbindir, ["%s/%s" % (ac.abs_builddir, f) for f in sbin_scripts])) if ac.libexecdir and libexec_scripts: data_files.append((ac.libexecdir, ["%s/%s" % (ac.abs_builddir, f) for f in libexec_scripts])) # Then there's all the stuff from rpkid/portal-gui/Makefile.in which # also needs to go into data_files. if not data_files: data_files = None setup(name = "rpkitoolkit", version = "1.0", description = "RPKI Toolkit", license = "BSD", url = "http://www.rpki.net/", cmdclass = {"autoconf" : autoconf, "build_ext" : build_ext, "build_data" : build_data, "build_openssl" : build_openssl, "install_data" : install_data, # "sdist" : sdist, }, package_dir = {"" : "rpkid"}, packages = ["rpki", "rpki.POW", "rpki.irdb", "rpki.gui", "rpki.gui.app", "rpki.gui.cacheview", "rpki.gui.api", "rpki.gui.routeview"], ext_modules = [Extension("rpki.POW._POW", ["rpkid/ext/POW.c"])], package_data = {"rpki.gui.app" : ["migrations/*.py", "static/*/*", "templates/*.html", "templates/*/*.html", "templatetags/*.py"], "rpki.gui.cacheview" : ["templates/*/*.html"] }, data_files = data_files)