1"""Convenience functions for working with git.
2
3This module does not include any tasks, only functions.
4
5At this point, these functions do not use any kind of library. They require
6the git binary on the path."""
7
8from paver.easy import sh
9import os, re
10
11def _format_path(provided_path):
12    return provided_path or os.getcwd()
13
14def _split_remote_branch_name(provided_name):
15    return provided_name.split("/")[1]
16
17def clone(url, dest_folder):
18    sh("git clone %(url)s %(path)s" % dict(url=url, path=dest_folder) )
19
20def pull(destination, remote="origin", branch="master"):
21    """Perform a git pull. Destination must be absolute path.
22    """
23    sh("cd %(destination)s; git pull %(remote)s %(branch)s" % dict(
24        destination=destination, remote=remote, branch=branch) )
25
26def latest_tag():
27    """Get the most recent git tag. Useful for using in package version."""
28    return str(sh("git describe --tags --always HEAD", capture=True).strip())
29
30def branch_list(path="", remote_branches_only=False, __override__=None):
31    """
32    Lists git branches for the repository specified (or CWD).
33    If remote_branches_only is specified will list branches that exist
34    on the remote. These branches may, or may not, have corresponding remote
35    tracking branches.
36
37    Returns a Python tuple. The first item in the tuple will be the current
38    branch, and the other item will be a list of branches for the repository.
39
40    Optional parameter path: the path to the git repo. Else uses os.getcwd()
41    """
42
43    remote_branches = ""
44    if remote_branches_only:
45        remote_branches = "-r"
46
47    if __override__ == None:
48        git_output = sh(  "cd %(repo_path)s; git branch %(remote)s" % dict(
49            repo_path = _format_path(path), remote = remote_branches ), capture=True  )
50    else:
51        git_output = __override__
52
53    if git_output == None:
54        return None, [] # should only hit this condition in testing...
55
56    current_branch = ""
57    branches = []
58    found_a_match = False
59    regex = re.compile(r"(\*?)\W*(.+)")
60
61    for line in git_output.split("\n"):
62        match_obj = regex.match(line)
63        if match_obj:
64            found_a_match = True
65            if match_obj.group(1):
66                current_branch = match_obj.group(2).strip()
67            if match_obj.group(2).strip():
68                branches.append( match_obj.group(2).strip() )
69
70    if found_a_match is False:
71        raise "git branch did not return output expected. Returned %s" % git_output
72
73    return current_branch, branches
74
75def branch_checkout(branch_name, path=""):
76    """Checkout a git branch.
77
78    Take the branch name to checkout, and optional path parameter
79    (the path to the git repo. Else uses os.getcwd())
80    """
81
82    sh( "cd %(repo_path)s; git checkout %(branch_name)s" % dict(
83        repo_path = _format_path(path),
84        branch_name=branch_name) )
85
86def branch_track_remote(remote_branch_name, local_branch_name=None, path=""):
87    local_branch_name = ( local_branch_name or _split_remote_branch_name(remote_branch_name) )
88
89    sh( "cd %(repo_path)s; git checkout -b %(branch_name)s --track %(remote_branch_name)s" % dict(
90        repo_path = _format_path(path),
91        branch_name=local_branch_name,
92        remote_branch_name=remote_branch_name) )
93
94