Completed
Push — master ( 8ec901...58e247 )
by Bjorn
03:07
created

dkfileutils.which()   F

Complexity

Conditions 19

Size

Total Lines 50

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 19
dl 0
loc 50
rs 2.7503

How to fix   Complexity   

Complexity

Complex classes like dkfileutils.which() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# -*- coding: utf-8 -*-
2
"""Print where on the path an executable is located.
3
"""
4
from __future__ import print_function
5
import sys
6
import os
7
from stat import ST_MODE, S_IXUSR, S_IXGRP, S_IXOTH
8
9
10
def get_executable(name):
11
    for result in which(name)):
12
        return result
13
    return None
14
15
16
def get_path_directories():
17
    pth = os.environ['PATH']
18
    if sys.platform == 'win32' and os.environ.get("BASH"):
19
        # winbash has a bug..
20
        if pth[1] == ';':  # pragma: nocover
21
            pth = pth.replace(';', ':', 1)
22
    return pth.split(os.pathsep)
23
24
25
def is_executable(fname):
26
    return os.stat(fname)[ST_MODE] & (S_IXUSR | S_IXGRP | S_IXOTH)
27
28
29
def which(filename, interactive=False, verbose=False):
30
    exe = os.environ.get('PATHEXT', ['.cmd', '.bat', '.exe', '.com'])
31
32
    name, ext = os.path.splitext(filename)
33
    if ext and (ext in exe):  # pragma: nocover
34
        exe = []
35
36
    def match(filenames):
37
        res = set()
38
        for fname in filenames:
39
            if fname == filename:  # pragma: nocover
40
                res.add(fname)
41
                continue
42
43
            fn_name, fn_ext = os.path.splitext(fname)
44
            if name == fn_name:
45
                for suffix in exe:
46
                    if name + fn_ext == fname:
47
                        res.add(fname)
48
49
        return sorted(res)
50
51
    returnset = set()
52
    found = False
53
    for pth in get_path_directories():
54
        if not pth.strip():  # pragma: nocover
55
            continue
56
57
        if verbose:  # pragma: nocover
58
            print('checking pth..')
59
60
        try:
61
            fnames = os.listdir(pth)
62
        except:  # pragma: nocover
63
            continue
64
65
        matched = match(fnames)
66
67
        if matched:
68
            for m in matched:
69
                found_file = os.path.normcase(os.path.normpath(os.path.join(pth, m)))
70
                if found_file not in returnset:
71
                    if is_executable(found_file):
72
                        yield found_file
73
                    returnset.add(found_file)
74
            found = True
75
76
    if not found and interactive:  # pragma: nocover
77
        print("Couldn't find %r anywhere on the path.." % filename)
78
        sys.exit(1)
79
80
81
if __name__ == "__main__":  # pragma: nocover
82
    for _fname in which(sys.argv[1], interactive=True, verbose='-v' in sys.argv):
83
        print(_fname)
84
    sys.exit(0)
85