From 2c54bdc06263c74078fda88eb5fec37be055ca97 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 30 Sep 2023 20:15:00 -0700 Subject: [PATCH] pkgs/sage-conf_pypi/setup.py: Restructure like ..._conda, prepare for editable mode --- .gitignore | 10 ++++ pkgs/sage-conf_pypi/setup.py | 104 +++++++++++++++++++++++++---------- 2 files changed, 86 insertions(+), 28 deletions(-) diff --git a/.gitignore b/.gitignore index efdbfa8f616..2cec8a0cf62 100644 --- a/.gitignore +++ b/.gitignore @@ -175,6 +175,16 @@ build/bin/sage-build-env-config /pkgs/*/*.egg-info /pkgs/*/.tox +/pkgs/sage-conf_pypi/sage_root/config.log +/pkgs/sage-conf_pypi/sage_root/config.status +/pkgs/sage-conf_pypi/sage_root/local/ +/pkgs/sage-conf_pypi/sage_root/logs/ +/pkgs/sage-conf_pypi/sage_root/prefix +/pkgs/sage-conf_pypi/sage_root/src/bin/sage-env-config +/pkgs/sage-conf_pypi/sage_root/src/bin/sage-src-env-config +/pkgs/sage-conf_pypi/sage_root/upstream/ +/pkgs/sage-conf_pypi/sage_root/venv + /pkgs/sagemath-objects/setup.cfg /pkgs/sagemath-bliss/setup.cfg /pkgs/sagemath-coxeter3/setup.cfg diff --git a/pkgs/sage-conf_pypi/setup.py b/pkgs/sage-conf_pypi/setup.py index a689f4d617b..16686a848c9 100644 --- a/pkgs/sage-conf_pypi/setup.py +++ b/pkgs/sage-conf_pypi/setup.py @@ -3,40 +3,35 @@ import shutil import sysconfig import platform +import fnmatch from setuptools import setup from distutils.command.build_scripts import build_scripts as distutils_build_scripts from setuptools.command.build_py import build_py as setuptools_build_py -from setuptools.command.egg_info import egg_info as setuptools_egg_info -from distutils.errors import (DistutilsSetupError, DistutilsModuleError, - DistutilsOptionError) +from setuptools.command.editable_wheel import editable_wheel as setuptools_editable_wheel +from setuptools.errors import SetupError + class build_py(setuptools_build_py): def run(self): - DOT_SAGE = os.environ.get('DOT_SAGE', os.path.join(os.environ.get('HOME'), '.sage')) HERE = os.path.dirname(__file__) - with open(os.path.join(HERE, 'VERSION.txt')) as f: - sage_version = f.read().strip() + if self.editable_mode: + SAGE_ROOT = os.path.join(HERE, 'sage_root') + else: + SAGE_ROOT = self._create_writable_sage_root() + # For convenience, set up the homebrew env automatically. This is a no-op if homebrew is not present. - SETENV = '(. ./.homebrew-build-env 2> /dev/null || :)' - # After #30534, SAGE_LOCAL no longer contains any Python. So we key the SAGE_ROOT only to Sage version - # and architecture. - system = platform.system() - machine = platform.machine() - arch_tag = f'{system}-{machine}' - # TODO: These two should be user-configurable with options passed to "setup.py install" - SAGE_ROOT = os.path.join(DOT_SAGE, f'sage-{sage_version}-{arch_tag}') + if os.environ.get('CONDA_PREFIX', ''): + SETENV = ':' + else: + SETENV = '(. ./.homebrew-build-env 2> /dev/null || :)' + SAGE_LOCAL = os.path.join(SAGE_ROOT, 'local') + if os.path.exists(os.path.join(SAGE_ROOT, 'config.status')): - print(f'Reusing SAGE_ROOT={SAGE_ROOT}') + print(f'Reusing configured SAGE_ROOT={SAGE_ROOT}') else: - # config.status and other configure output has to be writable. - # So (until the Sage distribution supports VPATH builds - #21469), we have to make a copy of sage_root. - try: - shutil.copytree('sage_root', SAGE_ROOT) # will fail if already exists - except Exception: - raise DistutilsSetupError(f"the directory SAGE_ROOT={SAGE_ROOT} already exists but it is not configured. Please remove it and try again.") cmd = f"cd {SAGE_ROOT} && {SETENV} && ./configure --prefix={SAGE_LOCAL} --with-python={sys.executable} --enable-build-as-root --enable-download-from-upstream-url --with-system-python3=force --with-sage-venv --disable-notebook --disable-sagelib --disable-sage_conf --disable-doc" print(f"Running {cmd}") sys.stdout.flush() @@ -45,7 +40,18 @@ def run(self): sys.stdout.flush() PREREQ_SPKG = "_prereq bzip2 xz libffi" # includes python3 SPKG_DEPCHECK packages os.system(f'cd {SAGE_ROOT} && export SYSTEM=$(build/bin/sage-guess-package-system 2>/dev/null) && export PACKAGES="$(build/bin/sage-get-system-packages $SYSTEM {PREREQ_SPKG})" && [ -n "$PACKAGES" ] && echo "You can install the required build prerequisites using the following shell command" && echo "" && build/bin/sage-print-system-package-command $SYSTEM --verbose --sudo install $PACKAGES && echo ""') - raise DistutilsSetupError("configure failed") + raise SetupError("configure failed") + + # Copy over files generated by the configure script + # (see configure.ac AC_CONFIG_FILES) + if self.editable_mode: + pass # same file + else: + shutil.copyfile(os.path.join(SAGE_ROOT, 'pkgs', 'sage-conf', '_sage_conf', '_conf.py'), + os.path.join(HERE, '_sage_conf', '_conf.py')) + shutil.copyfile(os.path.join(SAGE_ROOT, 'src', 'bin', 'sage-env-config'), + os.path.join(HERE, 'bin', 'sage-env-config')) + # Here we run "make build" -- which builds everything except for sagelib because we # used configure --disable-sagelib # Alternative: @@ -61,13 +67,44 @@ def run(self): if os.system(cmd) != 0: raise DistutilsSetupError(f"make {TARGETS} failed") - # Install configuration - shutil.copyfile(os.path.join(SAGE_ROOT, 'pkgs', 'sage-conf', '_sage_conf', '_conf.py'), - os.path.join(HERE, '_sage_conf', '_conf.py')) - shutil.copyfile(os.path.join(SAGE_ROOT, 'src', 'bin', 'sage-env-config'), - os.path.join(HERE, 'bin', 'sage-env-config')) setuptools_build_py.run(self) + def _create_writable_sage_root(self): + HERE = os.path.dirname(__file__) + DOT_SAGE = os.environ.get('DOT_SAGE', os.path.join(os.environ.get('HOME'), '.sage')) + with open(os.path.join(HERE, 'VERSION.txt')) as f: + sage_version = f.read().strip() + # After #30534, SAGE_LOCAL no longer contains any Python. So we key the SAGE_ROOT only to Sage version + # and architecture. + system = platform.system() + machine = platform.machine() + arch_tag = f'{system}-{machine}' + # TODO: Should be user-configurable with config settings + SAGE_ROOT = os.path.join(DOT_SAGE, f'sage-{sage_version}-{arch_tag}') + + def ignore(path, names): + # exclude all embedded src trees + if fnmatch.fnmatch(path, f'*/build/pkgs/*'): + return ['src'] + ### ignore more stuff --- .tox etc. + return [name for name in names + if name in ('.tox', '.git', '__pycache__', + 'prefix', 'local', 'venv', 'upstream', + 'config.status', 'config.log', 'logs')] + + if not os.path.exists(os.path.join(SAGE_ROOT, 'config.status')): + # config.status and other configure output has to be writable. + # So (until the Sage distribution supports VPATH builds - #21469), we have to make a copy of sage_root. + try: + shutil.copytree('sage_root', SAGE_ROOT, + ignore=ignore) # will fail if already exists + except Exception as e: + raise SetupError(f"the directory SAGE_ROOT={SAGE_ROOT} already exists but it is not configured ({e}). " + "Please either remove it and try again, or install in editable mode (pip install -e).") + + return SAGE_ROOT + + class build_scripts(distutils_build_scripts): def run(self): @@ -76,6 +113,17 @@ def run(self): self.entry_points = self.distribution.entry_points = dict() distutils_build_scripts.run(self) + +class editable_wheel(setuptools_editable_wheel): + r""" + Customized so that exceptions raised by our build_py + do not lead to the "Customization incompatible with editable install" message + """ + _safely_run = setuptools_editable_wheel.run_command + + setup( - cmdclass=dict(build_py=build_py, build_scripts=build_scripts) + cmdclass=dict(build_py=build_py, + build_scripts=build_scripts, + editable_wheel=editable_wheel) )