Skip to content

Commit fd05c8a

Browse files
Refactor: Extract file mtime finding into shared helper function
Create get_latest_file_mtime() helper function in scm_workdir.py to eliminate code duplication across Git, Mercurial, and hybrid implementations. Changes: - Added get_latest_file_mtime() function to scm_workdir.py - Updated GitWorkdir.get_dirty_tag_date() to use shared helper - Updated HgWorkdir.get_dirty_tag_date() to use shared helper - Updated GitWorkdirHgClient.get_dirty_tag_date() to use shared helper - Removed duplicated mtime calculation logic from all implementations - Cleaned up unused imports (datetime/timezone in hg_git.py) This improves maintainability and ensures consistent behavior across all VCS implementations.
1 parent 64dc8cd commit fd05c8a

File tree

4 files changed

+46
-62
lines changed

4 files changed

+46
-62
lines changed

src/setuptools_scm/git.py

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from ._run_cmd import run as _run
2727
from .integration import data_from_mime
2828
from .scm_workdir import Workdir
29+
from .scm_workdir import get_latest_file_mtime
2930
from .version import ScmVersion
3031
from .version import meta
3132
from .version import tag_to_version
@@ -160,28 +161,11 @@ def get_dirty_tag_date(self) -> date | None:
160161
return None
161162

162163
changed_files = changed_files_res.stdout.strip().split("\n")
163-
if not changed_files or changed_files == [""]:
164-
return None
165-
166-
latest_mtime = 0.0
167-
for filepath in changed_files:
168-
full_path = self.path / filepath
169-
try:
170-
file_stat = full_path.stat()
171-
latest_mtime = max(latest_mtime, file_stat.st_mtime)
172-
except OSError:
173-
# File might not exist or be accessible, skip it
174-
continue
175-
176-
if latest_mtime > 0:
177-
# Convert to UTC date
178-
dt = datetime.fromtimestamp(latest_mtime, timezone.utc)
179-
return dt.date()
164+
return get_latest_file_mtime(changed_files, self.path)
180165

181166
except Exception as e:
182167
log.debug("Failed to get dirty tag date: %s", e)
183-
184-
return None
168+
return None
185169

186170
def is_shallow(self) -> bool:
187171
return self.path.joinpath(".git/shallow").is_file()

src/setuptools_scm/hg.py

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from ._version_cls import Version
1212
from .integration import data_from_mime
1313
from .scm_workdir import Workdir
14+
from .scm_workdir import get_latest_file_mtime
1415
from .version import ScmVersion
1516
from .version import meta
1617
from .version import tag_to_version
@@ -178,25 +179,7 @@ def get_dirty_tag_date(self) -> datetime.date | None:
178179
filepath = line[2:] # Skip status char and space
179180
changed_files.append(filepath)
180181

181-
if not changed_files:
182-
return None
183-
184-
latest_mtime = 0.0
185-
for filepath in changed_files:
186-
full_path = self.path / filepath
187-
try:
188-
file_stat = full_path.stat()
189-
latest_mtime = max(latest_mtime, file_stat.st_mtime)
190-
except OSError:
191-
# File might not exist or be accessible, skip it
192-
continue
193-
194-
if latest_mtime > 0:
195-
# Convert to UTC date
196-
dt = datetime.datetime.fromtimestamp(
197-
latest_mtime, datetime.timezone.utc
198-
)
199-
return dt.date()
182+
return get_latest_file_mtime(changed_files, self.path)
200183

201184
except Exception as e:
202185
log.debug("Failed to get dirty tag date: %s", e)

src/setuptools_scm/hg_git.py

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from .git import GitWorkdir
1414
from .hg import HG_COMMAND
1515
from .hg import HgWorkdir
16+
from .scm_workdir import get_latest_file_mtime
1617

1718
log = logging.getLogger(__name__)
1819

@@ -57,9 +58,6 @@ def get_dirty_tag_date(self) -> date | None:
5758
return None
5859

5960
try:
60-
from datetime import datetime
61-
from datetime import timezone
62-
6361
# Get list of changed files using hg status
6462
status_res = _run([HG_COMMAND, "status", "-m", "-a", "-r"], cwd=self.path)
6563
if status_res.returncode != 0:
@@ -72,29 +70,9 @@ def get_dirty_tag_date(self) -> date | None:
7270
filepath = line[2:] # Skip status char and space
7371
changed_files.append(filepath)
7472

75-
if not changed_files:
76-
return None
77-
78-
latest_mtime = 0.0
79-
for filepath in changed_files:
80-
full_path = self.path / filepath
81-
try:
82-
file_stat = full_path.stat()
83-
latest_mtime = max(latest_mtime, file_stat.st_mtime)
84-
except OSError:
85-
# File might not exist or be accessible, skip it
86-
continue
87-
88-
if latest_mtime > 0:
89-
# Convert to UTC date
90-
dt = datetime.fromtimestamp(latest_mtime, timezone.utc)
91-
return dt.date()
73+
return get_latest_file_mtime(changed_files, self.path)
9274

9375
except Exception as e:
94-
# Use the parent's log module
95-
import logging
96-
97-
log = logging.getLogger(__name__)
9876
log.debug("Failed to get dirty tag date: %s", e)
9977

10078
return None

src/setuptools_scm/scm_workdir.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,50 @@
11
from __future__ import annotations
22

3+
import logging
4+
35
from dataclasses import dataclass
6+
from datetime import date
7+
from datetime import datetime
8+
from datetime import timezone
49
from pathlib import Path
510

611
from ._config import Configuration
712
from .version import ScmVersion
813

14+
log = logging.getLogger(__name__)
15+
16+
17+
def get_latest_file_mtime(changed_files: list[str], base_path: Path) -> date | None:
18+
"""Get the latest modification time of the given files.
19+
20+
Args:
21+
changed_files: List of relative file paths
22+
base_path: Base directory path to resolve relative paths
23+
24+
Returns:
25+
The date of the most recently modified file, or None if no valid files found
26+
"""
27+
if not changed_files or changed_files == [""]:
28+
return None
29+
30+
latest_mtime = 0.0
31+
for filepath in changed_files:
32+
full_path = base_path / filepath
33+
try:
34+
file_stat = full_path.stat()
35+
latest_mtime = max(latest_mtime, file_stat.st_mtime)
36+
except OSError:
37+
# File might not exist or be accessible, skip it
38+
log.debug("Failed to get mtime for %s", full_path)
39+
continue
40+
41+
if latest_mtime > 0:
42+
# Convert to UTC date
43+
dt = datetime.fromtimestamp(latest_mtime, timezone.utc)
44+
return dt.date()
45+
46+
return None
47+
948

1049
@dataclass()
1150
class Workdir:

0 commit comments

Comments
 (0)