Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/devbot/git.py
blob: adfeb3318fa7909b56f98aa8e1b3f95ac1142e47 (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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import os
import subprocess

from devbot import command
from devbot import config


def _chdir(func):
    def wrapped(*args, **kwargs):
        orig_cwd = os.getcwd()

        os.chdir(args[0].local)
        result = func(*args, **kwargs)
        os.chdir(orig_cwd)

        return result

    return wrapped


class Module:
    def __init__(self, path=None, name=None, remote=None,
                 branch="master", tag=None, retry=10):
        if path is None or name is None or remote is None:
            raise RuntimeError("path, name and remote are required")

        self.remote = remote
        self.local = os.path.join(path, name)
        self.tag = tag

        self._path = path
        self._name = name
        self._branch = branch
        self._retry = 10

    def _clone(self):
        os.chdir(self._path)

        command.run(["git", "clone", "--progress", self.remote, self._name],
                    retry=self._retry)

        os.chdir(self.local)

        if self.tag:
            command.run(["git", "checkout", self.tag])
        else:
            command.run(["git", "checkout", self._branch])

    def update(self, revision=None):
        if not os.path.exists(os.path.join(self.local, ".git")):
            self._clone()
            return

        os.chdir(self.local)

        command.run(["git", "fetch"], retry=self._retry)

        if revision:
            command.run(["git", "checkout", revision])
        elif self.tag:
            command.run(["git", "checkout", self.tag])
        else:
            command.run(["git", "merge", "--ff-only",
                         "origin/%s" % self._branch])

    @_chdir
    def checkout(self, revision=None):
        if revision is None:
            revision = self.tag
            if revision is None:
                revision = self._branch

        command.run(["git", "checkout", revision])

    @_chdir
    def describe(self):
        return subprocess.check_output(["git", "describe"]).strip()

    @_chdir
    def get_commit_id(self):
        return subprocess.check_output(["git", "rev-parse", "HEAD"]).strip()

    @_chdir
    def get_annotation(self, tag):
        # FIXME this is fragile, there must be a better way

        show = subprocess.check_output(["git", "show", tag])

        annotation = []
        for line in show.split("\n"):
            ignore = False
            for start in ["tag ", "Tagger: ", "Date: "]:
                if line.startswith(start):
                    ignore = True

            if line.startswith("commit "):
                break

            if not ignore:
                annotation.append(line)

        return "\n".join(annotation)

    def clean(self):
        try:
            os.chdir(self.local)
        except OSError:
            return False

        command.run(["git", "clean", "-fdx"])

        return True


def get_module(module):
    return Module(path=config.get_source_dir(),
                  name=module.name,
                  remote=module.repo,
                  branch=module.branch,
                  tag=module.tag,
                  retry=10)