Skip to content

Commit 736c9a5

Browse files
committed
Refactor parts of build.
1 parent 4b84816 commit 736c9a5

File tree

6 files changed

+118
-106
lines changed

6 files changed

+118
-106
lines changed

.github/actions_build_conda.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@ conda info -a
1818
conda config --add channels conda-forge || exit 1
1919
conda config --add channels domdfcoding || exit 1
2020

21-
conda build conda -c conda-forge -c domdfcoding --output-folder conda/dist --skip-existing --numpy 1.16
21+
conda build conda -c conda-forge -c domdfcoding --output-folder conda/dist --skip-existing
2222

2323
exit 0

repo_helper/build.py

Lines changed: 63 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,12 @@
5252
from domdf_python_tools.typing import PathLike
5353
from packaging.specifiers import Specifier
5454
from packaging.version import Version
55+
from shippinglabel.checksum import get_record_entry
5556
from shippinglabel.requirements import ComparableRequirement, combine_requirements, read_requirements
5657

5758
# this package
5859
from repo_helper import __version__
59-
from repo_helper.conda import compile_requirements, validate_requirements
60+
from repo_helper.conda import get_conda_requirements, make_conda_description
6061
from repo_helper.configuration import parse_yaml
6162

6263
__all__ = ["Builder", "build_wheel", "build_sdist"]
@@ -102,11 +103,8 @@ def __init__(
102103
re.UNICODE,
103104
) + f"-{self.config['version']}"
104105

105-
build_dir = build_dir or self.repo_dir / "build/repo_helper_build"
106-
self.build_dir = PathPlus(build_dir)
107-
if self.build_dir.is_dir():
108-
shutil.rmtree(self.build_dir)
109-
self.build_dir.maybe_make(parents=True)
106+
self.build_dir = PathPlus(build_dir or self.repo_dir / "build/repo_helper_build")
107+
self.clear_build_dir()
110108
(self.build_dir / self.pkg_dir).maybe_make(parents=True)
111109

112110
out_dir = out_dir or self.repo_dir / "dist"
@@ -400,22 +398,12 @@ def write_conda_index(self, build_number: int = 1):
400398
build_string = f"py_{build_number}"
401399
# https://docs.conda.io/projects/conda-build/en/latest/resources/define-metadata.html#build-number-and-string
402400

403-
extras = []
404-
405-
for extra in self.config["conda_extras"]:
406-
extras.extend(self.config["extras_require"][extra])
407-
408-
all_requirements = validate_requirements(
409-
compile_requirements(self.repo_dir, extras),
410-
self.config["conda_channels"],
411-
)
412-
413401
index = {
414402
"name": self.config["pypi_name"].lower(),
415403
"version": self.config["version"],
416404
"build": build_string,
417405
"build_number": build_number,
418-
"depends": [str(req) for req in all_requirements],
406+
"depends": get_conda_requirements(self.repo_dir, self.config),
419407
"arch": None,
420408
"noarch": "python",
421409
"platform": None,
@@ -435,12 +423,7 @@ def write_conda_about(self):
435423
"""
436424

437425
github_url = "https://github.com/{username}/{repo_name}".format_map(self.config)
438-
439-
conda_description = self.config["conda_description"]
440-
if self.config["conda_channels"]:
441-
conda_description += "\n\n\n"
442-
conda_description += "Before installing please ensure you have added the following channels:"
443-
conda_description += ", ".join(self.config["conda_channels"])
426+
conda_description = make_conda_description(self.config["conda_description"], self.config["conda_channels"])
444427

445428
about = {
446429
"home": github_url,
@@ -478,27 +461,14 @@ def create_wheel_archive(self) -> str:
478461
:return: The filename of the created archive.
479462
"""
480463

464+
wheel_filename = self.out_dir / f"{self.archive_name}-{self.tag}.whl"
481465
self.out_dir.maybe_make(parents=True)
482466

483-
def get_record_entry(path: pathlib.Path, build_dir: pathlib.Path, blocksize: int = 1 << 20) -> str:
484-
sha256_hash = sha256()
485-
length = 0
486-
with path.open("rb") as f:
487-
for byte_block in iter(lambda: f.read(blocksize), b''):
488-
sha256_hash.update(byte_block)
489-
length += len(byte_block)
490-
sha256_hash.update(byte_block)
491-
492-
digest = "sha256=" + urlsafe_b64encode(sha256_hash.digest()).decode("latin1").rstrip('=')
493-
494-
return f"{path.relative_to(build_dir).as_posix()},sha256={digest},{length}"
495-
496-
wheel_filename = self.out_dir / f"{self.archive_name}-{self.tag}.whl"
497467
with ZipFile(wheel_filename, mode='w') as wheel_archive:
498468
with (self.dist_info / "RECORD").open('w') as fp:
499469
for file in (self.build_dir / self.pkg_dir).rglob('*'):
500470
if file.is_file():
501-
fp.write(get_record_entry(file, self.build_dir))
471+
fp.write(get_record_entry(file, relative_to=self.build_dir))
502472
fp.write('\n')
503473
wheel_archive.write(file, arcname=file.relative_to(self.build_dir))
504474

@@ -508,7 +478,7 @@ def get_record_entry(path: pathlib.Path, build_dir: pathlib.Path, blocksize: int
508478
if not file.is_file():
509479
continue
510480

511-
fp.write(get_record_entry(file, self.build_dir))
481+
fp.write(get_record_entry(file, relative_to=self.build_dir))
512482
fp.write('\n')
513483
wheel_archive.write(file, arcname=file.relative_to(self.build_dir))
514484

@@ -522,7 +492,8 @@ def get_record_entry(path: pathlib.Path, build_dir: pathlib.Path, blocksize: int
522492
Fore.GREEN(f"{emoji}Wheel created at {wheel_filename.resolve()}"),
523493
color=resolve_color_default(),
524494
)
525-
return os.path.basename(wheel_filename)
495+
496+
return wheel_filename.name
526497

527498
def create_conda_archive(self, wheel_contents_dir: PathLike, build_number: int = 1) -> str:
528499
"""
@@ -535,23 +506,22 @@ def create_conda_archive(self, wheel_contents_dir: PathLike, build_number: int =
535506
"""
536507

537508
build_string = f"py_{build_number}"
538-
539-
self.out_dir.maybe_make(parents=True)
540-
509+
site_packages = pathlib.PurePosixPath("site-packages")
541510
conda_filename = self.out_dir / f"{self.config['pypi_name'].lower()}-{self.config['version']}-{build_string}.tar.bz2"
511+
wheel_contents_dir = PathPlus(wheel_contents_dir)
542512

543-
site_packages = PathPlus("site-packages")
513+
self.out_dir.maybe_make(parents=True)
544514

545515
with tarfile.open(conda_filename, mode="w:bz2") as conda_archive:
546516
with (self.info_dir / "files").open('w') as fp:
547517

548-
for file in (PathPlus(wheel_contents_dir) / self.pkg_dir).rglob('*'):
518+
for file in (wheel_contents_dir / self.pkg_dir).rglob('*'):
549519
if file.is_file():
550520
filename = (site_packages / file.relative_to(wheel_contents_dir)).as_posix()
551521
fp.write(f"{filename}\n")
552522
conda_archive.add(str(file), arcname=filename)
553523

554-
for file in (PathPlus(wheel_contents_dir) / f"{self.archive_name}.dist-info").rglob('*'):
524+
for file in (wheel_contents_dir / f"{self.archive_name}.dist-info").rglob('*'):
555525
if file.name == "INSTALLER":
556526
file.write_text("conda")
557527

@@ -652,9 +622,7 @@ def build_conda(self) -> str:
652622
# Build the wheel first and clear the build directory
653623
wheel_file = self.build_wheel()
654624

655-
if self.build_dir.is_dir():
656-
shutil.rmtree(self.build_dir)
657-
self.build_dir.maybe_make(parents=True)
625+
self.clear_build_dir()
658626

659627
for license_file in self.repo_dir.glob("LICEN[CS]E"):
660628
target = self.info_dir / "license.txt"
@@ -668,39 +636,7 @@ def build_conda(self) -> str:
668636
if self.verbose:
669637
click.echo("Installing wheel into temporary directory")
670638

671-
command = [
672-
"pip",
673-
"install",
674-
str(self.out_dir / wheel_file),
675-
"--target",
676-
str(tmpdir),
677-
"--no-deps",
678-
"--no-compile",
679-
"--no-warn-script-location",
680-
"--no-warn-conflicts",
681-
"--disable-pip-version-check",
682-
]
683-
process = Popen(command, stdout=PIPE)
684-
(output, err) = process.communicate()
685-
exit_code = process.wait()
686-
687-
if self.verbose:
688-
click.echo((output or b'').decode("UTF-8"))
689-
click.echo((err or b'').decode("UTF-8"), err=True)
690-
691-
if exit_code != 0:
692-
err = err or b''
693-
694-
raise abort(
695-
dedent(
696-
f"""\
697-
Command '{' '.join(command)}' returned non-zero exit code {exit_code}:
698-
699-
{indent(err.decode("UTF-8"), ' ')}
700-
"""
701-
).rstrip() + '\n'
702-
)
703-
639+
pip_install_wheel(self.out_dir / wheel_file, tmpdir, self.verbose)
704640
conda_filename = self.create_conda_archive(str(tmpdir), build_number=build_number)
705641

706642
click.echo(
@@ -709,6 +645,15 @@ def build_conda(self) -> str:
709645
)
710646
return conda_filename
711647

648+
def clear_build_dir(self) -> None:
649+
"""
650+
Clear the build directory of any residue from previous builds.
651+
"""
652+
653+
if self.build_dir.is_dir():
654+
shutil.rmtree(self.build_dir)
655+
self.build_dir.maybe_make(parents=True)
656+
712657

713658
# copy_file(repo_dir / "__pkginfo__.py")
714659
# copy_file(repo_dir / "requirements.txt")
@@ -753,3 +698,39 @@ def build_sdist(sdist_directory, config_settings=None):
753698

754699
def get_requires_for_build_sdist(config_settings=None):
755700
return []
701+
702+
703+
def pip_install_wheel(wheel_file: PathLike, target_dir: PathLike, verbose: bool = False):
704+
command = [
705+
"pip",
706+
"install",
707+
os.fspath(wheel_file),
708+
"--target",
709+
os.fspath(target_dir),
710+
"--no-deps",
711+
"--no-compile",
712+
"--no-warn-script-location",
713+
"--no-warn-conflicts",
714+
"--disable-pip-version-check",
715+
]
716+
717+
process = Popen(command, stdout=PIPE)
718+
(output, err) = process.communicate()
719+
exit_code = process.wait()
720+
721+
if verbose:
722+
click.echo((output or b'').decode("UTF-8"))
723+
click.echo((err or b'').decode("UTF-8"), err=True)
724+
725+
if exit_code != 0:
726+
err = err or b''
727+
728+
message = dedent(
729+
f"""\
730+
Command '{' '.join(command)}' returned non-zero exit code {exit_code}:
731+
732+
{indent(err.decode("UTF-8"), ' ')}
733+
"""
734+
)
735+
736+
raise abort(message.rstrip() + '\n')

repo_helper/conda.py

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
# MA 02110-1301, USA.
2424
#
2525

26+
# stdlib
27+
from typing import Any, Dict, Iterable, List
28+
2629
# 3rd party
2730
import jinja2
2831
from domdf_python_tools.paths import PathPlus
@@ -53,6 +56,51 @@ def make_recipe(repo_dir: PathLike, recipe_file: PathLike) -> None:
5356

5457
config = parse_yaml(repo_dir)
5558

59+
requirements_block = '\n'.join([f" - {req}" for req in get_conda_requirements(repo_dir, config)])
60+
61+
templates = jinja2.Environment( # nosec: B701
62+
loader=jinja2.FileSystemLoader(str(template_dir)),
63+
undefined=jinja2.StrictUndefined,
64+
)
65+
66+
recipe_template = templates.get_template("conda_recipe.yaml")
67+
recipe_file.write_clean(
68+
recipe_template.render(
69+
requirements_block=requirements_block,
70+
conda_full_description=make_conda_description(
71+
config["conda_description"], config["conda_channels"]
72+
),
73+
**config,
74+
)
75+
)
76+
77+
# entry_points:
78+
# - {{ import_name }} = {{ import_name }}:main
79+
# skip_compile_pyc:
80+
# - "*/templates/*.py" # These should not (and cannot) be compiled
81+
82+
83+
def make_conda_description(summary: str, conda_channels: Iterable[str] = ()) -> str:
84+
"""
85+
Create a description for the Conda package from its summary and a list of channels required to install it.
86+
87+
:param summary:
88+
:param conda_channels:
89+
"""
90+
91+
conda_description = summary
92+
conda_channels = tuple(conda_channels)
93+
94+
if conda_channels:
95+
conda_description += "\n\n\n"
96+
conda_description += "Before installing please ensure you have added the following channels: "
97+
conda_description += ", ".join(conda_channels)
98+
conda_description += '\n'
99+
100+
return conda_description
101+
102+
103+
def get_conda_requirements(repo_dir: PathPlus, config: Dict[str, Any]) -> List[str]:
56104
extras = []
57105

58106
for extra in config["conda_extras"]:
@@ -63,22 +111,9 @@ def make_recipe(repo_dir: PathLike, recipe_file: PathLike) -> None:
63111
config["conda_channels"],
64112
)
65113

66-
requirements_entries = [f" - {req}" for req in all_requirements if req and req != "numpy"]
114+
requirements_entries = [str(req) for req in all_requirements if req and req != "numpy"]
67115

68116
if [v.specifier for v in all_requirements if v == "numpy"]:
69-
requirements_entries.append(" - numpy x.x")
70-
71-
requirements_block = '\n'.join(requirements_entries)
72-
73-
templates = jinja2.Environment( # nosec: B701
74-
loader=jinja2.FileSystemLoader(str(template_dir)),
75-
undefined=jinja2.StrictUndefined,
76-
)
77-
78-
recipe_template = templates.get_template("conda_recipe.yaml")
79-
recipe_file.write_clean(recipe_template.render(requirements_block=requirements_block, **config))
117+
requirements_entries.append("numpy>=1.19.0")
80118

81-
# entry_points:
82-
# - {{ import_name }} = {{ import_name }}:main
83-
# skip_compile_pyc:
84-
# - "*/templates/*.py" # These should not (and cannot) be compiled
119+
return requirements_entries

repo_helper/templates/actions_build_conda.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ conda info -a
1717
{% for channel in conda_channels %}
1818
conda config --add channels {{ channel }} || exit 1{% endfor %}
1919

20-
conda build conda {% for channel in conda_channels %}-c {{ channel }} {% endfor %}--output-folder conda/dist --skip-existing --numpy 1.16
20+
conda build conda {% for channel in conda_channels %}-c {{ channel }} {% endfor %}--output-folder conda/dist --skip-existing
2121

2222
exit 0

repo_helper/templates/conda_recipe.yaml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,7 @@ about:
3131
home: "https://github.com/{{ username }}/{{ repo_name }}"
3232
license: "{{ license }}"
3333
summary: "{{ short_desc }}"
34-
description: "{{ conda_description }}{% if conda_channels %}
35-
36-
37-
Before installing please ensure you have added the following channels: {{ ", ".join(conda_channels) }}
38-
{% endif %}"
34+
description: "{{ conda_full_description }}"
3935
doc_url: https://{{ repo_name }}.readthedocs.io
4036
dev_url: https://github.com/{{ username }}/{{ repo_name }}
4137

tests/test_files/test_ci_cd_/test_actions_deploy_conda_build.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ conda info -a
1717

1818
conda config --add channels conda-forge || exit 1
1919

20-
conda build conda -c conda-forge --output-folder conda/dist --skip-existing --numpy 1.16
20+
conda build conda -c conda-forge --output-folder conda/dist --skip-existing
2121

2222
exit 0

0 commit comments

Comments
 (0)