Exemplo n.º 1
0
class LogFetcher:
    def __init__(self, repo_path, user=None):
        self.repo_path = repo_path
        self.git = Git(repo_path)
        self.name = self.get_repo_name()
        self.user = user if user else self.get_default_user()
        self.headers = ['repo', 'sha', 'author', 'date', 'subject', 'body']

    def get_repo_name(self):
        repo = Repo(self.repo_path)
        url = urlparse(repo.remote().url)
        basename = url.path.split('/')[-1]
        return basename.replace('.git', '')

    def get_default_user(self):
        name = self.git.config('--get', 'user.name')
        email = self.git.config('--get', 'user.email')
        return '{} <{}>'.format(name, email)

    def get_entries(self):
        entries = []
        output = self.git.log(
            '--author={}'.format(self.user),
            '--pretty=format:%H|%an <%ae>|%ai|%s|%b~~~',
            '--no-merges'
        )
        for line in output.split('~~~')[:-1]:
            entry = [self.name]
            data = line.split('|')
            for item in data:
                entry.append(item.strip())
            entries.append(entry)
        return entries
Exemplo n.º 2
0
 def get_credentials(cls, repo=None):
     """
     Get credentials from the github.user and github.token config values
     """
     if repo:
         _git = repo.git
     else:
         _git = Git(os.getcwd())
     return cls(user=_git.config('github.user', with_exceptions=False),
                token=_git.config('github.token', with_exceptions=False))
Exemplo n.º 3
0
 def get_credentials(cls, repo=None):
     """
     Get credentials from the github.user and github.token config values
     """
     if repo:
         _git = repo.git
     else:
         _git = Git(os.getcwd())
     return cls(
         user=_git.config("github.user", with_exceptions=False),
         token=_git.config("github.token", with_exceptions=False),
     )
Exemplo n.º 4
0
 def get_credentials(cls, repo=None):
     """
     Get credentials from the github.user and github.token config values
     """
     if repo:
         _git = repo.git
     else:
         _git = Git(os.getcwd())
     return cls(
         user=_git.config('github.user'),
         token=_git.config('github.token')
         )
Exemplo n.º 5
0
class MyGit():
    def __init__(self, path):
        self.g = Git(path)

    def update_force(self, config=None):
        """
            强制更新 buckets
        """
        if 'http.proxy' in config:
            info_1 = self.g.config("--global", "http.proxy", config['git']['http.proxy'])
            self.g.checkout('*')
            pull_info = self.g.pull("--no-rebase")
            self.g.config("--global", "--unset", "http.proxy")
        else:
            self.g.checkout('*')
            pull_info = self.g.pull("--no-rebase")

        return pull_info
Exemplo n.º 6
0
def push_to_github(local_dir, repo_path, commit_message='No commit message was set.'):
    repo_list = repo_path.split('/')
    try:
        n = repo_list.index('tree')
    except ValueError:
        n = len(repo_list)
    repo_name = os.path.join(*repo_list[:n])
    account = my_account
    repo_url = '/'.join(['https://' + os.environ.get('GITHUB_USERNAME', None) + ':' + os.environ.get('GITHUB_PASSWORD', None) + '@github.com',account,repo_name])
    branch = repo_list[-1] if 'tree' in repo_list else None

    print(repo_url)

    os.system('cd')
    git_dir = os.path.join('dest_repo', repo_name)
    try:
        shutil.rmtree(git_dir)
        shutil.rmtree('dest_repo')
    except:
        pass
    os.system('md dest_repo')
    kwargs = { 'url': repo_url, 'to_path': git_dir }
    if branch:
        kwargs['branch'] = branch
    repo = Repo.clone_from(**kwargs)
    os.chdir(git_dir)
    os.system(' '.join(['cp', '-rf', os.path.join('..', '..', local_dir, '.'), '.']))

    origin = repo.remotes[0]

    gitcmd = Git('.')
    gitcmd.config('--add', 'user.name', os.environ.get('GITHUB_USERNAME', None))
    gitcmd.config('--add', 'user.email', os.environ.get('GITHUB_EMAIL', None))
    repo.git.add(A=True)
    repo.git.add(u=True)
    repo.index.commit(commit_message)
    repo.git.push('--set-upstream', 'origin', branch)
    stats = repo.head.commit.stats.total

    os.chdir('../..')
    shutil.rmtree('dest_repo')
    return stats
Exemplo n.º 7
0
class GitWrapper(object):
    """
    A wrapper for repo.git providing better stdout handling + better exeptions.

    It is preferred to repo.git because it doesn't print to stdout
    in real time. In addition, this wrapper provides better error
    handling (it provides stdout messages inside the exception, too).
    """

    def __init__(self, repo):
        if repo:
            #: :type: git.Repo
            self.repo = repo
            #: :type: git.Git
            self.git = self.repo.git
        else:
            #: :type: git.Git
            self.git = Git()

    def __del__(self):
        # Is the following true?

        # GitPython runs persistent git processes in  the working directory.
        # Therefore, when we use 'git up' in something like a test environment,
        # this might cause troubles because of the open file handlers (like
        # trying to remove the directory right after the test has finished).
        # 'clear_cache' kills the processes...

        if platform.system() == 'Windows':  # pragma: no cover
            pass
            # ... or rather "should kill", because but somehow it recently
            # started to not kill cat_file_header out of the blue (I even
            # tried running old code, but the once working code failed).
            # Thus, we kill it  manually here.
            if self.git.cat_file_header is not None:
                subprocess.call(("TASKKILL /F /T /PID {0} 2>nul 1>nul".format(
                    str(self.git.cat_file_header.proc.pid)
                )), shell=True)
            if self.git.cat_file_all is not None:
                subprocess.call(("TASKKILL /F /T /PID {0} 2>nul 1>nul".format(
                    str(self.git.cat_file_all.proc.pid)
                )), shell=True)

        self.git.clear_cache()

    def run(self, name, *args, **kwargs):
        """ Run a git command specified by name and args/kwargs. """

        tostdout = kwargs.pop('tostdout', False)
        stdout = six.b('')

        # Execute command
        cmd = getattr(self.git, name)(as_process=True, *args, **kwargs)

        # Capture output
        while True:
            output = cmd.stdout.read(1)

            # Print to stdout
            if tostdout:
                sys.stdout.write(output.decode('utf-8'))
                sys.stdout.flush()

            stdout += output

            if output == six.b(""):
                break

        # Wait for the process to quit
        try:
            cmd.wait()
        except GitCommandError as error:
            # Add more meta-information to errors
            message = "'{0}' returned exit status {1}".format(
                ' '.join(str(c) for c in error.command),
                error.status
            )

            raise GitError(message, stderr=error.stderr, stdout=stdout)

        return stdout.strip()

    def __getattr__(self, name):
        return lambda *args, **kwargs: self.run(name, *args, **kwargs)

    ###########################################################################
    # Overwrite some methods and add new ones
    ###########################################################################

    @contextmanager
    def stash(self):
        """
        A stashing contextmanager.
        It  stashes all changes inside and unstashed when done.
        """
        stashed = False

        if self.repo.is_dirty(submodules=False):
            if self.change_count > 1:
                message = 'stashing {0} changes'
            else:
                message = 'stashing {0} change'
            print(colored(
                message.format(self.change_count),
                'magenta'
            ))
            self.git.stash()
            stashed = True

        yield

        if stashed:
            print(colored('unstashing', 'magenta'))
            try:
                self.run('stash', 'pop')
            except GitError as e:
                raise UnstashError(stderr=e.stderr, stdout=e.stdout)

    def checkout(self, branch_name):
        """ Checkout a branch by name. """
        try:
            find(
                self.repo.branches, lambda b: b.name == branch_name
            ).checkout()
        except OrigCheckoutError as e:
            raise CheckoutError(branch_name, details=e)

    def rebase(self, target_branch):
        """ Rebase to target branch. """
        current_branch = self.repo.active_branch

        arguments = (
            ([self.config('git-up.rebase.arguments')] or []) +
            [target_branch.name]
        )
        try:
            self.run('rebase', *arguments)
        except GitError as e:
            raise RebaseError(current_branch.name, target_branch.name,
                              **e.__dict__)

    def config(self, key):
        """ Return `git config key` output or None. """
        try:
            return self.git.config(key)
        except GitCommandError:
            return None

    @property
    def change_count(self):
        """ The number of changes in the working directory. """
        status = self.git.status(porcelain=True, untracked_files='no').strip()
        if not status:
            return 0
        else:
            return len(status.split('\n'))

    @property
    def version(self):
        """
        Return git's version as a list of numbers.

        The original repo.git.version_info has problems with tome types of
        git version strings.
        """
        return re.search(r'\d+(\.\d+)+', self.git.version()).group(0)

    def is_version_min(self, required_version):
        """ Does git's version match the requirements? """
        return self.version.split('.') >= required_version.split('.')
Exemplo n.º 8
0
class GitWrapper:
    """
    A wrapper for repo.git providing better stdout handling + better exeptions.

    It is preferred to repo.git because it doesn't print to stdout
    in real time. In addition, this wrapper provides better error
    handling (it provides stdout messages inside the exception, too).
    """
    def __init__(self, repo):
        if repo:
            #: :type: git.Repo
            self.repo = repo
            #: :type: git.Git
            self.git = self.repo.git
        else:
            #: :type: git.Git
            self.git = Git()

    def __del__(self):
        # Is the following true?

        # GitPython runs persistent git processes in  the working directory.
        # Therefore, when we use 'git up' in something like a test environment,
        # this might cause troubles because of the open file handlers (like
        # trying to remove the directory right after the test has finished).
        # 'clear_cache' kills the processes...

        if platform.system() == 'Windows':  # pragma: no cover
            pass
            # ... or rather "should kill", because but somehow it recently
            # started to not kill cat_file_header out of the blue (I even
            # tried running old code, but the once working code failed).
            # Thus, we kill it  manually here.
            if self.git.cat_file_header is not None:
                subprocess.call(("TASKKILL /F /T /PID {} 2>nul 1>nul".format(
                    str(self.git.cat_file_header.proc.pid))),
                                shell=True)
            if self.git.cat_file_all is not None:
                subprocess.call(("TASKKILL /F /T /PID {} 2>nul 1>nul".format(
                    str(self.git.cat_file_all.proc.pid))),
                                shell=True)

        self.git.clear_cache()

    def _run(self, name, *args, **kwargs):
        """ Run a git command specified by name and args/kwargs. """

        stdout = b''
        cmd = getattr(self.git, name)

        # Ask cmd(...) to return a (status, stdout, stderr) tuple
        kwargs['with_extended_output'] = True

        # Execute command
        try:
            (_, stdout, _) = cmd(*args, **kwargs)
        except GitCommandError as error:
            # Add more meta-information to errors
            message = "'{}' returned exit status {}".format(
                ' '.join(str(c) for c in error.command), error.status)

            raise GitError(message, stderr=error.stderr, stdout=stdout)

        return stdout.strip()

    def __getattr__(self, name):
        return lambda *args, **kwargs: self._run(name, *args, **kwargs)

    ###########################################################################
    # Overwrite some methods and add new ones
    ###########################################################################

    @contextmanager
    def stasher(self):
        """
        A stashing contextmanager.
        """
        # nonlocal for python2
        stashed = [False]
        clean = [False]

        def stash():
            if clean[0] or not self.repo.is_dirty(submodules=False):
                clean[0] = True
                return
            if stashed[0]:
                return

            if self.change_count > 1:
                message = 'stashing {0} changes'
            else:
                message = 'stashing {0} change'
            print(colored(message.format(self.change_count), 'magenta'))
            try:
                self._run('stash')
            except GitError as e:
                raise StashError(stderr=e.stderr, stdout=e.stdout)

            stashed[0] = True

        yield stash

        if stashed[0]:
            print(colored('unstashing', 'magenta'))
            try:
                self._run('stash', 'pop')
            except GitError as e:
                raise UnstashError(stderr=e.stderr, stdout=e.stdout)

    def checkout(self, branch_name):
        """ Checkout a branch by name. """
        try:
            find(self.repo.branches,
                 lambda b: b.name == branch_name).checkout()
        except OrigCheckoutError as e:
            raise CheckoutError(branch_name, details=e)

    def rebase(self, target_branch):
        """ Rebase to target branch. """
        current_branch = self.repo.active_branch

        arguments = (([self.config('git-up.rebase.arguments')] or []) +
                     [target_branch.name])
        try:
            self._run('rebase', *arguments)
        except GitError as e:
            raise RebaseError(current_branch.name, target_branch.name,
                              **e.__dict__)

    def fetch(self, *args, **kwargs):
        """ Fetch remote commits. """

        # Unlike the other git commands, we want to output `git fetch`'s
        # output in real time. Therefore we use a different implementation
        # from `GitWrapper._run` which buffers all output.
        # In theory this may deadlock if `git fetch` prints more than 8 KB
        # to stderr which is here assumed to not happen in day-to-day use.

        stdout = b''

        # Execute command
        cmd = self.git.fetch(as_process=True, *args, **kwargs)

        # Capture output
        while True:
            output = cmd.stdout.read(1)

            sys.stdout.write(output.decode('utf-8'))
            sys.stdout.flush()

            stdout += output

            # Check for EOF
            if output == b"":
                break

        # Wait for the process to quit
        try:
            cmd.wait()
        except GitCommandError as error:
            # Add more meta-information to errors
            message = "'{}' returned exit status {}".format(
                ' '.join(str(c) for c in error.command), error.status)

            raise GitError(message, stderr=error.stderr, stdout=stdout)

        return stdout.strip()

    def push(self, *args, **kwargs):
        ''' Push commits to remote '''
        stdout = b''

        # Execute command
        cmd = self.git.push(as_process=True, *args, **kwargs)

        # Capture output
        while True:
            output = cmd.stdout.read(1)

            sys.stdout.write(output.decode('utf-8'))
            sys.stdout.flush()

            stdout += output

            # Check for EOF
            if output == b"":
                break

        # Wait for the process to quit
        try:
            cmd.wait()
        except GitCommandError as error:
            # Add more meta-information to errors
            message = "'{}' returned exit status {}".format(
                ' '.join(str(c) for c in error.command), error.status)

            raise GitError(message, stderr=error.stderr, stdout=stdout)

        return stdout.strip()

    def config(self, key):
        """ Return `git config key` output or None. """
        try:
            return self.git.config(key)
        except GitCommandError:
            return None

    @property
    def change_count(self):
        """ The number of changes in the working directory. """
        status = self.git.status(porcelain=True, untracked_files='no').strip()
        if not status:
            return 0
        else:
            return len(status.split('\n'))

    @property
    def version(self):
        """
        Return git's version as a list of numbers.

        The original repo.git.version_info has problems with tome types of
        git version strings.
        """
        return re.search(r'\d+(\.\d+)+', self.git.version()).group(0)

    def is_version_min(self, required_version):
        """ Does git's version match the requirements? """
        return self.version.split('.') >= required_version.split('.')