Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/devbot/git.py
blob: 4a86bd68504b8e021fb086ef768a3825ce02a302 (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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import os
import subprocess

from devbot import command
from devbot import utils

_root_path = None

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):
        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 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 diff(self):
        return subprocess.check_output(["git", "diff"])

    @_chdir
    def is_valid(self):
        result = subprocess.call(["git", "rev-parse", "HEAD"],
                                 stdout=utils.devnull,
                                 stderr=utils.devnull)
        return result == 0

    @_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 set_root_path(path):
    global _root_path
    _root_path = path

def get_root_module():
    remote = "git://git.sugarlabs.org/sugar-build/sugar-build.git"

    module = Module(name=os.path.basename(_root_path),
                    remote=remote,
                    path=os.path.dirname(_root_path))
    if not module.is_valid():
        return None

    return module