@@ -37,34 +37,93 @@ def __init__(self, cmd):
3737 )
3838
3939
40- class GitBDiff :
41- """Class which generates a branch diff."""
42-
43- # Name of primary branch - default is main
44- primary_branch = "main"
45-
46- # Match hex commit IDs
47- _hash_pattern = re .compile (r"^\s*([0-9a-f]{40})\s*$" )
40+ class GitBase :
41+ """
42+ Base class for gitbdiff functionality
43+ """
4844
4945 # Match branch names. This should catch all valid names but may
5046 # also some invalid names through. This should matter given that
5147 # it is being used to match git command output. For a complete
5248 # overview of the naming scheme, see man git check-ref-format
5349 _branch_pattern = re .compile (r"^\s*([^\s~\^\:\?\*\[]+[^.])\s*$" )
5450
55- def __init__ ( self , parent = None , repo = None ):
56- self . parent = parent or self . primary_branch
51+ # Text returned if in a detached head
52+ detached_head_reference = "detched_head_state"
5753
54+ def __init__ (self , parent = None , repo = None ):
5855 if repo is None :
5956 self ._repo = None
6057 else :
6158 self ._repo = Path (repo )
6259 if not self ._repo .is_dir ():
6360 raise GitBDiffError (f"{ repo } is not a directory" )
6461
62+ def get_branch_name (self ):
63+ """Get the name of the current branch."""
64+ result = None
65+ for line in self .run_git (["branch" , "--show-current" ]):
66+ # Set m to self._branch_pattern result
67+ # Then check m evaluates to True
68+ if m := self ._branch_pattern .match (line ):
69+ result = m .group (1 )
70+ break
71+ else :
72+ # Check for being in a Detached Head state
73+ for line in self .run_git (["branch" ]):
74+ if "HEAD detached" in line :
75+ result = self .detached_head_reference
76+ break
77+ else :
78+ raise GitBDiffError ("unable to get branch name" )
79+ return result
80+
81+ def run_git (self , args ):
82+ """Run a git command and yield the output."""
83+
84+ if not isinstance (args , list ):
85+ raise TypeError ("args must be a list" )
86+ cmd = ["git" ] + args
87+
88+ # Run the the command in the repo directory, capture the
89+ # output, and check for errors. The build in error check is
90+ # not used to allow specific git errors to be treated more
91+ # precisely
92+ proc = subprocess .run (
93+ cmd , capture_output = True , check = False , shell = False , cwd = self ._repo
94+ )
95+
96+ for line in proc .stderr .decode ("utf-8" ).split ("\n " ):
97+ if line .startswith ("fatal: not a git repository" ):
98+ raise GitBDiffNotGit (cmd )
99+ if line .startswith ("fatal: " ):
100+ raise GitBDiffError (line [7 :])
101+
102+ if proc .returncode != 0 :
103+ raise GitBDiffError (f"command returned { proc .returncode } " )
104+
105+ yield from proc .stdout .decode ("utf-8" ).split ("\n " )
106+
107+
108+ class GitBDiff (GitBase ):
109+ """Class which generates a branch diff."""
110+
111+ # Name of primary branch - default is main
112+ primary_branch = "main"
113+
114+ # Match hex commit IDs
115+ _hash_pattern = re .compile (r"^\s*([0-9a-f]{40})\s*$" )
116+
117+ def __init__ (self , parent = None , repo = None ):
118+ self .parent = parent or self .primary_branch
119+
120+ super ().__init__ (parent , repo )
121+
65122 self .ancestor = self .get_branch_point ()
66123 self .current = self .get_latest_commit ()
67124 self .branch = self .get_branch_name ()
125+ if self .branch == self .detached_head_reference :
126+ raise GitBDiffError ("Can't get a diff for a repo in detached head state" )
68127
69128 def get_branch_point (self ):
70129 """Get the branch point from the parent repo.
@@ -96,17 +155,6 @@ def get_latest_commit(self):
96155 raise GitBDiffError ("current revision not found" )
97156 return result
98157
99- def get_branch_name (self ):
100- """Get the name of the current branch."""
101- result = None
102- for line in self .run_git (["branch" , "--show-current" ]):
103- if m := self ._branch_pattern .match (line ):
104- result = m .group (1 )
105- break
106- else :
107- raise GitBDiffError ("unable to get branch name" )
108- return result
109-
110158 @property
111159 def is_branch (self ):
112160 """Whether this is a branch or main."""
@@ -126,28 +174,24 @@ def files(self):
126174 if line != "" :
127175 yield line
128176
129- def run_git (self , args ):
130- """Run a git command and yield the output."""
131177
132- if not isinstance (args , list ):
133- raise TypeError ("args must be a list" )
134- cmd = ["git" ] + args
178+ class GitInfo (GitBase ):
179+ """
180+ Class to contain info of a git repo
181+ """
135182
136- # Run the the command in the repo directory, capture the
137- # output, and check for errors. The build in error check is
138- # not used to allow specific git errors to be treated more
139- # precisely
140- proc = subprocess .run (
141- cmd , capture_output = True , check = False , shell = False , cwd = self ._repo
142- )
183+ def __init__ (self , repo = None ):
184+ super ().__init__ (repo = repo )
143185
144- for line in proc .stderr .decode ("utf-8" ).split ("\n " ):
145- if line .startswith ("fatal: not a git repository" ):
146- raise GitBDiffNotGit (cmd )
147- if line .startswith ("fatal: " ):
148- raise GitBDiffError (line [7 :])
186+ self .branch = self .get_branch_name ()
149187
150- if proc .returncode != 0 :
151- raise GitBDiffError (f"command returned { proc .returncode } " )
188+ def is_main (self ):
189+ """
190+ Returns true if branch matches a main-like branch name as defined below
191+ Count detached head as main-like as we cannot get a diff for this
192+ """
152193
153- yield from proc .stdout .decode ("utf-8" ).split ("\n " )
194+ main_like = ("main" , "stable" , "trunk" , "master" , self .detached_head_reference )
195+ if self .branch in main_like :
196+ return True
197+ return False
0 commit comments