123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- # ex:ts=4:sw=4:sts=4:et
- # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
- #
- # patchtestrepo: PatchTestRepo class used mainly to control a git repo from patchtest
- #
- # Copyright (C) 2016 Intel Corporation
- #
- # SPDX-License-Identifier: GPL-2.0-only
- #
- import os
- import utils
- import logging
- import json
- from patch import PatchTestPatch
- logger = logging.getLogger('patchtest')
- info=logger.info
- class PatchTestRepo(object):
- # prefixes used for temporal branches/stashes
- prefix = 'patchtest'
- def __init__(self, patch, repodir, commit=None, branch=None):
- self._repodir = repodir
- self._patch = PatchTestPatch(patch)
- self._current_branch = self._get_current_branch()
- # targeted branch defined on the patch may be invalid, so make sure there
- # is a corresponding remote branch
- valid_patch_branch = None
- if self._patch.branch in self.upstream_branches():
- valid_patch_branch = self._patch.branch
-
- # Target Branch
- # Priority (top has highest priority):
- # 1. branch given at cmd line
- # 2. branch given at the patch
- # 3. current branch
- self._branch = branch or valid_patch_branch or self._current_branch
- # Target Commit
- # Priority (top has highest priority):
- # 1. commit given at cmd line
- # 2. branch given at cmd line
- # 3. branch given at the patch
- # 3. current HEAD
- self._commit = self._get_commitid(commit) or \
- self._get_commitid(branch) or \
- self._get_commitid(valid_patch_branch) or \
- self._get_commitid('HEAD')
- self._workingbranch = "%s_%s" % (PatchTestRepo.prefix, os.getpid())
- # create working branch
- self._exec({'cmd': ['git', 'checkout', '-b', self._workingbranch, self._commit]})
- self._patchmerged = False
- # Check if patch can be merged using git-am
- self._patchcanbemerged = True
- try:
- self._exec({'cmd': ['git', 'am', '--keep-cr'], 'input': self._patch.contents})
- except utils.CmdException as ce:
- self._exec({'cmd': ['git', 'am', '--abort']})
- self._patchcanbemerged = False
- finally:
- # if patch was applied, remove it
- if self._patchcanbemerged:
- self._exec({'cmd':['git', 'reset', '--hard', self._commit]})
- # for debugging purposes, print all repo parameters
- logger.debug("Parameters")
- logger.debug("\tRepository : %s" % self._repodir)
- logger.debug("\tTarget Commit : %s" % self._commit)
- logger.debug("\tTarget Branch : %s" % self._branch)
- logger.debug("\tWorking branch : %s" % self._workingbranch)
- logger.debug("\tPatch : %s" % self._patch)
- @property
- def patch(self):
- return self._patch.path
- @property
- def branch(self):
- return self._branch
- @property
- def commit(self):
- return self._commit
- @property
- def ismerged(self):
- return self._patchmerged
- @property
- def canbemerged(self):
- return self._patchcanbemerged
- def _exec(self, cmds):
- _cmds = []
- if isinstance(cmds, dict):
- _cmds.append(cmds)
- elif isinstance(cmds, list):
- _cmds = cmds
- else:
- raise utils.CmdException({'cmd':str(cmds)})
- results = []
- cmdfailure = False
- try:
- results = utils.exec_cmds(_cmds, self._repodir)
- except utils.CmdException as ce:
- cmdfailure = True
- raise ce
- finally:
- if cmdfailure:
- for cmd in _cmds:
- logger.debug("CMD: %s" % ' '.join(cmd['cmd']))
- else:
- for result in results:
- cmd, rc, stdout, stderr = ' '.join(result['cmd']), result['returncode'], result['stdout'], result['stderr']
- logger.debug("CMD: %s RCODE: %s STDOUT: %s STDERR: %s" % (cmd, rc, stdout, stderr))
- return results
- def _get_current_branch(self, commit='HEAD'):
- cmd = {'cmd':['git', 'rev-parse', '--abbrev-ref', commit]}
- cb = self._exec(cmd)[0]['stdout']
- if cb == commit:
- logger.warning('You may be detached so patchtest will checkout to master after execution')
- cb = 'master'
- return cb
- def _get_commitid(self, commit):
- if not commit:
- return None
- try:
- cmd = {'cmd':['git', 'rev-parse', '--short', commit]}
- return self._exec(cmd)[0]['stdout']
- except utils.CmdException as ce:
- # try getting the commit under any remotes
- cmd = {'cmd':['git', 'remote']}
- remotes = self._exec(cmd)[0]['stdout']
- for remote in remotes.splitlines():
- cmd = {'cmd':['git', 'rev-parse', '--short', '%s/%s' % (remote, commit)]}
- try:
- return self._exec(cmd)[0]['stdout']
- except utils.CmdException:
- pass
- return None
- def upstream_branches(self):
- cmd = {'cmd':['git', 'branch', '--remotes']}
- remote_branches = self._exec(cmd)[0]['stdout']
- # just get the names, without the remote name
- branches = set(branch.split('/')[-1] for branch in remote_branches.splitlines())
- return branches
- def merge(self):
- if self._patchcanbemerged:
- self._exec({'cmd': ['git', 'am', '--keep-cr'],
- 'input': self._patch.contents,
- 'updateenv': {'PTRESOURCE':self._patch.path}})
- self._patchmerged = True
- def clean(self):
- self._exec({'cmd':['git', 'checkout', '%s' % self._current_branch]})
- self._exec({'cmd':['git', 'branch', '-D', self._workingbranch]})
- self._patchmerged = False
|