Passed
Pull Request — develop (#164)
by
unknown
01:48
created

gitsvn()   A

Complexity

Conditions 1

Size

Total Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
c 1
b 0
f 0
dl 0
loc 2
ccs 1
cts 1
cp 1
crap 1
rs 10
1
"""Utilities to call Git commands."""
2
3 1
import os
4 1
import logging
5 1
from contextlib import suppress
6
7 1
from . import common, settings
8 1
from .shell import call
9 1
from .exceptions import ShellError
10
11
12 1
log = logging.getLogger(__name__)
13
14
15 1
def git(*args, **kwargs):
16 1
    return call('git', *args, **kwargs)
17
18
19 1
def gitsvn(*args, **kwargs):
20
    return call('git', 'svn', *args, **kwargs)
21 1
22
23 1
def in_svn_repo():
24 1
    """Determine if the current working directory is inside a subversion repository."""
25 1
    output = git('show', '--shortstat', _show=False, _ignore=True)
26
    if any('git-svn-id' in line for line in output):
27 1
        return True
28 1
    return False
29 1
30
31 1
def clone(repo, path, *, cache=settings.CACHE, sparse_paths=None, rev=None):
32
    """Clone a new Git repository."""
33
    log.debug("Creating a new repository...")
34 1
    try:
35
        name = repo.split('/')[-1]
36 1
        if name.endswith(".git"):
37 1
            name = name[:-4]
38 1
39 1
        reference = os.path.join(cache, name + ".reference")
40 1
        if not os.path.isdir(reference):
41 1
            git('clone', '--mirror', repo, reference)
42 1
43
        normpath = os.path.normpath(path)
44 1
        if sparse_paths:
45 1
            os.mkdir(normpath)
46
            git('-C', normpath, 'init')
47
            git('-C', normpath, 'config', 'core.sparseCheckout', 'true')
48 1
            git('-C', normpath, 'remote', 'add', '-f', 'origin', reference)
49
50 1
            with open("%s/%s/.git/info/sparse-checkout" % (os.getcwd(), normpath), 'w') as fd:
51
                fd.writelines(sparse_paths)
52 1
            with open("%s/%s/.git/objects/info/alternates" % (os.getcwd(), normpath), 'w') as fd:
53 1
                fd.write("%s/objects" % reference)
54 1
55 1
            # We use directly the revision requested here in order to respect,
56
            # that not all repos have `master` as their default branch
57 1
            git('-C', normpath, 'pull', 'origin', rev)
58
        else:
59
            git('clone', '--reference', reference, repo, os.path.normpath(path))
60 1
    except ShellError:
61
        gitsvn('clone', '-r', 'HEAD', repo, path)
62 1
63
64 1
def fetch(repo, rev=None):
65
    """Fetch the latest changes from the remote repository."""
66 1
67
    if in_svn_repo() and rev:
68
        gitsvn('rebase', rev)
69 1
    else:
70
        git('remote', 'set-url', 'origin', repo)
71
        args = ['fetch', '--tags', '--force', '--prune', 'origin']
72 1
        if rev:
73
            if len(rev) == 40:
74 1
                pass  # fetch only works with a SHA if already present locally
75 1
            elif '@' in rev:
76
                pass  # fetch doesn't work with rev-parse
77
            else:
78 1
                args.append(rev)
79
        git(*args)
80 1
81 1
82 1
def valid():
83 1
    """Confirm the current directory is a valid working tree."""
84
    log.debug("Checking for a valid working tree...")
85 1
86
    try:
87
        git('rev-parse', '--is-inside-work-tree', _show=False)
88 1
    except ShellError:
89
        return False
90 1
    else:
91
        return True
92 1
93 1
94 1
def changes(include_untracked=False, display_status=True, _show=False):
95
    """Determine if there are changes in the working tree."""
96 1
    status = False
97 1
98 1
    try:
99
        # Refresh changes
100 1
        git('update-index', '-q', '--refresh', _show=False)
101
102 1
        # Check for uncommitted changes
103
        git('diff-index', '--quiet', 'HEAD', _show=_show)
104
105 1
        # Check for untracked files
106
        lines = git('ls-files', '--others', '--exclude-standard', _show=_show)
107 1
108
    except ShellError:
109
        status = True
110 1
111
    else:
112 1
        status = bool(lines) and include_untracked
113
114
    if status and display_status:
115 1
        with suppress(ShellError):
116
            lines = git('status', _show=True)
117 1
            common.show(*lines, color='git_changes')
118
119
    return status
120
121 1
122
def update(rev, *, clean=True, fetch=False):  # pylint: disable=redefined-outer-name
123 1
    """Update the working tree to the specified revision."""
124
    hide = {'_show': False, '_ignore': True}
125
126 1
    git('stash', **hide)
127
    if clean:
128 1
        git('clean', '--force', '-d', '-x', _show=False)
129 1
130 1
    if in_svn_repo():
131 1
        gitsvn('rebase', rev)
132 1
    else:
133 1
        rev = _get_sha_from_rev(rev)
134
        git('checkout', '--force', rev)
135 1
        git('branch', '--set-upstream-to', 'origin/' + rev, **hide)
136
137
        if fetch:
138
            # if `rev` was a branch it might be tracking something older
139
            git('pull', '--ff-only', '--no-rebase', **hide)
140
141
142
def get_url():
143
    """Get the current repository's URL."""
144
    return git('config', '--get', 'remote.origin.url', _show=False)[0]
145
146
147
def get_hash(_show=False):
148
    """Get the current working tree's hash."""
149
    return git('rev-parse', 'HEAD', _show=_show)[0]
150
151
152
def get_tag():
153
    """Get the current working tree's tag (if on a tag)."""
154
    return git('describe', '--tags', '--exact-match',
155
               _show=False, _ignore=True)[0]
156
157
158
def get_branch():
159
    """Get the current working tree's branch."""
160
    return git('rev-parse', '--abbrev-ref', 'HEAD', _show=False)[0]
161
162
163
def _get_sha_from_rev(rev):
164
    """Get a rev-parse string's hash."""
165
    if '@{' in rev:  # TODO: use regex for this
166
        parts = rev.split('@')
167
        branch = parts[0]
168
        date = parts[1].strip("{}")
169
        git('checkout', '--force', branch, _show=False)
170
        rev = git('rev-list', '-n', '1', '--before={!r}'.format(date),
171
                  branch, _show=False)[0]
172
    return rev
173