| #!/usr/bin/env python |
| # Copyright 1998-2021 Gentoo Authors |
| # Distributed under the terms of the GNU General Public License v2 |
| |
| try: |
| from setuptools.core import setup, Command |
| from setuptools.command.build import build |
| from setuptools.command.build_scripts import build_scripts |
| from setuptools.command.clean import clean |
| from setuptools.command.install import install |
| from setuptools.command.install_data import install_data |
| from setuptools.command.install_lib import install_lib |
| from setuptools.command.install_scripts import install_scripts |
| from setuptools.command.sdist import sdist |
| from setuptools.dep_util import newer |
| from setuptools.dir_util import mkpath, remove_tree |
| from setuptools.util import change_root, subst_vars |
| except ImportError: |
| from distutils.core import setup, Command |
| from distutils.command.build import build |
| from distutils.command.build_scripts import build_scripts |
| from distutils.command.clean import clean |
| from distutils.command.install import install |
| from distutils.command.install_data import install_data |
| from distutils.command.install_lib import install_lib |
| from distutils.command.install_scripts import install_scripts |
| from distutils.command.sdist import sdist |
| from distutils.dep_util import newer |
| from distutils.dir_util import mkpath, remove_tree |
| from distutils.util import change_root, subst_vars |
| |
| import codecs |
| import collections |
| import os |
| import os.path |
| import re |
| import subprocess |
| import sys |
| |
| # change the cwd to this one |
| os.chdir(os.path.dirname(os.path.realpath(__file__))) |
| |
| # TODO: |
| # - smarter rebuilds of docs w/ 'install_docbook' and 'install_epydoc'. |
| |
| x_scripts = { |
| 'bin': [ |
| 'bin/repoman', |
| ], |
| } |
| |
| |
| class x_build(build): |
| """ Build command with extra build_man call. """ |
| |
| def run(self): |
| build.run(self) |
| self.run_command('build_man') |
| |
| |
| class build_man(Command): |
| """ Perform substitutions in manpages. """ |
| |
| user_options = [ |
| ] |
| |
| def initialize_options(self): |
| self.build_base = None |
| |
| def finalize_options(self): |
| self.set_undefined_options('build', |
| ('build_base', 'build_base')) |
| |
| def run(self): |
| for d, files in self.distribution.data_files: |
| if not d.startswith('$mandir/'): |
| continue |
| |
| for source in files: |
| target = os.path.join(self.build_base, source) |
| mkpath(os.path.dirname(target)) |
| |
| if not newer(source, target) and not newer(__file__, target): |
| continue |
| |
| print('copying and updating %s -> %s' % ( |
| source, target)) |
| |
| with codecs.open(source, 'r', 'utf8') as f: |
| data = f.readlines() |
| data[0] = data[0].replace('VERSION', |
| self.distribution.get_version()) |
| with codecs.open(target, 'w', 'utf8') as f: |
| f.writelines(data) |
| |
| |
| class x_build_scripts_custom(build_scripts): |
| def finalize_options(self): |
| build_scripts.finalize_options(self) |
| if 'dir_name' in dir(self): |
| self.build_dir = os.path.join(self.build_dir, self.dir_name) |
| if self.dir_name in x_scripts: |
| self.scripts = x_scripts[self.dir_name] |
| else: |
| self.scripts = set(self.scripts) |
| for other_files in x_scripts.values(): |
| self.scripts.difference_update(other_files) |
| |
| def run(self): |
| # group scripts by subdirectory |
| split_scripts = collections.defaultdict(list) |
| for f in self.scripts: |
| dir_name = os.path.dirname(f[len('bin/'):]) |
| split_scripts[dir_name].append(f) |
| |
| base_dir = self.build_dir |
| base_scripts = self.scripts |
| for d, files in split_scripts.items(): |
| self.build_dir = os.path.join(base_dir, d) |
| self.scripts = files |
| self.copy_scripts() |
| |
| # restore previous values |
| self.build_dir = base_dir |
| self.scripts = base_scripts |
| |
| |
| class x_build_scripts_bin(x_build_scripts_custom): |
| dir_name = 'bin' |
| |
| |
| class x_build_scripts(build_scripts): |
| def initialize_option(self): |
| build_scripts.initialize_options(self) |
| |
| def finalize_options(self): |
| build_scripts.finalize_options(self) |
| |
| def run(self): |
| self.run_command('build_scripts_bin') |
| |
| |
| class x_clean(clean): |
| """ clean extended for doc & post-test cleaning """ |
| |
| def clean_tests(self): |
| # do not remove incorrect dirs accidentally |
| top_dir = os.path.normpath(os.path.join(self.build_lib, '..')) |
| cprefix = os.path.commonprefix((self.build_base, top_dir)) |
| if cprefix != self.build_base: |
| return |
| |
| bin_dir = os.path.join(top_dir, 'bin') |
| if os.path.exists(bin_dir): |
| remove_tree(bin_dir) |
| |
| conf_dir = os.path.join(top_dir, 'cnf') |
| if os.path.islink(conf_dir): |
| print('removing %s symlink' % repr(conf_dir)) |
| os.unlink(conf_dir) |
| |
| pni_file = os.path.join(top_dir, '.repoman_not_installed') |
| if os.path.exists(pni_file): |
| print('removing %s' % repr(pni_file)) |
| os.unlink(pni_file) |
| |
| def clean_man(self): |
| man_dir = os.path.join(self.build_base, 'man') |
| if os.path.exists(man_dir): |
| remove_tree(man_dir) |
| |
| def run(self): |
| if self.all: |
| self.clean_tests() |
| self.clean_docs() |
| self.clean_man() |
| |
| clean.run(self) |
| |
| |
| class x_install(install): |
| """ install command with extra Portage paths """ |
| |
| user_options = install.user_options + [ |
| # note: $prefix and $exec_prefix are reserved for Python install |
| ('system-prefix=', None, "Prefix for architecture-independent data"), |
| ('system-exec-prefix=', None, "Prefix for architecture-specific data"), |
| |
| ('bindir=', None, "Install directory for main executables"), |
| ('datarootdir=', None, "Data install root directory"), |
| ('docdir=', None, "Documentation install directory"), |
| ('htmldir=', None, "HTML documentation install directory"), |
| ('mandir=', None, "Manpage root install directory"), |
| ('portage-base=', 'b', "Portage install base"), |
| ('portage-bindir=', None, "Install directory for Portage internal-use executables"), |
| ('portage-datadir=', None, 'Install directory for data files'), |
| ('sbindir=', None, "Install directory for superuser-intended executables"), |
| ('sysconfdir=', None, 'System configuration path'), |
| ] |
| |
| # note: the order is important for proper substitution |
| paths = [ |
| ('system_prefix', '/usr'), |
| ('system_exec_prefix', '$system_prefix'), |
| |
| ('bindir', '$system_exec_prefix/bin'), |
| ('sbindir', '$system_exec_prefix/sbin'), |
| ('sysconfdir', '/etc'), |
| |
| ('datarootdir', '$system_prefix/share'), |
| ('docdir', '$datarootdir/doc/$package-$version'), |
| ('htmldir', '$docdir/html'), |
| ('mandir', '$datarootdir/man'), |
| |
| ('portage_base', '$system_exec_prefix/lib/portage'), |
| ('portage_bindir', '$portage_base/bin'), |
| ('portage_datadir', '$datarootdir/portage'), |
| |
| # not customized at the moment |
| ('logrotatedir', '$sysconfdir/logrotate.d'), |
| ('portage_confdir', '$portage_datadir/config'), |
| ('portage_setsdir', '$portage_confdir/sets'), |
| ] |
| |
| def initialize_options(self): |
| install.initialize_options(self) |
| |
| for key, default in self.paths: |
| setattr(self, key, default) |
| self.subst_paths = {} |
| |
| def finalize_options(self): |
| install.finalize_options(self) |
| |
| # substitute variables |
| new_paths = { |
| 'package': self.distribution.get_name(), |
| 'version': self.distribution.get_version(), |
| } |
| for key, _default in self.paths: |
| new_paths[key] = subst_vars(getattr(self, key), new_paths) |
| setattr(self, key, new_paths[key]) |
| self.subst_paths = new_paths |
| |
| |
| class x_install_data(install_data): |
| """ install_data with customized path support """ |
| |
| user_options = install_data.user_options |
| |
| def initialize_options(self): |
| install_data.initialize_options(self) |
| self.build_base = None |
| self.paths = None |
| |
| def finalize_options(self): |
| install_data.finalize_options(self) |
| self.set_undefined_options('build', |
| ('build_base', 'build_base')) |
| self.set_undefined_options('install', |
| ('subst_paths', 'paths')) |
| |
| def run(self): |
| self.run_command('build_man') |
| |
| def process_data_files(df): |
| for d, files in df: |
| # substitute man sources |
| if d.startswith('$mandir/'): |
| files = [os.path.join(self.build_base, v) for v in files] |
| |
| # substitute variables in path |
| d = subst_vars(d, self.paths) |
| yield (d, files) |
| |
| old_data_files = self.data_files |
| self.data_files = process_data_files(self.data_files) |
| |
| install_data.run(self) |
| self.data_files = old_data_files |
| |
| |
| class x_install_lib(install_lib): |
| """ install_lib command with Portage path substitution """ |
| |
| user_options = install_lib.user_options |
| |
| def initialize_options(self): |
| install_lib.initialize_options(self) |
| |
| def finalize_options(self): |
| install_lib.finalize_options(self) |
| self.set_undefined_options('install',) |
| |
| def install(self): |
| ret = install_lib.install(self) |
| |
| def rewrite_file(path, val_dict): |
| path = os.path.join(self.install_dir, path) |
| print('Rewriting %s' % path) |
| with codecs.open(path, 'r', 'utf-8') as f: |
| data = f.read() |
| |
| for varname, val in val_dict.items(): |
| regexp = r'(?m)^(%s\s*=).*$' % varname |
| repl = r'\1 %s' % repr(val) |
| |
| data = re.sub(regexp, repl, data) |
| |
| with codecs.open(path, 'w', 'utf-8') as f: |
| f.write(data) |
| |
| rewrite_file('repoman/__init__.py', { |
| 'VERSION': self.distribution.get_version(), |
| }) |
| |
| return ret |
| |
| |
| class x_install_scripts_custom(install_scripts): |
| def initialize_options(self): |
| install_scripts.initialize_options(self) |
| self.root = None |
| |
| def finalize_options(self): |
| self.set_undefined_options('install', |
| ('root', 'root'), |
| (self.var_name, 'install_dir')) |
| install_scripts.finalize_options(self) |
| self.build_dir = os.path.join(self.build_dir, self.dir_name) |
| |
| # prepend root |
| if self.root is not None: |
| self.install_dir = change_root(self.root, self.install_dir) |
| |
| |
| class x_install_scripts_bin(x_install_scripts_custom): |
| dir_name = 'bin' |
| var_name = 'bindir' |
| |
| |
| class x_install_scripts(install_scripts): |
| def initialize_option(self): |
| pass |
| |
| def finalize_options(self): |
| pass |
| |
| def run(self): |
| self.run_command('install_scripts_bin') |
| |
| |
| class x_sdist(sdist): |
| """ sdist defaulting to .tar.xz format, and archive files owned by root """ |
| |
| def initialize_options(self): |
| super().initialize_options() |
| self.formats = ['xztar'] |
| |
| def finalize_options(self): |
| if self.owner is None: |
| self.owner = 'root' |
| if self.group is None: |
| self.group = 'root' |
| |
| sdist.finalize_options(self) |
| |
| |
| class build_tests(x_build_scripts_custom): |
| """ Prepare build dir for running tests. """ |
| |
| def initialize_options(self): |
| x_build_scripts_custom.initialize_options(self) |
| self.build_base = None |
| self.build_lib = None |
| |
| def finalize_options(self): |
| x_build_scripts_custom.finalize_options(self) |
| self.set_undefined_options('build', |
| ('build_base', 'build_base'), |
| ('build_lib', 'build_lib')) |
| |
| # since we will be writing to $build_lib/.., it is important |
| # that we do not leave $build_base |
| self.top_dir = os.path.normpath(os.path.join(self.build_lib, '..')) |
| cprefix = os.path.commonprefix((self.build_base, self.top_dir)) |
| if cprefix != self.build_base: |
| raise SystemError('build_lib must be a subdirectory of build_base') |
| |
| self.build_dir = os.path.join(self.top_dir, 'bin') |
| |
| def run(self): |
| self.run_command('build_py') |
| |
| # install all scripts $build_lib/../bin |
| # (we can't do a symlink since we want shebangs corrected) |
| x_build_scripts_custom.run(self) |
| |
| # symlink 'cnf' directory |
| conf_dir = os.path.join(self.top_dir, 'cnf') |
| if os.path.exists(conf_dir): |
| if not os.path.islink(conf_dir): |
| raise SystemError('%s exists and is not a symlink (collision)' |
| % repr(conf_dir)) |
| os.unlink(conf_dir) |
| conf_src = os.path.relpath('cnf', self.top_dir) |
| print('Symlinking %s -> %s' % (conf_dir, conf_src)) |
| os.symlink(conf_src, conf_dir) |
| |
| # create $build_lib/../.repoman_not_installed |
| # to enable proper paths in tests |
| with open(os.path.join(self.top_dir, '.repoman_not_installed'), 'w'): |
| pass |
| |
| |
| class test(Command): |
| """ run tests """ |
| |
| user_options = [] |
| |
| def initialize_options(self): |
| self.build_lib = None |
| |
| def finalize_options(self): |
| self.set_undefined_options('build', |
| ('build_lib', 'build_lib')) |
| |
| def run(self): |
| self.run_command('build_tests') |
| subprocess.check_call([ |
| sys.executable, '-bWd', |
| os.path.join(self.build_lib, 'repoman/tests/runTests.py') |
| ]) |
| |
| |
| def find_packages(): |
| for dirpath, _dirnames, filenames in os.walk('lib'): |
| if '__init__.py' in filenames: |
| yield os.path.relpath(dirpath, 'lib') |
| |
| |
| def find_scripts(): |
| for dirpath, _dirnames, filenames in os.walk('bin'): |
| for f in filenames: |
| if f not in ['deprecated-path']: |
| yield os.path.join(dirpath, f) |
| |
| |
| def get_manpages(): |
| linguas = os.environ.get('LINGUAS') |
| if linguas is not None: |
| linguas = linguas.split() |
| |
| for dirpath, _dirnames, filenames in os.walk('man'): |
| groups = collections.defaultdict(list) |
| for f in filenames: |
| _fn, suffix = f.rsplit('.', 1) |
| groups[suffix].append(os.path.join(dirpath, f)) |
| |
| topdir = dirpath[len('man/'):] |
| if not topdir or linguas is None or topdir in linguas: |
| for g, mans in groups.items(): |
| yield [os.path.join('$mandir', topdir, 'man%s' % g), mans] |
| |
| |
| setup( |
| name = 'repoman', |
| version = '3.0.3', |
| url = 'https://wiki.gentoo.org/wiki/Project:Portage', |
| author = 'Gentoo Portage Development Team', |
| author_email = 'dev-portage@gentoo.org', |
| |
| package_dir = {'': 'lib'}, |
| packages = list(find_packages()), |
| # something to cheat build & install commands |
| scripts = list(find_scripts()), |
| |
| data_files = list(get_manpages()) + [ |
| ['$docdir', ['NEWS', 'RELEASE-NOTES']], |
| ['share/repoman/qa_data', ['cnf/qa_data/qa_data.yaml']], |
| ['share/repoman/linechecks', ['cnf/linechecks/linechecks.yaml']], |
| ['share/repoman/repository', [ |
| 'cnf/repository/linechecks.yaml', |
| 'cnf/repository/qa_data.yaml', |
| 'cnf/repository/repository.yaml']], |
| ], |
| |
| cmdclass = { |
| 'build': x_build, |
| 'build_man': build_man, |
| 'build_scripts': x_build_scripts, |
| 'build_scripts_bin': x_build_scripts_bin, |
| 'build_tests': build_tests, |
| 'clean': x_clean, |
| 'install': x_install, |
| 'install_data': x_install_data, |
| 'install_lib': x_install_lib, |
| 'install_scripts': x_install_scripts, |
| 'install_scripts_bin': x_install_scripts_bin, |
| 'sdist': x_sdist, |
| 'test': test, |
| }, |
| |
| classifiers = [ |
| 'Development Status :: 5 - Production/Stable', |
| 'Environment :: Console', |
| 'Intended Audience :: System Administrators', |
| 'License :: OSI Approved :: GNU General Public License v2 (GPLv2)', |
| 'Operating System :: POSIX', |
| 'Programming Language :: Python :: 3', |
| 'Topic :: System :: Installation/Setup' |
| ] |
| ) |