1# 2# Copyright (C) 2016 Intel Corporation 3# 4# SPDX-License-Identifier: MIT 5# 6"""Git repository interactions""" 7import os 8 9from oeqa.utils.commands import runCmd 10 11 12class GitError(Exception): 13 """Git error handling""" 14 pass 15 16class GitRepo(object): 17 """Class representing a Git repository clone""" 18 def __init__(self, path, is_topdir=False): 19 git_dir = self._run_git_cmd_at(['rev-parse', '--git-dir'], path) 20 git_dir = git_dir if os.path.isabs(git_dir) else os.path.join(path, git_dir) 21 self.git_dir = os.path.realpath(git_dir) 22 23 if self._run_git_cmd_at(['rev-parse', '--is-bare-repository'], path) == 'true': 24 self.bare = True 25 self.top_dir = self.git_dir 26 else: 27 self.bare = False 28 self.top_dir = self._run_git_cmd_at(['rev-parse', '--show-toplevel'], 29 path) 30 realpath = os.path.realpath(path) 31 if is_topdir and realpath != self.top_dir: 32 raise GitError("{} is not a Git top directory".format(realpath)) 33 34 @staticmethod 35 def _run_git_cmd_at(git_args, cwd, **kwargs): 36 """Run git command at a specified directory""" 37 git_cmd = 'git ' if isinstance(git_args, str) else ['git'] 38 git_cmd += git_args 39 ret = runCmd(git_cmd, ignore_status=True, cwd=cwd, **kwargs) 40 if ret.status: 41 cmd_str = git_cmd if isinstance(git_cmd, str) \ 42 else ' '.join(git_cmd) 43 raise GitError("'{}' failed with exit code {}: {}".format( 44 cmd_str, ret.status, ret.output)) 45 return ret.output.strip() 46 47 @staticmethod 48 def init(path, bare=False): 49 """Initialize a new Git repository""" 50 cmd = ['init'] 51 if bare: 52 cmd.append('--bare') 53 GitRepo._run_git_cmd_at(cmd, cwd=path) 54 return GitRepo(path, is_topdir=True) 55 56 def run_cmd(self, git_args, env_update=None): 57 """Run Git command""" 58 env = None 59 if env_update: 60 env = os.environ.copy() 61 env.update(env_update) 62 return self._run_git_cmd_at(git_args, self.top_dir, env=env) 63 64 def rev_parse(self, revision): 65 """Do git rev-parse""" 66 try: 67 return self.run_cmd(['rev-parse', '--verify', revision]) 68 except GitError: 69 # Revision does not exist 70 return None 71 72 def get_current_branch(self): 73 """Get current branch""" 74 try: 75 # Strip 11 chars, i.e. 'refs/heads' from the beginning 76 return self.run_cmd(['symbolic-ref', 'HEAD'])[11:] 77 except GitError: 78 return None 79 80 81