Skip to content

Commit

Permalink
feat: Add parameter --build-number to wheel builder (#229)
Browse files Browse the repository at this point in the history
* Add build-tag parameter

* Revert changes in sdist.py

* Add unit tests for build-number

* Update documentation

* Revert test_wheel.py

* Update src/pdm/backend/wheel.py

Applied suggestions from review

Co-authored-by: Frost Ming <[email protected]>

* Update src/pdm/backend/wheel.py

Applied suggestions from review

Co-authored-by: Frost Ming <[email protected]>

* Remove `:=` operator due to py3.7 support

---------

Co-authored-by: Frost Ming <[email protected]>
  • Loading branch information
0xfabioo and frostming authored Apr 16, 2024
1 parent 8183604 commit d7d15fb
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 6 deletions.
1 change: 1 addition & 0 deletions docs/build_config.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ Some build frontends such as [build] and [pdm] supports passing options from com
- `--python-tag=<tag>` Override the python implementation compatibility tag(e.g. `cp37`, `py3`, `pp3`)
- `--py-limited-api=<abi>` Python tag (`cp32`|`cp33`|`cpNN`) for abi3 wheel tag
- `--plat-name=<plat>` Override the platform name(e.g. `win_amd64`, `manylinux2010_x86_64`)
- `--build-number=<build-number>` Build number for this particular version. As specified in PEP-0427, this must start with a digit.
- `no-clean-build` Don't clean the build directory before the build starts, this can also work by setting env var `PDM_BUILD_NO_CLEAN` to `1`.

For example, you can supply these options with [build]:
Expand Down
40 changes: 34 additions & 6 deletions src/pdm/backend/wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

from pdm.backend._vendor.packaging import tags
from pdm.backend._vendor.packaging.specifiers import SpecifierSet
from pdm.backend._vendor.packaging.utils import canonicalize_name
from pdm.backend._vendor.packaging.utils import _build_tag_regex, canonicalize_name
from pdm.backend.base import Builder
from pdm.backend.hooks import Context
from pdm.backend.hooks.setuptools import SetuptoolsBuildHook
Expand Down Expand Up @@ -46,6 +46,8 @@
Tag: {tag}
"""

BUILD_TAG_FORMAT = "Build: {build_number}"

# Fix the date time for reproducible builds
try:
_env_date = time.gmtime(int(os.environ["SOURCE_DATE_EPOCH"]))[:6]
Expand Down Expand Up @@ -77,6 +79,7 @@ def __init__(
) -> None:
super().__init__(location, config_settings)
self.__tag: str | None = None
self.__build_number: str | None = None

def scheme_path(self, name: str, relative: str) -> str:
if name not in SCHEME_NAMES:
Expand Down Expand Up @@ -156,7 +159,11 @@ def build_artifact(
records.append(self._add_file_to_zip(zf, rel_path, full_path))
self._write_record(zf, records)

target = context.dist_dir / f"{self.name_version}-{self.tag}.whl"
name_version = self.name_version
if self.build_number:
name_version = f"{name_version}-{self.build_number}"

target = context.dist_dir / f"{name_version}-{self.tag}.whl"
if target.exists():
target.unlink()
shutil.move(temp_name, target)
Expand All @@ -168,6 +175,12 @@ def name_version(self) -> str:
version = to_filename(safe_version(self.config.metadata["version"]))
return f"{name}-{version}"

@property
def build_number(self) -> str | None:
if not self.__build_number:
self.__build_number = self._get_build_number()
return self.__build_number

@property
def dist_info_name(self) -> str:
return f"{self.name_version}.dist-info"
Expand All @@ -178,6 +191,18 @@ def tag(self) -> str:
self.__tag = self._get_tag()
return self.__tag

def _get_build_number(self) -> str | None:
cmd = "--build-number"
if cmd not in self.config_settings:
return None
build_number = self.config_settings[cmd]
if not _build_tag_regex.match(build_number):
raise ValueError(
f"Invalid build number: {build_number}, please refer to PEP 427"
)

return build_number

def _get_tag(self) -> str:
impl, abi, platform = self._get_platform_tags()
is_purelib = self.config.build_config.is_purelib
Expand Down Expand Up @@ -276,12 +301,15 @@ def _write_wheel_file(self, fp: IO[str], is_purelib: bool) -> None:
except ModuleNotFoundError:
version = "0.0.0+local"

fp.write(
WHEEL_FILE_FORMAT.format(
is_purelib=str(is_purelib).lower(), tag=self.tag, version=version
)
wheel_metadata = WHEEL_FILE_FORMAT.format(
is_purelib=str(is_purelib).lower(), tag=self.tag, version=version
)

if self.build_number:
wheel_metadata = f"{wheel_metadata}{BUILD_TAG_FORMAT.format(build_number=self.build_number)}"

fp.write(wheel_metadata)

def _write_entry_points(
self, fp: IO[str], entry_points: dict[str, dict[str, str]]
) -> None:
Expand Down
26 changes: 26 additions & 0 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,32 @@ def test_build_single_module(dist: Path) -> None:
assert "demo_module-0.1.0.dist-info/licenses/LICENSE" in zip_names


@pytest.mark.parametrize("name", ["demo-module"])
def test_build_single_module_with_build_number(dist: Path) -> None:
build_number = "20231241"
wheel_name = api.build_wheel(
dist.as_posix(),
config_settings={"--build-number": build_number},
)
assert wheel_name == f"demo_module-0.1.0-{build_number}-py3-none-any.whl"
with zipfile.ZipFile(dist / wheel_name) as zf:
wheel_metadata = email.message_from_bytes(
zf.read("demo_module-0.1.0.dist-info/WHEEL")
)
assert wheel_metadata["Build"] == build_number


@pytest.mark.parametrize("name", ["demo-module"])
def test_build_single_module_without_build_number(dist: Path) -> None:
wheel_name = api.build_wheel(dist.as_posix())
assert wheel_name == "demo_module-0.1.0-py3-none-any.whl"
with zipfile.ZipFile(dist / wheel_name) as zf:
wheel_metadata = email.message_from_bytes(
zf.read("demo_module-0.1.0.dist-info/WHEEL")
)
assert "Build" not in wheel_metadata


@pytest.mark.parametrize("name", ["demo-package"])
def test_build_package(dist: Path) -> None:
wheel_name = api.build_wheel(dist.as_posix())
Expand Down

0 comments on commit d7d15fb

Please sign in to comment.