GitPython 3.1.51__py3-none-any.whl → 3.1.53__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.
- git/__init__.py +1 -1
- git/cmd.py +13 -8
- git/config.py +16 -0
- git/index/fun.py +20 -3
- git/objects/submodule/base.py +141 -100
- git/repo/base.py +4 -3
- git/util.py +37 -24
- {gitpython-3.1.51.dist-info → gitpython-3.1.53.dist-info}/METADATA +1 -1
- {gitpython-3.1.51.dist-info → gitpython-3.1.53.dist-info}/RECORD +13 -13
- {gitpython-3.1.51.dist-info → gitpython-3.1.53.dist-info}/WHEEL +0 -0
- {gitpython-3.1.51.dist-info → gitpython-3.1.53.dist-info}/licenses/AUTHORS +0 -0
- {gitpython-3.1.51.dist-info → gitpython-3.1.53.dist-info}/licenses/LICENSE +0 -0
- {gitpython-3.1.51.dist-info → gitpython-3.1.53.dist-info}/top_level.txt +0 -0
git/__init__.py
CHANGED
git/cmd.py
CHANGED
|
@@ -903,29 +903,34 @@ class Git(metaclass=_GitMeta):
|
|
|
903
903
|
|
|
904
904
|
@overload
|
|
905
905
|
@classmethod
|
|
906
|
-
def polish_url(cls, url: str, is_cygwin: Literal[False] = ...) -> str: ...
|
|
906
|
+
def polish_url(cls, url: str, is_cygwin: Literal[False] = ..., expand_vars: bool = ...) -> str: ...
|
|
907
907
|
|
|
908
908
|
@overload
|
|
909
909
|
@classmethod
|
|
910
|
-
def polish_url(cls, url: str, is_cygwin: Union[None, bool] = None) -> str: ...
|
|
910
|
+
def polish_url(cls, url: str, is_cygwin: Union[None, bool] = None, expand_vars: bool = True) -> str: ...
|
|
911
911
|
|
|
912
912
|
@classmethod
|
|
913
|
-
def polish_url(cls, url: str, is_cygwin: Union[None, bool] = None) -> PathLike:
|
|
913
|
+
def polish_url(cls, url: str, is_cygwin: Union[None, bool] = None, expand_vars: bool = True) -> PathLike:
|
|
914
914
|
"""Remove any backslashes from URLs to be written in config files.
|
|
915
915
|
|
|
916
916
|
Windows might create config files containing paths with backslashes, but git
|
|
917
917
|
stops liking them as it will escape the backslashes. Hence we undo the escaping
|
|
918
918
|
just to be sure.
|
|
919
|
+
|
|
920
|
+
:param expand_vars:
|
|
921
|
+
Expand environment variables and an initial ``~``. Disable this for values
|
|
922
|
+
obtained from an untrusted source, such as remote URLs.
|
|
919
923
|
"""
|
|
920
924
|
if is_cygwin is None:
|
|
921
925
|
is_cygwin = cls.is_cygwin()
|
|
922
926
|
|
|
923
927
|
if is_cygwin:
|
|
924
|
-
url = cygpath(url)
|
|
928
|
+
url = cygpath(url, expand_vars=expand_vars)
|
|
925
929
|
else:
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
url
|
|
930
|
+
if expand_vars:
|
|
931
|
+
url = os.path.expandvars(url)
|
|
932
|
+
if url.startswith("~"):
|
|
933
|
+
url = os.path.expanduser(url)
|
|
929
934
|
url = url.replace("\\\\", "\\").replace("\\", "/")
|
|
930
935
|
return url
|
|
931
936
|
|
|
@@ -1353,7 +1358,7 @@ class Git(metaclass=_GitMeta):
|
|
|
1353
1358
|
|
|
1354
1359
|
# Allow the user to have the command executed in their working dir.
|
|
1355
1360
|
try:
|
|
1356
|
-
cwd = self._working_dir or os.getcwd() # type:
|
|
1361
|
+
cwd = self._working_dir or os.getcwd() # type: Optional[PathLike]
|
|
1357
1362
|
if not os.access(str(cwd), os.X_OK):
|
|
1358
1363
|
cwd = None
|
|
1359
1364
|
except FileNotFoundError:
|
git/config.py
CHANGED
|
@@ -897,6 +897,22 @@ class GitConfigParser(cp.RawConfigParser, metaclass=MetaParserBuilder):
|
|
|
897
897
|
def _assure_config_name_safe(self, name: "cp._SectionName", label: str) -> None:
|
|
898
898
|
if isinstance(name, str) and UNSAFE_CONFIG_CHARS_RE.search(name):
|
|
899
899
|
raise ValueError("Git config %s names must not contain CR, LF, or NUL" % label)
|
|
900
|
+
if label == "section" and isinstance(name, str):
|
|
901
|
+
in_quotes = False
|
|
902
|
+
escaped = False
|
|
903
|
+
for index, char in enumerate(name):
|
|
904
|
+
if escaped:
|
|
905
|
+
escaped = False
|
|
906
|
+
elif in_quotes and char == "\\":
|
|
907
|
+
escaped = True
|
|
908
|
+
elif char == '"':
|
|
909
|
+
if not in_quotes and (index == 0 or name[index - 1] not in " \t"):
|
|
910
|
+
raise ValueError("Git config quoted subsection names must begin after whitespace")
|
|
911
|
+
in_quotes = not in_quotes
|
|
912
|
+
elif char == "]" and not in_quotes:
|
|
913
|
+
raise ValueError("Git config section names must not contain an unquoted closing bracket")
|
|
914
|
+
if in_quotes:
|
|
915
|
+
raise ValueError("Git config section names must not contain an unterminated quote")
|
|
900
916
|
|
|
901
917
|
@needs_values
|
|
902
918
|
@set_dirty_and_flush_changes
|
git/index/fun.py
CHANGED
|
@@ -64,6 +64,17 @@ def hook_path(name: str, git_dir: PathLike) -> str:
|
|
|
64
64
|
return osp.join(git_dir, "hooks", name)
|
|
65
65
|
|
|
66
66
|
|
|
67
|
+
def _commit_hook_path(name: str, index: "IndexFile") -> str:
|
|
68
|
+
""":return: path to the named commit hook, respecting Git's core.hooksPath."""
|
|
69
|
+
with index.repo.config_reader() as config:
|
|
70
|
+
hooks_dir = config.get("core", "hooksPath", fallback="")
|
|
71
|
+
|
|
72
|
+
if not hooks_dir:
|
|
73
|
+
return hook_path(name, index.repo.git_dir)
|
|
74
|
+
|
|
75
|
+
return osp.abspath(osp.join(index.repo.working_dir, osp.expanduser(hooks_dir), name))
|
|
76
|
+
|
|
77
|
+
|
|
67
78
|
def _has_file_extension(path: str) -> str:
|
|
68
79
|
return osp.splitext(path)[1]
|
|
69
80
|
|
|
@@ -82,7 +93,7 @@ def run_commit_hook(name: str, index: "IndexFile", *args: str) -> None:
|
|
|
82
93
|
|
|
83
94
|
:raise git.exc.HookExecutionError:
|
|
84
95
|
"""
|
|
85
|
-
hp =
|
|
96
|
+
hp = _commit_hook_path(name, index)
|
|
86
97
|
if not os.access(hp, os.X_OK):
|
|
87
98
|
return
|
|
88
99
|
|
|
@@ -94,8 +105,14 @@ def run_commit_hook(name: str, index: "IndexFile", *args: str) -> None:
|
|
|
94
105
|
if sys.platform == "win32" and not _has_file_extension(hp):
|
|
95
106
|
# Windows only uses extensions to determine how to open files
|
|
96
107
|
# (doesn't understand shebangs). Try using bash to run the hook.
|
|
97
|
-
|
|
98
|
-
|
|
108
|
+
try:
|
|
109
|
+
bash_hp = osp.relpath(hp, index.repo.working_dir)
|
|
110
|
+
except ValueError:
|
|
111
|
+
# Different drives have no relative path on Windows. Git Bash accepts
|
|
112
|
+
# an absolute path in this form, although a relative path is preferable
|
|
113
|
+
# because it also works with the Windows Subsystem for Linux wrapper.
|
|
114
|
+
bash_hp = hp
|
|
115
|
+
cmd = ["bash.exe", Path(bash_hp).as_posix()]
|
|
99
116
|
|
|
100
117
|
process = safer_popen(
|
|
101
118
|
cmd + list(args),
|
git/objects/submodule/base.py
CHANGED
|
@@ -49,6 +49,7 @@ from typing import (
|
|
|
49
49
|
Callable,
|
|
50
50
|
Dict,
|
|
51
51
|
Iterator,
|
|
52
|
+
List,
|
|
52
53
|
Mapping,
|
|
53
54
|
Sequence,
|
|
54
55
|
TYPE_CHECKING,
|
|
@@ -738,122 +739,132 @@ class Submodule(IndexObject, TraversableIterableObj):
|
|
|
738
739
|
mrepo = None
|
|
739
740
|
# END init mrepo
|
|
740
741
|
|
|
742
|
+
def fetch_remotes(module_repo: "Repo") -> None:
|
|
743
|
+
rmts = module_repo.remotes
|
|
744
|
+
len_rmts = len(rmts)
|
|
745
|
+
for i, remote in enumerate(rmts):
|
|
746
|
+
op = FETCH
|
|
747
|
+
if i == 0:
|
|
748
|
+
op |= BEGIN
|
|
749
|
+
# END handle start
|
|
750
|
+
|
|
751
|
+
progress.update(
|
|
752
|
+
op,
|
|
753
|
+
i,
|
|
754
|
+
len_rmts,
|
|
755
|
+
prefix + "Fetching remote %s of submodule %r" % (remote, self.name),
|
|
756
|
+
)
|
|
757
|
+
# ===============================
|
|
758
|
+
if not dry_run:
|
|
759
|
+
remote.fetch(progress=progress)
|
|
760
|
+
# END handle dry-run
|
|
761
|
+
# ===============================
|
|
762
|
+
if i == len_rmts - 1:
|
|
763
|
+
op |= END
|
|
764
|
+
# END handle end
|
|
765
|
+
progress.update(
|
|
766
|
+
op,
|
|
767
|
+
i,
|
|
768
|
+
len_rmts,
|
|
769
|
+
prefix + "Done fetching remote of submodule %r" % self.name,
|
|
770
|
+
)
|
|
771
|
+
# END fetch new data
|
|
772
|
+
|
|
741
773
|
try:
|
|
742
774
|
# ENSURE REPO IS PRESENT AND UP-TO-DATE
|
|
743
775
|
#######################################
|
|
744
776
|
try:
|
|
745
777
|
mrepo = self.module()
|
|
746
|
-
|
|
747
|
-
len_rmts = len(rmts)
|
|
748
|
-
for i, remote in enumerate(rmts):
|
|
749
|
-
op = FETCH
|
|
750
|
-
if i == 0:
|
|
751
|
-
op |= BEGIN
|
|
752
|
-
# END handle start
|
|
753
|
-
|
|
754
|
-
progress.update(
|
|
755
|
-
op,
|
|
756
|
-
i,
|
|
757
|
-
len_rmts,
|
|
758
|
-
prefix + "Fetching remote %s of submodule %r" % (remote, self.name),
|
|
759
|
-
)
|
|
760
|
-
# ===============================
|
|
761
|
-
if not dry_run:
|
|
762
|
-
remote.fetch(progress=progress)
|
|
763
|
-
# END handle dry-run
|
|
764
|
-
# ===============================
|
|
765
|
-
if i == len_rmts - 1:
|
|
766
|
-
op |= END
|
|
767
|
-
# END handle end
|
|
768
|
-
progress.update(
|
|
769
|
-
op,
|
|
770
|
-
i,
|
|
771
|
-
len_rmts,
|
|
772
|
-
prefix + "Done fetching remote of submodule %r" % self.name,
|
|
773
|
-
)
|
|
774
|
-
# END fetch new data
|
|
778
|
+
fetch_remotes(mrepo)
|
|
775
779
|
except InvalidGitRepositoryError:
|
|
776
780
|
mrepo = None
|
|
777
781
|
if not init:
|
|
778
782
|
return self
|
|
779
783
|
# END early abort if init is not allowed
|
|
780
784
|
|
|
781
|
-
# There is no git-repository yet - but delete empty paths.
|
|
782
785
|
checkout_module_abspath = self.abspath
|
|
783
|
-
|
|
786
|
+
module_abspath = self._module_abspath(self.repo, self.path, self.name)
|
|
787
|
+
|
|
788
|
+
# ``git submodule deinit`` leaves the repository in
|
|
789
|
+
# ``.git/modules`` and empties the checkout. Reconnect that retained
|
|
790
|
+
# repository instead of trying to clone over it.
|
|
791
|
+
if not dry_run and osp.isdir(module_abspath):
|
|
784
792
|
try:
|
|
785
|
-
|
|
786
|
-
except
|
|
787
|
-
|
|
788
|
-
"Module directory at %r does already exist and is non-empty" % checkout_module_abspath
|
|
789
|
-
) from e
|
|
790
|
-
# END handle OSError
|
|
791
|
-
# END handle directory removal
|
|
792
|
-
|
|
793
|
-
# Don't check it out at first - nonetheless it will create a local
|
|
794
|
-
# branch according to the remote-HEAD if possible.
|
|
795
|
-
progress.update(
|
|
796
|
-
BEGIN | CLONE,
|
|
797
|
-
0,
|
|
798
|
-
1,
|
|
799
|
-
prefix
|
|
800
|
-
+ "Cloning url '%s' to '%s' in submodule %r" % (self.url, checkout_module_abspath, self.name),
|
|
801
|
-
)
|
|
802
|
-
if not dry_run:
|
|
803
|
-
if self.url.startswith("."):
|
|
804
|
-
url = urllib.parse.urljoin(self.repo.remotes.origin.url + "/", self.url)
|
|
793
|
+
git.Repo(module_abspath)
|
|
794
|
+
except InvalidGitRepositoryError:
|
|
795
|
+
pass
|
|
805
796
|
else:
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
797
|
+
if osp.lexists(checkout_module_abspath) and (
|
|
798
|
+
osp.islink(checkout_module_abspath)
|
|
799
|
+
or not osp.isdir(checkout_module_abspath)
|
|
800
|
+
or os.listdir(checkout_module_abspath)
|
|
801
|
+
):
|
|
802
|
+
raise OSError(
|
|
803
|
+
"Module directory at %r does already exist and is non-empty" % checkout_module_abspath
|
|
804
|
+
)
|
|
805
|
+
os.makedirs(checkout_module_abspath, exist_ok=True)
|
|
806
|
+
self._write_git_file_and_module_config(checkout_module_abspath, module_abspath)
|
|
807
|
+
mrepo = git.Repo(checkout_module_abspath)
|
|
808
|
+
mrepo.head.reset(mrepo.head.commit, index=True, working_tree=True)
|
|
809
|
+
fetch_remotes(mrepo)
|
|
810
|
+
with self.repo.config_writer() as writer:
|
|
811
|
+
writer.set_value(sm_section(self.name), "url", self.url)
|
|
812
|
+
|
|
813
|
+
if mrepo is None:
|
|
814
|
+
# There is no git-repository yet - but delete empty paths.
|
|
815
|
+
if not dry_run and osp.isdir(checkout_module_abspath):
|
|
816
|
+
try:
|
|
817
|
+
os.rmdir(checkout_module_abspath)
|
|
818
|
+
except OSError as e:
|
|
819
|
+
raise OSError(
|
|
820
|
+
"Module directory at %r does already exist and is non-empty" % checkout_module_abspath
|
|
821
|
+
) from e
|
|
822
|
+
# END handle directory removal
|
|
823
|
+
|
|
824
|
+
# Don't check it out at first - nonetheless it will create a local
|
|
825
|
+
# branch according to the remote-HEAD if possible.
|
|
826
|
+
progress.update(
|
|
827
|
+
BEGIN | CLONE,
|
|
828
|
+
0,
|
|
829
|
+
1,
|
|
830
|
+
prefix
|
|
831
|
+
+ "Cloning url '%s' to '%s' in submodule %r" % (self.url, checkout_module_abspath, self.name),
|
|
817
832
|
)
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
# Have a valid branch, but no checkout - make sure we can figure
|
|
835
|
-
# that out by marking the commit with a null_sha.
|
|
836
|
-
local_branch.set_object(Object(mrepo, self.NULL_BIN_SHA))
|
|
837
|
-
# END initial checkout + branch creation
|
|
838
|
-
|
|
839
|
-
# Make sure HEAD is not detached.
|
|
840
|
-
mrepo.head.set_reference(
|
|
841
|
-
local_branch,
|
|
842
|
-
logmsg="submodule: attaching head to %s" % local_branch,
|
|
833
|
+
if not dry_run:
|
|
834
|
+
if self.url.startswith("."):
|
|
835
|
+
url = urllib.parse.urljoin(self.repo.remotes.origin.url + "/", self.url)
|
|
836
|
+
else:
|
|
837
|
+
url = self.url
|
|
838
|
+
mrepo = self._clone_repo(
|
|
839
|
+
self.repo,
|
|
840
|
+
url,
|
|
841
|
+
self.path,
|
|
842
|
+
self.name,
|
|
843
|
+
n=True,
|
|
844
|
+
env=env,
|
|
845
|
+
multi_options=clone_multi_options,
|
|
846
|
+
allow_unsafe_options=allow_unsafe_options,
|
|
847
|
+
allow_unsafe_protocols=allow_unsafe_protocols,
|
|
843
848
|
)
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
849
|
+
progress.update(END | CLONE, 0, 1, prefix + "Done cloning to %s" % checkout_module_abspath)
|
|
850
|
+
|
|
851
|
+
if not dry_run:
|
|
852
|
+
# See whether we have a valid branch to check out.
|
|
853
|
+
try:
|
|
854
|
+
mrepo = cast("Repo", mrepo)
|
|
855
|
+
remote_branch = find_first_remote_branch(mrepo.remotes, self.branch_name)
|
|
856
|
+
local_branch = mkhead(mrepo, self.branch_path)
|
|
857
|
+
local_branch.set_object(Object(mrepo, self.NULL_BIN_SHA))
|
|
858
|
+
mrepo.head.set_reference(
|
|
859
|
+
local_branch,
|
|
860
|
+
logmsg="submodule: attaching head to %s" % local_branch,
|
|
861
|
+
)
|
|
862
|
+
mrepo.head.reference.set_tracking_branch(remote_branch)
|
|
863
|
+
except (IndexError, InvalidGitRepositoryError):
|
|
864
|
+
_logger.warning("Failed to checkout tracking branch %s", self.branch_path)
|
|
865
|
+
|
|
866
|
+
with self.repo.config_writer() as writer:
|
|
867
|
+
writer.set_value(sm_section(self.name), "url", self.url)
|
|
857
868
|
# END handle initialization
|
|
858
869
|
|
|
859
870
|
# DETERMINE SHAS TO CHECK OUT
|
|
@@ -1267,6 +1278,36 @@ class Submodule(IndexObject, TraversableIterableObj):
|
|
|
1267
1278
|
|
|
1268
1279
|
return self
|
|
1269
1280
|
|
|
1281
|
+
@unbare_repo
|
|
1282
|
+
def deinit(self, force: bool = False) -> "Submodule":
|
|
1283
|
+
"""Run ``git submodule deinit`` on this submodule.
|
|
1284
|
+
|
|
1285
|
+
This is a thin wrapper around ``git submodule deinit <path>``,
|
|
1286
|
+
which unregisters the submodule (removes its entry from
|
|
1287
|
+
``.git/config`` and empties the working-tree directory)
|
|
1288
|
+
without deleting the submodule from ``.gitmodules``
|
|
1289
|
+
or its checked-out repository under ``.git/modules/``.
|
|
1290
|
+
A subsequent :meth:`update` will re-initialize the
|
|
1291
|
+
submodule from the retained contents.
|
|
1292
|
+
|
|
1293
|
+
:param force:
|
|
1294
|
+
If ``True``, pass ``--force`` to ``git submodule deinit``. This
|
|
1295
|
+
allows deinitialization even when the submodule's working tree has
|
|
1296
|
+
local modifications that would otherwise block the command.
|
|
1297
|
+
|
|
1298
|
+
:return:
|
|
1299
|
+
self
|
|
1300
|
+
|
|
1301
|
+
:note:
|
|
1302
|
+
Doesn't work in bare repositories.
|
|
1303
|
+
"""
|
|
1304
|
+
args: List[str] = []
|
|
1305
|
+
if force:
|
|
1306
|
+
args.append("--force")
|
|
1307
|
+
args.extend(["--", str(self.path)])
|
|
1308
|
+
self.repo.git.submodule("deinit", *args)
|
|
1309
|
+
return self
|
|
1310
|
+
|
|
1270
1311
|
def set_parent_commit(self, commit: Union[Commit_ish, str, None], check: bool = True) -> "Submodule":
|
|
1271
1312
|
"""Set this instance to use the given commit whose tree is supposed to
|
|
1272
1313
|
contain the ``.gitmodules`` blob.
|
git/repo/base.py
CHANGED
|
@@ -1452,8 +1452,9 @@ class Repo:
|
|
|
1452
1452
|
if multi_options:
|
|
1453
1453
|
multi = shlex.split(" ".join(multi_options))
|
|
1454
1454
|
|
|
1455
|
+
clone_url = Git.polish_url(url, expand_vars=False)
|
|
1455
1456
|
if not allow_unsafe_protocols:
|
|
1456
|
-
Git.check_unsafe_protocols(
|
|
1457
|
+
Git.check_unsafe_protocols(clone_url)
|
|
1457
1458
|
if not allow_unsafe_options:
|
|
1458
1459
|
Git.check_unsafe_options(
|
|
1459
1460
|
options=Git._option_candidates([], kwargs),
|
|
@@ -1465,7 +1466,7 @@ class Repo:
|
|
|
1465
1466
|
proc = git.clone(
|
|
1466
1467
|
multi,
|
|
1467
1468
|
"--",
|
|
1468
|
-
|
|
1469
|
+
clone_url,
|
|
1469
1470
|
clone_path,
|
|
1470
1471
|
with_extended_output=True,
|
|
1471
1472
|
as_process=True,
|
|
@@ -1505,7 +1506,7 @@ class Repo:
|
|
|
1505
1506
|
# escape the backslashes. Hence we undo the escaping just to be sure.
|
|
1506
1507
|
if repo.remotes:
|
|
1507
1508
|
with repo.remotes[0].config_writer as writer:
|
|
1508
|
-
writer.set_value("url", Git.polish_url(repo.remotes[0].url))
|
|
1509
|
+
writer.set_value("url", Git.polish_url(repo.remotes[0].url, expand_vars=False))
|
|
1509
1510
|
# END handle remote repo
|
|
1510
1511
|
return repo
|
|
1511
1512
|
|
git/util.py
CHANGED
|
@@ -217,7 +217,7 @@ def rmtree(path: PathLike) -> None:
|
|
|
217
217
|
couldn't be deleted are read-only. Windows will not remove them in that case.
|
|
218
218
|
"""
|
|
219
219
|
|
|
220
|
-
def handler(function: Callable, path:
|
|
220
|
+
def handler(function: Callable[[str], Any], path: str, _excinfo: Any) -> None:
|
|
221
221
|
"""Callback for :func:`shutil.rmtree`.
|
|
222
222
|
|
|
223
223
|
This works as either a ``onexc`` or ``onerror`` style callback.
|
|
@@ -382,13 +382,13 @@ def py_where(program: str, path: Optional[PathLike] = None) -> List[str]:
|
|
|
382
382
|
return progs
|
|
383
383
|
|
|
384
384
|
|
|
385
|
-
def _cygexpath(drive: Optional[str], path: str) -> str:
|
|
385
|
+
def _cygexpath(drive: Optional[str], path: str, expand_vars: bool = True) -> str:
|
|
386
386
|
if osp.isabs(path) and not drive:
|
|
387
387
|
# Invoked from `cygpath()` directly with `D:Apps\123`?
|
|
388
388
|
# It's an error, leave it alone just slashes)
|
|
389
389
|
p = path # convert to str if AnyPath given
|
|
390
390
|
else:
|
|
391
|
-
p = path and osp.normpath(osp.expandvars(osp.expanduser(path)))
|
|
391
|
+
p = path and osp.normpath(osp.expandvars(osp.expanduser(path)) if expand_vars else path)
|
|
392
392
|
if osp.isabs(p):
|
|
393
393
|
if drive:
|
|
394
394
|
# Confusing, maybe a remote system should expand vars.
|
|
@@ -401,7 +401,7 @@ def _cygexpath(drive: Optional[str], path: str) -> str:
|
|
|
401
401
|
return p_str.replace("\\", "/")
|
|
402
402
|
|
|
403
403
|
|
|
404
|
-
_cygpath_parsers: Tuple[Tuple[Pattern[str], Callable, bool], ...] = (
|
|
404
|
+
_cygpath_parsers: Tuple[Tuple[Pattern[str], Callable[..., str], bool], ...] = (
|
|
405
405
|
# See: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
|
|
406
406
|
# and: https://www.cygwin.com/cygwin-ug-net/using.html#unc-paths
|
|
407
407
|
(
|
|
@@ -416,7 +416,7 @@ _cygpath_parsers: Tuple[Tuple[Pattern[str], Callable, bool], ...] = (
|
|
|
416
416
|
)
|
|
417
417
|
|
|
418
418
|
|
|
419
|
-
def cygpath(path: str) -> str:
|
|
419
|
+
def cygpath(path: str, expand_vars: bool = True) -> str:
|
|
420
420
|
"""Use :meth:`git.cmd.Git.polish_url` instead, that works on any environment."""
|
|
421
421
|
path = os.fspath(path) # Ensure is str and not AnyPath.
|
|
422
422
|
# Fix to use Paths when 3.5 dropped. Or to be just str if only for URLs?
|
|
@@ -424,12 +424,15 @@ def cygpath(path: str) -> str:
|
|
|
424
424
|
for regex, parser, recurse in _cygpath_parsers:
|
|
425
425
|
match = regex.match(path)
|
|
426
426
|
if match:
|
|
427
|
-
|
|
427
|
+
if parser is _cygexpath:
|
|
428
|
+
path = parser(*match.groups(), expand_vars=expand_vars)
|
|
429
|
+
else:
|
|
430
|
+
path = parser(*match.groups())
|
|
428
431
|
if recurse:
|
|
429
|
-
path = cygpath(path)
|
|
432
|
+
path = cygpath(path, expand_vars=expand_vars)
|
|
430
433
|
break
|
|
431
434
|
else:
|
|
432
|
-
path = _cygexpath(None, path)
|
|
435
|
+
path = _cygexpath(None, path, expand_vars=expand_vars)
|
|
433
436
|
|
|
434
437
|
return path
|
|
435
438
|
|
|
@@ -505,7 +508,7 @@ def get_user_id() -> str:
|
|
|
505
508
|
return "%s@%s" % (getpass.getuser(), platform.node())
|
|
506
509
|
|
|
507
510
|
|
|
508
|
-
def finalize_process(proc: Union[subprocess.Popen, "Git.AutoInterrupt"], **kwargs: Any) -> None:
|
|
511
|
+
def finalize_process(proc: Union["subprocess.Popen[Any]", "Git.AutoInterrupt"], **kwargs: Any) -> None:
|
|
509
512
|
"""Wait for the process (clone, fetch, pull or push) and handle its errors
|
|
510
513
|
accordingly."""
|
|
511
514
|
# TODO: No close proc-streams??
|
|
@@ -517,19 +520,21 @@ def expand_path(p: None, expand_vars: bool = ...) -> None: ...
|
|
|
517
520
|
|
|
518
521
|
|
|
519
522
|
@overload
|
|
520
|
-
def expand_path(p: PathLike, expand_vars: bool = ...) ->
|
|
523
|
+
def expand_path(p: PathLike, expand_vars: bool = ...) -> Optional[PathLike]:
|
|
521
524
|
# TODO: Support for Python 3.5 has been dropped, so these overloads can be improved.
|
|
522
525
|
...
|
|
523
526
|
|
|
524
527
|
|
|
525
528
|
def expand_path(p: Union[None, PathLike], expand_vars: bool = True) -> Optional[PathLike]:
|
|
526
|
-
if
|
|
527
|
-
return
|
|
529
|
+
if p is None:
|
|
530
|
+
return None
|
|
528
531
|
try:
|
|
529
|
-
|
|
532
|
+
if isinstance(p, Path):
|
|
533
|
+
return p.resolve()
|
|
534
|
+
expanded_path = osp.expanduser(os.fspath(p))
|
|
530
535
|
if expand_vars:
|
|
531
|
-
|
|
532
|
-
return osp.normpath(osp.abspath(
|
|
536
|
+
expanded_path = osp.expandvars(expanded_path)
|
|
537
|
+
return osp.normpath(osp.abspath(expanded_path))
|
|
533
538
|
except Exception:
|
|
534
539
|
return None
|
|
535
540
|
|
|
@@ -764,7 +769,7 @@ class CallableRemoteProgress(RemoteProgress):
|
|
|
764
769
|
|
|
765
770
|
__slots__ = ("_callable",)
|
|
766
771
|
|
|
767
|
-
def __init__(self, fn: Callable) -> None:
|
|
772
|
+
def __init__(self, fn: Callable[..., Any]) -> None:
|
|
768
773
|
self._callable = fn
|
|
769
774
|
super().__init__()
|
|
770
775
|
|
|
@@ -843,7 +848,7 @@ class Actor:
|
|
|
843
848
|
cls,
|
|
844
849
|
env_name: str,
|
|
845
850
|
env_email: str,
|
|
846
|
-
config_reader: Union[None, "GitConfigParser", "SectionConstraint"] = None,
|
|
851
|
+
config_reader: Union[None, "GitConfigParser", "SectionConstraint[GitConfigParser]"] = None,
|
|
847
852
|
) -> "Actor":
|
|
848
853
|
actor = Actor("", "")
|
|
849
854
|
user_id = None # We use this to avoid multiple calls to getpass.getuser().
|
|
@@ -879,7 +884,9 @@ class Actor:
|
|
|
879
884
|
return actor
|
|
880
885
|
|
|
881
886
|
@classmethod
|
|
882
|
-
def committer(
|
|
887
|
+
def committer(
|
|
888
|
+
cls, config_reader: Union[None, "GitConfigParser", "SectionConstraint[GitConfigParser]"] = None
|
|
889
|
+
) -> "Actor":
|
|
883
890
|
"""
|
|
884
891
|
:return:
|
|
885
892
|
:class:`Actor` instance corresponding to the configured committer. It
|
|
@@ -894,7 +901,9 @@ class Actor:
|
|
|
894
901
|
return cls._main_actor(cls.env_committer_name, cls.env_committer_email, config_reader)
|
|
895
902
|
|
|
896
903
|
@classmethod
|
|
897
|
-
def author(
|
|
904
|
+
def author(
|
|
905
|
+
cls, config_reader: Union[None, "GitConfigParser", "SectionConstraint[GitConfigParser]"] = None
|
|
906
|
+
) -> "Actor":
|
|
898
907
|
"""Same as :meth:`committer`, but defines the main author. It may be specified
|
|
899
908
|
in the environment, but defaults to the committer."""
|
|
900
909
|
return cls._main_actor(cls.env_author_name, cls.env_author_email, config_reader)
|
|
@@ -977,11 +986,11 @@ class IndexFileSHA1Writer:
|
|
|
977
986
|
|
|
978
987
|
__slots__ = ("f", "sha1")
|
|
979
988
|
|
|
980
|
-
def __init__(self, f: IO) -> None:
|
|
989
|
+
def __init__(self, f: IO[bytes]) -> None:
|
|
981
990
|
self.f = f
|
|
982
991
|
self.sha1 = make_sha(b"")
|
|
983
992
|
|
|
984
|
-
def write(self, data:
|
|
993
|
+
def write(self, data: bytes) -> int:
|
|
985
994
|
self.sha1.update(data)
|
|
986
995
|
return self.f.write(data)
|
|
987
996
|
|
|
@@ -1178,6 +1187,7 @@ class IterableList(List[T_IterableObj]): # type: ignore[type-var]
|
|
|
1178
1187
|
return super().__new__(cls)
|
|
1179
1188
|
|
|
1180
1189
|
def __init__(self, id_attr: str, prefix: str = "") -> None:
|
|
1190
|
+
super().__init__()
|
|
1181
1191
|
self._id_attr = id_attr
|
|
1182
1192
|
self._prefix = prefix
|
|
1183
1193
|
|
|
@@ -1207,7 +1217,9 @@ class IterableList(List[T_IterableObj]): # type: ignore[type-var]
|
|
|
1207
1217
|
# END for each item
|
|
1208
1218
|
return list.__getattribute__(self, attr)
|
|
1209
1219
|
|
|
1210
|
-
def __getitem__(
|
|
1220
|
+
def __getitem__( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]
|
|
1221
|
+
self, index: Union[SupportsIndex, int, slice, str]
|
|
1222
|
+
) -> T_IterableObj:
|
|
1211
1223
|
if isinstance(index, int):
|
|
1212
1224
|
return list.__getitem__(self, index)
|
|
1213
1225
|
elif isinstance(index, slice):
|
|
@@ -1285,7 +1297,7 @@ class IterableObj(Protocol):
|
|
|
1285
1297
|
:return:
|
|
1286
1298
|
list(Item,...) list of item instances
|
|
1287
1299
|
"""
|
|
1288
|
-
out_list: IterableList = IterableList(cls._id_attribute_)
|
|
1300
|
+
out_list: IterableList[T_IterableObj] = IterableList(cls._id_attribute_)
|
|
1289
1301
|
out_list.extend(cls.iter_items(repo, *args, **kwargs))
|
|
1290
1302
|
return out_list
|
|
1291
1303
|
|
|
@@ -1294,7 +1306,8 @@ class IterableClassWatcher(type):
|
|
|
1294
1306
|
"""Metaclass that issues :exc:`DeprecationWarning` when :class:`git.util.Iterable`
|
|
1295
1307
|
is subclassed."""
|
|
1296
1308
|
|
|
1297
|
-
def __init__(cls, name: str, bases: Tuple, clsdict: Dict) -> None:
|
|
1309
|
+
def __init__(cls, name: str, bases: Tuple[type, ...], clsdict: Dict[str, Any]) -> None:
|
|
1310
|
+
super().__init__(name, bases, clsdict)
|
|
1298
1311
|
for base in bases:
|
|
1299
1312
|
if type(base) is IterableClassWatcher:
|
|
1300
1313
|
warnings.warn(
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
git/__init__.py,sha256=
|
|
2
|
-
git/cmd.py,sha256=
|
|
1
|
+
git/__init__.py,sha256=JfSdrpLoaZem4xHAf_iZARfzAGTDgpy7K60ptkzAFC8,8899
|
|
2
|
+
git/cmd.py,sha256=nIJlOcTeRoOPVtg5IO_EmhVRCejB8reAfukilRXR6Yo,75230
|
|
3
3
|
git/compat.py,sha256=y1E6y6O2q5r8clSlr8ZNmuIWG9nmHuehQEsVsmBffs8,4526
|
|
4
|
-
git/config.py,sha256=
|
|
4
|
+
git/config.py,sha256=aLDSuDiiB67W-OLktJpYVjSLwgIqWJtPYbRllNhQ7Gw,38406
|
|
5
5
|
git/db.py,sha256=vIW9uWSbqu99zbuU2ZDmOhVOv1UPTmxrnqiCtRHCfjE,2368
|
|
6
6
|
git/diff.py,sha256=qkL8g0m7UoIB5TcY7X23DgEMAmBJ0ZpEVFdHR1pDKJU,27767
|
|
7
7
|
git/exc.py,sha256=Gc7g1pHpn8OmTse30NHmJVsBJ2CYH8LxaR8y8UA3lIM,7119
|
|
8
8
|
git/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
9
|
git/remote.py,sha256=rCbrMMjILsX08TGYai8wdxzHCHc4ba6vPt6tP9efOog,46881
|
|
10
10
|
git/types.py,sha256=d3oDduUGjfoqffcUL_GOD-3qroF8m3r9ai6Xi9_FraM,10279
|
|
11
|
-
git/util.py,sha256=
|
|
11
|
+
git/util.py,sha256=27MIkq6AhpjyAHF9r7UEA1pGYRAkxRMiZNo5IJGdJhU,44712
|
|
12
12
|
git/index/__init__.py,sha256=i-Nqb8Lufp9aFbmxpQBORmmQnjEVVM1Pn58fsQkyGgQ,406
|
|
13
13
|
git/index/base.py,sha256=6U-gbvhVa2YmW1v-JeT1TOW6wJHi1li5g9wume-iCmw,62260
|
|
14
|
-
git/index/fun.py,sha256=
|
|
14
|
+
git/index/fun.py,sha256=Cfrpq6GmhLXGVDDjYiXTN4f4bb35kvw6-cOGOBuJeGc,17862
|
|
15
15
|
git/index/typ.py,sha256=ZjRWp5J79OwFQor1XXN4C6JmHTDclD9H-tKZtAeqyTI,7019
|
|
16
16
|
git/index/util.py,sha256=f0BfE2JPkdypsB2Q_HJ8KU7MC45RRHywL_GWwxa_5hw,3676
|
|
17
17
|
git/objects/__init__.py,sha256=O6ZL_olX7e5-8iIbKviRPkVSJxN37WA-EC0q9d48U5Y,637
|
|
@@ -23,7 +23,7 @@ git/objects/tag.py,sha256=jAGESnpmTEv-dLakPzheT5ILZFFArcItnXYqfxfDrgc,4441
|
|
|
23
23
|
git/objects/tree.py,sha256=MmExcS59Iamb2cBqUvoHPdzgixabyvv5voHabossrl8,13898
|
|
24
24
|
git/objects/util.py,sha256=Nlza4zLgdPmr_Yasyvvs6c1rKtW_wMxI6wDmQpQ3ufw,23846
|
|
25
25
|
git/objects/submodule/__init__.py,sha256=6xySp767LVz3UylWgUalntS_nGXRuVzXxDuFAv_Wc2c,303
|
|
26
|
-
git/objects/submodule/base.py,sha256=
|
|
26
|
+
git/objects/submodule/base.py,sha256=NR8eP-dEr-U_EG8LahRRgJ2n2z1wZXY9V0w57pBbiIo,66328
|
|
27
27
|
git/objects/submodule/root.py,sha256=5eTtYNHasqdPq6q0oDCPr7IaO6uAHL3b4DxMoiO2LhE,20246
|
|
28
28
|
git/objects/submodule/util.py,sha256=sQqAYaiSJdFkZa9NlAuK_wTsMNiS-kkQnQjvIoJtc_o,3509
|
|
29
29
|
git/refs/__init__.py,sha256=DWlJNnsx-4jM_E-VycbP-FZUdn6iWhjnH_uZ_pZXBro,509
|
|
@@ -34,11 +34,11 @@ git/refs/remote.py,sha256=WTlkJtpu895jJxbknDNOwL31tivQY_AHQrvroUoFBX4,2902
|
|
|
34
34
|
git/refs/symbolic.py,sha256=7ScmZHwlqPDKX9bxVC5queSZXUgqEY7_J_Si6gDBSLw,36139
|
|
35
35
|
git/refs/tag.py,sha256=AKrFrMhkNzX8e9x5WmDRtHovbN9zYQghuKoneVW-TJg,5002
|
|
36
36
|
git/repo/__init__.py,sha256=CILSVH36fX_WxVFSjD9o1WF5LgsNedPiJvSngKZqfVU,210
|
|
37
|
-
git/repo/base.py,sha256=
|
|
37
|
+
git/repo/base.py,sha256=1HFBIKTLLjmVQXhJlesWIXP90xoNM1RTVQF2eIwLkgs,63781
|
|
38
38
|
git/repo/fun.py,sha256=PDFNkuTSGGoQc0EEEXjxHw2_KaKYvVjBZ9rrkwH5Q6Y,23462
|
|
39
|
-
gitpython-3.1.
|
|
40
|
-
gitpython-3.1.
|
|
41
|
-
gitpython-3.1.
|
|
42
|
-
gitpython-3.1.
|
|
43
|
-
gitpython-3.1.
|
|
44
|
-
gitpython-3.1.
|
|
39
|
+
gitpython-3.1.53.dist-info/licenses/AUTHORS,sha256=Iucx_CH3w7_4084yjM6C5BvKfLA8cVfYHWW2pVmpxSk,2410
|
|
40
|
+
gitpython-3.1.53.dist-info/licenses/LICENSE,sha256=hvyUwyGpr7wRUUcTURuv3tIl8lEA3MD3NQ6CvCMbi-s,1503
|
|
41
|
+
gitpython-3.1.53.dist-info/METADATA,sha256=IdYoD67td8TnivPczpNQpgODxRb9jAnqG-bA_RcL40g,14187
|
|
42
|
+
gitpython-3.1.53.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
43
|
+
gitpython-3.1.53.dist-info/top_level.txt,sha256=0hzDuIp8obv624V3GmbqsagBWkk8ohtGU-Bc1PmTT0o,4
|
|
44
|
+
gitpython-3.1.53.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|