Passed
Push — develop ( 4d6495...2dddb7 )
by Jace
03:19
created

gitman.shell   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 100
Duplicated Lines 0 %

Test Coverage

Coverage 86.27%

Importance

Changes 0
Metric Value
eloc 60
dl 0
loc 100
ccs 44
cts 51
cp 0.8627
rs 10
c 0
b 0
f 0
wmc 19

6 Functions

Rating   Name   Duplication   Size   Complexity  
A mkdir() 0 6 3
A show() 0 7 2
A ln() 0 8 3
B call() 0 38 5
A cd() 0 6 2
A rm() 0 8 4
1
"""Utilities to call shell programs."""
2
3 1
import logging
4 1
import os
5 1
import subprocess
6
7 1
from . import common
8 1
from .exceptions import ShellError
9
10 1
11 1
CMD_PREFIX = "$ "
12
OUT_PREFIX = "> "
13 1
14
log = logging.getLogger(__name__)
15
16 1
17
def call(name, *args, _show=True, _shell=False, _ignore=False):
18
    """Call a program with arguments.
19
20
    :param name: name of program to call
21
    :param args: list of command-line arguments
22
    :param _show: display the call on stdout
23
    :param _shell: force executing the program into a real shell
24
                   a Windows shell command (i.e: dir, echo) needs a real shell
25
                   but not a regular program (i.e: calc, git)
26
    :param _ignore: ignore non-zero return codes
27 1
    """
28
    program = show(name, *args, stdout=_show)
29 1
30
    command = subprocess.run(
31
        name if _shell else [name, *args], universal_newlines=True,
32
        stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
33
        shell=_shell
34
    )
35 1
36 1
    output = [line.strip() for line in command.stdout.splitlines()]
37 1
    for line in output:
38
        log.debug(OUT_PREFIX + line)
39 1
40 1
    if command.returncode == 0:
41
        return output
42 1
43 1
    if _ignore:
44 1
        log.debug("Ignored error from call to '%s'", name)
45
        return output
46
47 1
    message = (
48
        "An external program call failed." + "\n\n"
49
        "In working directory: " + os.getcwd() + "\n\n"
50
        "The following command produced a non-zero return code:" + "\n\n" +
51
        CMD_PREFIX + program + "\n" +
52
        command.stdout.strip()
53
    )
54 1
    raise ShellError(message, program=program, output=output)
55
56
57 1
def mkdir(path):
58 1
    if not os.path.exists(path):
59 1
        if os.name == 'nt':
60
            call("mkdir " + path, _shell=True)
61
        else:
62 1
            call('mkdir', '-p', path)
63
64
65 1
def cd(path, _show=True):
66 1
    if os.name == 'nt':
67
        show('cd', '/D', path, stdout=_show)
68
    else:
69 1
        show('cd', path, stdout=_show)
70 1
    os.chdir(path)
71
72
73 1
def ln(source, target):
74 1
    if os.name == 'nt':
75
        log.warning("Symlinks are not supported on Windows")
76
    else:
77 1
        dirpath = os.path.dirname(target)
78 1
        if not os.path.isdir(dirpath):
79 1
            mkdir(dirpath)
80 1
        call('ln', '-s', source, target)
81
82
83 1
def rm(path):
84 1
    if os.name == 'nt':
85
        if os.path.isfile(path):
86
            call("del /Q /F " + path, _shell=True)
87
        elif os.path.isdir(path):
88
            call("rmdir /Q /S " + path, _shell=True)
89
    else:
90 1
        call('rm', '-rf', path)
91
92
93 1
def show(name, *args, stdout=True):
94 1
    program = ' '.join([name, *args])
95 1
    if stdout:
96 1
        common.show(CMD_PREFIX + program, color='shell')
97
    else:
98 1
        log.debug(CMD_PREFIX + program)
99
    return program
100