Skip to content

Commit ade391d

Browse files
committed
Refactor packaging build helpers into dedicated modules
Split the old monolithic setup.py build logic into focused helper modules so static builds are coordinated by dedicated utilities rather than one giant script.
1 parent a241c56 commit ade391d

File tree

6 files changed

+638
-582
lines changed

6 files changed

+638
-582
lines changed

build_support/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

build_support/build_ext.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import os
2+
import sys
3+
from distutils import log
4+
from distutils.errors import DistutilsError
5+
6+
from setuptools.command.build_ext import build_ext as build_ext_orig
7+
8+
from .static_build import CrossCompileInfo, StaticBuildHelper
9+
10+
11+
class build_ext(build_ext_orig):
12+
def info(self, message):
13+
self.announce(message, level=log.INFO)
14+
15+
def run(self):
16+
ext = self.ext_map['xmlsec']
17+
self.debug = os.environ.get('PYXMLSEC_ENABLE_DEBUG', False)
18+
self.static = os.environ.get('PYXMLSEC_STATIC_DEPS', False)
19+
self.size_opt = os.environ.get('PYXMLSEC_OPTIMIZE_SIZE', True)
20+
21+
if self.static or sys.platform == 'win32':
22+
helper = StaticBuildHelper(self)
23+
helper.prepare(sys.platform)
24+
else:
25+
import pkgconfig
26+
27+
try:
28+
config = pkgconfig.parse('xmlsec1')
29+
except OSError as error:
30+
raise DistutilsError('Unable to invoke pkg-config.') from error
31+
except pkgconfig.PackageNotFoundError as error:
32+
raise DistutilsError('xmlsec1 is not installed or not in path.') from error
33+
34+
if config is None or not config.get('libraries'):
35+
raise DistutilsError('Bad or incomplete result returned from pkg-config.')
36+
37+
ext.define_macros.extend(config['define_macros'])
38+
ext.include_dirs.extend(config['include_dirs'])
39+
ext.library_dirs.extend(config['library_dirs'])
40+
ext.libraries.extend(config['libraries'])
41+
42+
import lxml
43+
44+
ext.include_dirs.extend(lxml.get_include())
45+
46+
ext.define_macros.extend(
47+
[('MODULE_NAME', self.distribution.metadata.name), ('MODULE_VERSION', self.distribution.metadata.version)]
48+
)
49+
for key, value in ext.define_macros:
50+
if key == 'XMLSEC_CRYPTO' and not (value.startswith('"') and value.endswith('"')):
51+
ext.define_macros.remove((key, value))
52+
ext.define_macros.append((key, f'"{value}"'))
53+
break
54+
55+
if sys.platform == 'win32':
56+
ext.extra_compile_args.append('/Zi')
57+
else:
58+
ext.extra_compile_args.extend(
59+
[
60+
'-g',
61+
'-std=c99',
62+
'-fPIC',
63+
'-fno-strict-aliasing',
64+
'-Wno-error=declaration-after-statement',
65+
'-Werror=implicit-function-declaration',
66+
]
67+
)
68+
69+
if self.debug:
70+
ext.define_macros.append(('PYXMLSEC_ENABLE_DEBUG', '1'))
71+
if sys.platform == 'win32':
72+
ext.extra_compile_args.append('/Od')
73+
else:
74+
ext.extra_compile_args.append('-Wall')
75+
ext.extra_compile_args.append('-O0')
76+
else:
77+
if self.size_opt:
78+
if sys.platform == 'win32':
79+
ext.extra_compile_args.append('/Os')
80+
else:
81+
ext.extra_compile_args.append('-Os')
82+
83+
super().run()
84+
85+
86+
__all__ = ('build_ext', 'CrossCompileInfo')

build_support/network.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import contextlib
2+
import json
3+
from urllib.request import Request, urlopen
4+
5+
6+
DEFAULT_USER_AGENT = 'https://github.com/xmlsec/python-xmlsec'
7+
DOWNLOAD_USER_AGENT = 'python-xmlsec build'
8+
9+
10+
def make_request(url, github_token=None, json_response=False):
11+
headers = {'User-Agent': DEFAULT_USER_AGENT}
12+
if github_token:
13+
headers['authorization'] = 'Bearer ' + github_token
14+
request = Request(url, headers=headers)
15+
with contextlib.closing(urlopen(request)) as response:
16+
charset = response.headers.get_content_charset() or 'utf-8'
17+
content = response.read().decode(charset)
18+
if json_response:
19+
return json.loads(content)
20+
return content
21+
22+
23+
def download_lib(url, filename):
24+
request = Request(url, headers={'User-Agent': DOWNLOAD_USER_AGENT})
25+
with urlopen(request) as response, open(filename, 'wb') as target:
26+
while True:
27+
chunk = response.read(8192)
28+
if not chunk:
29+
break
30+
target.write(chunk)

build_support/releases.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import html.parser
2+
import os
3+
import re
4+
from distutils import log
5+
from distutils.version import StrictVersion as Version
6+
7+
from .network import make_request
8+
9+
10+
class HrefCollector(html.parser.HTMLParser):
11+
def __init__(self, *args, **kwargs):
12+
super().__init__(*args, **kwargs)
13+
self.hrefs = []
14+
15+
def handle_starttag(self, tag, attrs):
16+
if tag == 'a':
17+
for name, value in attrs:
18+
if name == 'href':
19+
self.hrefs.append(value)
20+
21+
22+
def latest_release_from_html(url, matcher):
23+
content = make_request(url)
24+
collector = HrefCollector()
25+
collector.feed(content)
26+
hrefs = collector.hrefs
27+
28+
def comp(text):
29+
try:
30+
return Version(matcher.match(text).groupdict()['version'])
31+
except (AttributeError, ValueError):
32+
return Version('0.0')
33+
34+
latest = max(hrefs, key=comp)
35+
return f'{url}/{latest}'
36+
37+
38+
def latest_release_from_gnome_org_cache(url, lib_name):
39+
cache_url = f'{url}/cache.json'
40+
cache = make_request(cache_url, json_response=True)
41+
latest_version = cache[2][lib_name][-1]
42+
latest_source = cache[1][lib_name][latest_version]['tar.xz']
43+
return f'{url}/{latest_source}'
44+
45+
46+
def latest_release_json_from_github_api(repo):
47+
api_url = f'https://api.github.com/repos/{repo}/releases/latest'
48+
token = os.environ.get('GH_TOKEN')
49+
if token:
50+
log.info('Using GitHub token to avoid rate limiting')
51+
return make_request(api_url, token, json_response=True)
52+
53+
54+
def latest_openssl_release():
55+
return latest_release_json_from_github_api('openssl/openssl')['tarball_url']
56+
57+
58+
def latest_zlib_release():
59+
return latest_release_from_html('https://zlib.net/fossils', re.compile('zlib-(?P<version>.*).tar.gz'))
60+
61+
62+
def latest_libiconv_release():
63+
return latest_release_from_html('https://ftp.gnu.org/pub/gnu/libiconv', re.compile('libiconv-(?P<version>.*).tar.gz'))
64+
65+
66+
def latest_libxml2_release():
67+
return latest_release_from_gnome_org_cache('https://download.gnome.org/sources/libxml2', 'libxml2')
68+
69+
70+
def latest_libxslt_release():
71+
return latest_release_from_gnome_org_cache('https://download.gnome.org/sources/libxslt', 'libxslt')
72+
73+
74+
def latest_xmlsec_release():
75+
assets = latest_release_json_from_github_api('lsh123/xmlsec')['assets']
76+
(tar_gz,) = [asset for asset in assets if asset['name'].endswith('.tar.gz')]
77+
return tar_gz['browser_download_url']

0 commit comments

Comments
 (0)