Passed
Pull Request — develop (#185)
by Jace
01:38
created

gitman.commands.update()   B

Complexity

Conditions 8

Size

Total Lines 62
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 27
CRAP Score 8

Importance

Changes 0
Metric Value
cc 8
eloc 38
nop 8
dl 0
loc 62
ccs 27
cts 27
cp 1
crap 8
rs 7.1013
c 0
b 0
f 0

How to fix   Long Method    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
"""Functions to manage the installation of dependencies."""
2
3 1
import datetime
4 1
import functools
5 1
import logging
6 1
import os
7
8 1
from . import common, system
9 1
from .models import Config, Source, load_config
10
11 1
12
log = logging.getLogger(__name__)
13
14 1
15 1
def restore_cwd(func):
16
    @functools.wraps(func)
17 1
    def wrapped(*args, **kwargs):
18 1
        cwd = os.getcwd()
19 1
        result = func(*args, **kwargs)
20 1
        os.chdir(cwd)
21 1
        return result
22
23
    return wrapped
24 1
25
26 1
def init():
27
    """Create a new config file for the project."""
28 1
    success = False
29
30 1
    config = load_config()
31 1
32 1
    if config:
33
        msg = "Configuration file already exists: {}".format(config.path)
34
        common.show(msg, color='error')
35 1
36 1
    else:
37
        config = Config()
38 1
        source = Source(
39 1
            'git',
40 1
            name="sample_dependency",
41 1
            repo="https://github.com/githubtraining/hellogitworld",
42
        )
43 1
        config.sources.append(source)
44 1
        source = source.lock(rev="ebbbf773431ba07510251bb03f9525c7bab2b13a")
45 1
        config.sources_locked.append(source)
46
        config.save()
47 1
48 1
        msg = "Created sample config file: {}".format(config.path)
49
        common.show(msg, color='success')
50 1
        success = True
51
52
    msg = "To edit this config file, run: gitman edit"
53 1
    common.show(msg, color='message')
54 1
55
    return success
56
57
58
@restore_cwd
59
def install(
60
    *names,
61
    root=None,
62
    depth=None,
63
    force=False,
64
    fetch=False,
65
    clean=True,
66
    skip_changes=False,
67
):
68
    """Install dependencies for a project.
69 1
70
    Optional arguments:
71
72 1
    - `*names`: optional list of dependency directory names to filter on
73
    - `root`: specifies the path to the root working tree
74 1
    - `depth`: number of levels of dependencies to traverse
75
    - `force`: indicates uncommitted changes can be overwritten and
76 1
               script errors can be ignored
77 1
    - `fetch`: indicates the latest branches should always be fetched
78 1
    - `clean`: indicates untracked files should be deleted from dependencies
79 1
    - `skip_changes`: indicates dependencies with uncommitted changes
80 1
     should be skipped
81
    """
82
    log.info(
83
        "%sInstalling dependencies: %s",
84
        'force-' if force else '',
85 1
        ', '.join(names) if names else '<all>',
86 1
    )
87
    count = None
88 1
89
    config = load_config(root)
90
91 1
    if config:
92 1
        common.newline()
93
        common.show("Installing dependencies...", color='message', log=False)
94
        common.newline()
95
        count = config.install_dependencies(
96
            *names,
97
            update=False,
98
            depth=depth,
99
            force=force,
100
            fetch=fetch,
101
            clean=clean,
102
            skip_changes=skip_changes,
103
        )
104
105
        if count:
106
            _run_scripts(*names, depth=depth, force=force, _config=config)
107
108 1
    return _display_result("install", "Installed", count)
109
110
111
@restore_cwd
112 1
def update(
113
    *names,
114 1
    root=None,
115
    depth=None,
116 1
    recurse=False,
117 1
    force=False,
118 1
    clean=True,
119 1
    lock=None,  # pylint: disable=redefined-outer-name
120 1
    skip_changes=False,
121
):
122
    """Update dependencies for a project.
123
124
    Optional arguments:
125 1
126 1
    - `*names`: optional list of dependency directory names to filter on
127
    - `root`: specifies the path to the root working tree
128 1
    - `depth`: number of levels of dependencies to traverse
129 1
    - `recurse`: indicates nested dependencies should also be updated
130
    - `force`: indicates uncommitted changes can be overwritten and
131 1
               script errors can be ignored
132 1
    - `clean`: indicates untracked files should be deleted from dependencies
133
    - `lock`: indicates updated dependency versions should be recorded
134 1
    - `skip_changes`: indicates dependencies with uncommitted changes
135
     should be skipped
136
    """
137 1
    log.info(
138
        "%s dependencies%s: %s",
139
        'Force updating' if force else 'Updating',
140
        ', recursively' if recurse else '',
141
        ', '.join(names) if names else '<all>',
142
    )
143
    count = None
144
145
    config = load_config(root)
146
147 1
    if config:
148
        common.newline()
149 1
        common.show("Updating dependencies...", color='message', log=False)
150 1
        common.newline()
151 1
        count = config.install_dependencies(
152
            *names,
153
            update=True,
154 1
            depth=depth,
155 1
            recurse=recurse,
156
            force=force,
157
            fetch=True,
158
            clean=clean,
159
            skip_changes=skip_changes,
160
        )
161
162
        if count and lock is not False:
163
            common.show("Recording installed versions...", color='message', log=False)
164
            common.newline()
165 1
            config.lock_dependencies(
166 1
                *names, obey_existing=lock is None, skip_changes=skip_changes
167
            )
168 1
169
        if count:
170 1
            _run_scripts(*names, depth=depth, force=force, _config=config)
171 1
172 1
    return _display_result("update", "Updated", count)
173
174 1
175 1
def _run_scripts(*names, depth=None, force=False, _config=None):
176 1
    """Run post-install scripts.
177 1
178
    Optional arguments:
179 1
180 1
    - `*names`: optional list of dependency directory names filter on
181 1
    - `depth`: number of levels of dependencies to traverse
182
    - `force`: indicates script errors can be ignored
183 1
184
    """
185
    assert _config, "'_config' is required"
186 1
187 1
    common.show("Running scripts...", color='message', log=False)
188
    common.newline()
189
    _config.run_scripts(*names, depth=depth, force=force)
190
191
192
@restore_cwd
193
def display(*, root=None, depth=None, allow_dirty=True):
194
    """Display installed dependencies for a project.
195
196 1
    Optional arguments:
197 1
198
    - `root`: specifies the path to the root working tree
199 1
    - `depth`: number of levels of dependencies to traverse
200
    - `allow_dirty`: causes uncommitted changes to be ignored
201 1
202 1
    """
203 1
    log.info("Displaying dependencies...")
204 1
    count = None
205 1
206 1
    config = load_config(root)
207
208 1
    if config:
209
        common.newline()
210
        common.show(
211 1
            "Displaying current dependency versions...", color='message', log=False
212 1
        )
213
        common.newline()
214
        config.log(datetime.datetime.now().strftime("%F %T"))
215
        count = 0
216
        for identity in config.get_dependencies(depth=depth, allow_dirty=allow_dirty):
217
            count += 1
218
            config.log("{}: {} @ {}", *identity)
219
        config.log()
220
221 1
    return _display_result("display", "Displayed", count)
222 1
223
224 1
@restore_cwd
225
def lock(*names, root=None):
226 1
    """Lock current dependency versions for a project.
227 1
228 1
    Optional arguments:
229
230 1
    - `*names`: optional list of dependency directory names to filter on
231 1
    - `root`: specifies the path to the root working tree
232 1
233 1
    """
234 1
    log.info("Locking dependencies...")
235 1
    count = None
236
237 1
    config = load_config(root)
238
239
    if config:
240 1
        common.newline()
241
        common.show("Locking dependencies...", color='message', log=False)
242
        common.newline()
243
        count = config.lock_dependencies(*names, obey_existing=False)
244
        common.dedent(level=0)
245
246
    return _display_result("lock", "Locked", count)
247 1
248
249 1
@restore_cwd
250
def delete(*, root=None, force=False, keep_location=False):
251 1
    """Delete dependencies for a project.
252 1
253 1
    Optional arguments:
254
255 1
    - `root`: specifies the path to the root working tree
256 1
    - `force`: indicates uncommitted changes can be overwritten
257
    - `keep_location`: delete top level folder or keep the location
258 1
259
    """
260
    log.info("Deleting dependencies...")
261 1
    count = None
262
263
    config = load_config(root)
264
265
    if config:
266
        common.newline()
267
        common.show("Checking for uncommitted changes...", color='message', log=False)
268
        common.newline()
269 1
        count = len(list(config.get_dependencies(allow_dirty=force)))
270
        common.dedent(level=0)
271 1
        common.show("Deleting all dependencies...", color='message', log=False)
272
        common.newline()
273 1
        if keep_location:
274 1
            config.clean_dependencies()
275 1
        else:
276
            config.uninstall_dependencies()
277 1
278
    return _display_result("delete", "Deleted", count, allow_zero=True)
279
280 1
281
def show(*names, root=None):
282
    """Display the path of an installed dependency or internal file.
283
284
    - `name`: dependency name or internal file keyword
285
    - `root`: specifies the path to the root working tree
286
287
    """
288
    log.info("Finding paths...")
289
290
    config = load_config(root)
291
292
    if not config:
293
        log.error("No config found")
294
        return False
295
296 1
    for name in names or [None]:
297 1
        common.show(config.get_path(name), color='path')
298 1
299 1
    return True
300
301 1
302
def edit(*, root=None):
303 1
    """Open the confuration file for a project.
304 1
305 1
    Optional arguments:
306 1
307
    - `root`: specifies the path to the root working tree
308 1
309 1
    """
310
    log.info("Launching config...")
311
312
    config = load_config(root)
313
314
    if not config:
315
        log.error("No config found")
316
        return False
317
318
    return system.launch(config.path)
319
320
321
def _display_result(present, past, count, allow_zero=False):
322
    """Convert a command's dependency count to a return status.
323
324
    >>> _display_result("sample", "Sampled", 1)
325
    True
326
327
    >>> _display_result("sample", "Sampled", None)
328
    False
329
330
    >>> _display_result("sample", "Sampled", 0)
331
    False
332
333
    >>> _display_result("sample", "Sampled", 0, allow_zero=True)
334
    True
335
336
    """
337
    if count is None:
338
        log.warning("No dependencies to %s", present)
339
    elif count == 1:
340
        log.info("%s 1 dependency", past)
341
    else:
342
        log.info("%s %s dependencies", past, count)
343
344
    if count:
345
        return True
346
    if count is None:
347
        return False
348
349
    assert count == 0
350
    return allow_zero
351