Completed
Push — develop ( 3dabc3...f1379d )
by Jace
03:04 queued 17s
created

changes()   B

Complexity

Conditions 6

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 6

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 6
dl 0
loc 26
ccs 14
cts 14
cp 1
crap 6
rs 7.5384
c 2
b 0
f 0
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
8 1
from .shell import call
9 1
from .exceptions import ShellError
10
11
12 1
log = logging.getLogger(__name__)
0 ignored issues
show
Coding Style Naming introduced by
The name log does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
13
14
15 1
def git(*args, **kwargs):
0 ignored issues
show
Coding Style introduced by
This function should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
16 1
    return call('git', *args, **kwargs)
17
18
19 1
def clone(repo, path, *, cache=None):
20
    """Clone a new Git repository."""
21 1
    log.debug("Creating a new repository...")
22
23 1
    cache = cache or os.path.expanduser("~/.gitcache")
24 1
    cache = os.path.normpath(cache)
25
26 1
    name = repo.split('/')[-1]
27 1
    if name.endswith(".git"):
28 1
        name = name[:-4]
29
30 1
    reference = os.path.join(cache, name + ".reference")
31 1
    if not os.path.isdir(reference):
32 1
        git('clone', '--mirror', repo, reference)
33
34 1
    git('clone', '--reference', reference, repo, os.path.normpath(path))
35
36
37 1
def fetch(repo, rev=None):
38
    """Fetch the latest changes from the remote repository."""
39 1
    git('remote', 'set-url', 'origin', repo)
40 1
    args = ['fetch', '--tags', '--force', '--prune', 'origin']
41 1
    if rev:
42 1
        if len(rev) == 40:
43 1
            pass  # fetch only works with a SHA if already present locally
44 1
        elif '@' in rev:
45 1
            pass  # fetch doesn't work with rev-parse
46
        else:
47 1
            args.append(rev)
48 1
    git(*args)
0 ignored issues
show
Coding Style introduced by
Usage of * or ** arguments should usually be done with care.

Generally, there is nothing wrong with usage of * or ** arguments. For readability of the code base, we suggest to not over-use these language constructs though.

For more information, we can recommend this blog post from Ned Batchelder including its comments which also touches this aspect.

Loading history...
49
50
51 1
def valid():
52
    """Confirm the current directory is a valid working tree."""
53 1
    log.debug("Checking for a valid working tree...")
54
55 1
    try:
56 1
        git('rev-parse', '--is-inside-work-tree', _show=False)
57 1
    except ShellError:
58 1
        return False
59
    else:
60 1
        return True
61
62
63 1
def changes(include_untracked=False, display_status=True, _show=False):
64
    """Determine if there are changes in the working tree."""
65 1
    status = False
66
67 1
    try:
68
        # Refresh changes
69 1
        git('update-index', '-q', '--refresh', _show=False)
70
71
        # Check for uncommitted changes
72 1
        git('diff-index', '--quiet', 'HEAD', _show=_show)
73
74
        # Check for untracked files
75 1
        lines = git('ls-files', '--others', '--exclude-standard', _show=_show)
76
77 1
    except ShellError:
78 1
        status = True
79
80
    else:
81 1
        status = bool(lines) and include_untracked
82
83 1
    if status and display_status:
84 1
        with suppress(ShellError):
85 1
            lines = git('status', _show=True)
86 1
            common.show(*lines, color='git_changes')
0 ignored issues
show
Coding Style introduced by
Usage of * or ** arguments should usually be done with care.

Generally, there is nothing wrong with usage of * or ** arguments. For readability of the code base, we suggest to not over-use these language constructs though.

For more information, we can recommend this blog post from Ned Batchelder including its comments which also touches this aspect.

Loading history...
87
88 1
    return status
89
90
91 1
def update(rev, *, clean=True, fetch=False):  # pylint: disable=redefined-outer-name
0 ignored issues
show
introduced by
Locally disabling redefined-outer-name (W0621)
Loading history...
92
    """Update the working tree to the specified revision."""
93 1
    hide = {'_show': False, '_ignore': True}
94
95 1
    git('stash', **hide)
0 ignored issues
show
Coding Style introduced by
Usage of * or ** arguments should usually be done with care.

Generally, there is nothing wrong with usage of * or ** arguments. For readability of the code base, we suggest to not over-use these language constructs though.

For more information, we can recommend this blog post from Ned Batchelder including its comments which also touches this aspect.

Loading history...
96 1
    if clean:
97 1
        git('clean', '--force', '-d', '-x', _show=False)
98
99 1
    rev = _get_sha_from_rev(rev)
100 1
    git('checkout', '--force', rev)
101 1
    git('branch', '--set-upstream-to', 'origin/' + rev, **hide)
0 ignored issues
show
Coding Style introduced by
Usage of * or ** arguments should usually be done with care.

Generally, there is nothing wrong with usage of * or ** arguments. For readability of the code base, we suggest to not over-use these language constructs though.

For more information, we can recommend this blog post from Ned Batchelder including its comments which also touches this aspect.

Loading history...
102
103 1
    if fetch:
104
        # if `rev` was a branch it might be tracking something older
105 1
        git('pull', '--ff-only', '--no-rebase', **hide)
0 ignored issues
show
Coding Style introduced by
Usage of * or ** arguments should usually be done with care.

Generally, there is nothing wrong with usage of * or ** arguments. For readability of the code base, we suggest to not over-use these language constructs though.

For more information, we can recommend this blog post from Ned Batchelder including its comments which also touches this aspect.

Loading history...
106
107
108 1
def get_url():
109
    """Get the current repository's URL."""
110 1
    return git('config', '--get', 'remote.origin.url', _show=False)[0]
111
112
113 1
def get_hash(_show=False):
114
    """Get the current working tree's hash."""
115 1
    return git('rev-parse', 'HEAD', _show=_show)[0]
116
117
118 1
def get_tag():
119
    """Get the current working tree's tag (if on a tag)."""
120 1
    return git('describe', '--tags', '--exact-match',
121
               _show=False, _ignore=True)[0]
122
123
124 1
def get_branch():
125
    """Get the current working tree's branch."""
126 1
    return git('rev-parse', '--abbrev-ref', 'HEAD', _show=False)[0]
127
128
129 1
def _get_sha_from_rev(rev):
130
    """Get a rev-parse string's hash."""
131 1
    if '@{' in rev:  # TODO: use regex for this
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
132 1
        parts = rev.split('@')
133 1
        branch = parts[0]
134 1
        date = parts[1].strip("{}")
135 1
        git('checkout', '--force', branch, _show=False)
136 1
        rev = git('rev-list', '-n', '1', '--before={!r}'.format(date),
137
                  branch, _show=False)[0]
138
    return rev
139