Completed
Pull Request — develop (#107)
by Jace
02:53
created

gitman.update()   C

Complexity

Conditions 7

Size

Total Lines 38

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 7
Metric Value
cc 7
dl 0
loc 38
ccs 16
cts 16
cp 1
crap 7
rs 5.5
1
"""Functions to manage the installation of dependencies."""
2
3 1
import os
4 1
import functools
5 1
import logging
6
7 1
from . import common, system
8 1
from .config import load
9
10 1
log = logging.getLogger(__name__)
11
12
13 1
def restore_cwd(func):
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...
14 1
    @functools.wraps(func)
15
    def wrapped(*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
        cwd = os.getcwd()
17 1
        result = func(*args, **kwargs)
18 1
        os.chdir(cwd)
19 1
        return result
20 1
    return wrapped
21
22
23 1
@restore_cwd
24 1
def install(*names, root=None, depth=None,
25
            force=False, fetch=False, clean=True):
26
    """Install dependencies for a project.
27
28
    Optional arguments:
29
30
    - `*names`: optional list of dependency directory names to filter on
31
    - `root`: specifies the path to the root working tree
32
    - `depth`: number of levels of dependencies to traverse
33
    - `force`: indicates uncommitted changes can be overwritten
34
    - `fetch`: indicates the latest branches should always be fetched
35
    - `clean`: indicates untracked files should be deleted from dependencies
36
37
    """
38 1
    log.info("%sInstalling dependencies: %s",
39
             'force-' if force else '',
40
             ', '.join(names) if names else '<all>')
41 1
    count = None
42
43 1
    root = _find_root(root)
44 1
    config = load(root)
45
46 1
    if config:
47 1
        common.show("Installing dependencies...", log=False)
48 1
        common.show()
49 1
        count = config.install_deps(*names, update=False, depth=depth,
50
                                    force=force, fetch=fetch, clean=clean)
51
52 1
    return _display_result("install", "Installed", count)
53
54
55 1
@restore_cwd
56 1
def update(*names, root=None, depth=None,
57
           recurse=False, force=False, clean=True, lock=None):  # pylint: disable=redefined-outer-name
58
    """Update dependencies for a project.
59
60
    Optional arguments:
61
62
    - `*names`: optional list of dependency directory names to filter on
63
    - `root`: specifies the path to the root working tree
64
    - `depth`: number of levels of dependencies to traverse
65
    - `recurse`: indicates nested dependencies should also be updated
66
    - `force`: indicates uncommitted changes can be overwritten
67
    - `clean`: indicates untracked files should be deleted from dependencies
68
    - `lock`: indicates actual dependency versions should be recorded
69
70
    """
71 1
    log.info("%s dependencies%s: %s",
72
             'Force updating' if force else 'Updating',
73
             ', recursively' if recurse else '',
74
             ', '.join(names) if names else '<all>')
75 1
    count = None
76
77 1
    root = _find_root(root)
78 1
    config = load(root)
79
80 1
    if config:
81 1
        common.show("Updating dependencies...", log=False)
82 1
        common.show()
83 1
        count = config.install_deps(
84
            *names, update=True, depth=depth,
85
            recurse=recurse, force=force, fetch=True, clean=clean)
86 1
        common.dedent(level=0)
87 1
        if count and lock is not False:
88 1
            common.show("Recording installed versions...", log=False)
89 1
            common.show()
90 1
            config.lock_deps(*names, obey_existing=lock is None)
91
92 1
    return _display_result("update", "Updated", count)
93
94
95 1
@restore_cwd
96 1
def display(root=None, depth=None, allow_dirty=True):
97
    """Display installed dependencies for a project.
98
99
    Optional arguments:
100
101
    - `root`: specifies the path to the root working tree
102
    - `depth`: number of levels of dependencies to traverse
103
    - `allow_dirty`: causes uncommitted changes to be ignored
104
105
    """
106 1
    log.info("Displaying dependencies...")
107 1
    count = None
108
109 1
    root = _find_root(root)
110 1
    config = load(root)
111
112 1
    if config:
113
        common.show("Displaying current dependency versions...", log=False)
114
        common.show()
115
        count = len(list(config.get_deps(depth=depth, allow_dirty=allow_dirty)))
116
117 1
    return _display_result("display", "Displayed", count)
118
119
120 1
@restore_cwd
121 1
def lock(*names, root=None):
122
    """Lock current dependency versions for a project.
123
124
    Optional arguments:
125
126
    - `*names`: optional list of dependency directory names to filter on
127
    - `root`: specifies the path to the root working tree
128
129
    """
130 1
    log.info("Locking dependencies...")
131 1
    count = None
132
133 1
    root = _find_root(root)
134 1
    config = load(root)
135
136 1
    if config:
137 1
        common.show("Locking dependencies...", log=False)
138 1
        common.show()
139 1
        count = config.lock_deps(*names, obey_existing=False)
140 1
        common.dedent(level=0)
141
142 1
    return _display_result("lock", "Locked", count)
143
144
145 1
@restore_cwd
146 1
def delete(root=None, force=False):
147
    """Delete dependencies for a project.
148
149
    Optional arguments:
150
151
    - `root`: specifies the path to the root working tree
152
    - `force`: indicates uncommitted changes can be overwritten
153
154
    """
155 1
    log.info("Deleting dependencies...")
156 1
    count = None
157
158 1
    root = _find_root(root)
159 1
    config = load(root)
160
161 1
    if config:
162 1
        common.show("Checking for uncommitted changes...", log=False)
163 1
        common.show()
164 1
        count = len(list(config.get_deps(allow_dirty=force)))
165 1
        common.dedent(level=0)
166 1
        common.show("Deleting all dependencies...", log=False)
167 1
        common.show()
168 1
        config.uninstall_deps()
169
170 1
    return _display_result("delete", "Deleted", count, allow_zero=True)
171
172
173 1
@restore_cwd
174 1
def edit(root=None):
175
    """Open the confuration file for a project.
176
177
    Optional arguments:
178
179
    - `root`: specifies the path to the root working tree
180
181
    """
182 1
    log.info("Launching configuration...")
183
184 1
    root = _find_root(root)
185 1
    config = load(root)
186
187 1
    if config:
188 1
        return system.launch(config.path)
189
    else:
190 1
        log.error("No configuration found")
191 1
        return False
192
193
194 1
def _find_root(root, cwd=None):
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...
195 1
    if cwd is None:
196 1
        cwd = os.getcwd()
197 1
        log.info("Current directory: %s", cwd)
198
199 1
    if root:
200 1
        root = os.path.abspath(root)
201 1
        log.info("Specified root: %s", root)
202
    else:
203 1
        path = cwd
204 1
        prev = None
205
206 1
        log.info("Searching for root...")
207 1
        while path != prev:
208 1
            log.debug("Checking path: %s", path)
209 1
            if '.git' in os.listdir(path):
210 1
                root = path
211 1
                break
212 1
            prev = path
213 1
            path = os.path.dirname(path)
214
215 1
        if root:
216 1
            log.info("Found root: %s", root)
217
        else:
218 1
            root = cwd
219 1
            log.warning("No root found, default: %s", root)
220
221 1
    return root
222
223
224 1
def _display_result(present, past, count, allow_zero=False):
225
    """Convert a command's dependency count to a return status.
226
227
    >>> _display_result("sample", "Sampled", 1)
228
    True
229
230
    >>> _display_result("sample", "Sampled", None)
231
    False
232
233
    >>> _display_result("sample", "Sampled", 0)
234
    False
235
236
    >>> _display_result("sample", "Sampled", 0, allow_zero=True)
237
    True
238
239
    """
240 1
    if count is None:
241 1
        log.warning("No dependencies to %s", present)
242 1
    elif count == 1:
243 1
        log.info("%s 1 dependency", past)
244
    else:
245 1
        log.info("%s %s dependencies", past, count)
246
247 1
    if count:
248 1
        return True
249 1
    elif count is None:
250 1
        return False
251
    else:
252 1
        assert count == 0
253
        return allow_zero
254