From 2dc861fbea36b6e6a57e6acbd9eb9340a9e0f4fe Mon Sep 17 00:00:00 2001 From: Leonardo Barcaroli Date: Mon, 21 Jan 2019 09:32:41 +0100 Subject: [PATCH] bdist_wheel packaging --- requirements_build.txt | 1 + setup.cfg | 2 +- setup.py | 112 ++++++++++++++++++++++++++++++----------- 3 files changed, 85 insertions(+), 30 deletions(-) create mode 100644 requirements_build.txt diff --git a/requirements_build.txt b/requirements_build.txt new file mode 100644 index 0000000..c72fbe9 --- /dev/null +++ b/requirements_build.txt @@ -0,0 +1 @@ +wheel>=0.32.3 diff --git a/setup.cfg b/setup.cfg index f49cf2f..0777e75 100644 --- a/setup.cfg +++ b/setup.cfg @@ -12,7 +12,7 @@ search = __version__ = '{current_version}' replace = __version__ = '{new_version}' [bdist_wheel] -universal = 1 +universal = 0 [flake8] exclude = docs diff --git a/setup.py b/setup.py index b91a946..239eb35 100644 --- a/setup.py +++ b/setup.py @@ -6,14 +6,17 @@ from collections import namedtuple from html.parser import HTMLParser import os -from urllib.error import HTTPError, URLError -from urllib.request import urlopen import pkg_resources -from setuptools import setup, find_packages -from setuptools.command.develop import develop -from setuptools.command.install import install +from setuptools import setup, find_packages # noqa +from setuptools.command.develop import develop # noqa +from setuptools.command.install import install # noqa +from setuptools.command.bdist_egg import bdist_egg # noqa import sys import tarfile +import typing as T +from urllib.error import HTTPError, URLError +from urllib.request import urlopen +from wheel.bdist_wheel import bdist_wheel # noqa import zipfile @@ -32,14 +35,14 @@ requirements = [ ] setup_requirements = [ -] +] # type: T.List[str] test_requirements = [ -] +] # type: T.List[str] class GitTags(HTMLParser): - tags = list() + tags: T.List[str] = list() take_next = 0 def handle_starttag(self, tag, attrs): @@ -63,7 +66,8 @@ def retrieve_page(url: str) -> bytes: from and URI, handling the errors. """ try: - content = urlopen(url).read() + with urlopen(url) as conn: + content = conn.read() except HTTPError as e: print("Connection error: {!s}".format(e)) raise @@ -101,26 +105,31 @@ def create_local_folder() -> None: bin_path = pkg_resources.resource_filename(PKG_NAME, BIN_PATH) -def assemble_driver_uri() -> str: +def assemble_driver_uri( + version: T.Optional[str]=None, + platform: T.Optional[str]=None + ) -> str: """ Selects the right geckodriver URI. """ # TODO: use pkg_resources.get_platform() - latest_vers = find_latest_version(GECKO_RELEASE_PATH) - platform = sys.platform - is_64bits = sys.maxsize > 2**32 - if is_64bits: - full_platform = '{}64'.format(platform) - else: - full_platform = '{}64'.format(platform) + if not version: + version = find_latest_version(GECKO_RELEASE_PATH) + if not platform: + s_platform = sys.platform + is_64bits = sys.maxsize > 2**32 + if is_64bits: + platform = '{}64'.format(s_platform) + else: + platform = '{}64'.format(s_platform) if 'win' in platform: ext = 'zip' else: ext = 'tar.gz' return '{base}/releases/download/{vers}/geckodriver-{vers}-{platform}.{ext}'.format( base=GECKO_RELEASE_PATH, - vers=latest_vers, - platform=full_platform, + vers=version, + platform=platform, ext=ext ) @@ -142,11 +151,13 @@ def download_driver_bin(uri: str, path: str) -> None: elif name.endswith(".tar.gz"): with tarfile.open(filepath, 'r') as r: r.extractall(path) + else: + raise RuntimeError("Unrecognized file extension: %s", name) finally: os.remove(filepath) -def postinstall() -> None: +def postinstall(platform: T.Optional[str]=None) -> None: """ Performs all the postintallation flow, donwloading in the right place the geckodriver binary. @@ -154,25 +165,66 @@ def postinstall() -> None: # target_path = os.path.join(os.path.abspath(os.path.curdir), 'bot_z', 'bin') target_path = pkg_resources.resource_filename('bot_z', 'bin') pkg_resources.ensure_directory(os.path.join(target_path, 'target')) - gecko_uri = assemble_driver_uri() + version = os.environ.get('BOTZ_GECKO_VERSION') + gecko_uri = assemble_driver_uri(version, platform) print("[POSTINSTALL] gecko_uri: {}".format(gecko_uri)) download_driver_bin(gecko_uri, target_path) +def translate_platform_to_gecko_vers(plat: str) -> str: + """ + Map appropriately the platform provided on the command line + to the one used by PEP 513. + """ + PLATS = { + "win32": "win32", + "win-amd64": "win64", + "manylinux1-i686": "linux32", + "manylinux1-x86_64": "linux64", + "macosx": "macos", + } + try: + return PLATS[plat] + except KeyError as e: + print("Allowed platforms are: {!r}".format(list(PLATS.keys()))) + raise + + # From: https://stackoverflow.com/a/36902139 -class PostDevelopCommand(develop): - """Post-installation for development mode.""" +class CustomDevelopCommand(develop): + """Custom installation for development mode.""" def run(self): super().run() print("POSTINSTALL") postinstall() -class PostInstallCommand(install): - """Post-installation for installation mode.""" +class CustomInstallCommand(install): + """Custom installation for installation mode.""" def run(self): super().run() - postinstall() + opts = self.distribution.get_cmdline_options() + if 'bdist_wheel' in opts: + platform = translate_platform_to_gecko_vers( + opts['bdist_wheel'].get('plat-name') + ) + postinstall(platform) + + +# From: https://stackoverflow.com/a/45150383 +class CustomBDistWheel(bdist_wheel): + """ + Custom bdist_wheel command to ship the right binary + of geckodriver. + """ + def finalize_options(self): + super().finalize_options() + self.root_is_pure = False + + def get_tag(self): + python, abi, plat = super().get_tag() + python, abi = 'py3', 'none' + return python, abi, plat setup( @@ -185,14 +237,16 @@ setup( url='https://git.abbiamoundominio.org/blallo/BotZ', packages=find_packages(include=['bot_z']), cmdclass={ - 'develop': PostDevelopCommand, - 'install': PostInstallCommand, + 'develop': CustomDevelopCommand, + 'install': CustomInstallCommand, + 'bdist_wheel': CustomBDistWheel, }, entry_points={ 'console_scripts': [ 'bot_z=bot_z.cli:main' ] }, + package_data = {'bot_z': ['bot_z/bin/geckodriver']}, include_package_data=True, install_requires=requirements, license="GLWTS Public Licence", @@ -201,7 +255,7 @@ setup( classifiers=[ 'Development Status :: 2 - Pre-Alpha', 'Intended Audience :: Developers', - 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', + 'License :: GLWTS Public Licence', 'Natural Language :: English', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.7',