~ubuntu-branches/debian/experimental/nuitka/experimental

« back to all changes in this revision

Viewing changes to nuitka/utils/Utils.py

  • Committer: Package Import Robot
  • Author(s): Kay Hayen
  • Date: 2015-04-06 17:20:44 UTC
  • mfrom: (1.1.37)
  • Revision ID: package-import@ubuntu.com-20150406172044-grhy9sk7g0whu2ag
Tags: 0.5.12+ds-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#     Copyright 2015, Kay Hayen, mailto:kay.hayen@gmail.com
 
2
#
 
3
#     Part of "Nuitka", an optimizing Python compiler that is compatible and
 
4
#     integrates with CPython, but also works on its own.
 
5
#
 
6
#     Licensed under the Apache License, Version 2.0 (the "License");
 
7
#     you may not use this file except in compliance with the License.
 
8
#     You may obtain a copy of the License at
 
9
#
 
10
#        http://www.apache.org/licenses/LICENSE-2.0
 
11
#
 
12
#     Unless required by applicable law or agreed to in writing, software
 
13
#     distributed under the License is distributed on an "AS IS" BASIS,
 
14
#     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
15
#     See the License for the specific language governing permissions and
 
16
#     limitations under the License.
 
17
#
 
18
""" Utility module.
 
19
 
 
20
Here the small things for file/dir names, Python version, CPU counting,
 
21
memory usage, etc. that fit nowhere else and don't deserve their own names.
 
22
 
 
23
"""
 
24
 
 
25
import os
 
26
import subprocess
 
27
import sys
 
28
 
 
29
from nuitka.PythonVersions import python_version
 
30
 
 
31
 
 
32
def getOS():
 
33
    if os.name == "nt":
 
34
        return "Windows"
 
35
    elif os.name == "posix":
 
36
        return os.uname()[0]
 
37
    else:
 
38
        assert False, os.name
 
39
 
 
40
 
 
41
def getArchitecture():
 
42
    if getOS() == "Windows":
 
43
        if "AMD64" in sys.version:
 
44
            return "x86_64"
 
45
        else:
 
46
            return "x86"
 
47
    else:
 
48
        return os.uname()[4]
 
49
 
 
50
 
 
51
def relpath(path):
 
52
    try:
 
53
        return os.path.relpath(path)
 
54
    except ValueError:
 
55
        # On Windows, paths on different devices prevent it to work. Use that
 
56
        # full path then.
 
57
        if getOS() == "Windows":
 
58
            return os.path.abspath(path)
 
59
        raise
 
60
 
 
61
 
 
62
def abspath(path):
 
63
    return os.path.abspath(path)
 
64
 
 
65
 
 
66
def joinpath(*parts):
 
67
    return os.path.join(*parts)
 
68
 
 
69
 
 
70
def splitpath(path):
 
71
    return tuple(
 
72
        element
 
73
        for element in
 
74
        os.path.split(path)
 
75
        if element
 
76
    )
 
77
 
 
78
 
 
79
def basename(path):
 
80
    return os.path.basename(path)
 
81
 
 
82
 
 
83
def dirname(path):
 
84
    return os.path.dirname(path)
 
85
 
 
86
 
 
87
def normpath(path):
 
88
    return os.path.normpath(path)
 
89
 
 
90
 
 
91
def normcase(path):
 
92
    return os.path.normcase(path)
 
93
 
 
94
 
 
95
def getExtension(path):
 
96
    return os.path.splitext(path)[1]
 
97
 
 
98
 
 
99
def isFile(path):
 
100
    return os.path.isfile(path)
 
101
 
 
102
 
 
103
def isDir(path):
 
104
    return os.path.isdir(path)
 
105
 
 
106
 
 
107
def isLink(path):
 
108
    return os.path.islink(path)
 
109
 
 
110
 
 
111
def areSamePaths(path1, path2):
 
112
    path1 = normcase(abspath(normpath(path1)))
 
113
    path2 = normcase(abspath(normpath(path2)))
 
114
 
 
115
    return path1 == path2
 
116
 
 
117
 
 
118
def readLink(path):
 
119
    return os.readlink(path)
 
120
 
 
121
 
 
122
def listDir(path):
 
123
    """ Give a sorted path, base filename pairs of a directory."""
 
124
 
 
125
    return sorted(
 
126
        [
 
127
            (
 
128
                joinpath(path, filename),
 
129
                filename
 
130
            )
 
131
            for filename in
 
132
            os.listdir(path)
 
133
        ]
 
134
    )
 
135
 
 
136
 
 
137
def getFileList(path):
 
138
    for root, _dirnames, filenames in os.walk(path):
 
139
        for filename in filenames:
 
140
            yield joinpath(root, filename)
 
141
 
 
142
 
 
143
def deleteFile(path, must_exist):
 
144
    if must_exist or isFile(path):
 
145
        os.unlink(path)
 
146
 
 
147
 
 
148
def makePath(path):
 
149
    os.makedirs(path)
 
150
 
 
151
 
 
152
def getCoreCount():
 
153
    cpu_count = 0
 
154
 
 
155
    # Try to sum up the CPU cores, if the kernel shows them.
 
156
    try:
 
157
        # Try to get the number of logical processors
 
158
        with open("/proc/cpuinfo") as cpuinfo_file:
 
159
            cpu_count = cpuinfo_file.read().count("processor\t:")
 
160
    except IOError:
 
161
        pass
 
162
 
 
163
    if not cpu_count:
 
164
        import multiprocessing
 
165
        cpu_count = multiprocessing.cpu_count()
 
166
 
 
167
    return cpu_count
 
168
 
 
169
 
 
170
def callExec(args):
 
171
    """ Do exec in a portable way preserving exit code.
 
172
 
 
173
        On Windows, unfortunately there is no real exec, so we have to spawn
 
174
        a new process instead.
 
175
    """
 
176
 
 
177
    # On Windows os.execl does not work properly
 
178
    if getOS() != "Windows":
 
179
        # The star arguments is the API of execl, pylint: disable=W0142
 
180
        os.execl(*args)
 
181
    else:
 
182
        args = list(args)
 
183
        del args[1]
 
184
 
 
185
        try:
 
186
            sys.exit(
 
187
                subprocess.call(args)
 
188
            )
 
189
        except KeyboardInterrupt:
 
190
            # There was a more relevant stack trace already, so abort this
 
191
            # right here, pylint: disable=W0212
 
192
            os._exit(2)
 
193
 
 
194
 
 
195
def encodeNonAscii(var_name):
 
196
    """ Encode variable name that is potentially not ASCII to ASCII only.
 
197
 
 
198
        For Python3, unicode identifiers can be used, but these are not
 
199
        possible in C++03, so we need to replace them.
 
200
    """
 
201
    if python_version < 300:
 
202
        return var_name
 
203
    else:
 
204
        # Using a escaping here, because that makes it safe in terms of not
 
205
        # to occur in the encoding escape sequence for unicode use.
 
206
        var_name = var_name.replace("$$", "$_$")
 
207
 
 
208
        var_name = var_name.encode("ascii", "xmlcharrefreplace")
 
209
        var_name = var_name.decode("ascii")
 
210
 
 
211
        return var_name.replace("&#", "$$").replace(';', "")
 
212
 
 
213
 
 
214
def isExecutableCommand(command):
 
215
    path = os.environ["PATH"]
 
216
 
 
217
    suffixes = (".exe",) if getOS() == "Windows" else ("",)
 
218
    path_sep = ';' if getOS() == "Windows" else ':'
 
219
 
 
220
    for part in path.split(path_sep):
 
221
        if not part:
 
222
            continue
 
223
 
 
224
        for suffix in suffixes:
 
225
            if isFile(joinpath(part, command + suffix)):
 
226
                return True
 
227
 
 
228
    return False
 
229
 
 
230
 
 
231
def getOwnProcessMemoryUsage():
 
232
    """ Memory usage of own process in bytes.
 
233
 
 
234
    """
 
235
 
 
236
    if getOS() == "Windows":
 
237
        # adapted from http://code.activestate.com/recipes/578513
 
238
        import ctypes
 
239
        from ctypes import wintypes
 
240
 
 
241
        # Lets allow this to match Windows API it reflects,
 
242
        # pylint: disable=C0103
 
243
        class PROCESS_MEMORY_COUNTERS_EX(ctypes.Structure):
 
244
            _fields_ = [
 
245
                ("cb", wintypes.DWORD),
 
246
                ("PageFaultCount", wintypes.DWORD),
 
247
                ("PeakWorkingSetSize", ctypes.c_size_t),
 
248
                ("WorkingSetSize", ctypes.c_size_t),
 
249
                ("QuotaPeakPagedPoolUsage", ctypes.c_size_t),
 
250
                ("QuotaPagedPoolUsage", ctypes.c_size_t),
 
251
                ("QuotaPeakNonPagedPoolUsage", ctypes.c_size_t),
 
252
                ("QuotaNonPagedPoolUsage", ctypes.c_size_t),
 
253
                ("PagefileUsage", ctypes.c_size_t),
 
254
                ("PeakPagefileUsage", ctypes.c_size_t),
 
255
                ("PrivateUsage", ctypes.c_size_t),
 
256
            ]
 
257
 
 
258
        GetProcessMemoryInfo = ctypes.windll.psapi.GetProcessMemoryInfo
 
259
        GetProcessMemoryInfo.argtypes = [
 
260
            wintypes.HANDLE,
 
261
            ctypes.POINTER(PROCESS_MEMORY_COUNTERS_EX),
 
262
            wintypes.DWORD,
 
263
        ]
 
264
        GetProcessMemoryInfo.restype = wintypes.BOOL
 
265
 
 
266
        counters = PROCESS_MEMORY_COUNTERS_EX()
 
267
        rv = GetProcessMemoryInfo(
 
268
            ctypes.windll.kernel32.GetCurrentProcess(),
 
269
            ctypes.byref(counters),
 
270
            ctypes.sizeof(counters)
 
271
        )
 
272
 
 
273
        if not rv:
 
274
            raise ctypes.WinError()
 
275
 
 
276
        return counters.PrivateUsage
 
277
    else:
 
278
        # Posix only code, pylint: disable=F0401,I0021
 
279
        import resource
 
280
 
 
281
        # The value is from "getrusage", which has OS dependent scaling, at least
 
282
        # MacOS and Linux different
 
283
        if getOS() == "Darwin":
 
284
            factor = 1
 
285
        else:
 
286
            factor = 1024
 
287
 
 
288
        return resource.getrusage(resource.RUSAGE_SELF).ru_maxrss * factor
 
289
 
 
290
 
 
291
def getHumanReadableProcessMemoryUsage(value = None):
 
292
    if value is None:
 
293
        value = getOwnProcessMemoryUsage()
 
294
 
 
295
    if abs(value) < 1024*1014:
 
296
        return "%.2f KB (%d bytes)" % (
 
297
            value / 1024.0,
 
298
            value
 
299
        )
 
300
    elif abs(value) < 1024*1014*1024:
 
301
        return "%.2f MB (%d bytes)" % (
 
302
            value / (1024*1024.0),
 
303
            value
 
304
        )
 
305
    elif abs(value) < 1024*1014*1024*1024:
 
306
        return "%.2f GB (%d bytes)" % (
 
307
            value / (1024*1024*1024.0),
 
308
            value
 
309
        )
 
310
    else:
 
311
        return "%d bytes" % value
 
312
 
 
313
 
 
314
class MemoryWatch:
 
315
    def __init__(self):
 
316
        self.start = getOwnProcessMemoryUsage()
 
317
        self.stop = None
 
318
 
 
319
    def finish(self):
 
320
        self.stop = getOwnProcessMemoryUsage()
 
321
 
 
322
    def asStr(self):
 
323
        return getHumanReadableProcessMemoryUsage(self.stop - self.start)