summaryrefslogtreecommitdiff
path: root/buildscripts/utils.py
blob: e62be1f83056e3cbbf0f776a0f3a3deaf4c3f845 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
"""Various utilities that are handy."""

import codecs
import re
import os
import os.path
import subprocess
import sys


def getAllSourceFiles(arr=None, prefix="."):
    if arr is None:
        arr = []

    if not os.path.isdir(prefix):
        # assume a file
        arr.append(prefix)
        return arr

    for x in os.listdir(prefix):
        if (x.startswith(".")
            or x.startswith("pcre-")
            or x.startswith("32bit")
            or x.startswith("mongodb-")
            or x.startswith("debian")
            or x.startswith("mongo-cxx-driver")
            or x.startswith("sqlite")
            or "gotools" in x
            or x.find("mozjs") != -1):
            continue

        def isFollowableDir(prefix, full):
            if not os.path.isdir(full):
                return False
            if not os.path.islink(full):
                return True
            # Follow softlinks in the modules directory (e.g: enterprise).
            if os.path.split(prefix)[1] == "modules":
                return True
            return False

        full = prefix + "/" + x
        if isFollowableDir(prefix, full):
            getAllSourceFiles(arr, full)
        else:
            if full.endswith(".cpp") or full.endswith(".h") or full.endswith(".c"):
                full = full.replace("//", "/")
                arr.append(full)

    return arr


def getGitBranch():
    if not os.path.exists(".git") or not os.path.isdir(".git"):
        return None

    version = open(".git/HEAD", "r").read().strip()
    if not version.startswith("ref: "):
        return version
    version = version.split("/")
    version = version[len(version)-1]
    return version


def getGitBranchString(prefix="", postfix=""):
    t = re.compile("[/\\\]").split(os.getcwd())
    if len(t) > 2 and t[len(t)-1] == "mongo":
        par = t[len(t)-2]
        m = re.compile(".*_([vV]\d+\.\d+)$").match(par)
        if m is not None:
            return prefix + m.group(1).lower() + postfix
        if par.find("Nightly") > 0:
            return ""

    b = getGitBranch()
    if b is None or b == "master":
        return ""
    return prefix + b + postfix


def getGitVersion():
    if not os.path.exists(".git") or not os.path.isdir(".git"):
        return "nogitversion"

    version = open(".git/HEAD", "r").read().strip()
    if not version.startswith("ref: "):
        return version
    version = version[5:]
    f = ".git/" + version
    if not os.path.exists(f):
        return version
    return open(f, "r").read().strip()


def getGitDescribe():
    with open(os.devnull, "r+") as devnull:
        proc = subprocess.Popen(
            "git describe",
            stdout=subprocess.PIPE,
            stderr=devnull,
            stdin=devnull,
            shell=True)
        return proc.communicate()[0].strip()


def execsys(args):
    import subprocess
    if isinstance(args, str):
        r = re.compile("\s+")
        args = r.split(args)
    p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    r = p.communicate()
    return r


def which(executable):
    if sys.platform == "win32":
        paths = os.environ.get("Path", "").split(";")
    else:
        paths = os.environ.get("PATH", "").split(":")

    for path in paths:
        path = os.path.expandvars(path)
        path = os.path.expanduser(path)
        path = os.path.abspath(path)
        executable_path = os.path.join(path, executable)
        if os.path.exists(executable_path):
            return executable_path

    return executable


def find_python(min_version=(2, 5)):
    try:
        if sys.version_info >= min_version:
            return sys.executable
    except AttributeError:
        # In case the version of Python is somehow missing sys.version_info or sys.executable.
        pass

    version = re.compile(r"[Pp]ython ([\d\.]+)", re.MULTILINE)
    binaries = (
        "python27", "python2.7", "python26", "python2.6", "python25", "python2.5", "python")
    for binary in binaries:
        try:
            out, err = subprocess.Popen(
                [binary, "-V"], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
            for stream in (out, err):
                match = version.search(stream)
                if match:
                    versiontuple = tuple(map(int, match.group(1).split(".")))
                    if versiontuple >= min_version:
                        return which(binary)
        except:
            pass

    raise Exception(
        "could not find suitable Python (version >= %s)" % ".".join(str(v) for v in min_version))


# unicode is a pain. some strings cannot be unicode()'d
# but we want to just preserve the bytes in a human-readable
# fashion. this codec error handler will substitute the
# repr() of the offending bytes into the decoded string
# at the position they occurred
def replace_with_repr(unicode_error):
    offender = unicode_error.object[unicode_error.start:unicode_error.end]
    return (unicode(repr(offender).strip("'").strip('"')), unicode_error.end)

codecs.register_error("repr", replace_with_repr)