relenv 0.21.0__tar.gz → 0.21.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. {relenv-0.21.0/relenv.egg-info → relenv-0.21.2}/PKG-INFO +1 -1
  2. {relenv-0.21.0 → relenv-0.21.2}/relenv/build/__init__.py +1 -1
  3. {relenv-0.21.0 → relenv-0.21.2}/relenv/build/common.py +98 -0
  4. {relenv-0.21.0 → relenv-0.21.2}/relenv/build/linux.py +4 -4
  5. relenv-0.21.2/relenv/build/windows.py +519 -0
  6. {relenv-0.21.0 → relenv-0.21.2}/relenv/common.py +16 -4
  7. {relenv-0.21.0 → relenv-0.21.2}/relenv/pyversions.py +1 -1
  8. {relenv-0.21.0 → relenv-0.21.2}/relenv/runtime.py +33 -4
  9. {relenv-0.21.0 → relenv-0.21.2/relenv.egg-info}/PKG-INFO +1 -1
  10. {relenv-0.21.0 → relenv-0.21.2}/tests/test_verify_build.py +23 -0
  11. relenv-0.21.0/relenv/build/windows.py +0 -258
  12. {relenv-0.21.0 → relenv-0.21.2}/LICENSE.md +0 -0
  13. {relenv-0.21.0 → relenv-0.21.2}/MANIFEST.in +0 -0
  14. {relenv-0.21.0 → relenv-0.21.2}/NOTICE +0 -0
  15. {relenv-0.21.0 → relenv-0.21.2}/README.md +0 -0
  16. {relenv-0.21.0 → relenv-0.21.2}/pyproject.toml +0 -0
  17. {relenv-0.21.0 → relenv-0.21.2}/relenv/__init__.py +0 -0
  18. {relenv-0.21.0 → relenv-0.21.2}/relenv/__main__.py +0 -0
  19. {relenv-0.21.0 → relenv-0.21.2}/relenv/_scripts/install_vc_build.ps1 +0 -0
  20. {relenv-0.21.0 → relenv-0.21.2}/relenv/build/darwin.py +0 -0
  21. {relenv-0.21.0 → relenv-0.21.2}/relenv/buildenv.py +0 -0
  22. {relenv-0.21.0 → relenv-0.21.2}/relenv/check.py +0 -0
  23. {relenv-0.21.0 → relenv-0.21.2}/relenv/create.py +0 -0
  24. {relenv-0.21.0 → relenv-0.21.2}/relenv/fetch.py +0 -0
  25. {relenv-0.21.0 → relenv-0.21.2}/relenv/manifest.py +0 -0
  26. {relenv-0.21.0 → relenv-0.21.2}/relenv/relocate.py +0 -0
  27. {relenv-0.21.0 → relenv-0.21.2}/relenv/toolchain.py +0 -0
  28. {relenv-0.21.0 → relenv-0.21.2}/relenv.egg-info/SOURCES.txt +0 -0
  29. {relenv-0.21.0 → relenv-0.21.2}/relenv.egg-info/dependency_links.txt +0 -0
  30. {relenv-0.21.0 → relenv-0.21.2}/relenv.egg-info/entry_points.txt +0 -0
  31. {relenv-0.21.0 → relenv-0.21.2}/relenv.egg-info/requires.txt +0 -0
  32. {relenv-0.21.0 → relenv-0.21.2}/relenv.egg-info/top_level.txt +0 -0
  33. {relenv-0.21.0 → relenv-0.21.2}/setup.cfg +0 -0
  34. {relenv-0.21.0 → relenv-0.21.2}/setup.py +0 -0
  35. {relenv-0.21.0 → relenv-0.21.2}/tests/__init__.py +0 -0
  36. {relenv-0.21.0 → relenv-0.21.2}/tests/conftest.py +0 -0
  37. {relenv-0.21.0 → relenv-0.21.2}/tests/test_build.py +0 -0
  38. {relenv-0.21.0 → relenv-0.21.2}/tests/test_common.py +0 -0
  39. {relenv-0.21.0 → relenv-0.21.2}/tests/test_create.py +0 -0
  40. {relenv-0.21.0 → relenv-0.21.2}/tests/test_downloads.py +0 -0
  41. {relenv-0.21.0 → relenv-0.21.2}/tests/test_fips_photon.py +0 -0
  42. {relenv-0.21.0 → relenv-0.21.2}/tests/test_relocate.py +0 -0
  43. {relenv-0.21.0 → relenv-0.21.2}/tests/test_runtime.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: relenv
3
- Version: 0.21.0
3
+ Version: 0.21.2
4
4
  Project-URL: Source Code, https://github.com/saltstack/relative-environment-for-python
5
5
  Project-URL: Documentation, https://relenv.readthedocs.io/en/latest/
6
6
  Project-URL: Changelog, https://relenv.readthedocs.io/en/latest/changelog.html
@@ -152,7 +152,7 @@ def main(args):
152
152
  build_version = requested
153
153
  else:
154
154
  pyversions = python_versions(args.python)
155
- build_version = pyversions.keys()[0]
155
+ build_version = sorted(list(pyversions.keys()))[-1]
156
156
 
157
157
  # print(pyversions)
158
158
  # print(pyversions[0].major)
@@ -38,6 +38,7 @@ from relenv.common import (
38
38
  runcmd,
39
39
  work_dirs,
40
40
  fetch_url,
41
+ Version,
41
42
  )
42
43
  import relenv.relocate
43
44
 
@@ -358,6 +359,99 @@ def build_sqlite(env, dirs, logfp):
358
359
  runcmd(["make", "install"], env=env, stderr=logfp, stdout=logfp)
359
360
 
360
361
 
362
+ def update_ensurepip(directory):
363
+ """
364
+ Update bundled dependencies for ensurepip (pip & setuptools).
365
+ """
366
+ # ensurepip bundle location
367
+ bundle_dir = directory / "ensurepip" / "_bundled"
368
+
369
+ # Make sure the destination directory exists
370
+ bundle_dir.mkdir(parents=True, exist_ok=True)
371
+
372
+ # Detect existing whl. Later versions of python don't include setuptools. We
373
+ # only want to update whl files that python expects to be there
374
+ pip_version = "25.2"
375
+ setuptools_version = "80.9.0"
376
+ update_pip = False
377
+ update_setuptools = False
378
+ for file in bundle_dir.glob("*.whl"):
379
+
380
+ log.debug("Checking whl: %s", str(file))
381
+ if file.name.startswith("pip-"):
382
+ found_version = file.name.split("-")[1]
383
+ log.debug("Found version %s", found_version)
384
+ if Version(found_version) >= Version(pip_version):
385
+ log.debug("Found correct pip version or newer: %s", found_version)
386
+ else:
387
+ file.unlink()
388
+ update_pip = True
389
+ if file.name.startswith("setuptools-"):
390
+ found_version = file.name.split("-")[1]
391
+ log.debug("Found version %s", found_version)
392
+ if Version(found_version) >= Version(setuptools_version):
393
+ log.debug(
394
+ "Found correct setuptools version or newer: %s", found_version
395
+ )
396
+ else:
397
+ file.unlink()
398
+ update_setuptools = True
399
+
400
+ # Download whl files and update __init__.py
401
+ init_file = directory / "ensurepip" / "__init__.py"
402
+ if update_pip:
403
+ whl = f"pip-{pip_version}-py3-none-any.whl"
404
+ whl_path = "b7/3f/945ef7ab14dc4f9d7f40288d2df998d1837ee0888ec3659c813487572faa"
405
+ url = f"https://files.pythonhosted.org/packages/{whl_path}/{whl}"
406
+ download_url(url=url, dest=bundle_dir)
407
+ assert (bundle_dir / whl).exists()
408
+
409
+ # Update __init__.py
410
+ old = "^_PIP_VERSION.*"
411
+ new = f'_PIP_VERSION = "{pip_version}"'
412
+ patch_file(path=init_file, old=old, new=new)
413
+
414
+ # setuptools
415
+ if update_setuptools:
416
+ whl = f"setuptools-{setuptools_version}-py3-none-any.whl"
417
+ whl_path = "a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772"
418
+ url = f"https://files.pythonhosted.org/packages/{whl_path}/{whl}"
419
+ download_url(url=url, dest=bundle_dir)
420
+ assert (bundle_dir / whl).exists()
421
+
422
+ # setuptools
423
+ old = "^_SETUPTOOLS_VERSION.*"
424
+ new = f'_SETUPTOOLS_VERSION = "{setuptools_version}"'
425
+ patch_file(path=init_file, old=old, new=new)
426
+
427
+ log.debug("ensurepip __init__.py contents:")
428
+ log.debug(init_file.read_text())
429
+
430
+
431
+ def patch_file(path, old, new):
432
+ """
433
+ Search a file line by line for a string to replace.
434
+
435
+ :param path: Location of the file to search
436
+ :type path: str
437
+ :param old: The value that will be replaced
438
+ :type path: str
439
+ :param new: The value that will replace the 'old' value.
440
+ :type path: str
441
+ """
442
+ log.debug("Patching file: %s", path)
443
+ import re
444
+
445
+ with open(path, "r") as fp:
446
+ content = fp.read()
447
+ new_content = ""
448
+ for line in content.splitlines():
449
+ line = re.sub(old, new, line)
450
+ new_content += line + "\n"
451
+ with open(path, "w") as fp:
452
+ fp.write(new_content)
453
+
454
+
361
455
  def tarball_version(href):
362
456
  if href.endswith("tar.gz"):
363
457
  try:
@@ -1457,6 +1551,9 @@ def finalize(env, dirs, logfp):
1457
1551
 
1458
1552
  pymodules = libdir / find_pythonlib(libdir)
1459
1553
 
1554
+ # update ensurepip
1555
+ update_ensurepip(pymodules)
1556
+
1460
1557
  cwd = os.getcwd()
1461
1558
  modname = find_sysconfigdata(pymodules)
1462
1559
  path = sys.path
@@ -1474,6 +1571,7 @@ def finalize(env, dirs, logfp):
1474
1571
  bindir = pathlib.Path(dirs.prefix) / "bin"
1475
1572
  sitepackages = pymodules / "site-packages"
1476
1573
  install_runtime(sitepackages)
1574
+
1477
1575
  # Install pip
1478
1576
  python = dirs.prefix / "bin" / "python3"
1479
1577
  if env["RELENV_HOST_ARCH"] != env["RELENV_BUILD_ARCH"]:
@@ -379,11 +379,11 @@ def build_python(env, dirs, logfp):
379
379
  )
380
380
 
381
381
  if pathlib.Path("setup.py").exists():
382
- with tempfile.NamedTemporaryFile(mode="w", suffix="_patch") as patch_file:
383
- patch_file.write(PATCH)
384
- patch_file.flush()
382
+ with tempfile.NamedTemporaryFile(mode="w", suffix="_patch") as p_file:
383
+ p_file.write(PATCH)
384
+ p_file.flush()
385
385
  runcmd(
386
- ["patch", "-p0", "-i", patch_file.name],
386
+ ["patch", "-p0", "-i", p_file.name],
387
387
  env=env,
388
388
  stderr=logfp,
389
389
  stdout=logfp,
@@ -0,0 +1,519 @@
1
+ # Copyright 2022-2025 Broadcom.
2
+ # SPDX-License-Identifier: Apache-2
3
+ """
4
+ The windows build process.
5
+ """
6
+ import glob
7
+ import json
8
+ import logging
9
+ import os
10
+ import pathlib
11
+ import shutil
12
+ import sys
13
+ import tarfile
14
+
15
+ from .common import (
16
+ builds,
17
+ create_archive,
18
+ download_url,
19
+ extract_archive,
20
+ install_runtime,
21
+ MODULE_DIR,
22
+ patch_file,
23
+ runcmd,
24
+ update_ensurepip,
25
+ )
26
+ from ..common import arches, WIN32, Version
27
+
28
+ log = logging.getLogger(__name__)
29
+
30
+ ARCHES = arches[WIN32]
31
+
32
+ if sys.platform == WIN32:
33
+ import ctypes
34
+
35
+ kernel32 = ctypes.windll.kernel32
36
+ kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
37
+
38
+
39
+ def populate_env(env, dirs):
40
+ """
41
+ Make sure we have the correct environment variables set.
42
+
43
+ :param env: The environment dictionary
44
+ :type env: dict
45
+ :param dirs: The working directories
46
+ :type dirs: ``relenv.build.common.Dirs``
47
+ """
48
+ env["MSBUILDDISABLENODEREUSE"] = "1"
49
+
50
+
51
+ def update_props(source, old, new):
52
+ """
53
+ Overwrite a dependency string for Windows PCBuild.
54
+
55
+ :param source: Python's source directory
56
+ :type source: str
57
+ :param old: Regular expression to search for
58
+ :type old: str
59
+ :param new: Replacement text
60
+ :type new: str
61
+ """
62
+ patch_file(source / "PCbuild" / "python.props", old, new)
63
+ patch_file(source / "PCbuild" / "get_externals.bat", old, new)
64
+
65
+
66
+ def get_externals_source(externals_dir, url):
67
+ """
68
+ Download external source code dependency.
69
+
70
+ Download source code and extract to the "externals" directory in the root of
71
+ the python source. Only works with a tarball
72
+ """
73
+ zips_dir = externals_dir / "zips"
74
+ zips_dir.mkdir(parents=True, exist_ok=True)
75
+ local_file = download_url(url=url, dest=str(zips_dir))
76
+ extract_archive(archive=str(local_file), to_dir=str(externals_dir))
77
+ try:
78
+ os.remove(local_file)
79
+ except OSError:
80
+ log.exception("Failed to remove temporary file")
81
+
82
+
83
+ def get_externals_bin(source_root, url):
84
+ """
85
+ Download external binary dependency.
86
+
87
+ Download binaries to the "externals" directory in the root of the python
88
+ source.
89
+ """
90
+ pass
91
+
92
+
93
+ def update_sqlite(dirs, env):
94
+ """
95
+ Update the SQLITE library.
96
+ """
97
+ version = "3.50.4.0"
98
+ url = "https://sqlite.org/2025/sqlite-autoconf-3500400.tar.gz"
99
+ sha256 = "a3db587a1b92ee5ddac2f66b3edb41b26f9c867275782d46c3a088977d6a5b18"
100
+ ref_loc = f"cpe:2.3:a:sqlite:sqlite:{version}:*:*:*:*:*:*:*"
101
+ target_dir = dirs.source / "externals" / f"sqlite-{version}"
102
+ target_dir.parent.mkdir(parents=True, exist_ok=True)
103
+ if not target_dir.exists():
104
+ update_props(dirs.source, r"sqlite-\d+.\d+.\d+.\d+", f"sqlite-{version}")
105
+ get_externals_source(externals_dir=dirs.source / "externals", url=url)
106
+ # # we need to fix the name of the extracted directory
107
+ extracted_dir = dirs.source / "externals" / "sqlite-autoconf-3500400"
108
+ shutil.move(str(extracted_dir), str(target_dir))
109
+ # Update externals.spdx.json with the correct version, url, and hash
110
+ # This became a thing in 3.12
111
+ if env["RELENV_PY_MAJOR_VERSION"] in ["3.12"]:
112
+ spdx_json = dirs.source / "Misc" / "externals.spdx.json"
113
+ with open(str(spdx_json), "r") as f:
114
+ data = json.load(f)
115
+ for pkg in data["packages"]:
116
+ if pkg["name"] == "sqlite":
117
+ pkg["versionInfo"] = version
118
+ pkg["downloadLocation"] = url
119
+ pkg["checksums"][0]["checksumValue"] = sha256
120
+ pkg["externalRefs"][0]["referenceLocator"] = ref_loc
121
+ with open(str(spdx_json), "w") as f:
122
+ json.dump(data, f, indent=2)
123
+
124
+
125
+ def update_xz(dirs, env):
126
+ """
127
+ Update the XZ library.
128
+ """
129
+ version = "5.6.2"
130
+ url = f"https://github.com/tukaani-project/xz/releases/download/v{version}/xz-{version}.tar.xz"
131
+ sha256 = "8bfd20c0e1d86f0402f2497cfa71c6ab62d4cd35fd704276e3140bfb71414519"
132
+ ref_loc = f"cpe:2.3:a:tukaani:xz:{version}:*:*:*:*:*:*:*"
133
+ target_dir = dirs.source / "externals" / f"xz-{version}"
134
+ target_dir.parent.mkdir(parents=True, exist_ok=True)
135
+ if not target_dir.exists():
136
+ update_props(dirs.source, r"xz-\d+.\d+.\d+", f"xz-{version}")
137
+ get_externals_source(externals_dir=dirs.source / "externals", url=url)
138
+ # Starting with version v5.5.0, XZ-Utils removed the ability to compile
139
+ # with MSBuild. We are bringing the config.h from the last version that
140
+ # had it, 5.4.7
141
+ config_file = target_dir / "src" / "common" / "config.h"
142
+ config_file_source = dirs.root / "_resources" / "xz" / "config.h"
143
+ if not config_file.exists():
144
+ shutil.copy(str(config_file_source), str(config_file))
145
+ # Update externals.spdx.json with the correct version, url, and hash
146
+ # This became a thing in 3.12
147
+ if env["RELENV_PY_MAJOR_VERSION"] in ["3.12", "3.13", "3.14"]:
148
+ spdx_json = dirs.source / "Misc" / "externals.spdx.json"
149
+ with open(str(spdx_json), "r") as f:
150
+ data = json.load(f)
151
+ for pkg in data["packages"]:
152
+ if pkg["name"] == "xz":
153
+ pkg["versionInfo"] = version
154
+ pkg["downloadLocation"] = url
155
+ pkg["checksums"][0]["checksumValue"] = sha256
156
+ pkg["externalRefs"][0]["referenceLocator"] = ref_loc
157
+ with open(str(spdx_json), "w") as f:
158
+ json.dump(data, f, indent=2)
159
+
160
+
161
+ def update_expat(dirs, env):
162
+ """
163
+ Update the EXPAT library.
164
+ """
165
+ # Patch <src>/Modules/expat/refresh.sh. When the SBOM is created, refresh.sh
166
+ # is scanned for the expat version, even though it doesn't run on Windows.
167
+ version = "2.7.3"
168
+ hash = "821ac9710d2c073eaf13e1b1895a9c9aa66c1157a99635c639fbff65cdbdd732"
169
+ url = f'https://github.com/libexpat/libexpat/releases/download/R_{version.replace(".", "_")}/expat-{version}.tar.xz'
170
+ bash_refresh = dirs.source / "Modules" / "expat" / "refresh.sh"
171
+ old = r'expected_libexpat_tag="R_\d+_\d+_\d"'
172
+ new = f'expected_libexpat_tag="R_{version.replace(".", "_")}"'
173
+ patch_file(bash_refresh, old=old, new=new)
174
+ old = r'expected_libexpat_version="\d+.\d+.\d"'
175
+ new = f'expected_libexpat_version="{version}"'
176
+ patch_file(bash_refresh, old=old, new=new)
177
+ old = 'expected_libexpat_sha256=".*"'
178
+ new = f'expected_libexpat_sha256="{hash}"'
179
+ patch_file(bash_refresh, old=old, new=new)
180
+ get_externals_source(externals_dir=dirs.source / "Modules" / "expat", url=url)
181
+ # Copy *.h and *.c to expat directory
182
+ expat_lib_dir = dirs.source / "Modules" / "expat" / f"expat-{version}" / "lib"
183
+ expat_dir = dirs.source / "Modules" / "expat"
184
+ for file in glob.glob(str(expat_lib_dir / "*.h")):
185
+ if expat_dir / os.path.basename(file):
186
+ (expat_dir / os.path.basename(file)).unlink()
187
+ shutil.move(file, str(expat_dir))
188
+ for file in glob.glob(str(expat_lib_dir / "*.c")):
189
+ if expat_dir / os.path.basename(file):
190
+ (expat_dir / os.path.basename(file)).unlink()
191
+ shutil.move(file, str(expat_dir))
192
+ # Update sbom.spdx.json with the correct hashes. This became a thing in 3.12
193
+ # python Tools/build/generate_sbom.py doesn't work because it requires a git
194
+ # repository, so we have to do it manually.
195
+ if env["RELENV_PY_MAJOR_VERSION"] in ["3.12", "3.13", "3.14"]:
196
+ checksums = {
197
+ "Modules/expat/expat.h": [
198
+ {
199
+ "algorithm": "SHA1",
200
+ "checksumValue": "a4395dd0589a97aab0904f7a5f5dc5781a086aa2",
201
+ },
202
+ {
203
+ "algorithm": "SHA256",
204
+ "checksumValue": "610b844bbfa3ec955772cc825db4d4db470827d57adcb214ad372d0eaf00e591",
205
+ },
206
+ ],
207
+ "Modules/expat/expat_external.h": [
208
+ {
209
+ "algorithm": "SHA1",
210
+ "checksumValue": "8fdf2e79a7ab46a3c76c74ed7e5fe641cbef308d",
211
+ },
212
+ {
213
+ "algorithm": "SHA256",
214
+ "checksumValue": "ffb960af48b80935f3856a16e87023524b104f7fc1e58104f01db88ba7bfbcc9",
215
+ },
216
+ ],
217
+ "Modules/expat/internal.h": [
218
+ {
219
+ "algorithm": "SHA1",
220
+ "checksumValue": "7dce7d98943c5db33ae05e54801dcafb4547b9dd",
221
+ },
222
+ {
223
+ "algorithm": "SHA256",
224
+ "checksumValue": "6bfe307d52e7e4c71dbc30d3bd902a4905cdd83bbe4226a7e8dfa8e4c462a157",
225
+ },
226
+ ],
227
+ "Modules/expat/refresh.sh": [
228
+ {
229
+ "algorithm": "SHA1",
230
+ "checksumValue": "71812ca27328697a8dcae1949cd638717538321a",
231
+ },
232
+ {
233
+ "algorithm": "SHA256",
234
+ "checksumValue": "64fd1368de41e4ebc14593c65f5a676558aed44bd7d71c43ae05d06f9086d3b0",
235
+ },
236
+ ],
237
+ "Modules/expat/xmlparse.c": [
238
+ {
239
+ "algorithm": "SHA1",
240
+ "checksumValue": "4c81a1f04fc653877c63c834145c18f93cd95f3e",
241
+ },
242
+ {
243
+ "algorithm": "SHA256",
244
+ "checksumValue": "04a379615f476d55f95ca1853107e20627b48ca4afe8d0fd5981ac77188bf0a6",
245
+ },
246
+ ],
247
+ "Modules/expat/xmlrole.h": [
248
+ {
249
+ "algorithm": "SHA1",
250
+ "checksumValue": "ac2964cca107f62dd133bfd4736a9a17defbc401",
251
+ },
252
+ {
253
+ "algorithm": "SHA256",
254
+ "checksumValue": "92e41f373b67f6e0dcd7735faef3c3f1e2c17fe59e007e6b74beef6a2e70fa88",
255
+ },
256
+ ],
257
+ "Modules/expat/xmltok.c": [
258
+ {
259
+ "algorithm": "SHA1",
260
+ "checksumValue": "1e2d35d90a1c269217f83d3bdf3c71cc22cb4c3f",
261
+ },
262
+ {
263
+ "algorithm": "SHA256",
264
+ "checksumValue": "98d0fc735041956cc2e7bbbe2fb8f03130859410e0aee5e8015f406a37c02a3c",
265
+ },
266
+ ],
267
+ "Modules/expat/xmltok.h": [
268
+ {
269
+ "algorithm": "SHA1",
270
+ "checksumValue": "d126831eaa5158cff187a8c93f4bc1c8118f3b17",
271
+ },
272
+ {
273
+ "algorithm": "SHA256",
274
+ "checksumValue": "91bf003a725a675761ea8d92cebc299a76fd28c3a950572f41bc7ce5327ee7b5",
275
+ },
276
+ ],
277
+ }
278
+ spdx_json = dirs.source / "Misc" / "sbom.spdx.json"
279
+ with open(str(spdx_json), "r") as f:
280
+ data = json.load(f)
281
+ for file in data["files"]:
282
+ if file["fileName"] in checksums.keys():
283
+ print(file["fileName"])
284
+ file["checksums"] = checksums[file["fileName"]]
285
+ with open(str(spdx_json), "w") as f:
286
+ json.dump(data, f, indent=2)
287
+
288
+
289
+ def update_expat_check(env):
290
+ """
291
+ Check if the given python version should get an updated libexpat.
292
+
293
+ Patch libexpat on these versions and below:
294
+ - 3.9.23
295
+ - 3.10.18
296
+ - 3.11.13
297
+ - 3.12.11
298
+ - 3.13.7
299
+ """
300
+ relenv_version = Version(env["RELENV_PY_VERSION"])
301
+ if relenv_version.minor == 9 and relenv_version.micro <= 23:
302
+ return True
303
+ elif relenv_version.minor == 10 and relenv_version.micro <= 18:
304
+ return True
305
+ elif relenv_version.minor == 11 and relenv_version.micro <= 13:
306
+ return True
307
+ elif relenv_version.minor == 12 and relenv_version.micro <= 11:
308
+ return True
309
+ elif relenv_version.minor == 13 and relenv_version.micro <= 7:
310
+ return True
311
+ return False
312
+
313
+
314
+ def build_python(env, dirs, logfp):
315
+ """
316
+ Run the commands to build Python.
317
+
318
+ :param env: The environment dictionary
319
+ :type env: dict
320
+ :param dirs: The working directories
321
+ :type dirs: ``relenv.build.common.Dirs``
322
+ :param logfp: A handle for the log file
323
+ :type logfp: file
324
+ """
325
+ # Override default versions
326
+
327
+ # Create externals directory
328
+ externals_dir = dirs.source / "externals"
329
+ externals_dir.mkdir(parents=True, exist_ok=True)
330
+
331
+ # SQLITE
332
+ # TODO: Python 3.12 started creating an SBOM. We're doing something wrong
333
+ # TODO: updating sqlite so SBOM creation is failing. Gating here until we
334
+ # TODO: fix this. Here's the original gate:
335
+ # if env["RELENV_PY_MAJOR_VERSION"] in ["3.10", "3.11", "3.12"]:
336
+ if env["RELENV_PY_MAJOR_VERSION"] in ["3.10", "3.11"]:
337
+ update_sqlite(dirs=dirs, env=env)
338
+
339
+ # XZ-Utils
340
+ # TODO: Python 3.12 started creating an SBOM. We're doing something wrong
341
+ # TODO: updating XZ so SBOM creation is failing. Gating here until we fix
342
+ # TODO: this. Here's the original gate:
343
+ # if env["RELENV_PY_MAJOR_VERSION"] in ["3.10", "3.11", "3.12", "3.13", "3.14"]:
344
+ if env["RELENV_PY_MAJOR_VERSION"] in ["3.10", "3.11"]:
345
+ update_xz(dirs=dirs, env=env)
346
+
347
+ # TODO: This was my attempt to fix the expat error during build... it failed
348
+ # TODO: so we're just skipping for now.
349
+ if env["RELENV_PY_MAJOR_VERSION"] in ["3.10", "3.11"]:
350
+ if update_expat_check(env=env):
351
+ update_expat(dirs=dirs, env=env)
352
+
353
+ arch_to_plat = {
354
+ "amd64": "x64",
355
+ "x86": "win32",
356
+ "arm64": "arm64",
357
+ }
358
+ arch = env["RELENV_HOST_ARCH"]
359
+ plat = arch_to_plat[arch]
360
+ cmd = [
361
+ str(dirs.source / "PCbuild" / "build.bat"),
362
+ "-p",
363
+ plat,
364
+ "--no-tkinter",
365
+ ]
366
+
367
+ log.info("Start PCbuild")
368
+ runcmd(cmd, env=env, stderr=logfp, stdout=logfp)
369
+ log.info("PCbuild finished")
370
+
371
+ # This is where build.bat puts everything
372
+ # TODO: For now we'll only support 64bit
373
+ if arch == "amd64":
374
+ build_dir = dirs.source / "PCbuild" / arch
375
+ else:
376
+ build_dir = dirs.source / "PCbuild" / plat
377
+ bin_dir = dirs.prefix / "Scripts"
378
+ bin_dir.mkdir(parents=True, exist_ok=True)
379
+
380
+ # Move python binaries
381
+ binaries = [
382
+ "py.exe",
383
+ "pyw.exe",
384
+ "python.exe",
385
+ "pythonw.exe",
386
+ "python3.dll",
387
+ f"python{ env['RELENV_PY_MAJOR_VERSION'].replace('.', '') }.dll",
388
+ "vcruntime140.dll",
389
+ "venvlauncher.exe",
390
+ "venvwlauncher.exe",
391
+ ]
392
+ for binary in binaries:
393
+ shutil.move(src=str(build_dir / binary), dst=str(bin_dir / binary))
394
+
395
+ # Create DLLs directory
396
+ (dirs.prefix / "DLLs").mkdir(parents=True, exist_ok=True)
397
+ # Move all library files to DLLs directory (*.pyd, *.dll)
398
+ for file in glob.glob(str(build_dir / "*.pyd")):
399
+ shutil.move(src=file, dst=str(dirs.prefix / "DLLs"))
400
+ for file in glob.glob(str(build_dir / "*.dll")):
401
+ shutil.move(src=file, dst=str(dirs.prefix / "DLLs"))
402
+
403
+ # Copy include directory
404
+ shutil.copytree(
405
+ src=str(dirs.source / "Include"),
406
+ dst=str(dirs.prefix / "Include"),
407
+ dirs_exist_ok=True,
408
+ )
409
+ if "3.13" not in env["RELENV_PY_MAJOR_VERSION"]:
410
+ shutil.copy(
411
+ src=str(dirs.source / "PC" / "pyconfig.h"),
412
+ dst=str(dirs.prefix / "Include"),
413
+ )
414
+
415
+ # Copy library files
416
+ shutil.copytree(
417
+ src=str(dirs.source / "Lib"),
418
+ dst=str(dirs.prefix / "Lib"),
419
+ dirs_exist_ok=True,
420
+ )
421
+ os.makedirs(str(dirs.prefix / "Lib" / "site-packages"), exist_ok=True)
422
+
423
+ # Create libs directory
424
+ (dirs.prefix / "libs").mkdir(parents=True, exist_ok=True)
425
+ # Copy lib files
426
+ shutil.copy(
427
+ src=str(build_dir / "python3.lib"),
428
+ dst=str(dirs.prefix / "libs" / "python3.lib"),
429
+ )
430
+ pylib = f"python{ env['RELENV_PY_MAJOR_VERSION'].replace('.', '') }.lib"
431
+ shutil.copy(
432
+ src=str(build_dir / pylib),
433
+ dst=str(dirs.prefix / "libs" / pylib),
434
+ )
435
+
436
+
437
+ build = builds.add("win32", populate_env=populate_env)
438
+
439
+ build.add(
440
+ "python",
441
+ build_func=build_python,
442
+ download={
443
+ "url": "https://www.python.org/ftp/python/{version}/Python-{version}.tar.xz",
444
+ "version": build.version,
445
+ "checksum": "d31d548cd2c5ca2ae713bebe346ba15e8406633a",
446
+ },
447
+ )
448
+
449
+
450
+ def finalize(env, dirs, logfp):
451
+ """
452
+ Finalize sitecustomize, relenv runtime, and pip for Windows.
453
+
454
+ :param env: The environment dictionary
455
+ :type env: dict
456
+ :param dirs: The working directories
457
+ :type dirs: ``relenv.build.common.Dirs``
458
+ :param logfp: A handle for the log file
459
+ :type logfp: file
460
+ """
461
+ # Lay down site customize
462
+ sitepackages = dirs.prefix / "Lib" / "site-packages"
463
+ install_runtime(sitepackages)
464
+
465
+ # update ensurepip
466
+ update_ensurepip(dirs.prefix / "Lib")
467
+
468
+ # Install pip
469
+ python = dirs.prefix / "Scripts" / "python.exe"
470
+ runcmd([str(python), "-m", "ensurepip"], env=env, stderr=logfp, stdout=logfp)
471
+
472
+ def runpip(pkg):
473
+ # XXX Support cross pip installs on windows
474
+ env = os.environ.copy()
475
+ target = None
476
+ cmd = [
477
+ str(python),
478
+ "-m",
479
+ "pip",
480
+ "install",
481
+ str(pkg),
482
+ ]
483
+ if target:
484
+ cmd.append("--target={}".format(target))
485
+ runcmd(cmd, env=env, stderr=logfp, stdout=logfp)
486
+
487
+ runpip("wheel")
488
+ # This needs to handle running from the root of the git repo and also from
489
+ # an installed Relenv
490
+ if (MODULE_DIR.parent / ".git").exists():
491
+ runpip(MODULE_DIR.parent)
492
+ else:
493
+ runpip("relenv")
494
+
495
+ for root, _, files in os.walk(dirs.prefix):
496
+ for file in files:
497
+ if file.endswith(".pyc"):
498
+ os.remove(pathlib.Path(root) / file)
499
+
500
+ globs = [
501
+ "*.exe",
502
+ "*.py",
503
+ "*.pyd",
504
+ "*.dll",
505
+ "*.lib",
506
+ "*.whl",
507
+ "/Include/*",
508
+ "/Lib/site-packages/*",
509
+ ]
510
+ archive = f"{dirs.prefix}.tar.xz"
511
+ with tarfile.open(archive, mode="w:xz") as fp:
512
+ create_archive(fp, dirs.prefix, globs, logfp)
513
+
514
+
515
+ build.add(
516
+ "relenv-finalize",
517
+ build_func=finalize,
518
+ wait_on=["python"],
519
+ )
@@ -18,7 +18,7 @@ import threading
18
18
  import time
19
19
 
20
20
  # relenv package version
21
- __version__ = "0.21.0"
21
+ __version__ = "0.21.2"
22
22
 
23
23
  MODULE_DIR = pathlib.Path(__file__).resolve().parent
24
24
 
@@ -336,12 +336,19 @@ def extract_archive(to_dir, archive):
336
336
  :type archive: str
337
337
  """
338
338
  if archive.endswith("tgz"):
339
+ log.debug("Found tgz archive")
340
+ read_type = "r:gz"
341
+ elif archive.endswith("tar.gz"):
342
+ log.debug("Found tar.gz archive")
339
343
  read_type = "r:gz"
340
344
  elif archive.endswith("xz"):
345
+ log.debug("Found xz archive")
341
346
  read_type = "r:xz"
342
347
  elif archive.endswith("bz2"):
348
+ log.debug("Found bz2 archive")
343
349
  read_type = "r:bz2"
344
350
  else:
351
+ log.warning("Found unknown archive type: %s", archive)
345
352
  read_type = "r"
346
353
  with tarfile.open(archive, read_type) as t:
347
354
  t.extractall(to_dir)
@@ -411,6 +418,7 @@ def fetch_url(url, fp, backoff=3, timeout=30):
411
418
  n += 1
412
419
  try:
413
420
  fin = urllib.request.urlopen(url, timeout=timeout)
421
+ break
414
422
  except (
415
423
  urllib.error.HTTPError,
416
424
  urllib.error.URLError,
@@ -420,6 +428,8 @@ def fetch_url(url, fp, backoff=3, timeout=30):
420
428
  raise RelenvException(f"Error fetching url {url} {exc}")
421
429
  log.debug("Unable to connect %s", url)
422
430
  time.sleep(n * 10)
431
+ else:
432
+ raise RelenvException(f"Error fetching url: {url}")
423
433
  log.info("url opened %s", url)
424
434
  try:
425
435
  total = 0
@@ -434,7 +444,6 @@ def fetch_url(url, fp, backoff=3, timeout=30):
434
444
  block = fin.read(10240)
435
445
  finally:
436
446
  fin.close()
437
- # fp.close()
438
447
  log.info("Download complete %s", url)
439
448
 
440
449
 
@@ -514,18 +523,21 @@ def download_url(url, dest, verbose=True, backoff=3, timeout=60):
514
523
  """
515
524
  local = get_download_location(url, dest)
516
525
  if verbose:
517
- print(f"Downloading {url} -> {local}")
526
+ log.debug(f"Downloading {url} -> {local}")
518
527
  fout = open(local, "wb")
519
528
  try:
520
529
  fetch_url(url, fout, backoff, timeout)
521
530
  except Exception as exc:
522
531
  if verbose:
523
- print(f"Unable to download: {url} {exc}", file=sys.stderr, flush=True)
532
+ log.error("Unable to download: %s\n%s", url, exc)
524
533
  try:
525
534
  os.unlink(local)
526
535
  except OSError:
527
536
  pass
528
537
  raise
538
+ finally:
539
+ fout.close()
540
+ log.debug(f"Finished downloading {url} -> {local}")
529
541
  return local
530
542
 
531
543
 
@@ -340,7 +340,7 @@ def main(args):
340
340
  if not pyversions:
341
341
  print(f"Unknown minor version {requested}")
342
342
  sys.exit(1)
343
- build_version = list(pyversions.keys())[0]
343
+ build_version = sorted(list(pyversions.keys()))[-1]
344
344
  print(build_version)
345
345
  sys.exit()
346
346
 
@@ -750,12 +750,39 @@ def wrap_req_install(name):
750
750
  mod = importlib.import_module(name)
751
751
 
752
752
  def wrap(func):
753
- if mod.InstallRequirement.install.__code__.co_argcount == 9:
753
+ if mod.InstallRequirement.install.__code__.co_argcount == 7:
754
+
755
+ @functools.wraps(func)
756
+ def wrapper(
757
+ self,
758
+ root=None,
759
+ home=None,
760
+ prefix=None,
761
+ warn_script_location=True,
762
+ use_user_site=False,
763
+ pycompile=True,
764
+ ):
765
+ try:
766
+ if TARGET.TARGET:
767
+ TARGET.INSTALL = True
768
+ home = TARGET.PATH
769
+ return func(
770
+ self,
771
+ root,
772
+ home,
773
+ prefix,
774
+ warn_script_location,
775
+ use_user_site,
776
+ pycompile,
777
+ )
778
+ finally:
779
+ TARGET.INSTALL = False
780
+
781
+ elif mod.InstallRequirement.install.__code__.co_argcount == 8:
754
782
 
755
783
  @functools.wraps(func)
756
784
  def wrapper(
757
785
  self,
758
- install_options,
759
786
  global_options=None,
760
787
  root=None,
761
788
  home=None,
@@ -770,7 +797,6 @@ def wrap_req_install(name):
770
797
  home = TARGET.PATH
771
798
  return func(
772
799
  self,
773
- install_options,
774
800
  global_options,
775
801
  root,
776
802
  home,
@@ -783,10 +809,12 @@ def wrap_req_install(name):
783
809
  TARGET.INSTALL = False
784
810
 
785
811
  else:
812
+ # Oldest version of this method sigature with 9 arguments.
786
813
 
787
814
  @functools.wraps(func)
788
815
  def wrapper(
789
816
  self,
817
+ install_options,
790
818
  global_options=None,
791
819
  root=None,
792
820
  home=None,
@@ -801,6 +829,7 @@ def wrap_req_install(name):
801
829
  home = TARGET.PATH
802
830
  return func(
803
831
  self,
832
+ install_options,
804
833
  global_options,
805
834
  root,
806
835
  home,
@@ -845,8 +874,8 @@ def install_cargo_config():
845
874
  # load the ssl module. Causing out setup_openssl method to fail to load
846
875
  # fips module.
847
876
  dirs = common().work_dirs()
848
- triplet = common().get_triplet()
849
877
  cargo_home = dirs.data / "cargo"
878
+ triplet = common().get_triplet()
850
879
 
851
880
  toolchain = common().get_toolchain()
852
881
  if not toolchain:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: relenv
3
- Version: 0.21.0
3
+ Version: 0.21.2
4
4
  Project-URL: Source Code, https://github.com/saltstack/relative-environment-for-python
5
5
  Project-URL: Documentation, https://relenv.readthedocs.io/en/latest/
6
6
  Project-URL: Changelog, https://relenv.readthedocs.io/en/latest/changelog.html
@@ -1859,3 +1859,26 @@ def test_import_ssl_module(pyexec):
1859
1859
  assert proc.returncode == 0
1860
1860
  assert proc.stdout.decode() == ""
1861
1861
  assert proc.stderr.decode() == ""
1862
+
1863
+
1864
+ @pytest.mark.skip_unless_on_linux
1865
+ @pytest.mark.parametrize("pip_version", ["25.2", "25.3"])
1866
+ def test_install_setuptools_25_2_to_25_3(pipexec, build, minor_version, pip_version):
1867
+ """
1868
+ Validate we handle the changes to pip._internal.req.InstallRequirement.install signature.
1869
+ """
1870
+ subprocess.run(
1871
+ [str(pipexec), "install", "--upgrade", f"pip=={pip_version}"],
1872
+ check=True,
1873
+ )
1874
+ subprocess.run(
1875
+ [
1876
+ str(pipexec),
1877
+ "install",
1878
+ "--upgrade",
1879
+ "--no-binary=:all:",
1880
+ "--no-cache-dir",
1881
+ "setuptools",
1882
+ ],
1883
+ check=True,
1884
+ )
@@ -1,258 +0,0 @@
1
- # Copyright 2022-2025 Broadcom.
2
- # SPDX-License-Identifier: Apache-2
3
- """
4
- The windows build process.
5
- """
6
- import glob
7
- import shutil
8
- import sys
9
- import os
10
- import pathlib
11
- import tarfile
12
- import logging
13
- from .common import runcmd, create_archive, MODULE_DIR, builds, install_runtime
14
- from ..common import arches, WIN32
15
-
16
- log = logging.getLogger(__name__)
17
-
18
- ARCHES = arches[WIN32]
19
-
20
- if sys.platform == WIN32:
21
- import ctypes
22
-
23
- kernel32 = ctypes.windll.kernel32
24
- kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
25
-
26
-
27
- def populate_env(env, dirs):
28
- """
29
- Make sure we have the correct environment variables set.
30
-
31
- :param env: The environment dictionary
32
- :type env: dict
33
- :param dirs: The working directories
34
- :type dirs: ``relenv.build.common.Dirs``
35
- """
36
- env["MSBUILDDISABLENODEREUSE"] = "1"
37
-
38
-
39
- def patch_file(path, old, new):
40
- """
41
- Search a file line by line for a string to replace.
42
-
43
- :param path: Location of the file to search
44
- :type path: str
45
- :param old: The value that will be replaced
46
- :type path: str
47
- :param new: The value that will replace the 'old' value.
48
- :type path: str
49
- """
50
- import re
51
-
52
- with open(path, "r") as fp:
53
- content = fp.read()
54
- new_content = ""
55
- for line in content.splitlines():
56
- re.sub(old, new, line)
57
- new_content += line + os.linesep
58
- with open(path, "w") as fp:
59
- fp.write(new_content)
60
-
61
-
62
- def override_dependency(source, old, new):
63
- """
64
- Overwrite a dependency string for Windoes PCBuild.
65
-
66
- :param source: Python's source directory
67
- :type path: str
68
- :param old: Regular expression to search for
69
- :type path: str
70
- :param new: Replacement text
71
- :type path: str
72
- """
73
- patch_file(source / "PCbuild" / "python.props", old, new)
74
- patch_file(source / "PCbuild" / "get_externals.bat", old, new)
75
-
76
-
77
- def build_python(env, dirs, logfp):
78
- """
79
- Run the commands to build Python.
80
-
81
- :param env: The environment dictionary
82
- :type env: dict
83
- :param dirs: The working directories
84
- :type dirs: ``relenv.build.common.Dirs``
85
- :param logfp: A handle for the log file
86
- :type logfp: file
87
- """
88
- # Override default versions
89
- if env["RELENV_PY_MAJOR_VERSION"] in [
90
- "3.10",
91
- "3.11",
92
- ]:
93
- override_dependency(dirs.source, r"sqlite-\d+.\d+.\d+.\d+", "sqlite-3.50.4.0")
94
- override_dependency(dirs.source, r"xz-\d+.\d+.\d+", "xz-5.6.2")
95
-
96
- arch_to_plat = {
97
- "amd64": "x64",
98
- "x86": "win32",
99
- "arm64": "arm64",
100
- }
101
- arch = env["RELENV_HOST_ARCH"]
102
- plat = arch_to_plat[arch]
103
- cmd = [
104
- str(dirs.source / "PCbuild" / "build.bat"),
105
- "-p",
106
- plat,
107
- "--no-tkinter",
108
- ]
109
- log.info("Start PCbuild")
110
- runcmd(cmd, env=env, stderr=logfp, stdout=logfp)
111
- log.info("PCbuild finished")
112
-
113
- # This is where build.bat puts everything
114
- # TODO: For now we'll only support 64bit
115
- if arch == "amd64":
116
- build_dir = dirs.source / "PCbuild" / arch
117
- else:
118
- build_dir = dirs.source / "PCbuild" / plat
119
- bin_dir = dirs.prefix / "Scripts"
120
- bin_dir.mkdir(parents=True, exist_ok=True)
121
-
122
- # Move python binaries
123
- binaries = [
124
- "py.exe",
125
- "pyw.exe",
126
- "python.exe",
127
- "pythonw.exe",
128
- "python3.dll",
129
- f"python{ env['RELENV_PY_MAJOR_VERSION'].replace('.', '') }.dll",
130
- "vcruntime140.dll",
131
- "venvlauncher.exe",
132
- "venvwlauncher.exe",
133
- ]
134
- for binary in binaries:
135
- shutil.move(src=str(build_dir / binary), dst=str(bin_dir / binary))
136
-
137
- # Create DLLs directory
138
- (dirs.prefix / "DLLs").mkdir(parents=True, exist_ok=True)
139
- # Move all library files to DLLs directory (*.pyd, *.dll)
140
- for file in glob.glob(str(build_dir / "*.pyd")):
141
- shutil.move(src=file, dst=str(dirs.prefix / "DLLs"))
142
- for file in glob.glob(str(build_dir / "*.dll")):
143
- shutil.move(src=file, dst=str(dirs.prefix / "DLLs"))
144
-
145
- # Copy include directory
146
- shutil.copytree(
147
- src=str(dirs.source / "Include"),
148
- dst=str(dirs.prefix / "Include"),
149
- dirs_exist_ok=True,
150
- )
151
- if "3.13" not in env["RELENV_PY_MAJOR_VERSION"]:
152
- shutil.copy(
153
- src=str(dirs.source / "PC" / "pyconfig.h"),
154
- dst=str(dirs.prefix / "Include"),
155
- )
156
-
157
- # Copy library files
158
- shutil.copytree(
159
- src=str(dirs.source / "Lib"),
160
- dst=str(dirs.prefix / "Lib"),
161
- dirs_exist_ok=True,
162
- )
163
- os.makedirs(str(dirs.prefix / "Lib" / "site-packages"), exist_ok=True)
164
-
165
- # Create libs directory
166
- (dirs.prefix / "libs").mkdir(parents=True, exist_ok=True)
167
- # Copy lib files
168
- shutil.copy(
169
- src=str(build_dir / "python3.lib"),
170
- dst=str(dirs.prefix / "libs" / "python3.lib"),
171
- )
172
- pylib = f"python{ env['RELENV_PY_MAJOR_VERSION'].replace('.', '') }.lib"
173
- shutil.copy(
174
- src=str(build_dir / pylib),
175
- dst=str(dirs.prefix / "libs" / pylib),
176
- )
177
-
178
-
179
- build = builds.add("win32", populate_env=populate_env)
180
-
181
- build.add(
182
- "python",
183
- build_func=build_python,
184
- download={
185
- "url": "https://www.python.org/ftp/python/{version}/Python-{version}.tar.xz",
186
- "version": build.version,
187
- "checksum": "d31d548cd2c5ca2ae713bebe346ba15e8406633a",
188
- },
189
- )
190
-
191
-
192
- def finalize(env, dirs, logfp):
193
- """
194
- Finalize sitecustomize, relenv runtime, and pip for Windows.
195
-
196
- :param env: The environment dictionary
197
- :type env: dict
198
- :param dirs: The working directories
199
- :type dirs: ``relenv.build.common.Dirs``
200
- :param logfp: A handle for the log file
201
- :type logfp: file
202
- """
203
- # Lay down site customize
204
- sitepackages = dirs.prefix / "Lib" / "site-packages"
205
-
206
- install_runtime(sitepackages)
207
-
208
- # Install pip
209
- python = dirs.prefix / "Scripts" / "python.exe"
210
- runcmd([str(python), "-m", "ensurepip"], env=env, stderr=logfp, stdout=logfp)
211
-
212
- def runpip(pkg):
213
- # XXX Support cross pip installs on windows
214
- env = os.environ.copy()
215
- target = None
216
- cmd = [
217
- str(python),
218
- "-m",
219
- "pip",
220
- "install",
221
- str(pkg),
222
- ]
223
- if target:
224
- cmd.append("--target={}".format(target))
225
- runcmd(cmd, env=env, stderr=logfp, stdout=logfp)
226
-
227
- runpip("wheel")
228
- # This needs to handle running from the root of the git repo and also from
229
- # an installed Relenv
230
- if (MODULE_DIR.parent / ".git").exists():
231
- runpip(MODULE_DIR.parent)
232
- else:
233
- runpip("relenv")
234
-
235
- for root, _, files in os.walk(dirs.prefix):
236
- for file in files:
237
- if file.endswith(".pyc"):
238
- os.remove(pathlib.Path(root) / file)
239
-
240
- globs = [
241
- "*.exe",
242
- "*.py",
243
- "*.pyd",
244
- "*.dll",
245
- "*.lib",
246
- "/Include/*",
247
- "/Lib/site-packages/*",
248
- ]
249
- archive = f"{dirs.prefix}.tar.xz"
250
- with tarfile.open(archive, mode="w:xz") as fp:
251
- create_archive(fp, dirs.prefix, globs, logfp)
252
-
253
-
254
- build.add(
255
- "relenv-finalize",
256
- build_func=finalize,
257
- wait_on=["python"],
258
- )
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes