makepatch 0.0.1__py3-none-any.whl
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.
- makepatch/__hook__.py +7 -0
- makepatch/__init__.py +0 -0
- makepatch/_config.py +18 -0
- makepatch/hooks/__init__.py +1 -0
- makepatch/hooks/_patch.py +88 -0
- makepatch/scripts/__init__.py +0 -0
- makepatch-0.0.1.dist-info/METADATA +8 -0
- makepatch-0.0.1.dist-info/RECORD +10 -0
- makepatch-0.0.1.dist-info/WHEEL +4 -0
- makepatch-0.0.1.dist-info/entry_points.txt +7 -0
makepatch/__hook__.py
ADDED
makepatch/__init__.py
ADDED
|
File without changes
|
makepatch/_config.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from collections.abc import Iterable
|
|
2
|
+
from typing import final, Annotated
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel, Field
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
__config = None
|
|
8
|
+
|
|
9
|
+
@final
|
|
10
|
+
class ClippyConfig(BaseModel):
|
|
11
|
+
module_source: Annotated[str, Field(alias="module-source")]
|
|
12
|
+
excludes: Annotated[Iterable[str], Field(default_factory=frozenset)]
|
|
13
|
+
dev_excludes: Annotated[Iterable[str], Field(alias="module-source", default_factory=frozenset)]
|
|
14
|
+
|
|
15
|
+
def __init__(self, /):
|
|
16
|
+
global __config
|
|
17
|
+
if __config:
|
|
18
|
+
raise RuntimeError("Configuration already initialized")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from ._patch import ClippyPatchHook
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import override
|
|
4
|
+
|
|
5
|
+
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
|
|
6
|
+
|
|
7
|
+
import shutil, subprocess, tomllib
|
|
8
|
+
|
|
9
|
+
if __debug__ and __import__("typing").TYPE_CHECKING:
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ClippyPatchHook(BuildHookInterface):
|
|
14
|
+
@property
|
|
15
|
+
def __root(self):
|
|
16
|
+
return Path(self.root)
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def __config(self):
|
|
20
|
+
with open(self.__root / "pyproject.toml", "rb") as f:
|
|
21
|
+
pyproject = tomllib.load(f)
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
config = pyproject["tool"]["patcher"]
|
|
25
|
+
except KeyError as e:
|
|
26
|
+
raise RuntimeError("[tool.patcher] not found in pyproject.toml") from e
|
|
27
|
+
return config["module-source"], frozenset(config.get("excludes", set()))
|
|
28
|
+
|
|
29
|
+
@override
|
|
30
|
+
def initialize(self, version: str, build_data: dict[str, Any]) -> None:
|
|
31
|
+
module_name, exclude_globs = self.__config
|
|
32
|
+
|
|
33
|
+
src = self.__root / "work" / "sources" / module_name
|
|
34
|
+
if not src.exists(): raise RuntimeError(f"{src} not exists")
|
|
35
|
+
elif not src.is_dir(): raise RuntimeError(f"{src} is not a directory")
|
|
36
|
+
|
|
37
|
+
excludes = set()
|
|
38
|
+
for glob in exclude_globs:
|
|
39
|
+
excludes |= set(str(excluded.relative_to(src)) for excluded in src.rglob(glob) if str(excluded.relative_to(src)).startswith(glob.split(os.sep)[0]))
|
|
40
|
+
|
|
41
|
+
patches = self.__root / "patches"
|
|
42
|
+
if not patches.exists(): raise RuntimeError(f"{patches} not exists")
|
|
43
|
+
elif not patches.is_dir(): raise RuntimeError(f"{patches} is not a directory")
|
|
44
|
+
|
|
45
|
+
if str(module_name).startswith("src"):
|
|
46
|
+
module_name = module_name[4:]
|
|
47
|
+
dst = self.__root / "src" / module_name
|
|
48
|
+
if dst.exists():
|
|
49
|
+
if not dst.is_dir(): raise RuntimeError(f"{dst} is not a directory")
|
|
50
|
+
shutil.rmtree(dst)
|
|
51
|
+
dst.mkdir(parents=True)
|
|
52
|
+
|
|
53
|
+
# Copy sources, skipping excludes
|
|
54
|
+
for src_file in src.rglob("*"):
|
|
55
|
+
if not src_file.is_file(): continue
|
|
56
|
+
|
|
57
|
+
rel = src_file.relative_to(src)
|
|
58
|
+
if str(rel) in excludes: continue
|
|
59
|
+
|
|
60
|
+
dst_file = dst / rel
|
|
61
|
+
dst_file.parent.mkdir(parents=True, exist_ok=True)
|
|
62
|
+
shutil.copy2(src_file, dst_file)
|
|
63
|
+
|
|
64
|
+
# Apply patches
|
|
65
|
+
for patch_file in sorted(patches.rglob("*.patch")):
|
|
66
|
+
rel_patch = patch_file.relative_to(patches)
|
|
67
|
+
# e.g. foo.py.patch → foo.py
|
|
68
|
+
target_rel = rel_patch.with_suffix("")
|
|
69
|
+
target = dst / target_rel
|
|
70
|
+
|
|
71
|
+
if not target.parent.exists():
|
|
72
|
+
target.parent.mkdir(parents=True, exist_ok=False)
|
|
73
|
+
|
|
74
|
+
result = subprocess.run(
|
|
75
|
+
["patch", "--unified", str(target), str(patch_file)],
|
|
76
|
+
capture_output=True,
|
|
77
|
+
text=True,
|
|
78
|
+
)
|
|
79
|
+
if result.returncode != 0:
|
|
80
|
+
raise RuntimeError(f"Failed to apply {rel_patch}:\n{result.stderr}")
|
|
81
|
+
|
|
82
|
+
def finalize(self, version: str, build_data: dict[str, Any], artifact_path: str) -> None:
|
|
83
|
+
module_source, _ = self.__config
|
|
84
|
+
if str(module_source).startswith("src"):
|
|
85
|
+
module_source = module_source[4:]
|
|
86
|
+
dst = self.__root / "src" / module_source
|
|
87
|
+
if dst.exists():
|
|
88
|
+
shutil.rmtree(dst)
|
|
File without changes
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
makepatch/__hook__.py,sha256=ov-ZExdRe2dhvnocD01_58Z37eBryz8sTaTAbFEHM-4,171
|
|
2
|
+
makepatch/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
makepatch/_config.py,sha256=GlyVVm9ZsolzDKSiupoTMTmOHVSNCMdyo-_AzArw3Wo,565
|
|
4
|
+
makepatch/hooks/__init__.py,sha256=8JvonoGcrgihzhk7eUIwQPwr2oTL58IfF44tAk2vOYc,37
|
|
5
|
+
makepatch/hooks/_patch.py,sha256=xjaKYDJkhekGfBomXOKH5pOiP209hNtt6G4kHv-kfQs,3335
|
|
6
|
+
makepatch/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
makepatch-0.0.1.dist-info/WHEEL,sha256=fWriCkzqm-pffF5af4gJC9iI5FMFaJTuN9UxxxzOmdY,81
|
|
8
|
+
makepatch-0.0.1.dist-info/entry_points.txt,sha256=8xpxWiGS9XHoBCcyoVcfkRfjW2WnvamePMfI3_WJsOs,141
|
|
9
|
+
makepatch-0.0.1.dist-info/METADATA,sha256=2kQkR1g2KEOP011WEC73brgoEzEW_wM-HQsAhJbm6Q8,242
|
|
10
|
+
makepatch-0.0.1.dist-info/RECORD,,
|