ambuild2/util.py
author David Anderson <dvander@alliedmods.net>
Mon Nov 11 14:19:43 2013 -0800 (2013-11-11)
changeset 168 2260bcc1f88c
parent 167 a559eb423181
child 175 28bbe68ad4a2
permissions -rw-r--r--
Fix bugs in symlink/copy and don't Pickle optparse.
danderson@56
     1
# vim: set sts=2 ts=8 sw=2 tw=99 et: 
dvander@75
     2
import errno
danderson@56
     3
import subprocess
dvander@94
     4
import re, os, sys
danderson@56
     5
import multiprocessing
dvander@67
     6
try:
dvander@67
     7
  import __builtin__ as builtins
dvander@67
     8
except:
dvander@67
     9
  import builtins
dvander@67
    10
try:
dvander@67
    11
  import cPickle as pickle
dvander@67
    12
except:
dvander@67
    13
  import pickle
danderson@56
    14
danderson@56
    15
def Platform():
danderson@56
    16
  if IsWindows():
danderson@56
    17
    return 'windows'
danderson@56
    18
  if IsMac():
danderson@56
    19
    return 'mac'
dvander@75
    20
  if IsLinux():
danderson@56
    21
    return 'linux'
dvander@75
    22
  if IsFreeBSD():
dvander@75
    23
    return 'freebsd'
dvander@75
    24
  if IsOpenBSD():
dvander@75
    25
    return 'openbsd'
dvander@75
    26
  if IsNetBSD():
dvander@75
    27
    return 'netbsd'
dvander@75
    28
  if IsSolaris():
dvander@75
    29
    return 'solaris'
danderson@56
    30
  return 'unknown'
danderson@56
    31
dvander@75
    32
def IsLinux():
dvander@75
    33
  return sys.platform[0:5] == 'linux'
dvander@75
    34
dvander@75
    35
def IsFreeBSD():
dvander@75
    36
  return sys.platform[0:7] == 'freebsd'
dvander@75
    37
dvander@75
    38
def IsNetBSD():
dvander@75
    39
  return sys.platform[0:6] == 'netbsd'
dvander@75
    40
dvander@75
    41
def IsOpenBSD():
dvander@75
    42
  return sys.platform[0:7] == 'openbsd'
dvander@75
    43
danderson@56
    44
def IsWindows():
danderson@56
    45
  return sys.platform == 'win32' or sys.platform == 'cygwin'
danderson@56
    46
danderson@56
    47
def IsMac():
dvander@75
    48
  return sys.platform == 'darwin' or sys.platform[0:6] == 'Darwin'
dvander@75
    49
dvander@75
    50
def IsSolaris():
dvander@75
    51
  return sys.platform[0:5] == 'sunos'
danderson@56
    52
danderson@56
    53
def IsUnixy():
dvander@75
    54
  return not IsWindows()
dvander@75
    55
dvander@75
    56
def IsBSD():
dvander@75
    57
  return IsMac() or IsFreeBSD() or IsOpenBSD() or IsNetBSD()
danderson@56
    58
danderson@56
    59
def ExecutableSuffix():
danderson@56
    60
  if IsWindows():
danderson@56
    61
    return '.exe'
danderson@56
    62
  else:
danderson@56
    63
    return ''
danderson@56
    64
danderson@56
    65
def SharedLibSuffix():
danderson@56
    66
  if IsWindows():
danderson@56
    67
    return '.dll'
danderson@56
    68
  elif sys.platform == 'darwin':
danderson@56
    69
    return '.dylib'
danderson@56
    70
  else:
danderson@56
    71
    return '.so'
danderson@56
    72
danderson@56
    73
def StaticLibSuffix():
danderson@56
    74
  if IsUnixy():
danderson@56
    75
    return '.a'
danderson@56
    76
  return '.lib'
danderson@56
    77
danderson@56
    78
def StaticLibPrefix():
danderson@56
    79
  if IsWindows():
danderson@56
    80
    return ''
danderson@56
    81
  else:
danderson@56
    82
    return 'lib'
danderson@56
    83
danderson@56
    84
def WaitForProcess(process):
danderson@56
    85
  out, err = process.communicate()
danderson@56
    86
  process.stdoutText = out.decode()
danderson@56
    87
  process.stderrText = err.decode()
danderson@56
    88
  return process.returncode
danderson@56
    89
danderson@56
    90
def CreateProcess(argv, executable = None):
danderson@56
    91
  pargs = { 'args': argv }
danderson@56
    92
  pargs['stdout'] = subprocess.PIPE
danderson@56
    93
  pargs['stderr'] = subprocess.PIPE
danderson@56
    94
  if executable != None:
danderson@56
    95
    pargs['executable'] = executable
danderson@56
    96
  try:
danderson@56
    97
    process = subprocess.Popen(**pargs)
danderson@56
    98
  except:
danderson@56
    99
    return None
danderson@56
   100
  return process
danderson@56
   101
danderson@56
   102
def MakePath(*list):
danderson@56
   103
  path = os.path.join(*list)
danderson@56
   104
  if IsWindows():
danderson@56
   105
    path = path.replace('\\\\', '\\')
danderson@56
   106
  return path
danderson@56
   107
danderson@56
   108
def RemoveFolderAndContents(path):
danderson@56
   109
  for file in os.listdir(path):
danderson@56
   110
    subpath = os.path.join(path, file)
danderson@56
   111
    try:
danderson@56
   112
      if os.path.isfile(subpath) or os.path.islink(subpath):
danderson@56
   113
        os.unlink(subpath)
danderson@56
   114
      elif os.path.isdir(subpath):
danderson@56
   115
        RemoveFolderAndContents(subpath)
danderson@56
   116
    except:
danderson@56
   117
      pass
danderson@56
   118
  os.rmdir(path)
danderson@56
   119
danderson@56
   120
class FolderChanger:
danderson@56
   121
  def __init__(self, folder):
danderson@56
   122
    self.old = os.getcwd()
danderson@56
   123
    self.new = folder
danderson@56
   124
danderson@56
   125
  def __enter__(self):
dvander@94
   126
    if self.new:
dvander@94
   127
      os.chdir(self.new)
danderson@56
   128
danderson@56
   129
  def __exit__(self, type, value, traceback):
danderson@56
   130
    os.chdir(self.old)
danderson@56
   131
danderson@56
   132
class Guard:
danderson@56
   133
  def __init__(self, obj):
danderson@56
   134
    self.obj = obj
danderson@56
   135
danderson@56
   136
  def __enter__(self):
danderson@56
   137
    return self.obj
danderson@56
   138
danderson@56
   139
  def __exit__(self, type, value, traceback):
danderson@56
   140
    self.obj.close()
danderson@56
   141
dvander@128
   142
def Execute(argv, shell=False):
dvander@61
   143
  p = subprocess.Popen(
dvander@61
   144
      args=argv,
dvander@61
   145
      stdout=subprocess.PIPE,
dvander@61
   146
      stderr=subprocess.PIPE,
dvander@128
   147
      shell=shell
dvander@61
   148
  )
danderson@56
   149
  stdout, stderr = p.communicate()
dvander@105
   150
  out = stdout.decode('utf8')
dvander@105
   151
  err = stderr.decode('utf8')
dvander@61
   152
  return p, out, err
dvander@67
   153
dvander@67
   154
def typeof(x):
dvander@67
   155
  return builtins.type(x)
dvander@67
   156
dvander@67
   157
if str == bytes:
dvander@67
   158
  # Python 2.7. sqlite blob is buffer
dvander@67
   159
  BlobType = buffer
dvander@67
   160
else:
dvander@67
   161
  BlobType = bytes
dvander@68
   162
dvander@68
   163
def Unpickle(blob):
dvander@68
   164
  if type(blob) != bytes:
dvander@68
   165
    blob = bytes(blob)
dvander@68
   166
  return pickle.loads(blob)
dvander@75
   167
danderson@150
   168
# We don't want to dump Python 3 pickle format since then ambuild couldn't
danderson@150
   169
# run it if you using Python 2.
danderson@150
   170
PICKLE_PROTOCOL = min(2, pickle.HIGHEST_PROTOCOL)
danderson@150
   171
danderson@150
   172
def DiskPickle(obj, fp):
danderson@150
   173
  return pickle.dump(obj, fp, PICKLE_PROTOCOL)
danderson@150
   174
danderson@150
   175
def CompatPickle(obj):
danderson@150
   176
  return pickle.dumps(obj, PICKLE_PROTOCOL)
danderson@150
   177
dvander@90
   178
def str2b(s):
dvander@90
   179
  if bytes is str:
dvander@90
   180
    return s
dvander@90
   181
  return bytes(s, 'utf8')
dvander@94
   182
dvander@94
   183
sReadIncludes = 0
dvander@94
   184
sLookForIncludeGuard = 1
dvander@94
   185
sFoundIncludeGuard = 2
dvander@94
   186
sIgnoring = 3
dvander@94
   187
def ParseGCCDeps(text):
dvander@94
   188
  deps = set()
dvander@94
   189
  strip = False
dvander@94
   190
  new_text = ''
dvander@94
   191
dvander@94
   192
  state = sReadIncludes
dvander@94
   193
  for line in re.split('\n+', text):
dvander@94
   194
    if state == sReadIncludes:
dvander@94
   195
      m = re.match('\.+\s+(.+)\s*$', line)
dvander@94
   196
      if m == None:
dvander@94
   197
        state = sLookForIncludeGuard
dvander@94
   198
      else:
dvander@94
   199
        name = m.groups()[0]
dvander@94
   200
        if os.path.exists(name):
dvander@94
   201
          strip = True
dvander@94
   202
          deps.add(name)
dvander@94
   203
        else:
dvander@94
   204
          state = LookForIncludeGuard
dvander@94
   205
    if state == sLookForIncludeGuard:
dvander@94
   206
      if line.startswith('Multiple include guards may be useful for:'):
dvander@94
   207
        state = sFoundIncludeGuard
dvander@94
   208
        strip = True
dvander@94
   209
      else:
dvander@94
   210
        state = sReadIncludes
dvander@94
   211
        strip = False
dvander@94
   212
    elif state == sFoundIncludeGuard:
dvander@94
   213
      if not line in deps:
dvander@94
   214
        strip = False
dvander@94
   215
        state = sIgnoring
dvander@94
   216
    if not strip and len(line):
dvander@94
   217
      new_text += line + '\n'
dvander@94
   218
  return new_text, deps
dvander@128
   219
dvander@128
   220
def ParseMSVCDeps(out):
dvander@128
   221
  deps = []
dvander@128
   222
  new_text = ''
dvander@128
   223
  for line in out.split('\n'):
dvander@128
   224
    m = re.match('Note: including file:\s+(.+)$', line)
dvander@128
   225
    if m != None:
dvander@128
   226
      file = m.groups()[0].strip()
dvander@128
   227
      deps.append(file)
dvander@128
   228
    else:
dvander@128
   229
      new_text += line
dvander@128
   230
  return new_text, deps
dvander@128
   231
dvander@128
   232
if hasattr(os, 'symlink'):
dvander@128
   233
  def symlink(target, link):
dvander@128
   234
    os.symlink(target, link)
dvander@130
   235
    return 0, '', ''
dvander@128
   236
elif IsWindows():
dvander@128
   237
  def symlink(target, link):
dvander@128
   238
    argv = [
dvander@128
   239
      'mklink',
dvander@128
   240
      '"{0}"'.format(link),
dvander@128
   241
      '"{0}"'.format(target)
dvander@128
   242
    ]
dvander@128
   243
    p, out, err = Execute(argv, shell=True)
dvander@128
   244
    return p.returncode, out, err
dvander@130
   245
dvander@130
   246
if IsUnixy():
dvander@130
   247
  ConsoleGreen = '\033[92m'
dvander@130
   248
  ConsoleRed = '\033[91m'
dvander@130
   249
  ConsoleNormal = '\033[0m'
dvander@130
   250
  ConsoleBlue = '\033[94m'
dvander@130
   251
  ConsoleHeader = '\033[95m'
dvander@130
   252
else:
dvander@130
   253
  ConsoleGreen = ''
dvander@130
   254
  ConsoleRed = ''
dvander@130
   255
  ConsoleNormal = ''
dvander@130
   256
  ConsoleBlue = ''
dvander@130
   257
  ConsoleHeader = ''
dvander@130
   258
dvander@130
   259
def IsColor(text):
dvander@130
   260
  return text.startswith('\033[')
dvander@130
   261
dvander@130
   262
sConsoleColorsEnabled = True
dvander@130
   263
def DisableConsoleColors():
dvander@130
   264
  global sConsoleColorsEnabled
dvander@130
   265
  sConsoleColorsEnabled = False
dvander@130
   266
dvander@130
   267
def con_print(fp, args):
dvander@130
   268
  for arg in args:
dvander@130
   269
    if not sConsoleColorsEnabled and IsColor(arg):
dvander@130
   270
      continue
dvander@130
   271
    fp.write(arg)
dvander@130
   272
  fp.write('\n')
dvander@130
   273
dvander@130
   274
def con_out(*args):
dvander@130
   275
  con_print(sys.stdout, args)
dvander@130
   276
dvander@130
   277
def con_err(*args):
dvander@130
   278
  con_print(sys.stderr, args)
dvander@163
   279
dvander@163
   280
LambdaType = type(lambda: None)
dvander@163
   281
dvander@163
   282
def IsLambda(v):
dvander@163
   283
  return type(v) == LambdaType
dvander@163
   284
dvander@167
   285
if str == bytes:
dvander@167
   286
  def IsString(v):
dvander@167
   287
    return type(v) == str or type(v) == unicode
dvander@167
   288
else:
dvander@167
   289
  def IsString(v):
dvander@167
   290
    return type(v) == str
dvander@168
   291
dvander@168
   292
class Expando(object):
dvander@168
   293
  pass