Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/git/refs/reference.py: 43%
53 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1from git.util import (
2 LazyMixin,
3 IterableObj,
4)
5from .symbolic import SymbolicReference, T_References
8# typing ------------------------------------------------------------------
10from typing import Any, Callable, Iterator, Type, Union, TYPE_CHECKING # NOQA
11from git.types import Commit_ish, PathLike, _T # NOQA
13if TYPE_CHECKING: 13 ↛ 14line 13 didn't jump to line 14, because the condition on line 13 was never true
14 from git.repo import Repo
16# ------------------------------------------------------------------------------
19__all__ = ["Reference"]
21# { Utilities
24def require_remote_ref_path(func: Callable[..., _T]) -> Callable[..., _T]:
25 """A decorator raising a TypeError if we are not a valid remote, based on the path"""
27 def wrapper(self: T_References, *args: Any) -> _T:
28 if not self.is_remote():
29 raise ValueError("ref path does not point to a remote reference: %s" % self.path)
30 return func(self, *args)
32 # END wrapper
33 wrapper.__name__ = func.__name__
34 return wrapper
37# }END utilities
40class Reference(SymbolicReference, LazyMixin, IterableObj):
42 """Represents a named reference to any object. Subclasses may apply restrictions though,
43 i.e. Heads can only point to commits."""
45 __slots__ = ()
46 _points_to_commits_only = False
47 _resolve_ref_on_create = True
48 _common_path_default = "refs"
50 def __init__(self, repo: "Repo", path: PathLike, check_path: bool = True) -> None:
51 """Initialize this instance
52 :param repo: Our parent repository
54 :param path:
55 Path relative to the .git/ directory pointing to the ref in question, i.e.
56 refs/heads/master
57 :param check_path: if False, you can provide any path. Otherwise the path must start with the
58 default path prefix of this type."""
59 if check_path and not str(path).startswith(self._common_path_default + "/"):
60 raise ValueError(f"Cannot instantiate {self.__class__.__name__!r} from path {path}")
61 self.path: str # SymbolicReference converts to string atm
62 super(Reference, self).__init__(repo, path)
64 def __str__(self) -> str:
65 return self.name
67 # { Interface
69 # @ReservedAssignment
70 def set_object(
71 self,
72 object: Union[Commit_ish, "SymbolicReference", str],
73 logmsg: Union[str, None] = None,
74 ) -> "Reference":
75 """Special version which checks if the head-log needs an update as well
76 :return: self"""
77 oldbinsha = None
78 if logmsg is not None:
79 head = self.repo.head
80 if not head.is_detached and head.ref == self:
81 oldbinsha = self.commit.binsha
82 # END handle commit retrieval
83 # END handle message is set
85 super(Reference, self).set_object(object, logmsg)
87 if oldbinsha is not None:
88 # /* from refs.c in git-source
89 # * Special hack: If a branch is updated directly and HEAD
90 # * points to it (may happen on the remote side of a push
91 # * for example) then logically the HEAD reflog should be
92 # * updated too.
93 # * A generic solution implies reverse symref information,
94 # * but finding all symrefs pointing to the given branch
95 # * would be rather costly for this rare event (the direct
96 # * update of a branch) to be worth it. So let's cheat and
97 # * check with HEAD only which should cover 99% of all usage
98 # * scenarios (even 100% of the default ones).
99 # */
100 self.repo.head.log_append(oldbinsha, logmsg)
101 # END check if the head
103 return self
105 # NOTE: Don't have to overwrite properties as the will only work without a the log
107 @property
108 def name(self) -> str:
109 """:return: (shortest) Name of this reference - it may contain path components"""
110 # first two path tokens are can be removed as they are
111 # refs/heads or refs/tags or refs/remotes
112 tokens = self.path.split("/")
113 if len(tokens) < 3:
114 return self.path # could be refs/HEAD
115 return "/".join(tokens[2:])
117 @classmethod
118 def iter_items(
119 cls: Type[T_References],
120 repo: "Repo",
121 common_path: Union[PathLike, None] = None,
122 *args: Any,
123 **kwargs: Any,
124 ) -> Iterator[T_References]:
125 """Equivalent to SymbolicReference.iter_items, but will return non-detached
126 references as well."""
127 return cls._iter_items(repo, common_path)
129 # }END interface
131 # { Remote Interface
133 @property # type: ignore ## mypy cannot deal with properties with an extra decorator (2021-04-21)
134 @require_remote_ref_path
135 def remote_name(self) -> str:
136 """
137 :return:
138 Name of the remote we are a reference of, such as 'origin' for a reference
139 named 'origin/master'"""
140 tokens = self.path.split("/")
141 # /refs/remotes/<remote name>/<branch_name>
142 return tokens[2]
144 @property # type: ignore ## mypy cannot deal with properties with an extra decorator (2021-04-21)
145 @require_remote_ref_path
146 def remote_head(self) -> str:
147 """:return: Name of the remote head itself, i.e. master.
148 :note: The returned name is usually not qualified enough to uniquely identify
149 a branch"""
150 tokens = self.path.split("/")
151 return "/".join(tokens[3:])
153 # } END remote interface