summaryrefslogtreecommitdiffstats
path: root/src/git_tftpd/git.py
blob: 695ccb569b2e1bc018f5e9926becde6d822072f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import os

from dulwich.client import get_transport_and_path
from dulwich.errors import UpdateRefsError, SendPackError
from dulwich.refs import SYMREF
from dulwich.repo import Repo

from twisted.python import log


LOCAL_BRANCH_PREFIX = 'refs/heads/'
REMOTE_BRANCH_PREFIX = 'refs/remotes/'


class GitRepo(object):
    """ Simple high-level wrapper for dulwich. """

    def __init__(self, repo):
        self.path = repo
        self.repo = Repo(repo)

    def stage(self, filenames):
        paths = [os.path.relpath(filename, self.path)
                 for filename in filenames]
        log.msg('Staging: %s' % ', '.join(paths), system='git')
        self.repo.stage(paths)

    def has_changed(self):
        head = self.repo.object_store[self.repo.head()]
        index = self.repo.open_index()
        if any(index.changes_from_tree(self.repo.object_store, head.tree)):
            return True

        log.msg('No changes', system='git')
        return False

    def commit(self, message, committer):
        log.msg('Committing: %s' % message, system='git')
        self.repo.do_commit(message, committer=committer)

    def _get_git_remote_url(self, remote_name):
        try:
            config = self.repo.get_config()
            return config.get(("remote", remote_name), "url")
        except KeyError:
            pass
        return None

    def _get_git_branch(self):
        contents = self.repo.refs.read_ref('HEAD')
        if not contents.startswith(SYMREF):
            return None

        refname = contents[len(SYMREF):]
        if refname.startswith(LOCAL_BRANCH_PREFIX):
            return refname[len(LOCAL_BRANCH_PREFIX):]

        return refname

    def push(self, remote):
        remote_location = self._get_git_remote_url(remote)
        if remote_location is not None:
            branch = self._get_git_branch()
            local_ref = '%s%s' % (LOCAL_BRANCH_PREFIX, branch)
            log.msg('Pushing %s to %s' % (branch, remote_location),
                    system='git')

            def update_refs(refs):
                refs[local_ref] = self.repo.refs['HEAD']
                return refs

            client, path = get_transport_and_path(remote_location)
            try:
                new_refs = client.send_pack(
                    path, update_refs,
                    self.repo.object_store.generate_pack_contents)

                # update remote refs
                if local_ref in new_refs:
                    remote_ref = '%s%s/%s' % (REMOTE_BRANCH_PREFIX,
                                              remote, branch)
                    self.repo.refs[remote_ref] = new_refs[local_ref]
            except (UpdateRefsError, SendPackError) as e:
                log.err(e, system='git')
        else:
            log.msg('Not pushing, origin remote not found', system='git')