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

1from git.util import ( 

2 LazyMixin, 

3 IterableObj, 

4) 

5from .symbolic import SymbolicReference, T_References 

6 

7 

8# typing ------------------------------------------------------------------ 

9 

10from typing import Any, Callable, Iterator, Type, Union, TYPE_CHECKING # NOQA 

11from git.types import Commit_ish, PathLike, _T # NOQA 

12 

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 

15 

16# ------------------------------------------------------------------------------ 

17 

18 

19__all__ = ["Reference"] 

20 

21# { Utilities 

22 

23 

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""" 

26 

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) 

31 

32 # END wrapper 

33 wrapper.__name__ = func.__name__ 

34 return wrapper 

35 

36 

37# }END utilities 

38 

39 

40class Reference(SymbolicReference, LazyMixin, IterableObj): 

41 

42 """Represents a named reference to any object. Subclasses may apply restrictions though, 

43 i.e. Heads can only point to commits.""" 

44 

45 __slots__ = () 

46 _points_to_commits_only = False 

47 _resolve_ref_on_create = True 

48 _common_path_default = "refs" 

49 

50 def __init__(self, repo: "Repo", path: PathLike, check_path: bool = True) -> None: 

51 """Initialize this instance 

52 :param repo: Our parent repository 

53 

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) 

63 

64 def __str__(self) -> str: 

65 return self.name 

66 

67 # { Interface 

68 

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 

84 

85 super(Reference, self).set_object(object, logmsg) 

86 

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 

102 

103 return self 

104 

105 # NOTE: Don't have to overwrite properties as the will only work without a the log 

106 

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:]) 

116 

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) 

128 

129 # }END interface 

130 

131 # { Remote Interface 

132 

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] 

143 

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:]) 

152 

153 # } END remote interface