import glob import logging import os import shutil import subprocess import time from jinja2 import FileSystemLoader, Environment TEMPLATES_PATH = os.path.join(os.path.dirname(__file__), 'templates') logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger(__name__) def render_template(template_name, **kwargs): env = Environment(loader=FileSystemLoader(TEMPLATES_PATH)) return env.get_template(template_name).render(**kwargs) def strip_slash(filename): if filename[0] == '/': filename = filename[1:] return filename def copy_and_overwrite(src, dst): if os.path.exists(dst): shutil.rmtree(dst) shutil.copytree(src, dst, ignore=shutil.ignore_patterns('.tox', '.git', '*.pyc', '.eggs', '*.egg-info')) def create_file_from_template(filename, template, **kwargs): with open(filename, 'w') as f: f.write(render_template(template, **kwargs)) def create_debian_files(debian_folder, **kwargs): for filename in ['control', 'changelog', 'compat', 'rules']: create_file_from_template(os.path.join(debian_folder, filename), '{}.j2'.format(filename), **kwargs) os.chmod(os.path.join(debian_folder, 'rules'), 0o0755) def create_setup_file(build_folder, **kwargs): create_file_from_template(os.path.join(build_folder, 'setup.py'), 'setup.py.j2', **kwargs) def add_file(src_filename, dst_filename): if os.path.exists(src_filename): logger.info('Copy file {} to {}'.format(src_filename, dst_filename)) shutil.copyfile(src_filename, dst_filename) def add_files(build_folder, debian_folder, package_name, files): for file in files: src_file, dst_file = file.split(':') if dst_file: dst_file = strip_slash(dst_file) tmp_file = os.path.join(build_folder, dst_file) dst_dir = os.path.dirname(tmp_file) if not os.path.exists(dst_dir): logging.info('Creating directory {}'.format(dst_dir)) os.makedirs(dst_dir, 0o0755) logger.info('Copy custom file {} to {}'.format(src_file, tmp_file)) add_file(src_file, tmp_file) with open(os.path.join(debian_folder, '{}.install'.format(package_name)), 'a') as f: f.write("{} /{}\n".format(dst_file, os.path.dirname(dst_file))) def prepare_package(build_folder, source_folder, **kwargs): kwargs['package_date'] = time.strftime('%a, %d %b %Y %H:%M:%S %z') if source_folder: logger.info('Packaging source folder: {}'.format(source_folder)) copy_and_overwrite(source_folder, build_folder) elif kwargs.get('python_package'): logger.info('Packaging Python application: {}'.format(kwargs.get('python_package'))) create_setup_file(build_folder, **kwargs) else: raise Exception('You must provide a python package to install or a source folder') debian_folder = os.path.join(build_folder, 'debian') if not os.path.exists(debian_folder): os.makedirs(debian_folder) create_debian_files(debian_folder, **kwargs) add_files(build_folder, debian_folder, kwargs.get('package_name'), kwargs.get('files') or []) for hook in ['preinst', 'postinst', 'prerm', 'postrm']: hook_filename = kwargs.get(hook) if hook_filename: add_file(hook_filename, os.path.join(debian_folder, hook)) def create_package(build_folder, install_folder, package_version): os.chdir(build_folder) env = os.environ.copy() env['DH_VIRTUALENV_INSTALL_ROOT'] = install_folder env['DH_UPGRADE_PIP'] = '' env['DH_UPGRADE_SETUPTOOLS'] = '' env['PBR_VERSION'] = package_version subprocess.call(['dpkg-buildpackage', '-us', '-uc'], env=env) def move_packages(binary_folder): for debian_file in glob.glob('/*.deb'): dst_filename = os.path.join(binary_folder, os.path.basename(debian_file)) if os.path.exists(dst_filename): os.remove(dst_filename) shutil.move(debian_file, binary_folder) def build(build_folder, binary_folder, install_folder, source_folder, **kwargs): prepare_package(build_folder, source_folder, **kwargs) create_package(build_folder, install_folder, kwargs.get('package_version')) move_packages(binary_folder)