Esempio n. 1
0
class Repository(object):
    GIT_LOG_STR = 'git log -r {0} --format="%H%n%an%n%at%n###%n%s%n%n%b%n###%n" -n1'
    HASH_REGEX = r'(?P<hash>[0-9a-f]+)'
    AUTHOR_REGEX = r'(?P<author>[\w]+)'
    TIME_REGEX = r'(?P<time>[\d]+)'
    MESSAGE_REGEX = r'###\n(?P<message>.+)\n###'
    LOG_REGEX = (HASH_REGEX + r'\n' + AUTHOR_REGEX + r'\n' + TIME_REGEX +
                 r'\n' + MESSAGE_REGEX)
    LOG_REGEX_C = re.compile(LOG_REGEX, re.DOTALL)

    GIT_FILES_STR = 'git diff --name-only {0} {0}^'

    def __init__(self):
        self.info = RepositoryInfo()
        self.info.prepare()

    def get_commit(self, commit_id):
        # Get the data from git log
        log_cmd = self.GIT_LOG_STR.format(commit_id)
        invoker = Invoker(log_cmd)
        invoker.invoke()
        if invoker.status != 0:
            raise RepositoryException('Something bad happened!\n' +
                                      'Command = ' + str(invoker.cmd))
        match = self.LOG_REGEX_C.match(invoker.stdout)
        if match is None:
            raise RepositoryException('Unknown log format!\n' +
                                      'Command = ' + str(invoker.cmd))
        commit_hash = match.group('hash')
        author = match.group('author')
        time = match.group('time')
        message = match.group('message')

        # Get the files from git diff
        files_cmd = self.GIT_FILES_STR.format(commit_id)
        invoker = Invoker(files_cmd)
        invoker.invoke()
        if invoker.status != 0:
            raise RepositoryException('Something bad happened!\n' +
                                      'Command = ' + str(invoker.cmd))
        files = [self.info.get_path() + '/' + x
                     for x in invoker.stdout.split('\n')]

        return Commit(commit_hash, author, time, message, files)

    def get_last_commit(self):
        return self.get_commit('HEAD')

    def get_path(self):
        return self.info.get_path()
Esempio n. 2
0
class Commit(object):
    CPP_LINT_PATH = '/scripts/bin/cpplint'
    CPP_FILES_REGEX = r'.*\.(cpp|cc|h|hpp)$'
    CPP_FILES_REGEX_C = re.compile(CPP_FILES_REGEX)

    AMEND_STR = 'git commit --amend --file={0} --reset-author --no-verify'

    VERIFY_CMD = 'git log {0}'

    def __init__(self, commit_hash, author, time, message, files):
        self.commit_hash = commit_hash
        self.author = author
        self.time = time
        self.message = CommitMessage(message)
        self.files = files
        self._ri = RepositoryInfo()
        self._ri.prepare()
        self.verify()

    def verify(self):
        """Raises exception if something isn't as expected."""
        invoker = Invoker(self.VERIFY_CMD.format(self.commit_hash))
        invoker.invoke()
        if invoker.status != 0:
            raise CommitException('Revision ' + self.commit_hash +
                                  ' does not exist!')
        return True

    def get_cpp_files(self):
        """Returns all cpp files from this commit."""
        cpp_files = []
        for f in self.files:
            if self.CPP_FILES_REGEX_C.match(f):
                cpp_files.append(f)
        return cpp_files

    def lint(self, save_to=None):
        """Lints all files in this commit.
        BUG: Lints the file from the cache, not the one from the index.
        TODO: Create lint class
        """
        if save_to is not None:
            if isinstance(save_to, str):
                f = open(save_to, 'a+')
                f.close()
        cpp_lint_cmd = self._ri.get_path() + self.CPP_LINT_PATH
        cpp_files = self.get_cpp_files()
        if len(cpp_files) == 0:
            print('[SUCCESS] Nothing to lint!')
            return
        cmd = [cpp_lint_cmd]
        cmd.extend(cpp_files)
        print('Linting', len(cpp_files), ' cpp files...')
        invoker = Invoker(cmd)
        invoker.invoke()
        print(invoker.stdout)
        print('[SUCCESS] Lint complete!\n')
        if save_to is not None:
            if isinstance(save_to, file):
                save_to.write(invoker.stdout)
            else:
                f = open(save_to, "w")
                f.write(invoker.stdout)

    def review(self, tests_filename=None):
        """Sends this commit to the reviewboard."""
        rbi = ReviewBoardInvoker(self.message, tests_filename=tests_filename,
                                 revision=self.commit_hash)
        rbi.invoke()
        rb_id = rbi.get_reviewboard_id()
        return rb_id

    def amend(self):
        """This amends the current commit.
        WARNING: current commit should be the last one.
        """
        f = tempfile.NamedTemporaryFile()
        f.write(self.message.get_raw_message().encode())
        f.seek(0, os.SEEK_SET)
        cmd = self.AMEND_STR.format(f.name)
        invoker = Invoker(cmd)
        invoker.invoke()
        if invoker.status != 0:
            message = '{0}\n{1}\n{0}\n{2}\n{0}\n[FAIL] Amending failed!'.format(
                '-'*80, invoker.stdout, invoker.stderr)
            raise CommitException(message)

    def get_field(self, field):
        if field not in self.message.fields:
            return None
        if not self.message.fields[field].nonempty():
            return None
        return self.message.fields[field].get_value()