Skip to content

Commit b718960

Browse files
committed
Validate every fspath with tests
1 parent b5abe0f commit b718960

File tree

15 files changed

+81
-47
lines changed

15 files changed

+81
-47
lines changed

git/index/base.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ def raise_exc(e: Exception) -> NoReturn:
434434
# characters.
435435
if abs_path not in resolved_paths:
436436
for f in self._iter_expand_paths(glob.glob(abs_path)):
437-
yield os.fspath(f).replace(rs, "")
437+
yield str(f).replace(rs, "")
438438
continue
439439
# END glob handling
440440
try:
@@ -569,7 +569,7 @@ def resolve_blobs(self, iter_blobs: Iterator[Blob]) -> "IndexFile":
569569
for blob in iter_blobs:
570570
stage_null_key = (blob.path, 0)
571571
if stage_null_key in self.entries:
572-
raise ValueError("Path %r already exists at stage 0" % os.fspath(blob.path))
572+
raise ValueError("Path %r already exists at stage 0" % str(blob.path))
573573
# END assert blob is not stage 0 already
574574

575575
# Delete all possible stages.
@@ -652,15 +652,14 @@ def _to_relative_path(self, path: PathLike) -> PathLike:
652652
653653
:raise ValueError:
654654
"""
655-
path = os.fspath(path)
656655
if not osp.isabs(path):
657656
return path
658657
if self.repo.bare:
659658
raise InvalidGitRepositoryError("require non-bare repository")
660659
if not osp.normpath(path).startswith(os.fspath(self.repo.working_tree_dir)):
661660
raise ValueError("Absolute path %r is not in git repository at %r" % (path, self.repo.working_tree_dir))
662661
result = os.path.relpath(path, self.repo.working_tree_dir)
663-
if path.endswith(os.sep) and not result.endswith(os.sep):
662+
if os.fspath(path).endswith(os.sep) and not result.endswith(os.sep):
664663
result += os.sep
665664
return result
666665

@@ -1364,7 +1363,7 @@ def make_exc() -> GitCommandError:
13641363
if not folder.endswith("/"):
13651364
folder += "/"
13661365
for entry in self.entries.values():
1367-
if os.fspath(entry.path).startswith(folder):
1366+
if entry.path.startswith(folder):
13681367
p = entry.path
13691368
self._write_path_to_stdin(proc, p, p, make_exc, fprogress, read_from_stdout=False)
13701369
checked_out_files.append(p)

git/index/fun.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ def run_commit_hook(name: str, index: "IndexFile", *args: str) -> None:
8787
return
8888

8989
env = os.environ.copy()
90-
env["GIT_INDEX_FILE"] = safe_decode(index.path)
90+
env["GIT_INDEX_FILE"] = safe_decode(os.fspath(index.path))
9191
env["GIT_EDITOR"] = ":"
9292
cmd = [hp]
9393
try:
@@ -167,7 +167,7 @@ def write_cache(
167167
beginoffset = tell()
168168
write(entry.ctime_bytes) # ctime
169169
write(entry.mtime_bytes) # mtime
170-
path_str = os.fspath(entry.path)
170+
path_str = str(entry.path)
171171
path: bytes = force_bytes(path_str, encoding=defenc)
172172
plen = len(path) & CE_NAMEMASK # Path length
173173
assert plen == len(path), "Path %s too long to fit into index" % entry.path

git/index/typ.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ def __init__(self, paths: Sequence[PathLike]) -> None:
5858

5959
def __call__(self, stage_blob: Tuple[StageType, Blob]) -> bool:
6060
blob_pathlike: PathLike = stage_blob[1].path
61-
blob_path = Path(blob_pathlike)
61+
blob_path: Path = blob_pathlike if isinstance(blob_pathlike, Path) else Path(blob_pathlike)
6262
for pathlike in self.paths:
63-
path = Path(pathlike)
63+
path: Path = pathlike if isinstance(pathlike, Path) else Path(pathlike)
6464
# TODO: Change to use `PosixPath.is_relative_to` once Python 3.8 is no
6565
# longer supported.
6666
filter_parts = path.parts

git/index/util.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ class TemporaryFileSwap:
3737
__slots__ = ("file_path", "tmp_file_path")
3838

3939
def __init__(self, file_path: PathLike) -> None:
40-
self.file_path = os.fspath(file_path)
41-
dirname, basename = osp.split(self.file_path)
40+
self.file_path = file_path
41+
dirname, basename = osp.split(file_path)
4242
fd, self.tmp_file_path = tempfile.mkstemp(prefix=basename, dir=dirname)
4343
os.close(fd)
4444
with contextlib.suppress(OSError): # It may be that the source does not exist.
@@ -106,7 +106,7 @@ def git_working_dir(func: Callable[..., _T]) -> Callable[..., _T]:
106106
@wraps(func)
107107
def set_git_working_dir(self: "IndexFile", *args: Any, **kwargs: Any) -> _T:
108108
cur_wd = os.getcwd()
109-
os.chdir(os.fspath(self.repo.working_tree_dir))
109+
os.chdir(self.repo.working_tree_dir)
110110
try:
111111
return func(self, *args, **kwargs)
112112
finally:

git/objects/submodule/base.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ def _clone_repo(
352352
module_abspath_dir = osp.dirname(module_abspath)
353353
if not osp.isdir(module_abspath_dir):
354354
os.makedirs(module_abspath_dir)
355-
module_checkout_path = osp.join(os.fspath(repo.working_tree_dir), path)
355+
module_checkout_path = osp.join(repo.working_tree_dir, path)
356356

357357
if url.startswith("../"):
358358
remote_name = cast("RemoteReference", repo.active_branch.tracking_branch()).remote_name
@@ -1016,7 +1016,7 @@ def move(self, module_path: PathLike, configuration: bool = True, module: bool =
10161016
return self
10171017
# END handle no change
10181018

1019-
module_checkout_abspath = join_path_native(os.fspath(self.repo.working_tree_dir), module_checkout_path)
1019+
module_checkout_abspath = join_path_native(str(self.repo.working_tree_dir), module_checkout_path)
10201020
if osp.isfile(module_checkout_abspath):
10211021
raise ValueError("Cannot move repository onto a file: %s" % module_checkout_abspath)
10221022
# END handle target files
@@ -1229,7 +1229,7 @@ def remove(
12291229
wtd = mod.working_tree_dir
12301230
del mod # Release file-handles (Windows).
12311231
gc.collect()
1232-
rmtree(wtd)
1232+
rmtree(str(wtd))
12331233
# END delete tree if possible
12341234
# END handle force
12351235

@@ -1313,7 +1313,7 @@ def set_parent_commit(self, commit: Union[Commit_ish, str, None], check: bool =
13131313
# If check is False, we might see a parent-commit that doesn't even contain the
13141314
# submodule anymore. in that case, mark our sha as being NULL.
13151315
try:
1316-
self.binsha = pctree[os.fspath(self.path)].binsha
1316+
self.binsha = pctree[str(self.path)].binsha
13171317
except KeyError:
13181318
self.binsha = self.NULL_BIN_SHA
13191319

@@ -1395,7 +1395,7 @@ def rename(self, new_name: str) -> "Submodule":
13951395
destination_module_abspath = self._module_abspath(self.repo, self.path, new_name)
13961396
source_dir = mod.git_dir
13971397
# Let's be sure the submodule name is not so obviously tied to a directory.
1398-
if os.fspath(destination_module_abspath).startswith(os.fspath(mod.git_dir)):
1398+
if str(destination_module_abspath).startswith(str(mod.git_dir)):
13991399
tmp_dir = self._module_abspath(self.repo, self.path, str(uuid.uuid4()))
14001400
os.renames(source_dir, tmp_dir)
14011401
source_dir = tmp_dir

git/refs/head.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
__all__ = ["HEAD", "Head"]
1010

11-
import os
1211
from git.config import GitConfigParser, SectionConstraint
1312
from git.exc import GitCommandError
1413
from git.util import join_path
@@ -45,7 +44,6 @@ class HEAD(SymbolicReference):
4544
__slots__ = ()
4645

4746
def __init__(self, repo: "Repo", path: PathLike = _HEAD_NAME) -> None:
48-
path = os.fspath(path)
4947
if path != self._HEAD_NAME:
5048
raise ValueError("HEAD instance must point to %r, got %r" % (self._HEAD_NAME, path))
5149
super().__init__(repo, path)

git/refs/log.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
__all__ = ["RefLog", "RefLogEntry"]
55

66
from mmap import mmap
7-
import os
87
import os.path as osp
98
import re
109
import time as _time
@@ -168,7 +167,7 @@ def __init__(self, filepath: Union[PathLike, None] = None) -> None:
168167
"""Initialize this instance with an optional filepath, from which we will
169168
initialize our data. The path is also used to write changes back using the
170169
:meth:`write` method."""
171-
self._path = None if filepath is None else os.fspath(filepath)
170+
self._path = filepath
172171
if filepath is not None:
173172
self._read_from_file()
174173
# END handle filepath

git/refs/symbolic.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
__all__ = ["SymbolicReference"]
55

66
import os
7+
from pathlib import Path
78

89
from gitdb.exc import BadName, BadObject
910

@@ -76,10 +77,10 @@ class SymbolicReference:
7677

7778
def __init__(self, repo: "Repo", path: PathLike, check_path: bool = False) -> None:
7879
self.repo = repo
79-
self.path = os.fspath(path)
80+
self.path: PathLike = path
8081

8182
def __str__(self) -> str:
82-
return self.path
83+
return os.fspath(self.path)
8384

8485
def __repr__(self) -> str:
8586
return '<git.%s "%s">' % (self.__class__.__name__, self.path)
@@ -103,7 +104,7 @@ def name(self) -> str:
103104
In case of symbolic references, the shortest assumable name is the path
104105
itself.
105106
"""
106-
return self.path
107+
return os.fspath(self.path)
107108

108109
@property
109110
def abspath(self) -> PathLike:
@@ -212,7 +213,7 @@ def _check_ref_name_valid(ref_path: PathLike) -> None:
212213
raise ValueError(f"Invalid reference '{ref_path}': references cannot end with a forward slash (/)")
213214
elif previous == "@" and one_before_previous is None:
214215
raise ValueError(f"Invalid reference '{ref_path}': references cannot be '@'")
215-
elif any(component.endswith(".lock") for component in os.fspath(ref_path).split("/")):
216+
elif any(component.endswith(".lock") for component in Path(ref_path).parts):
216217
raise ValueError(
217218
f"Invalid reference '{ref_path}': references cannot have slash-separated components that end with"
218219
" '.lock'"
@@ -235,7 +236,7 @@ def _get_ref_info_helper(
235236
tokens: Union[None, List[str], Tuple[str, str]] = None
236237
repodir = _git_dir(repo, ref_path)
237238
try:
238-
with open(os.path.join(repodir, os.fspath(ref_path)), "rt", encoding="UTF-8") as fp:
239+
with open(os.path.join(repodir, ref_path), "rt", encoding="UTF-8") as fp:
239240
value = fp.read().rstrip()
240241
# Don't only split on spaces, but on whitespace, which allows to parse lines like:
241242
# 60b64ef992065e2600bfef6187a97f92398a9144 branch 'master' of git-server:/path/to/repo
@@ -706,7 +707,7 @@ def _create(
706707
if not force and os.path.isfile(abs_ref_path):
707708
target_data = str(target)
708709
if isinstance(target, SymbolicReference):
709-
target_data = target.path
710+
target_data = os.fspath(target.path)
710711
if not resolve:
711712
target_data = "ref: " + target_data
712713
with open(abs_ref_path, "rb") as fd:
@@ -930,4 +931,4 @@ def from_path(cls: Type[T_References], repo: "Repo", path: PathLike) -> T_Refere
930931

931932
def is_remote(self) -> bool:
932933
""":return: True if this symbolic reference points to a remote branch"""
933-
return self.path.startswith(self._remote_common_path_default + "/")
934+
return os.fspath(self.path).startswith(self._remote_common_path_default + "/")

git/repo/base.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,8 @@ class Repo:
126126
working_dir: PathLike
127127
"""The working directory of the git command."""
128128

129-
_working_tree_dir: Optional[str] = None
129+
# stored as string for easier processing, but annotated as path for clearer intention
130+
_working_tree_dir: Optional[PathLike] = None
130131

131132
git_dir: PathLike
132133
"""The ``.git`` repository directory."""
@@ -215,13 +216,13 @@ def __init__(
215216
epath = path or os.getenv("GIT_DIR")
216217
if not epath:
217218
epath = os.getcwd()
219+
epath = os.fspath(epath)
218220
if Git.is_cygwin():
219221
# Given how the tests are written, this seems more likely to catch Cygwin
220222
# git used from Windows than Windows git used from Cygwin. Therefore
221223
# changing to Cygwin-style paths is the relevant operation.
222-
epath = cygpath(os.fspath(epath))
224+
epath = cygpath(epath)
223225

224-
epath = os.fspath(epath)
225226
if expand_vars and re.search(self.re_envvars, epath):
226227
warnings.warn(
227228
"The use of environment variables in paths is deprecated"
@@ -306,7 +307,7 @@ def __init__(
306307
self._working_tree_dir = None
307308
# END working dir handling
308309

309-
self.working_dir: str = self._working_tree_dir or self.common_dir
310+
self.working_dir: PathLike = self._working_tree_dir or self.common_dir
310311
self.git = self.GitCommandWrapperType(self.working_dir)
311312

312313
# Special handling, in special times.
@@ -366,7 +367,7 @@ def description(self, descr: str) -> None:
366367
fp.write((descr + "\n").encode(defenc))
367368

368369
@property
369-
def working_tree_dir(self) -> Optional[str]:
370+
def working_tree_dir(self) -> Optional[PathLike]:
370371
"""
371372
:return:
372373
The working tree directory of our git repository.
@@ -554,7 +555,7 @@ def tag(self, path: PathLike) -> TagReference:
554555

555556
@staticmethod
556557
def _to_full_tag_path(path: PathLike) -> str:
557-
path_str = os.fspath(path)
558+
path_str = str(path)
558559
if path_str.startswith(TagReference._common_path_default + "/"):
559560
return path_str
560561
if path_str.startswith(TagReference._common_default + "/"):
@@ -1355,6 +1356,7 @@ def _clone(
13551356
) -> "Repo":
13561357
odbt = kwargs.pop("odbt", odb_default_type)
13571358

1359+
# url may be a path and this has no effect if it is a string
13581360
url = os.fspath(url)
13591361
path = os.fspath(path)
13601362

git/repo/fun.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ def is_git_dir(d: PathLike) -> bool:
6262
clearly indicates that we don't support it. There is the unlikely danger to
6363
throw if we see directories which just look like a worktree dir, but are none.
6464
"""
65-
d = os.fspath(d)
6665
if osp.isdir(d):
6766
if (osp.isdir(osp.join(d, "objects")) or "GIT_OBJECT_DIRECTORY" in os.environ) and osp.isdir(
6867
osp.join(d, "refs")

0 commit comments

Comments
 (0)