Skip to content

Commit 037049d

Browse files
committed
Reduce cyclomatic complexity below 9 in diff and update-patch commands
Extract per-project logic from Diff.__call__ (was CC=11) into _diff_project and from UpdatePatch.__call__ (was CC=10) into _process_project. All methods now have CC <= 8. https://claude.ai/code/session_01RTgPqrX37jFkK843dq65Bu
1 parent 67d6c5d commit 037049d

2 files changed

Lines changed: 111 additions & 96 deletions

File tree

dfetch/commands/diff.py

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,11 @@
5858
import pathlib
5959

6060
import dfetch.commands.command
61+
import dfetch.manifest.project
6162
from dfetch.log import get_logger
6263
from dfetch.project import create_super_project
6364
from dfetch.project.metadata import Metadata
64-
from dfetch.project.superproject import NoVcsSuperProject, RevisionRange
65+
from dfetch.project.superproject import NoVcsSuperProject, RevisionRange, SuperProject
6566
from dfetch.util.util import in_directory
6667

6768
logger = get_logger(__name__)
@@ -123,47 +124,55 @@ def __call__(self, args: argparse.Namespace) -> None:
123124
had_errors: bool = False
124125
for project in projects:
125126
try:
126-
if not os.path.exists(project.destination):
127-
raise RuntimeError(
128-
"You cannot generate a diff of a project that was never fetched"
129-
)
130-
subproject = superproject.get_sub_project(project)
131-
132-
if not subproject:
133-
raise RuntimeError("No subproject!")
134-
135-
old_rev = old_rev or superproject.get_file_revision(
136-
subproject.metadata_path
137-
)
138-
if not old_rev:
139-
raise RuntimeError(
140-
"When not providing any revisions, dfetch starts from"
141-
f" the last revision to {Metadata.FILENAME} in {subproject.local_path}."
142-
" Please either commit this, or specify a revision to start from with --revs"
143-
)
144-
patch = superproject.diff(
145-
project.destination,
146-
revisions=RevisionRange(old_rev, new_rev),
147-
ignore=(Metadata.FILENAME,),
148-
)
149-
150-
msg = self._rev_msg(old_rev, new_rev)
151-
if patch:
152-
patch_path = pathlib.Path(f"{project.name}.patch")
153-
logger.print_info_line(
154-
project.name,
155-
f"Generating patch {patch_path} {msg} in {superproject.root_directory}",
156-
)
157-
patch_path.write_text(patch, encoding="UTF-8")
158-
else:
159-
logger.print_info_line(project.name, f"No diffs found {msg}")
127+
self._diff_project(superproject, project, old_rev, new_rev)
160128
except RuntimeError as exc:
161129
logger.print_warning_line(project.name, str(exc))
162130
had_errors = True
163131

164132
if had_errors:
165133
raise RuntimeError()
166134

135+
def _diff_project(
136+
self,
137+
superproject: SuperProject,
138+
project: dfetch.manifest.project.ProjectEntry,
139+
old_rev: str,
140+
new_rev: str,
141+
) -> None:
142+
"""Generate a diff patch for a single project."""
143+
if not os.path.exists(project.destination):
144+
raise RuntimeError(
145+
"You cannot generate a diff of a project that was never fetched"
146+
)
147+
subproject = superproject.get_sub_project(project)
148+
149+
if not subproject:
150+
raise RuntimeError("No subproject!")
151+
152+
old_rev = old_rev or superproject.get_file_revision(subproject.metadata_path)
153+
if not old_rev:
154+
raise RuntimeError(
155+
"When not providing any revisions, dfetch starts from"
156+
f" the last revision to {Metadata.FILENAME} in {subproject.local_path}."
157+
" Please either commit this, or specify a revision to start from with --revs"
158+
)
159+
patch = superproject.diff(
160+
project.destination,
161+
revisions=RevisionRange(old_rev, new_rev),
162+
ignore=(Metadata.FILENAME,),
163+
)
164+
165+
msg = self._rev_msg(old_rev, new_rev)
166+
if patch:
167+
patch_path = pathlib.Path(f"{project.name}.patch")
168+
logger.print_info_line(
169+
project.name,
170+
f"Generating patch {patch_path} {msg} in {superproject.root_directory}",
171+
)
172+
patch_path.write_text(patch, encoding="UTF-8")
173+
else:
174+
logger.print_info_line(project.name, f"No diffs found {msg}")
175+
167176
@staticmethod
168177
def _parse_revs(revs_arg: str) -> tuple[str, str]:
169178
revs = [r for r in revs_arg.strip(":").split(":", maxsplit=1) if r]

dfetch/commands/update_patch.py

Lines changed: 67 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
from dfetch.project import create_super_project
4141
from dfetch.project.gitsuperproject import GitSuperProject
4242
from dfetch.project.metadata import Metadata
43-
from dfetch.project.superproject import NoVcsSuperProject, RevisionRange
43+
from dfetch.project.superproject import NoVcsSuperProject, RevisionRange, SuperProject
4444
from dfetch.util.util import (
4545
check_no_path_traversal,
4646
in_directory,
@@ -88,73 +88,79 @@ def __call__(self, args: argparse.Namespace) -> None:
8888
with in_directory(superproject.root_directory):
8989
for project in superproject.manifest.selected_projects(args.projects):
9090
try:
91-
subproject = dfetch.project.create_sub_project(project)
92-
destination = project.destination
93-
94-
def _ignored(dst: str = destination) -> list[str]:
95-
return list(superproject.ignored_files(dst))
96-
97-
# Check if the project has a patch, maybe suggest creating one?
98-
if not subproject.patch:
99-
logger.print_warning_line(
100-
project.name,
101-
f'skipped - there is no patch file, use "dfetch diff {project.name}"'
102-
" to generate one instead",
103-
)
104-
continue
105-
106-
# Check if the project was ever fetched
107-
on_disk_version = subproject.on_disk_version()
108-
if not on_disk_version:
109-
logger.print_warning_line(
110-
project.name,
111-
f'skipped - the project was never fetched before, use "dfetch update {project.name}"',
112-
)
113-
continue
114-
115-
# Make sure no uncommitted changes (don't care about ignored files)
116-
if superproject.has_local_changes_in_dir(subproject.local_path):
117-
logger.print_warning_line(
118-
project.name,
119-
f"skipped - Uncommitted changes in {subproject.local_path}",
120-
)
121-
continue
122-
123-
# force update to fetched version from metadata without applying patch
124-
subproject.update(
125-
force=True,
126-
ignored_files_callback=_ignored,
127-
patch_count=len(subproject.patch) - 1,
128-
)
129-
130-
# generate reverse patch
131-
patch_text = superproject.diff(
132-
subproject.local_path,
133-
revisions=RevisionRange("", ""),
134-
ignore=(Metadata.FILENAME,),
135-
reverse=True,
136-
)
137-
138-
# Select patch to overwrite & make backup
139-
if not self._update_patch(
140-
subproject.patch[-1],
141-
superproject.root_directory,
142-
project.name,
143-
patch_text,
144-
):
145-
continue
146-
147-
# force update again to fetched version from metadata but with applying patch
148-
subproject.update(
149-
force=True, ignored_files_callback=_ignored, patch_count=-1
150-
)
91+
self._process_project(superproject, project)
15192
except RuntimeError as exc:
15293
logger.print_warning_line(project.name, str(exc))
15394
had_errors = True
15495

15596
if had_errors:
15697
raise RuntimeError()
15798

99+
def _process_project(
100+
self,
101+
superproject: SuperProject,
102+
project: dfetch.manifest.project.ProjectEntry,
103+
) -> None:
104+
"""Perform the patch update for a single project."""
105+
subproject = dfetch.project.create_sub_project(project)
106+
destination = project.destination
107+
108+
def _ignored(dst: str = destination) -> list[str]:
109+
return list(superproject.ignored_files(dst))
110+
111+
# Check if the project has a patch, maybe suggest creating one?
112+
if not subproject.patch:
113+
logger.print_warning_line(
114+
project.name,
115+
f'skipped - there is no patch file, use "dfetch diff {project.name}"'
116+
" to generate one instead",
117+
)
118+
return
119+
120+
# Check if the project was ever fetched
121+
on_disk_version = subproject.on_disk_version()
122+
if not on_disk_version:
123+
logger.print_warning_line(
124+
project.name,
125+
f'skipped - the project was never fetched before, use "dfetch update {project.name}"',
126+
)
127+
return
128+
129+
# Make sure no uncommitted changes (don't care about ignored files)
130+
if superproject.has_local_changes_in_dir(subproject.local_path):
131+
logger.print_warning_line(
132+
project.name,
133+
f"skipped - Uncommitted changes in {subproject.local_path}",
134+
)
135+
return
136+
137+
# force update to fetched version from metadata without applying patch
138+
subproject.update(
139+
force=True,
140+
ignored_files_callback=_ignored,
141+
patch_count=len(subproject.patch) - 1,
142+
)
143+
144+
# generate reverse patch
145+
patch_text = superproject.diff(
146+
subproject.local_path,
147+
revisions=RevisionRange("", ""),
148+
ignore=(Metadata.FILENAME,),
149+
reverse=True,
150+
)
151+
152+
# Select patch to overwrite & make backup
153+
if not self._update_patch(
154+
subproject.patch[-1],
155+
superproject.root_directory,
156+
project.name,
157+
patch_text,
158+
):
159+
return
160+
161+
# force update again to fetched version from metadata but with applying patch
162+
subproject.update(force=True, ignored_files_callback=_ignored, patch_count=-1)
163+
158164
def _update_patch(
159165
self,
160166
patch_to_update: str,

0 commit comments

Comments
 (0)