diff --git a/.github/workflows/linuxbrew.yml b/.github/workflows/linuxbrew.yml index d8996fd6..c3ede39b 100644 --- a/.github/workflows/linuxbrew.yml +++ b/.github/workflows/linuxbrew.yml @@ -6,6 +6,9 @@ jobs: strategy: matrix: python: ["3.9", "3.10", "3.11", "3.12", "3.13"] + env: + # For some unknown reason, linuxbrew tries to use "gcc-11" by default, which doesn't exist. + CC: gcc steps: - uses: actions/checkout@v3 - name: Install brew diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index 1b82d22d..f639637e 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -26,6 +26,7 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | export PKG_CONFIG_PATH="$(brew --prefix)/opt/libxml2/lib/pkgconfig" + export PYXMLSEC_LIBXML2_VERSION="$(pkg-config --modversion libxml-2.0)" python -m build rm -rf build/ - name: Set environment variables diff --git a/.github/workflows/manylinux.yml b/.github/workflows/manylinux.yml index a44776b3..db8ea913 100644 --- a/.github/workflows/manylinux.yml +++ b/.github/workflows/manylinux.yml @@ -5,11 +5,11 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-abi: [cp36-cp36m, cp37-cp37m, cp38-cp38, cp39-cp39, cp310-cp310, cp311-cp311] + python-abi: [cp38-cp38, cp39-cp39, cp310-cp310, cp311-cp311, cp312-cp312, cp313-cp313] image: - manylinux2014_x86_64 - manylinux_2_28_x86_64 - - musllinux_1_1_x86_64 + - musllinux_1_2_x86_64 container: quay.io/pypa/${{ matrix.image }} steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/sdist.yml b/.github/workflows/sdist.yml index e987cdce..04f22c14 100644 --- a/.github/workflows/sdist.yml +++ b/.github/workflows/sdist.yml @@ -2,7 +2,11 @@ name: sdist on: [push, pull_request] jobs: sdist: - runs-on: ubuntu-latest + # Avoid Ubuntu 24.04 in sdist workflows, because it contains libxmlsec1-dev + # v1.2.39, which has a bug that causes tests/test_pkcs11.py to fail. + # (It thinks the softhsm engine has a public key instead of a private key.) + # libxmlsec1 <=1.2.33 or >=1.2.42 works. TODO: Try 26.04 when available. + runs-on: ubuntu-22.04 strategy: matrix: python: ["3.9", "3.10", "3.11", "3.12", "3.13"] diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index af3fb57d..f9294fd3 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -19,7 +19,11 @@ permissions: {} jobs: sdist: - runs-on: ubuntu-latest + # Avoid Ubuntu 24.04 in sdist workflows, because it contains libxmlsec1-dev + # v1.2.39, which has a bug that causes tests/test_pkcs11.py to fail. + # (It thinks the softhsm engine has a public key instead of a private key.) + # libxmlsec1 <=1.2.33 or >=1.2.42 works. TODO: Try 26.04 when available. + runs-on: ubuntu-22.04 permissions: contents: write @@ -100,8 +104,8 @@ jobs: include: ${{ fromJson(needs.generate-wheels-matrix.outputs.include) }} env: - PYXMLSEC_LIBXML2_VERSION: 2.13.5 - PYXMLSEC_LIBXSLT_VERSION: 1.1.42 + PYXMLSEC_LIBXML2_VERSION: 2.14.4 + PYXMLSEC_LIBXSLT_VERSION: 1.1.43 steps: - name: Check out the repo diff --git a/pyproject.toml b/pyproject.toml index 8c03f910..540f91c1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,12 +54,10 @@ skip = [ "*-musllinux_i686", # LXML doesn't publish wheels for these platforms, which makes it # difficult for us to build wheels, so we exclude them. - "cp36-manylinux_aarch64", - "cp37-manylinux_aarch64", - "cp36-musllinux_aarch64", - "cp37-musllinux_aarch64", - "cp36-macosx*", - "cp37-macosx*", + "cp36-*", + "cp37-*", + "cp38-manylinux_aarch64", + "cp38-musllinux_aarch64", "cp38-macosx*", ] test-command = "pytest -v --color=yes {package}/tests" diff --git a/requirements.txt b/requirements.txt index 3490b822..014bfe10 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -lxml >= 3.8.0, !=4.7.0 --no-binary=lxml +lxml >= 3.8.0, !=4.7.0 diff --git a/setup.py b/setup.py index 92588ebc..8d3d4b94 100644 --- a/setup.py +++ b/setup.py @@ -70,22 +70,18 @@ def latest_release_from_gnome_org_cache(url, lib_name): return '{}/{}'.format(url, latest_source) -def latest_release_from_github_api(repo): - api_url = 'https://api.github.com/repos/{}/releases'.format(repo) +def latest_release_json_from_github_api(repo): + api_url = 'https://api.github.com/repos/{}/releases/latest'.format(repo) # if we are running in CI, pass along the GH_TOKEN, so we don't get rate limited token = os.environ.get("GH_TOKEN") if token: log.info("Using GitHub token to avoid rate limiting") - api_releases = make_request(api_url, token, json_response=True) - releases = [r['tarball_url'] for r in api_releases if r['prerelease'] is False and r['draft'] is False] - if not releases: - raise DistutilsError('No release found for {}'.format(repo)) - return releases[0] + return make_request(api_url, token, json_response=True) def latest_openssl_release(): - return latest_release_from_github_api('openssl/openssl') + return latest_release_json_from_github_api('openssl/openssl')['tarball_url'] def latest_zlib_release(): @@ -105,7 +101,9 @@ def latest_libxslt_release(): def latest_xmlsec_release(): - return latest_release_from_html('https://www.aleksey.com/xmlsec/download/', re.compile('xmlsec1-(?P.*).tar.gz')) + assets = latest_release_json_from_github_api('lsh123/xmlsec')['assets'] + (tar_gz,) = [asset for asset in assets if asset['name'].endswith('.tar.gz')] + return tar_gz['browser_download_url'] class CrossCompileInfo: @@ -381,7 +379,7 @@ def prepare_static_build(self, build_platform): url = latest_xmlsec_release() self.info('{:10}: {}'.format('xmlsec1', 'PYXMLSEC_XMLSEC1_VERSION unset, downloading latest from {}'.format(url))) else: - url = 'https://www.aleksey.com/xmlsec/download/xmlsec1-{}.tar.gz'.format(self.xmlsec1_version) + url = 'https://github.com/lsh123/xmlsec/releases/download/{v}/xmlsec1-{v}.tar.gz'.format(v=self.xmlsec1_version) self.info( '{:10}: {}'.format( 'xmlsec1', 'PYXMLSEC_XMLSEC1_VERSION={}, downloading from {}'.format(self.xmlsec1_version, url) @@ -435,43 +433,41 @@ def prepare_static_build(self, build_platform): openssl_config_cmd.append(cross_compiling.triplet) else: openssl_config_cmd.insert(0, './config') - subprocess.check_output(openssl_config_cmd, cwd=str(openssl_dir), env=env) - subprocess.check_output(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(openssl_dir), env=env) - subprocess.check_output( + subprocess.check_call(openssl_config_cmd, cwd=str(openssl_dir), env=env) + subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(openssl_dir), env=env) + subprocess.check_call( ['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install_sw'], cwd=str(openssl_dir), env=env ) self.info('Building zlib') zlib_dir = next(self.build_libs_dir.glob('zlib-*')) - subprocess.check_output(['./configure', prefix_arg], cwd=str(zlib_dir), env=env) - subprocess.check_output(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(zlib_dir), env=env) - subprocess.check_output(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(zlib_dir), env=env) + subprocess.check_call(['./configure', prefix_arg], cwd=str(zlib_dir), env=env) + subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(zlib_dir), env=env) + subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(zlib_dir), env=env) - host_arg = "" + host_arg = [] if cross_compiling: - host_arg = '--host={}'.format(cross_compiling.arch) + host_arg = ['--host={}'.format(cross_compiling.arch)] self.info('Building libiconv') libiconv_dir = next(self.build_libs_dir.glob('libiconv-*')) - subprocess.check_output( + subprocess.check_call( [ './configure', prefix_arg, '--disable-dependency-tracking', '--disable-shared', - host_arg, + *host_arg, ], cwd=str(libiconv_dir), env=env, ) - subprocess.check_output(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(libiconv_dir), env=env) - subprocess.check_output( - ['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(libiconv_dir), env=env - ) + subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(libiconv_dir), env=env) + subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(libiconv_dir), env=env) self.info('Building LibXML2') libxml2_dir = next(self.build_libs_dir.glob('libxml2-*')) - subprocess.check_output( + subprocess.check_call( [ './configure', prefix_arg, @@ -481,19 +477,17 @@ def prepare_static_build(self, build_platform): '--without-python', '--with-iconv={}'.format(self.prefix_dir), '--with-zlib={}'.format(self.prefix_dir), - host_arg, + *host_arg, ], cwd=str(libxml2_dir), env=env, ) - subprocess.check_output(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(libxml2_dir), env=env) - subprocess.check_output( - ['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(libxml2_dir), env=env - ) + subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(libxml2_dir), env=env) + subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(libxml2_dir), env=env) self.info('Building libxslt') libxslt_dir = next(self.build_libs_dir.glob('libxslt-*')) - subprocess.check_output( + subprocess.check_call( [ './configure', prefix_arg, @@ -502,27 +496,26 @@ def prepare_static_build(self, build_platform): '--without-python', '--without-crypto', '--with-libxml-prefix={}'.format(self.prefix_dir), - host_arg, + *host_arg, ], cwd=str(libxslt_dir), env=env, ) - subprocess.check_output(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(libxslt_dir), env=env) - subprocess.check_output( - ['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(libxslt_dir), env=env - ) + subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(libxslt_dir), env=env) + subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(libxslt_dir), env=env) self.info('Building xmlsec1') ldflags.append('-lpthread') env['LDFLAGS'] = ' '.join(ldflags) xmlsec1_dir = next(self.build_libs_dir.glob('xmlsec1-*')) - subprocess.check_output( + subprocess.check_call( [ './configure', prefix_arg, '--disable-shared', '--disable-gost', '--enable-md5', + '--enable-ripemd160', '--disable-crypto-dl', '--enable-static=yes', '--enable-shared=no', @@ -531,20 +524,18 @@ def prepare_static_build(self, build_platform): '--with-openssl={}'.format(self.prefix_dir), '--with-libxml={}'.format(self.prefix_dir), '--with-libxslt={}'.format(self.prefix_dir), - host_arg, + *host_arg, ], cwd=str(xmlsec1_dir), env=env, ) - subprocess.check_output( + subprocess.check_call( ['make', '-j{}'.format(multiprocessing.cpu_count() + 1)] + ['-I{}'.format(str(self.prefix_dir / 'include')), '-I{}'.format(str(self.prefix_dir / 'include' / 'libxml'))], cwd=str(xmlsec1_dir), env=env, ) - subprocess.check_output( - ['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(xmlsec1_dir), env=env - ) + subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(xmlsec1_dir), env=env) ext = self.ext_map['xmlsec'] ext.define_macros = [