aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'setup.py')
-rw-r--r--[-rwxr-xr-x]setup.py330
1 files changed, 154 insertions, 176 deletions
diff --git a/setup.py b/setup.py
index 5273192f..4149fae3 100755..100644
--- a/setup.py
+++ b/setup.py
@@ -1,39 +1,64 @@
-#!/usr/bin/env python3
-
+import logging
import os
import sys
from collections import defaultdict
-from itertools import chain
+from contextlib import contextmanager
+from pathlib import Path
from textwrap import dedent
-from setuptools import setup
-from distutils import log
-from distutils.command import build_clib as dst_build_clib
-from distutils.command import install_data as dst_install_data
-from distutils.command import install_lib as dst_install_lib
-from distutils.util import byte_compile
-from snakeoil.dist import distutils_extensions as pkgdist
+from setuptools import setup, Command
+from setuptools.command.build import SubCommand, build as orig_build
+from setuptools.command.install import install as orig_install
+from setuptools.command.sdist import sdist as orig_sdist
+from wheel.bdist_wheel import bdist_wheel as orig_bdist_wheel
+
+
+use_system_tree_sitter_bash = bool(os.environ.get(
+ 'USE_SYSTEM_TREE_SITTER_BASH', False))
+
-pkgdist_setup, pkgdist_cmds = pkgdist.setup()
+@contextmanager
+def sys_path():
+ orig_path = sys.path[:]
+ sys.path.insert(0, str(Path.cwd() / 'src'))
+ try:
+ yield
+ finally:
+ sys.path = orig_path
-DATA_INSTALL_OFFSET = 'share/pkgcheck'
-use_system_tree_sitter_bash = bool(os.environ.get('USE_SYSTEM_TREE_SITTER_BASH', False))
+class build_treesitter(Command, SubCommand):
+ description = 'build tree-sitter-bash library'
+ def initialize_options(self):
+ pass
-class install_lib(dst_install_lib.install_lib):
- """Wrapper to install bash parsing library."""
+ def finalize_options(self):
+ pass
+
+ def get_source_files(self):
+ cwd = Path(__file__).parent / 'tree-sitter-bash/src'
+ return [
+ str(cwd / 'GNUmakefile'), str(cwd / 'tree_sitter/parser.h'),
+ str(cwd / 'parser.c'), str(cwd / 'scanner.cc'),
+ ]
+
+ library_path = Path(__file__).parent / 'src/pkgcheck/bash/lang.so'
def run(self):
- super().run()
if not use_system_tree_sitter_bash:
- build_clib = self.reinitialize_command('build_clib')
- build_clib.ensure_finalized()
- self.copy_tree(build_clib.build_clib, self.install_dir)
+ if not self.library_path.exists():
+ logging.info('building tree-sitter-bash library')
+ with sys_path():
+ from pkgcheck.bash import build_library
+ build_library(self.library_path, ['tree-sitter-bash'])
-class install(pkgdist.install):
- """Install wrapper to generate and install pkgcheck-related files."""
+class build(orig_build):
+ sub_commands = orig_build.sub_commands + [('build_treesitter', None)]
+
+
+class install(orig_install):
def finalize_options(self):
"""Force platlib install since non-python libraries are included."""
@@ -42,175 +67,128 @@ class install(pkgdist.install):
def run(self):
super().run()
- target = self.install_data
- root = self.root or '/'
- if target.startswith(root):
- target = os.path.join('/', os.path.relpath(target, root))
- target = os.path.abspath(target)
-
- if not self.dry_run:
- # Install configuration data so the program can find its content,
- # rather than assuming it is running from a tarball/git repo.
- write_obj_lists(self.install_lib, target)
-
-
-def write_obj_lists(python_base, install_prefix):
- """Generate config file of keyword, check, and other object lists."""
- objects_path = os.path.join(python_base, pkgdist.MODULE_NAME, "_objects.py")
- os.makedirs(os.path.dirname(objects_path), exist_ok=True)
- log.info(f'writing config to {objects_path!r}')
-
- wheel_install = (
- install_prefix != os.path.abspath(sys.prefix)
- and not install_prefix.startswith(pkgdist.REPODIR)
- )
-
- # hack to drop quotes on modules in generated files
- class _kls:
-
- def __init__(self, module):
- self.module = module
-
- def __repr__(self):
- return self.module
-
- with pkgdist.syspath(pkgdist.PACKAGEDIR):
- from pkgcheck import objects
-
- modules = defaultdict(set)
- objs = defaultdict(list)
- for obj in ('KEYWORDS', 'CHECKS', 'REPORTERS'):
- for name, cls in getattr(objects, obj).items():
- parent, module = cls.__module__.rsplit('.', 1)
- modules[parent].add(module)
- objs[obj].append((name, _kls(f'{module}.{name}')))
-
- keywords = tuple(objs['KEYWORDS'])
- checks = tuple(objs['CHECKS'])
- reporters = tuple(objs['REPORTERS'])
-
- with open(objects_path, 'w') as f:
- os.chmod(objects_path, 0o644)
- for k, v in sorted(modules.items()):
- f.write(f"from {k} import {', '.join(sorted(v))}\n")
- f.write(dedent(f"""\
- KEYWORDS = {keywords}
- CHECKS = {checks}
- REPORTERS = {reporters}
- """))
-
- const_path = os.path.join(python_base, pkgdist.MODULE_NAME, "_const.py")
- with open(const_path, 'w') as f:
- os.chmod(const_path, 0o644)
- # write install path constants to config
- if wheel_install:
- # write more dynamic _const file for wheel installs
- f.write(dedent("""\
- import os.path as osp
- import sys
- INSTALL_PREFIX = osp.abspath(sys.prefix)
- DATA_PATH = osp.join(INSTALL_PREFIX, {!r})
- """.format(DATA_INSTALL_OFFSET)))
- else:
- f.write("INSTALL_PREFIX=%r\n" % install_prefix)
- f.write("DATA_PATH=%r\n" %
- os.path.join(install_prefix, DATA_INSTALL_OFFSET))
- f.close()
+ self.write_obj_lists()
+ self.generate_files()
- # byte compile generated modules
- for path in (const_path, objects_path):
- byte_compile([path], prefix=python_base)
- byte_compile([path], optimize=1, prefix=python_base)
- byte_compile([path], optimize=2, prefix=python_base)
+ self.copy_tree('data', self.install_data)
+ install_dir = Path(self.install_lib)
+ if not use_system_tree_sitter_bash:
+ self.reinitialize_command('build').ensure_finalized()
+ (dst := install_dir / 'pkgcheck/bash').mkdir(parents=True, exist_ok=True)
+ self.copy_file(build_treesitter.library_path, dst / 'lang.so',
+ preserve_mode=True, preserve_times=False)
-class install_data(dst_install_data.install_data):
- """Generate data files for install.
+ def write_obj_lists(self):
+ """Generate config file of keyword, check, and other object lists."""
+ (base_dir := Path(self.install_lib) / "pkgcheck").mkdir(parents=True, exist_ok=True)
+ objects_path = base_dir / "_objects.py"
+ const_path = base_dir / "_const.py"
+ verinfo_path = base_dir / "_verinfo.py"
- Currently this includes keyword, check, and reporter name lists.
- """
+ # hack to drop quotes on modules in generated files
+ class _kls:
- def run(self):
- self._generate_files()
- super().run()
+ def __init__(self, module):
+ self.module = module
+
+ def __repr__(self):
+ return self.module
- def _generate_files(self):
- with pkgdist.syspath(pkgdist.PACKAGEDIR):
+ with sys_path():
+ from pkgcheck import objects
+
+ modules = defaultdict(set)
+ objs = defaultdict(list)
+ for obj in ('KEYWORDS', 'CHECKS', 'REPORTERS'):
+ for name, cls in getattr(objects, obj).items():
+ parent, module = cls.__module__.rsplit('.', 1)
+ modules[parent].add(module)
+ objs[obj].append((name, _kls(f'{module}.{name}')))
+
+ keywords = tuple(objs['KEYWORDS'])
+ checks = tuple(objs['CHECKS'])
+ reporters = tuple(objs['REPORTERS'])
+
+ logging.info(f'writing objects to {objects_path!r}')
+ with objects_path.open('w') as f:
+ objects_path.chmod(0o644)
+ for k, v in sorted(modules.items()):
+ f.write(f"from {k} import {', '.join(sorted(v))}\n")
+ f.write(dedent(f"""\
+ KEYWORDS = {keywords}
+ CHECKS = {checks}
+ REPORTERS = {reporters}
+ """))
+
+ logging.info(f'writing path constants to {const_path!r}')
+ with const_path.open('w') as f:
+ const_path.chmod(0o644)
+ f.write(dedent("""\
+ from os.path import abspath, exists, join
+ import sys
+ INSTALL_PREFIX = abspath(sys.prefix)
+ if not exists(join(INSTALL_PREFIX, 'lib/pkgcore')):
+ INSTALL_PREFIX = abspath(sys.base_prefix)
+ DATA_PATH = join(INSTALL_PREFIX, 'share/pkgcheck')
+ """))
+
+ logging.info("generating version info")
+ from snakeoil.version import get_git_version
+ verinfo_path.write_text(f"version_info={get_git_version(Path(__file__).parent)!r}")
+
+ def generate_files(self):
+ with sys_path():
from pkgcheck import base, objects
from pkgcheck.addons import caches
- os.makedirs(os.path.join(pkgdist.REPODIR, '.generated'), exist_ok=True)
- files = []
+ (dst := Path(self.install_data) / 'share/pkgcheck').mkdir(parents=True, exist_ok=True)
- # generate available scopes
- path = os.path.join(pkgdist.REPODIR, '.generated', 'scopes')
- with open(path, 'w') as f:
- f.write('\n'.join(base.scopes) + '\n')
- files.append(os.path.join('.generated', 'scopes'))
+ logging.info('Generating available scopes')
+ (dst / 'scopes').write_text('\n'.join(base.scopes) + '\n')
- # generate available cache types
- path = os.path.join(pkgdist.REPODIR, '.generated', 'caches')
+ logging.info('Generating available cache types')
cache_objs = caches.CachedAddon.caches.values()
- with open(path, 'w') as f:
- f.write('\n'.join(x.type for x in cache_objs))
- files.append(os.path.join('.generated', 'caches'))
+ (dst / 'caches').write_text('\n'.join(x.type for x in cache_objs) + '\n')
- # generate available object lists
for obj in ('KEYWORDS', 'CHECKS', 'REPORTERS'):
- log.info(f'Generating {obj.lower()} list')
- path = os.path.join(pkgdist.REPODIR, '.generated', obj.lower())
- with open(path, 'w') as f:
- f.write('\n'.join(getattr(objects, obj)) + '\n')
- files.append(os.path.join('.generated', obj.lower()))
- self.data_files.append(('share/pkgcheck', files))
+ logging.info(f'Generating {obj.lower()} list')
+ (dst / obj.lower()).write_text('\n'.join(getattr(objects, obj)) + '\n')
-class build_clib(dst_build_clib.build_clib):
- """Build bash parsing library."""
+class bdist_wheel(orig_bdist_wheel):
- def run(self):
- if not use_system_tree_sitter_bash:
- with pkgdist.syspath(pkgdist.PACKAGEDIR):
- from pkgcheck.bash import build_library
- path = os.path.join(self.build_clib, 'pkgcheck', 'bash', 'lang.so')
- build_library(path, ['tree-sitter-bash'])
-
-
-class build(pkgdist.build):
- """Force build_clib to run to build bash parsing library."""
-
- sub_commands = pkgdist.build.sub_commands[:]
- sub_commands.append(('build_clib', None))
-
-
-setup(**dict(
- pkgdist_setup,
- license='BSD',
- author='Tim Harder',
- author_email='radhermit@gmail.com',
- description='pkgcore-based QA utility for ebuild repos',
- url='https://github.com/pkgcore/pkgcheck',
- data_files=list(chain(
- pkgdist.data_mapping('share/bash-completion/completions', 'completion/bash'),
- pkgdist.data_mapping('share/zsh/site-functions', 'completion/zsh'),
- pkgdist.data_mapping(DATA_INSTALL_OFFSET, 'data'),
- )),
- cmdclass=dict(
- pkgdist_cmds,
- install_data=install_data,
- install_lib=install_lib,
- install=install,
- build_clib=build_clib,
- build=build,
- ),
- classifiers=[
- 'License :: OSI Approved :: BSD License',
- 'Programming Language :: Python :: 3.9',
- 'Programming Language :: Python :: 3.10',
- 'Programming Language :: Python :: 3.11',
- ],
- extras_require={
- 'network': ['requests'],
- },
- distclass=pkgdist.BinaryDistribution,
-))
+ def finalize_options(self):
+ super().finalize_options()
+ self.root_is_pure = False # Mark us as not a pure python package
+
+ def get_tag(self):
+ _, _, plat = super().get_tag()
+ # We don't contain any python source, nor any python extensions
+ return 'py3', 'none', plat
+
+
+class sdist(orig_sdist):
+
+ def make_release_tree(self, base_dir, files):
+ super().make_release_tree(base_dir, files)
+ base_dir = Path(base_dir)
+
+ if (man_page := Path(__file__).parent / 'build/sphinx/man/pkgcheck.1').exists():
+ (base_dir / 'man').mkdir(parents=True, exist_ok=True)
+ self.copy_file(man_page, base_dir / 'man/pkgcheck.1', preserve_mode=False, preserve_times=False)
+
+ logging.info("generating version info")
+ from snakeoil.version import get_git_version
+ (base_dir / 'src/pkgcheck/_verinfo.py').write_text(f"version_info={get_git_version(Path(__file__).parent)!r}")
+
+
+setup(
+ cmdclass={
+ 'bdist_wheel': bdist_wheel,
+ 'build': build,
+ 'build_treesitter': build_treesitter,
+ 'install': install,
+ 'sdist': sdist,
+ }
+)