1"""
2Git SCM backend for Digress.
3"""
4
5from subprocess import Popen, PIPE, STDOUT
6import re
7
8from digress.errors import SCMError
9
10GIT_BRANCH_EXPR = re.compile("[*] (.*)")
11
12def checkout(revision):
13    """
14    Checkout a revision from git.
15    """
16    proc = Popen([
17        "git",
18        "checkout",
19        "-f",
20        revision
21    ], stdout=PIPE, stderr=STDOUT)
22
23    output = proc.communicate()[0].strip()
24    if proc.returncode != 0:
25        raise SCMError("checkout error: %s" % output)
26
27def rev_parse(ref):
28    proc = Popen([
29        "git",
30        "rev-parse",
31        ref
32    ], stdout=PIPE, stderr=STDOUT)
33
34    output = proc.communicate()[0].strip()
35    if proc.returncode != 0:
36        raise SCMError("rev-parse error: %s" % output)
37    return output
38
39def current_rev():
40    """
41    Get the current revision.
42    """
43    return rev_parse("HEAD")
44
45def current_branch():
46    """
47    Get the current branch.
48    """
49    proc = Popen([
50        "git",
51        "branch",
52        "--no-color"
53    ], stdout=PIPE, stderr=STDOUT)
54
55    output = proc.communicate()[0].strip()
56    if proc.returncode != 0:
57        raise SCMError("branch error: %s" % output)
58    branch_name = GIT_BRANCH_EXPR.findall(output)[0]
59    return branch_name != "(no branch)" and branch_name or None
60
61def revisions(rev_a, rev_b):
62    """
63    Get a list of revisions from one to another.
64    """
65    proc = Popen([
66        "git",
67        "log",
68        "--format=%H", ("%s...%s" % (rev_a, rev_b))
69    ], stdout=PIPE, stderr=STDOUT)
70
71    output = proc.communicate()[0].strip()
72    if proc.returncode != 0:
73        raise SCMError("log error: %s" % output)
74    return output.split("\n")
75
76def stash():
77    """
78    Stash the repository.
79    """
80    proc = Popen([
81        "git",
82        "stash",
83        "save",
84        "--keep-index"
85    ], stdout=PIPE, stderr=STDOUT)
86
87    output = proc.communicate()[0].strip()
88    if proc.returncode != 0:
89        raise SCMError("stash error: %s" % output)
90
91def unstash():
92    """
93    Unstash the repository.
94    """
95    proc = Popen(["git", "stash", "pop"], stdout=PIPE, stderr=STDOUT)
96    proc.communicate()
97
98def bisect(*args):
99    """
100    Perform a bisection.
101    """
102    proc = Popen((["git", "bisect"] + list(args)), stdout=PIPE, stderr=STDOUT)
103    output = proc.communicate()[0]
104    if proc.returncode != 0:
105        raise SCMError("bisect error: %s" % output)
106    return output
107
108def dirty():
109    """
110    Check if the working tree is dirty.
111    """
112    proc = Popen(["git", "status"], stdout=PIPE, stderr=STDOUT)
113    output = proc.communicate()[0].strip()
114    if proc.returncode != 0:
115        raise SCMError("status error: %s" % output)
116    if "modified:" in output:
117        return True
118    else:
119        return False
120