Skip to content

Commit 58a6ef8

Browse files
ben-ednaspoorcc
authored andcommitted
Introduce Patch class for cleaner API
1 parent a52319e commit 58a6ef8

13 files changed

Lines changed: 355 additions & 309 deletions

dfetch/commands/format_patch.py

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@
2929
import pathlib
3030
import re
3131

32-
import patch_ng
33-
3432
import dfetch.commands.command
3533
import dfetch.manifest.project
3634
import dfetch.project
@@ -40,14 +38,7 @@
4038
from dfetch.project.subproject import SubProject
4139
from dfetch.project.svnsubproject import SvnSubProject
4240
from dfetch.util.util import catch_runtime_exceptions, in_directory
43-
from dfetch.vcs.patch import (
44-
PatchAuthor,
45-
PatchInfo,
46-
add_prefix_to_patch,
47-
convert_patch_to,
48-
dump_patch,
49-
parse_patch,
50-
)
41+
from dfetch.vcs.patch import Patch, PatchAuthor, PatchInfo, PatchType
5142

5243
logger = get_logger(__name__)
5344

@@ -112,7 +103,7 @@ def __call__(self, args: argparse.Namespace) -> None:
112103
continue
113104

114105
version = subproject.on_disk_version()
115-
for idx, patch in enumerate(subproject.patch, start=1):
106+
for idx, patch_file in enumerate(subproject.patch, start=1):
116107

117108
patch_info = PatchInfo(
118109
author=PatchAuthor(
@@ -125,20 +116,19 @@ def __call__(self, args: argparse.Namespace) -> None:
125116
revision="" if not version else version.revision,
126117
)
127118

128-
corrected_patch = convert_patch_to(
129-
parse_patch(patch), _determine_target_patch_type(subproject)
119+
patch = Patch.from_file(patch_file).convert_type(
120+
_determine_target_patch_type(subproject)
130121
)
131-
prefixed_patch = add_prefix_to_patch(
132-
corrected_patch,
133-
path_prefix=re.split(r"\*", subproject.source, 1)[0].rstrip(
134-
"/"
135-
),
122+
patch.add_prefix(
123+
re.split(r"\*", subproject.source, 1)[0].rstrip("/")
136124
)
137125

138-
output_patch_file = output_dir_path / pathlib.Path(patch).name
126+
output_patch_file = (
127+
output_dir_path / pathlib.Path(patch_file).name
128+
)
139129
output_patch_file.write_text(
140-
subproject.create_formatted_patch_header(patch_info)
141-
+ dump_patch(prefixed_patch)
130+
patch.dump_header(patch_info) + patch.dump(),
131+
encoding="utf-8",
142132
)
143133

144134
logger.print_info_line(
@@ -150,13 +140,13 @@ def __call__(self, args: argparse.Namespace) -> None:
150140
raise RuntimeError("\n".join(exceptions))
151141

152142

153-
def _determine_target_patch_type(subproject: SubProject) -> str:
143+
def _determine_target_patch_type(subproject: SubProject) -> PatchType:
154144
"""Determine the subproject type for the patch."""
155145
if isinstance(subproject, GitSubProject):
156-
required_type = patch_ng.GIT
146+
required_type = PatchType.GIT
157147
elif isinstance(subproject, SvnSubProject):
158-
required_type = patch_ng.SVN
148+
required_type = PatchType.SVN
159149
else:
160-
required_type = patch_ng.PLAIN
150+
required_type = PatchType.PLAIN
161151

162-
return str(required_type)
152+
return required_type

dfetch/project/gitsubproject.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from dfetch.project.subproject import SubProject
1111
from dfetch.util.util import safe_rmtree
1212
from dfetch.vcs.git import GitLocalRepo, GitRemote, get_git_version
13-
from dfetch.vcs.patch import PatchInfo
1413

1514
logger = get_logger(__name__)
1615

@@ -112,7 +111,3 @@ def _determine_fetched_version(self, version: Version, fetched_sha: str) -> Vers
112111
def get_default_branch(self) -> str: # type: ignore
113112
"""Get the default branch of this repository."""
114113
return self._remote_repo.get_default_branch()
115-
116-
def create_formatted_patch_header(self, patch_info: PatchInfo) -> str:
117-
"""Create a formatted patch header for the given patch info."""
118-
return patch_info.to_git_header()

dfetch/project/gitsuperproject.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
from dfetch.project.superproject import RevisionRange, SuperProject
1919
from dfetch.util.util import resolve_absolute_path
2020
from dfetch.vcs.git import GitLocalRepo
21-
from dfetch.vcs.patch import reverse_patch
2221

2322
logger = get_logger(__name__)
2423

@@ -138,14 +137,9 @@ def diff(
138137
combined_diff += [diff_since_revision]
139138

140139
untracked_files_patch = local_repo.untracked_files_patch(ignore)
141-
if untracked_files_patch:
140+
if not untracked_files_patch.is_empty():
142141
if reverse:
143-
reversed_patch = reverse_patch(untracked_files_patch.encode("utf-8"))
144-
if not reversed_patch:
145-
raise RuntimeError(
146-
"Failed to reverse untracked files patch; patch parsing returned empty."
147-
)
148-
untracked_files_patch = reversed_patch
149-
combined_diff += [untracked_files_patch]
142+
untracked_files_patch.reverse()
143+
combined_diff += [untracked_files_patch.dump()]
150144

151145
return "\n".join(combined_diff)

dfetch/project/subproject.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from dfetch.project.metadata import Metadata
1414
from dfetch.util.util import hash_directory, safe_rm
1515
from dfetch.util.versions import latest_tag_from_list
16-
from dfetch.vcs.patch import PatchInfo, apply_patch
16+
from dfetch.vcs.patch import Patch
1717

1818
logger = get_logger(__name__)
1919

@@ -161,7 +161,7 @@ def _apply_patches(self, count: int = -1) -> list[str]:
161161
normalized_patch_path = str(relative_patch_path.as_posix())
162162

163163
self._log_project(f'Applying patch "{normalized_patch_path}"')
164-
result = apply_patch(normalized_patch_path, root=self.local_path)
164+
result = Patch.from_file(normalized_patch_path).apply(root=self.local_path)
165165

166166
if result.encoding_warning:
167167
self._log_project(
@@ -395,9 +395,3 @@ def is_license_file(filename: str) -> bool:
395395
fnmatch.fnmatch(filename.lower(), pattern)
396396
for pattern in SubProject.LICENSE_GLOBS
397397
)
398-
399-
@abstractmethod
400-
def create_formatted_patch_header(self, patch_info: PatchInfo) -> str:
401-
"""Create a formatted patch header for the given patch info."""
402-
del patch_info
403-
return ""

dfetch/project/svnsubproject.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
find_non_matching_files,
1414
safe_rm,
1515
)
16-
from dfetch.vcs.patch import PatchInfo
1716
from dfetch.vcs.svn import SvnRemote, SvnRepo, get_svn_version
1817

1918
logger = get_logger(__name__)
@@ -180,7 +179,3 @@ def _get_revision(self, branch: str) -> str:
180179
def get_default_branch(self) -> str:
181180
"""Get the default branch of this repository."""
182181
return SvnRepo.DEFAULT_BRANCH
183-
184-
def create_formatted_patch_header(self, patch_info: PatchInfo) -> str:
185-
"""Create a formatted patch header for the given patch info."""
186-
return patch_info.to_svn_header()

dfetch/project/svnsuperproject.py

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,7 @@
2020
in_directory,
2121
resolve_absolute_path,
2222
)
23-
from dfetch.vcs.patch import (
24-
combine_patches,
25-
create_svn_patch_for_new_file,
26-
reverse_patch,
27-
)
23+
from dfetch.vcs.patch import Patch, PatchType
2824
from dfetch.vcs.svn import SvnRepo
2925

3026
logger = get_logger(__name__)
@@ -116,22 +112,18 @@ def diff(
116112
if new:
117113
new, old = old, new
118114

119-
filtered = repo.create_diff(old, new, ignore)
115+
patch = repo.create_diff(old, new, ignore)
120116

121117
if new:
122-
return filtered
118+
return patch.dump()
123119

124-
patches: list[bytes] = [filtered.encode("utf-8")] if filtered else []
125120
with in_directory(path):
126-
for file_path in repo.untracked_files(".", ignore):
127-
patch = create_svn_patch_for_new_file(file_path)
128-
if patch:
129-
patches.append(patch.encode("utf-8"))
130-
131-
patch_str = combine_patches(patches)
121+
patch.extend(
122+
Patch.for_new_files(repo.untracked_files(".", ignore), PatchType.SVN)
123+
)
132124

133125
# SVN has no way of producing a reverse working copy patch, reverse ourselves
134-
if reverse and not new:
135-
patch_str = reverse_patch(patch_str.encode("UTF-8"))
126+
if reverse:
127+
patch.reverse()
136128

137-
return patch_str
129+
return patch.dump()

dfetch/vcs/git.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from dfetch.log import get_logger
1313
from dfetch.util.cmdline import SubprocessCommandError, run_on_cmdline
1414
from dfetch.util.util import in_directory, safe_rmtree
15-
from dfetch.vcs.patch import create_git_patch_for_new_file
15+
from dfetch.vcs.patch import Patch, PatchType
1616

1717
logger = get_logger(__name__)
1818

@@ -457,7 +457,7 @@ def any_changes_or_untracked(path: str) -> bool:
457457
.splitlines()
458458
)
459459

460-
def untracked_files_patch(self, ignore: Sequence[str] | None = None) -> str:
460+
def untracked_files_patch(self, ignore: Sequence[str] | None = None) -> Patch:
461461
"""Create a diff for untracked files."""
462462
with in_directory(self._path):
463463
untracked_files = (
@@ -476,10 +476,9 @@ def untracked_files_patch(self, ignore: Sequence[str] | None = None) -> str:
476476
]
477477

478478
if untracked_files:
479-
return "\n".join(
480-
[create_git_patch_for_new_file(file) for file in untracked_files]
481-
)
482-
return ""
479+
return Patch.for_new_files(untracked_files, PatchType.GIT)
480+
481+
return Patch.empty()
483482

484483
@staticmethod
485484
def submodules() -> list[Submodule]:

0 commit comments

Comments
 (0)